diff options
-rw-r--r-- | docs/common-patterns.rst | 7 | ||||
-rw-r--r-- | docs/contracts.rst | 47 | ||||
-rw-r--r-- | docs/control-structures.rst | 7 | ||||
-rw-r--r-- | docs/frequently-asked-questions.rst | 30 | ||||
-rw-r--r-- | docs/miscellaneous.rst | 2 | ||||
-rw-r--r-- | docs/solidity-by-example.rst | 2 | ||||
-rw-r--r-- | docs/structure-of-a-contract.rst | 50 | ||||
-rw-r--r-- | docs/types.rst | 258 | ||||
-rw-r--r-- | docs/units-and-global-variables.rst | 2 |
9 files changed, 219 insertions, 186 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst index 842b7c37..679552ff 100644 --- a/docs/common-patterns.rst +++ b/docs/common-patterns.rst @@ -179,6 +179,7 @@ function finishes. AreWeDoneYet, Finished } + // This is the current stage. Stages public stage = Stages.AcceptingBlindedBids; @@ -188,9 +189,11 @@ function finishes. if (stage != _stage) throw; _ } + function nextStage() internal { stage = Stages(uint(stage) + 1); } + // Perform timed transitions. Be sure to mention // this modifier first, otherwise the guards // will not take the new stage into account. @@ -211,6 +214,7 @@ function finishes. { // We will not implement that here } + function reveal() timedTransitions atStage(Stages.RevealBids) @@ -227,6 +231,7 @@ function finishes. _ nextStage(); } + function g() timedTransitions atStage(Stages.AnotherStage) @@ -235,12 +240,14 @@ function finishes. // If you want to use `return` here, // you have to call `nextStage()` manually. } + function h() timedTransitions atStage(Stages.AreWeDoneYet) transitionNext { } + function i() timedTransitions atStage(Stages.Finished) diff --git a/docs/contracts.rst b/docs/contracts.rst index ddfeb78c..dd75e857 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -25,27 +25,28 @@ API, this is done as follows:: // The json abi array generated by the compiler var abiArray = [ - { - "inputs":[ - {"name":"x","type":"uint256"}, - {"name":"y","type":"uint256"} - ], - "type":"constructor" - }, - { - "constant":true, - "inputs":[], - "name":"x", - "outputs":[{"name":"","type":"bytes32"}], - "type":"function" - } + { + "inputs":[ + {"name":"x","type":"uint256"}, + {"name":"y","type":"uint256"} + ], + "type":"constructor" + }, + { + "constant":true, + "inputs":[], + "name":"x", + "outputs":[{"name":"","type":"bytes32"}], + "type":"function" + } ]; var MyContract = web3.eth.contract(abiArray); // deploy new contract var contractInstance = MyContract.new( - 10, 11, - {from: myAccount, gas: 1000000} + 10, + 11, + {from: myAccount, gas: 1000000} ); .. index:: constructor;arguments @@ -375,13 +376,13 @@ possible. contract Caller { - function callTest(address testAddress) { - Test(testAddress).call(0xabcdef01); // hash does not exist - // results in Test(testAddress).x becoming == 1. - Rejector r = Rejector(0x123); - r.send(2 ether); - // results in r.balance == 0 - } + function callTest(address testAddress) { + Test(testAddress).call(0xabcdef01); // hash does not exist + // results in Test(testAddress).x becoming == 1. + Rejector r = Rejector(0x123); + r.send(2 ether); + // results in r.balance == 0 + } } .. index:: ! event diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 0a233763..8d1788d3 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -55,6 +55,8 @@ of other contracts, the amount of Wei sent with the call and the gas can be spec contract InfoFeed { function info() returns (uint ret) { return 42; } } + + contract Consumer { InfoFeed feed; function setFeed(address addr) { feed = InfoFeed(addr); } @@ -77,10 +79,12 @@ of unused parameters (especially return parameters) can be omitted. contract c { function f(uint key, uint value) { ... } + function g() { // named arguments f({value: 2, key: 3}); } + // omitted parameters function func(uint k, uint) returns(uint) { return k; @@ -212,7 +216,7 @@ In the following example, we show how `throw` can be used to easily revert an Et contract Sharer { function sendHalf(address addr) returns (uint balance) { - if (!addr.send(msg.value/2)) + if (!addr.send(msg.value / 2)) throw; // also reverts the transfer to Sharer return this.balance; } @@ -290,6 +294,7 @@ you really know what you are doing. for (uint i = 0; i < _data.length; ++i) o_sum += _data[i]; } + // We know that we only access the array in bounds, so we can avoid the check. // 0x20 needs to be added to an array because the first slot contains the // array length. diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 1b78d666..ff4d6fc0 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -692,11 +692,11 @@ 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:: - struct user{ + struct user { mapping(string => address) usedContracts; } - function somefunction{ + function somefunction { user user1; user1.usedContracts["Hello"] = "World"; user user2 = user1; @@ -715,6 +715,8 @@ You will need to make sure that you have both contracts aware of each other's pr In this example:: contract B {} + + contract A { address child; @@ -758,21 +760,21 @@ Sure. Take care that if you cross the memory / storage boundary, independent copies will be created:: contract C { - uint[20] x; + uint[20] x; - function f() { - g(x); - h(x); - } + function f() { + g(x); + h(x); + } - function g(uint[20] y) { - y[2] = 3; - } + function g(uint[20] y) { + y[2] = 3; + } - function h(uint[20] storage y) { - y[3] = 4; - } - } + function h(uint[20] storage y) { + y[3] = 4; + } + } The call to `g(x)` will not have an effect on `x` because it needs to create an independent copy of the storage value in memory diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst index f2ad0f88..19fbe85c 100644 --- a/docs/miscellaneous.rst +++ b/docs/miscellaneous.rst @@ -51,9 +51,11 @@ There are some types in Solidity's type system that have no counterpart in the s if (useB) f = b; return f(x); } + function a(uint x) returns (uint z) { return x * x; } + function b(uint x) returns (uint z) { return 2 * x; } diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 028bfa22..6aa072e3 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -292,7 +292,7 @@ activate themselves. } Blind Auction -================ +============= The previous open auction is extended to a blind auction in the following. The advantage of a blind auction is diff --git a/docs/structure-of-a-contract.rst b/docs/structure-of-a-contract.rst index 6685566d..79f78422 100644 --- a/docs/structure-of-a-contract.rst +++ b/docs/structure-of-a-contract.rst @@ -21,8 +21,8 @@ State variables are values which are permanently stored in contract storage. :: contract SimpleStorage { - uint storedData; // State variable - // ... + uint storedData; // State variable + // ... } See the :ref:`types` section for valid state variable types and @@ -39,9 +39,9 @@ Functions are the executable units of code within a contract. :: contract SimpleAuction { - function bid() { // Function - // ... - } + function bid() { // Function + // ... + } } :ref:`function-calls` can happen internally or externally @@ -59,16 +59,16 @@ Function modifiers can be used to amend the semantics of functions in a declarat :: contract Purchase { - address public seller; + address public seller; - modifier onlySeller() { // Modifier - if (msg.sender != seller) throw; - _ - } + modifier onlySeller() { // Modifier + if (msg.sender != seller) throw; + _ + } - function abort() onlySeller { // Modifier usage - // ... - } + function abort() onlySeller { // Modifier usage + // ... + } } .. _structure-events: @@ -81,12 +81,12 @@ Events are convenience interfaces with the EVM logging facilities. :: contract SimpleAuction { - event HighestBidIncreased(address bidder, uint amount); // Event + event HighestBidIncreased(address bidder, uint amount); // Event - function bid() { - // ... - HighestBidIncreased(msg.sender, msg.value); // Triggering event - } + function bid() { + // ... + HighestBidIncreased(msg.sender, msg.value); // Triggering event + } } See :ref:`events` in contracts section for information on how events are declared @@ -103,12 +103,12 @@ Structs are custom defined types that can group several variables (see :: contract Ballot { - struct Voter { // Struct - uint weight; - bool voted; - address delegate; - uint vote; - } + struct Voter { // Struct + uint weight; + bool voted; + address delegate; + uint vote; + } } .. _structure-enum-types: @@ -122,5 +122,5 @@ Enums can be used to create custom types with a finite set of values (see :: contract Purchase { - enum State { Created, Locked, Inactive } // Enum + enum State { Created, Locked, Inactive } // Enum } diff --git a/docs/types.rst b/docs/types.rst index bd972bef..4beea9e0 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -171,21 +171,21 @@ to and from all integer types but implicit conversion is not allowed. enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } ActionChoices choice; ActionChoices constant defaultChoice = ActionChoices.GoStraight; - function setGoStraight() - { + + function setGoStraight() { choice = ActionChoices.GoStraight; } + // Since enum types are not part of the ABI, the signature of "getChoice" // will automatically be changed to "getChoice() returns (uint8)" // for all matters external to Solidity. The integer type used is just // large enough to hold all enum values, i.e. if you have more values, // `uint16` will be used and so on. - function getChoice() returns (ActionChoices) - { + function getChoice() returns (ActionChoices) { return choice; } - function getDefaultChoice() returns (uint) - { + + function getDefaultChoice() returns (uint) { return uint(defaultChoice); } } @@ -226,26 +226,28 @@ memory-stored reference type does not create a copy. :: - contract c { - uint[] x; // the data location of x is storage - // the data location of memoryArray is memory - function f(uint[] memoryArray) { - x = memoryArray; // works, copies the whole array to storage - var y = x; // works, assigns a pointer, data location of y is storage - y[7]; // fine, returns the 8th element - y.length = 2; // fine, modifies x through y - delete x; // fine, clears the array, also modifies y - // The following does not work; it would need to create a new temporary / - // unnamed array in storage, but storage is "statically" allocated: - // y = memoryArray; - // This does not work either, since it would "reset" the pointer, but there - // is no sensible location it could point to. - // delete y; - g(x); // calls g, handing over a reference to x - h(x); // calls h and creates an independent, temporary copy in memory - } - function g(uint[] storage storageArray) internal {} - function h(uint[] memoryArray) {} + contract C { + uint[] x; // the data location of x is storage + + // the data location of memoryArray is memory + function f(uint[] memoryArray) { + x = memoryArray; // works, copies the whole array to storage + var y = x; // works, assigns a pointer, data location of y is storage + y[7]; // fine, returns the 8th element + y.length = 2; // fine, modifies x through y + delete x; // fine, clears the array, also modifies y + // The following does not work; it would need to create a new temporary / + // unnamed array in storage, but storage is "statically" allocated: + // y = memoryArray; + // This does not work either, since it would "reset" the pointer, but there + // is no sensible location it could point to. + // delete y; + g(x); // calls g, handing over a reference to x + h(x); // calls h and creates an independent, temporary copy in memory + } + + function g(uint[] storage storageArray) internal {} + function h(uint[] memoryArray) {} } Summary @@ -303,12 +305,12 @@ the `.length` member. :: contract C { - function f(uint len) { - uint[] memory a = new uint[](7); - bytes memory b = new bytes(len); - // Here we have a.length == 7 and b.length == len - a[6] = 8; - } + function f(uint len) { + uint[] memory a = new uint[](7); + bytes memory b = new bytes(len); + // Here we have a.length == 7 and b.length == len + a[6] = 8; + } } @@ -339,51 +341,59 @@ Members :: contract ArrayContract { - uint[2**20] m_aLotOfIntegers; - // Note that the following is not a pair of arrays but an array of pairs. - bool[2][] m_pairsOfFlags; - // newPairs is stored in memory - the default for function arguments - function setAllFlagPairs(bool[2][] newPairs) { - // assignment to a storage array replaces the complete array - m_pairsOfFlags = newPairs; - } - function setFlagPair(uint index, bool flagA, bool flagB) { - // access to a non-existing index will throw an exception - m_pairsOfFlags[index][0] = flagA; - m_pairsOfFlags[index][1] = flagB; - } - function changeFlagArraySize(uint newSize) { - // if the new size is smaller, removed array elements will be cleared - m_pairsOfFlags.length = newSize; - } - function clear() { - // these clear the arrays completely - delete m_pairsOfFlags; - delete m_aLotOfIntegers; - // identical effect here - m_pairsOfFlags.length = 0; - } - bytes m_byteData; - function byteArrays(bytes data) { - // byte arrays ("bytes") are different as they are stored without padding, - // but can be treated identical to "uint8[]" - m_byteData = data; - m_byteData.length += 7; - m_byteData[3] = 8; - delete m_byteData[2]; - } - function addFlag(bool[2] flag) returns (uint) { - return m_pairsOfFlags.push(flag); - } - function createMemoryArray(uint size) returns (bytes) { - // Dynamic memory arrays are created using `new`: - uint[2][] memory arrayOfPairs = new uint[2][](size); - // Create a dynamic byte array: - bytes memory b = new bytes(200); - for (uint i = 0; i < b.length; i++) - b[i] = byte(i); - return b; - } + uint[2**20] m_aLotOfIntegers; + // Note that the following is not a pair of arrays but an array of pairs. + bool[2][] m_pairsOfFlags; + // newPairs is stored in memory - the default for function arguments + + function setAllFlagPairs(bool[2][] newPairs) { + // assignment to a storage array replaces the complete array + m_pairsOfFlags = newPairs; + } + + function setFlagPair(uint index, bool flagA, bool flagB) { + // access to a non-existing index will throw an exception + m_pairsOfFlags[index][0] = flagA; + m_pairsOfFlags[index][1] = flagB; + } + + function changeFlagArraySize(uint newSize) { + // if the new size is smaller, removed array elements will be cleared + m_pairsOfFlags.length = newSize; + } + + function clear() { + // these clear the arrays completely + delete m_pairsOfFlags; + delete m_aLotOfIntegers; + // identical effect here + m_pairsOfFlags.length = 0; + } + + bytes m_byteData; + + function byteArrays(bytes data) { + // byte arrays ("bytes") are different as they are stored without padding, + // but can be treated identical to "uint8[]" + m_byteData = data; + m_byteData.length += 7; + m_byteData[3] = 8; + delete m_byteData[2]; + } + + function addFlag(bool[2] flag) returns (uint) { + return m_pairsOfFlags.push(flag); + } + + function createMemoryArray(uint size) returns (bytes) { + // Dynamic memory arrays are created using `new`: + uint[2][] memory arrayOfPairs = new uint[2][](size); + // Create a dynamic byte array: + bytes memory b = new bytes(200); + for (uint i = 0; i < b.length; i++) + b[i] = byte(i); + return b; + } } @@ -400,41 +410,46 @@ shown in the following example: :: contract CrowdFunding { - // Defines a new type with two fields. - struct Funder { - address addr; - uint amount; - } - struct Campaign { - address beneficiary; - uint fundingGoal; - uint numFunders; - uint amount; - mapping (uint => Funder) funders; - } - uint numCampaigns; - mapping (uint => Campaign) campaigns; - function newCampaign(address beneficiary, uint goal) returns (uint campaignID) { - campaignID = numCampaigns++; // campaignID is return variable - // Creates new struct and saves in storage. We leave out the mapping type. - campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0); - } - function contribute(uint campaignID) { - Campaign c = campaigns[campaignID]; + // Defines a new type with two fields. + struct Funder { + address addr; + uint amount; + } + + struct Campaign { + address beneficiary; + uint fundingGoal; + uint numFunders; + uint amount; + mapping (uint => Funder) funders; + } + + uint numCampaigns; + mapping (uint => Campaign) campaigns; + + function newCampaign(address beneficiary, uint goal) returns (uint campaignID) { + campaignID = numCampaigns++; // campaignID is return variable + // Creates new struct and saves in storage. We leave out the mapping type. + campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0); + } + + function contribute(uint campaignID) { + Campaign c = campaigns[campaignID]; // Creates a new temporary memory struct, initialised with the given values // and copies it over to storage. // Note that you can also use Funder(msg.sender, msg.value) to initialise. - c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value}); - c.amount += msg.value; - } - function checkGoalReached(uint campaignID) returns (bool reached) { - Campaign c = campaigns[campaignID]; - if (c.amount < c.fundingGoal) - return false; - c.beneficiary.send(c.amount); - c.amount = 0; - return true; - } + c.funders[c.numFunders++] = Funder({addr: msg.sender, amount: msg.value}); + c.amount += msg.value; + } + + function checkGoalReached(uint campaignID) returns (bool reached) { + Campaign c = campaigns[campaignID]; + if (c.amount < c.fundingGoal) + return false; + c.beneficiary.send(c.amount); + c.amount = 0; + return true; + } } The contract does not provide the full functionality of a crowdfunding @@ -495,18 +510,19 @@ It is important to note that `delete a` really behaves like an assignment to `a` :: contract DeleteExample { - uint data; - uint[] dataArray; - function f() { - uint x = data; - delete x; // sets x to 0, does not affect data - delete data; // sets data to 0, does not affect x which still holds a copy - uint[] y = dataArray; - delete dataArray; // this sets dataArray.length to zero, but as uint[] is a complex object, also - // y is affected which is an alias to the storage object - // On the other hand: "delete y" is not valid, as assignments to local variables - // referencing storage objects can only be made from existing storage objects. - } + uint data; + uint[] dataArray; + + function f() { + uint x = data; + delete x; // sets x to 0, does not affect data + delete data; // sets data to 0, does not affect x which still holds a copy + uint[] y = dataArray; + delete dataArray; // this sets dataArray.length to zero, but as uint[] is a complex object, also + // y is affected which is an alias to the storage object + // On the other hand: "delete y" is not valid, as assignments to local variables + // referencing storage objects can only be made from existing storage objects. + } } .. index:: ! type;conversion, ! cast diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst index 05fb4b3c..9ddf52b1 100644 --- a/docs/units-and-global-variables.rst +++ b/docs/units-and-global-variables.rst @@ -35,7 +35,7 @@ These suffixes cannot be applied to variables. If you want to interpret some input variable in e.g. days, you can do it in the following way:: function f(uint start, uint daysAfter) { - if (now >= start + daysAfter * 1 days) { ... } + if (now >= start + daysAfter * 1 days) { ... } } Special Variables and Functions |