diff options
Diffstat (limited to 'docs')
-rw-r--r-- | docs/solidity-by-example.rst | 46 | ||||
-rw-r--r-- | docs/types.rst | 22 |
2 files changed, 33 insertions, 35 deletions
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 7d325746..adf00546 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -90,7 +90,7 @@ of votes. // If the first argument of `require` evaluates // to `false`, execution terminates and all // changes to the state and to Ether balances - // are reverted. + // are reverted. // This used to consume all gas in old EVM versions, but // not anymore. // It is often a good idea to use `require` to check if @@ -708,7 +708,7 @@ For a contract that fulfills payments, the signed message must include: A replay attack is when a signed message is reused to claim authorization for a second action. To avoid replay attacks we will use the same as in Ethereum transactions -themselves, a so-called nonce, which is the number of transactions sent by an +themselves, a so-called nonce, which is the number of transactions sent by an account. The smart contract will check if a nonce is used multiple times. @@ -731,7 +731,7 @@ Packing arguments Now that we have identified what information to include in the signed message, we are ready to put the message together, hash it, and sign it. For simplicity, we just concatenate the data. -The +The `ethereumjs-abi <https://github.com/ethereumjs/ethereumjs-abi>`_ library provides a function called ``soliditySHA3`` that mimics the behavior of Solidity's ``keccak256`` function applied to arguments encoded @@ -750,7 +750,7 @@ creates the proper signature for the ``ReceiverPays`` example: ["address", "uint256", "uint256", "address"], [recipient, amount, nonce, contractAddress] ).toString("hex"); - + web3.personal.sign(hash, web3.eth.defaultAccount, callback); } @@ -779,7 +779,7 @@ at the end of this chapter). Computing the Message Hash -------------------------- - + The smart contract needs to know exactly what parameters were signed, and so it must recreate the message from the parameters and use that for signature verification. The functions ``prefixed`` and @@ -801,7 +801,7 @@ The full contract constructor() public payable {} - function claimPayment(uint256 amount, uint256 nonce, bytes signature) public { + function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) public { require(!usedNonces[nonce]); usedNonces[nonce] = true; @@ -820,7 +820,7 @@ The full contract } /// signature methods. - function splitSignature(bytes sig) + function splitSignature(bytes memory sig) internal pure returns (uint8 v, bytes32 r, bytes32 s) @@ -839,7 +839,7 @@ The full contract return (v, r, s); } - function recoverSigner(bytes32 message, bytes sig) + function recoverSigner(bytes32 message, bytes memory sig) internal pure returns (address) @@ -874,7 +874,7 @@ two parties (Alice and Bob). Using it involves three steps: 1. Alice funds a smart contract with Ether. This "opens" the payment channel. 2. Alice signs messages that specify how much of that Ether is owed to the recipient. This step is repeated for each payment. 3. Bob "closes" the payment channel, withdrawing their portion of the Ether and sending the remainder back to the sender. - + Not ethat only steps 1 and 3 require Ethereum transactions, step 2 means that the sender transmits a cryptographically signed message to the recipient via off chain ways (e.g. email). This means only two transactions are required to support any number of transfers. @@ -906,7 +906,7 @@ Each message includes the following information: * The smart contract's address, used to prevent cross-contract replay attacks. * The total amount of Ether that is owed the recipient so far. - + A payment channel is closed just once, at the of a series of transfers. Because of this, only one of the messages sent will be redeemed. This is why each message specifies a cumulative total amount of Ether owed, rather than the @@ -926,7 +926,7 @@ Here is the modified javascript code to cryptographically sign a message from th [contractAddress, amount] ); } - + function signMessage(message, callback) { web3.personal.sign( "0x" + message.toString("hex"), @@ -934,10 +934,10 @@ Here is the modified javascript code to cryptographically sign a message from th callback ); } - + // contractAddress is used to prevent cross-contract replay attacks. // amount, in wei, specifies how much Ether should be sent. - + function signPayment(contractAddress, amount, callback) { var message = constructPaymentMessage(contractAddress, amount); signMessage(message, callback); @@ -1003,7 +1003,7 @@ The full contract expiration = now + duration; } - function isValidSignature(uint256 amount, bytes signature) + function isValidSignature(uint256 amount, bytes memory signature) internal view returns (bool) @@ -1017,7 +1017,7 @@ The full contract /// the recipient can close the channel at any time by presenting a /// signed amount from the sender. the recipient will be sent that amount, /// and the remainder will go back to the sender - function close(uint256 amount, bytes signature) public { + function close(uint256 amount, bytes memory signature) public { require(msg.sender == recipient); require(isValidSignature(amount, signature)); @@ -1043,7 +1043,7 @@ The full contract /// All functions below this are just taken from the chapter /// 'creating and verifying signatures' chapter. - function splitSignature(bytes sig) + function splitSignature(bytes memory sig) internal pure returns (uint8 v, bytes32 r, bytes32 s) @@ -1058,11 +1058,11 @@ The full contract // final byte (first byte of the next 32 bytes) v := byte(0, mload(add(sig, 96))) } - + return (v, r, s); } - - function recoverSigner(bytes32 message, bytes sig) + + function recoverSigner(bytes32 message, bytes memory sig) internal pure returns (address) @@ -1083,7 +1083,7 @@ Note: The function ``splitSignature`` is very simple and does not use all securi A real implementation should use a more rigorously tested library, such as openzepplin's `version <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/ECRecovery.sol>`_ of this code. - + Verifying Payments ------------------ @@ -1101,7 +1101,7 @@ The recipient should verify each message using the following process: 2. Verify that the new total is the expected amount. 3. Verify that the new total does not exceed the amount of Ether escrowed. 4. Verify that the signature is valid and comes from the payment channel sender. - + We'll use the `ethereumjs-util <https://github.com/ethereumjs/ethereumjs-util>`_ library to write this verifications. The final step can be done a number of ways, but if it's being done in **JavaScript**. @@ -1117,14 +1117,14 @@ above: ["\x19Ethereum Signed Message:\n32", hash] ); } - + function recoverSigner(message, signature) { var split = ethereumjs.Util.fromRpcSig(signature); var publicKey = ethereumjs.Util.ecrecover(message, split.v, split.r, split.s); var signer = ethereumjs.Util.pubToAddress(publicKey).toString("hex"); return signer; } - + function isValidSignature(contractAddress, amount, signature, expectedSigner) { var message = prefixed(constructPaymentMessage(contractAddress, amount)); var signer = recoverSigner(message, signature); diff --git a/docs/types.rst b/docs/types.rst index 18400dee..0e0f4b13 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -580,16 +580,18 @@ variables are held). Data location ------------- + Every complex type, i.e. *arrays* and *structs*, has an additional -annotation, the "data location", about whether it is stored in memory or in storage. Depending on the -context, there is always a default, but it can be overridden by appending -either ``storage`` or ``memory`` to the type. The default for function parameters (including return parameters) is ``memory``, the default for local variables is ``storage`` and the location is forced -to ``storage`` for state variables (obviously). +annotation, the "data location", about where it is stored. There are three data locations: +``memory``, ``storage`` and ``calldata``. Calldata is only valid for parameters of external contract +functions and is required for this type of parameter. Calldata is a non-modifiable, +non-persistent area where function arguments are stored, and behaves mostly like memory. + -There is also a third data location, ``calldata``, which is a non-modifiable, -non-persistent area where function arguments are stored. Function parameters -(not return parameters) of external functions are forced to ``calldata`` and -behave mostly like ``memory``. +.. note:: + Prior to version 0.5.0 the data location could be omitted, and would default to different locations + depending on the kind of variable, function type, etc., but all complex types must now give an explicit + data location. Data locations are important because they change how assignments behave: assignments between storage and memory and also to a state variable (even from other state variables) @@ -635,10 +637,6 @@ Forced data location: - parameters (not return) of external functions: calldata - state variables: storage -Default data location: - - parameters (also return) of functions: memory - - all other local variables: storage - .. index:: ! array .. _arrays: |