常见问题解答¶

This list was originally compiled by fivedogit.

Basic Questions¶

Is it possible to do something on a specific block number? (e.g. publish a contract or execute a transaction)¶

Transactions are not guaranteed to happen on the next block or any futurespecific block, since it is up to the miners to include transactions and not upto the submitter of the transaction. This applies to function calls/transactions and contractcreation transactions.

If you want to schedule future calls of your contract, you can use thealarm clock.

What is the transaction “payload”?¶

This is just the bytecode “data” sent along with the request.

Is there a decompiler available?¶

There is no exact decompiler to Solidity, butPorosity is close.Because some information like variable names, comments, andsource code formatting is lost in the compilation process,it is not possible to completely recover the original source code.

Bytecode can be disassembled to opcodes, a service that is provided byseveral blockchain explorers.

Contracts on the blockchain should have their original sourcecode published if they are to be used by third parties.

Create a contract that can be killed and return funds¶

First, a word of warning: Killing contracts sounds like a good idea, because “cleaning up”is always good, but as seen above, it does not really clean up. Furthermore,if Ether is sent to removed contracts, the Ether will be forever lost.

If you want to deactivate your contracts, it is preferable to disable them by changing someinternal state which causes all functions to throw. This will make it impossibleto use the contract and ether sent to the contract will be returned automatically.

Now to answering the question: Inside a constructor, msg.sender is thecreator. Save it. Then selfdestruct(creator); to kill and return funds.

example

Note that if you import "mortal" at the top of your contracts and declarecontract SomeContract is mortal { and compile with a compiler that alreadyhas it (which includes Remix), thenkill() is taken care of for you. Once a contract is “mortal”, then you cancontractname.kill.sendTransaction({from:eth.coinbase}), just the same as myexamples.

Can you return an array or a string from a solidity function call?¶

Yes. See array_receiver_and_returner.sol.

What is problematic, though, is returning any variably-sized data (e.g. avariably-sized array like uint[]) from a fuction called from within Solidity.This is a limitation of the EVM and will be solved with the next protocol update.

Returning variably-sized data as part of an external transaction or call is fine.

Is it possible to in-line initialize an array like so: string[] myarray = ["a", "b"];¶

Yes. However it should be noted that this currently only works with statically sized memory arrays. You can even create an inline memoryarray in the return statement. Pretty cool, huh?

Example:

  1. pragma solidity ^0.4.16;
  2.  
  3. contract C {
  4. function f() public pure returns (uint8[5]) {
  5. string[4] memory adaArr = ["This", "is", "an", "array"];
  6. return ([1, 2, 3, 4, 5]);
  7. }
  8. }

Can a contract function return a struct?¶

Yes, but only in internal function calls.

If I return an enum, I only get integer values in web3.js. How to get the named values?¶

Enums are not supported by the ABI, they are just supported by Solidity.You have to do the mapping yourself for now, we might provide some helplater.

Can state variables be initialized in-line?¶

Yes, this is possible for all types (even for structs). However, for arrays itshould be noted that you must declare them as static memory arrays.

Examples:

  1. pragma solidity ^0.4.0;
  2.  
  3. contract C {
  4. struct S {
  5. uint a;
  6. uint b;
  7. }
  8.  
  9. S public x = S(1, 2);
  10. string name = "Ada";
  11. string[4] adaArr = ["This", "is", "an", "array"];
  12. }
  13.  
  14. contract D {
  15. C c = new C();
  16. }

How do structs work?¶

See struct_and_for_loop_tester.sol.

How do for loops work?¶

Very similar to JavaScript. There is one point to watch out for, though:

If you use for (var i = 0; i < a.length; i ++) { a[i] = i; }, thenthe type of i will be inferred only from 0, whose type is uint8.This means that if a has more than 255 elements, your loop willnot terminate because i can only hold values up to 255.

Better use for (uint i = 0; i < a.length…

See struct_and_for_loop_tester.sol.

What are some examples of basic string manipulation (substring, indexOf, charAt, etc)?¶

There are some string utility functions at stringUtils.solwhich will be extended in the future. In addition, Arachnid has written solidity-stringutils.

For now, if you want to modify a string (even when you only want to know its length),you should always convert it to a bytes first:

  1. pragma solidity ^0.4.0;
  2.  
  3. contract C {
  4. string s;
  5.  
  6. function append(byte c) public {
  7. bytes(s).push(c);
  8. }
  9.  
  10. function set(uint i, byte c) public {
  11. bytes(s)[i] = c;
  12. }
  13. }

Can I concatenate two strings?¶

You have to do it manually for now.

Why is the low-level function .call() less favorable than instantiating a contract with a variable (ContractB b;) and executing its functions (b.doSomething();)?¶

If you use actual functions, the compiler will tell you if the typesor your arguments do not match, if the function does not existor is not visible and it will do the packing of thearguments for you.

See ping.sol andpong.sol.

Is unused gas automatically refunded?¶

Yes and it is immediate, i.e. done as part of the transaction.

When returning a value of say uint type, is it possible to return an undefined or “null”-like value?¶

This is not possible, because all types use up the full value range.

You have the option to throw on error, which will also revert the wholetransaction, which might be a good idea if you ran into an unexpectedsituation.

If you do not want to throw, you can return a pair:

  1. pragma solidity ^0.4.16;
  2.  
  3. contract C {
  4. uint[] counters;
  5.  
  6. function getCounter(uint index)
  7. public
  8. view
  9. returns (uint counter, bool error) {
  10. if (index >= counters.length)
  11. return (0, true);
  12. else
  13. return (counters[index], false);
  14. }
  15.  
  16. function checkCounter(uint index) public view {
  17. var (counter, error) = getCounter(index);
  18. if (error) {
  19. // ...
  20. } else {
  21. // ...
  22. }
  23. }
  24. }

Are comments included with deployed contracts and do they increase deployment gas?¶

No, everything that is not needed for execution is removed during compilation.This includes, among others, comments, variable names and type names.

What happens if you send ether along with a function call to a contract?¶

It gets added to the total balance of the contract, just like when you send ether when creating a contract.You can only send ether along to a function that has the payable modifier,otherwise an exception is thrown.

Is it possible to get a tx receipt for a transaction executed contract-to-contract?¶

No, a function call from one contract to another does not create its own transaction,you have to look in the overall transaction. This is also the reason why severalblock explorer do not show Ether sent between contracts correctly.

What is the memory keyword? What does it do?¶

The Ethereum Virtual Machine has three areas where it can store items.

The first is “storage”, where all the contract state variables reside.Every contract has its own storage and it is persistent between function callsand quite expensive to use.

The second is “memory”, this is used to hold temporary values. Itis erased between (external) function calls and is cheaper to use.

The third one is the stack, which is used to hold small local variables.It is almost free to use, but can only hold a limited amount of values.

For almost all types, you cannot specify where they should be stored, becausethey are copied everytime they are used.

The types where the so-called storage location is important are structsand arrays. If you e.g. pass such variables in function calls, theirdata is not copied if it can stay in memory or stay in storage.This means that you can modify their content in the called functionand these modifications will still be visible in the caller.

There are defaults for the storage location depending on which typeof variable it concerns:

  • state variables are always in storage
  • function arguments are in memory by default
  • local variables of struct, array or mapping type reference storage by default
  • local variables of value type (i.e. neither array, nor struct nor mapping) are stored in the stack
    Example:
  1. pragma solidity ^0.4.0;
  2.  
  3. contract C {
  4. uint[] data1;
  5. uint[] data2;
  6.  
  7. function appendOne() public {
  8. append(data1);
  9. }
  10.  
  11. function appendTwo() public {
  12. append(data2);
  13. }
  14.  
  15. function append(uint[] storage d) internal {
  16. d.push(1);
  17. }
  18. }

The function append can work both on data1 and data2 and its modifications will bestored permanently. If you remove the storage keyword, the defaultis to use memory for function arguments. This has the effect thatat the point where append(data1) or append(data2) is called, anindependent copy of the state variable is created in memory andappend operates on this copy (which does not support .push - but thatis another issue). The modifications to this independent copy do notcarry back to data1 or data2.

A common mistake is to declare a local variable and assume that it willbe created in memory, although it will be created in storage:

  1. /// THIS CONTRACT CONTAINS AN ERROR
  2.  
  3. pragma solidity ^0.4.0;
  4.  
  5. contract C {
  6. uint someVariable;
  7. uint[] data;
  8.  
  9. function f() public {
  10. uint[] x;
  11. x.push(2);
  12. data = x;
  13. }
  14. }

The type of the local variable x is uint[] storage, but sincestorage is not dynamically allocated, it has to be assigned froma state variable before it can be used. So no space in storage will beallocated for x, but instead it functions only as an alias fora pre-existing variable in storage.

What will happen is that the compiler interprets x as a storagepointer and will make it point to the storage slot 0 by default.This has the effect that someVariable (which resides at storageslot 0) is modified by x.push(2).

The correct way to do this is the following:

  1. pragma solidity ^0.4.0;
  2.  
  3. contract C {
  4. uint someVariable;
  5. uint[] data;
  6.  
  7. function f() public {
  8. uint[] x = data;
  9. x.push(2);
  10. }
  11. }

Advanced Questions¶

How do you get a random number in a contract? (Implement a self-returning gambling contract.)¶

Getting randomness right is often the crucial part in a crypto project andmost failures result from bad random number generators.

If you do not want it to be safe, you build something similar to the coin flipperbut otherwise, rather use a contract that supplies randomness, like the RANDAO.

Get return value from non-constant function from another contract¶

The key point is that the calling contract needs to know about the function it intends to call.

See ping.soland pong.sol.

Get contract to do something when it is first mined¶

Use the constructor. Anything inside it will be executed when the contract is first mined.

See replicator.sol.

How do you create 2-dimensional arrays?¶

See 2D_array.sol.

Note that filling a 10x10 square of uint8 + contract creation took more than 800,000gas at the time of this writing. 17x17 took 2,000,000 gas. With the limit at3.14 million… well, there’s a pretty low ceiling for what you can create rightnow.

Note that merely “creating” the array is free, the costs are in filling it.

Note2: Optimizing storage access can pull the gas costs down considerably, because32 uint8 values can be stored in a single slot. The problem is that these optimizationscurrently do not work across loops and also have a problem with bounds checking.You might get much better results in the future, though.

What happens to a struct’s mapping when copying over a struct?¶

This is a very interesting question. Suppose that we have a contract field set up like such:

  1. struct User {
  2. mapping(string => string) comments;
  3. }
  4.  
  5. function somefunction public {
  6. User user1;
  7. user1.comments["Hello"] = "World";
  8. User user2 = user1;
  9. }

In this case, the mapping of the struct being copied over into the userList is ignored as there is no “list of mapped keys”.Therefore it is not possible to find out which values should be copied over.

How do I initialize a contract with only a specific amount of wei?¶

Currently the approach is a little ugly, but there is little that can be done to improve it.In the case of a contract A calling a new instance of contract B, parentheses have to be used aroundnew B because B.value would refer to a member of B called value.You will need to make sure that you have both contracts aware of each other’s presence and that contract B has a payable constructor.In this example:

  1. pragma solidity ^0.4.0;
  2.  
  3. contract B {
  4. function B() public payable {}
  5. }
  6.  
  7. contract A {
  8. address child;
  9.  
  10. function test() public {
  11. child = (new B).value(10)(); //construct a new B with 10 wei
  12. }
  13. }

Can a contract function accept a two-dimensional array?¶

This is not yet implemented for external calls and dynamic arrays -you can only use one level of dynamic arrays.

What is the relationship between bytes32 and string? Why is it that bytes32 somevar = "stringliteral"; works and what does the saved 32-byte hex value mean?¶

The type bytes32 can hold 32 (raw) bytes. In the assignment bytes32 samevar = "stringliteral";,the string literal is interpreted in its raw byte form and if you inspect somevar andsee a 32-byte hex value, this is just "stringliteral" in hex.

The type bytes is similar, only that it can change its length.

Finally, string is basically identical to bytes only that it is assumedto hold the UTF-8 encoding of a real string. Since string stores thedata in UTF-8 encoding it is quite expensive to compute the number ofcharacters in the string (the encoding of some characters takes morethan a single byte). Because of that, string s; s.length is not yetsupported and not even index access s[2]. But if you want to accessthe low-level byte encoding of the string, you can usebytes(s).length and bytes(s)[2] which will result in the numberof bytes in the UTF-8 encoding of the string (not the number ofcharacters) and the second byte (not character) of the UTF-8 encodedstring, respectively.

Can a contract pass an array (static size) or string or bytes (dynamic size) to another contract?¶

Sure. Take care that if you cross the memory / storage boundary,independent copies will be created:

  1. pragma solidity ^0.4.16;
  2.  
  3. contract C {
  4. uint[20] x;
  5.  
  6. function f() public {
  7. g(x);
  8. h(x);
  9. }
  10.  
  11. function g(uint[20] y) internal pure {
  12. y[2] = 3;
  13. }
  14.  
  15. function h(uint[20] storage y) internal {
  16. y[3] = 4;
  17. }
  18. }

The call to g(x) will not have an effect on x because it needsto create an independent copy of the storage value in memory(the default storage location is memory). On the other hand,h(x) successfully modifies x because only a referenceand not a copy is passed.

Sometimes, when I try to change the length of an array with ex: arrayname.length = 7; I get a compiler error Value must be an lvalue. Why?¶

You can resize a dynamic array in storage (i.e. an array declared at thecontract level) with arrayname.length = <some new length>;. If you get the“lvalue” error, you are probably doing one of two things wrong.

  • You might be trying to resize an array in “memory”, or
  • You might be trying to resize a non-dynamic array.
  1. // This will not compile
  2.  
  3. pragma solidity ^0.4.18;
  4.  
  5. contract C {
  6. int8[] dynamicStorageArray;
  7. int8[5] fixedStorageArray;
  8.  
  9. function f() {
  10. int8[] memory memArr; // Case 1
  11. memArr.length++; // illegal
  12.  
  13. int8[5] storage storageArr = fixedStorageArray; // Case 2
  14. storageArr.length++; // illegal
  15.  
  16. int8[] storage storageArr2 = dynamicStorageArray;
  17. storageArr2.length++; // legal
  18.  
  19.  
  20. }
  21. }

Important note: In Solidity, array dimensions are declared backwards from the way youmight be used to declaring them in C or Java, but they are access as inC or Java.

For example, int8[][5] somearray; are 5 dynamic int8 arrays.

The reason for this is that T[5] is always an array of 5 T’s,no matter whether T itself is an array or not (this is not thecase in C or Java).

Is it possible to return an array of strings (string[]) from a Solidity function?¶

Not yet, as this requires two levels of dynamic arrays (string is a dynamic array itself).

If you issue a call for an array, it is possible to retrieve the whole array? Or must you write a helper function for that?¶

The automatic getter function for a public state variable of array type only returnsindividual elements. If you want to return the complete array, you have tomanually write a function to do that.

What could have happened if an account has storage value(s) but no code? Example: http://test.ether.camp/account/5f740b3a43fbb99724ce93a879805f4dc89178b5¶

The last thing a constructor does is returning the code of the contract.The gas costs for this depend on the length of the code and it might bethat the supplied gas is not enough. This situation is the only onewhere an “out of gas” exception does not revert changes to the state,i.e. in this case the initialisation of the state variables.

https://github.com/ethereum/wiki/wiki/Subtleties

After a successful CREATE operation’s sub-execution, if the operation returns x, 5 len(x) gas is subtracted from the remaining gas before the contract is created. If the remaining gas is less than 5 len(x), then no gas is subtracted, the code of the created contract becomes the empty string, but this is not treated as an exceptional condition - no reverts happen.

What does the following strange check do in the Custom Token contract?¶

  1. require((balanceOf[_to] + _value) >= balanceOf[_to]);

Integers in Solidity (and most other machine-related programming languages) are restricted to a certain range.For uint256, this is 0 up to 2**256 - 1. If the result of some operation on those numbersdoes not fit inside this range, it is truncated. These truncations can haveserious consequences, so code like the oneabove is necessary to avoid certain attacks.

More Questions?¶

If you have more questions or your question is not answered here, please talk to us ongitter or file an issue.

原文: http://solidity.apachecn.org/cn/doc/v0.4.21/frequently-asked-questions.html