A sequence number, issued by the originating EOA, used to prevent message replay
The price of gas (in wei) the originator is willing to pay
The maximum amount of gas the originator is willing to buy for this transaction
The destination Ethereum address
The amount of ether to send to the destination
The variable-length binary data payload
The three components of an ECDSA digital signature of the originating EOA
nonce: A scalar value equal to the number of transactions sent from this address or, in the case of accounts with associated code, the number of contract-creations made by this account.
Imagine you wish to make two transactions. You have an important payment to make of 6 ether, and also another payment of 8 ether. You sign and broadcast the 6-ether transaction first, because it is the more important one, and then you sign and broadcast the second, 8-ether transaction. Sadly, you have overlooked the fact that your account contains only 10 ether, so the network can’t accept both transactions: one of them will fail. Because you sent the more important 6-ether one first, you understandably expect that one to go through and the 8-ether one to be rejected. However, in a decentralized system like Ethereum, nodes may receive the transactions in either order; there is no guarantee that a particular node will have one transaction propagated to it before the other. As such, it will almost certainly be the case that some nodes receive the 6-ether transaction first and others receive the 8-ether transaction first. Without the nonce, it would be random as to which one gets accepted and which rejected. However, with the nonce included, the first transaction you sent will have a nonce of, let’s say, 3, while the 8-ether transaction has the next nonce value (i.e., 4). So, that transaction will be ignored until the transactions with nonces from 0 to 3 have been processed, even if it is received first. Phew!
Now imagine you have an account with 100 ether. Fantastic! You find someone online who will accept payment in ether for a mcguffin-widget that you really want to buy. You send them 2 ether and they send you the mcguffin-widget. Lovely. To make that 2-ether payment, you signed a transaction sending 2 ether from your account to their account, and then broadcast it to the Ethereum network to be verified and included on the blockchain. Now, without a nonce value in the transaction, a second transaction sending 2 ether to the same address a second time will look exactly the same as the first transaction. This means that anyone who sees your transaction on the Ethereum network (which means everyone, including the recipient or your enemies) can “replay” the transaction again and again and again until all your ether is gone simply by copying and pasting your original transaction and resending it to the network. However, with the nonce value included in the transaction data, every single transaction is unique, even when sending the same amount of ether to the same recipient address multiple times. Thus, by having the incrementing nonce as part of the transaction, it is simply not possible for anyone to “duplicate” a payment you have made.
> web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f")
40
> web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", \
"pending")
40
> web3.eth.sendTransaction({from: web3.eth.accounts[0], to: \
"0xB0920c523d582040f2BCB1bD7FB1c7C1ECEbdB34", value: web3.toWei(0.01, "ether")});
> web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", \
"pending")
41
> web3.eth.sendTransaction({from: web3.eth.accounts[0], to: \
"0xB0920c523d582040f2BCB1bD7FB1c7C1ECEbdB34", value: web3.toWei(0.01, "ether")});
> web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", \
"pending")
41
> web3.eth.sendTransaction({from: web3.eth.accounts[0], to: \
"0xB0920c523d582040f2BCB1bD7FB1c7C1ECEbdB34", value: web3.toWei(0.01, "ether")});
> web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f", \
"pending")
41
$ curl --data '{"method":"parity_nextNonce", \
"params":["0x9e713963a92c02317a681b9bb3065a8249de124f"],\
"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST \
localhost:8545
{"jsonrpc":"2.0","result":"0x32","id":1}
The web3 interface offers a gasPrice suggestion, by calculating a median price across several blocks (we can use the truffle console or any JavaScript web3 console to do that):
> web3.eth.getGasPrice(console.log)
> null BigNumber { s: 1, e: 10, c: [ 10000000000 ] }
The second important field related to gas is gasLimit. In simple terms, gasLimit gives the maximum number of units of gas the transaction originator is willing to buy in order to complete the transaction. For simple payments, meaning transactions that transfer ether from one EOA to another EOA, the gas amount needed is fixed at 21,000 gas units. To calculate how much ether that will cost, you multiply 21,000 by the gasPrice you’re willing to pay. For example:
> web3.eth.getGasPrice(function(err, res) {console.log(res*21000)} )
> 210000000000000
src=web3.eth.accounts[0];dst=web3.eth.accounts[1];
web3.eth.sendTransaction({from:src,to:dst,\value:web3.toWei(0.01,"ether"),data:""});
web3.eth.sendTransaction({from:src,to:dst,\value:web3.toWei(0.01,"ether"),data:"0x1234"});
web3.eth.sendTransaction({from:src,to:dst,value:0,data:"0x1234"});
web3.eth.sendTransaction({from:src,to:dst,value:0,data:""}));
The first 4 bytes of the Keccak-256 hash of the function’s prototype. This allows the contract to unambiguously identify which function you wish to invoke.
The function’s arguments, encoded according to the rules for the various elementary types defined in the ABI specification.
functionwithdraw(uintwithdraw_amount)public{
withdraw(uint256)
> web3.sha3("withdraw(uint256)");
'0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f'
> withdraw_amount = web3.toWei(0.01, "ether"); '10000000000000000' > withdraw_amount_hex = web3.toHex(withdraw_amount); '0x2386f26fc10000'
2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000
0x000000000000000000000000000000000000dEaD
$ solc --bin Faucet.sol Binary: 6060604052341561000f57600080fd5b60e58061001d6000396000f30060606040526004361060...
> src = web3.eth.accounts[0];
> faucet_code = \
"0x6060604052341561000f57600080fd5b60e58061001d6000396000f300606...f0029";
> web3.eth.sendTransaction({from: src, to: 0, data: faucet_code, \
gas: 113558, gasPrice: 200000000000});
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b"
> eth.getTransactionReceipt( \
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b");
{
blockHash: "0x6fa7d8bf982490de6246875deb2c21e5f3665b4422089c060138fc3907a95bb2",
blockNumber: 3105256,
contractAddress: "0xb226270965b43373e98ffc6e2c7693c17e2cf40b",
cumulativeGasUsed: 113558,
from: "0x2a966a87db5913c1b22a59b0d8a11cc51c167a89",
gasUsed: 113558,
logs: [],
logsBloom: \
"0x00000000000000000000000000000000000000000000000000...00000",
status: "0x1",
to: null,
transactionHash: \
"0x7bcc327ae5d369f75b98c0d59037eec41d44dfae75447fd753d9f2db9439124b",
transactionIndex: 0
}
> contract_address = "0xb226270965b43373e98ffc6e2c7693c17e2cf40b"
> web3.eth.sendTransaction({from: src, to: contract_address, \
value: web3.toWei(0.1, "ether"), data: ""});
"0x6ebf2e1fe95cc9c1fe2e1a0dc45678ccd127d374fdf145c5c8e6cd4ea2e6ca9f"
> web3.eth.sendTransaction({from: src, to: contract_address, value: 0, data: \
"0x2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000"});
"0x59836029e7ce43e92daf84313816ca31420a76a9a571b69e31ec4bf4b37cd16e"
k is the signing private key.
m is the RLP-encoded transaction.
Fkeccak256 is the Keccak-256 hash function.
Fsig is the signing algorithm.
Sig is the resulting signature.
The function Fsig produces a signature Sig that is composed of two values, commonly referred to as r and s:
A cryptographically secure random number q, which is used as the ephemeral private key
The corresponding ephemeral public key Q, generated from q and the elliptic curve generator point G
q is the ephemeral private key.
r is the x coordinate of the ephemeral public key.
k is the signing (EOA owner’s) private key.
m is the transaction data.
p is the prime order of the elliptic curve.
Check all inputs are correctly formed
Calculate w = s-1 mod p
Calculate u1 = Keccak256(m) * w mod p
Calculate u2 = r * w mod p
Finally, calculate the point on the elliptic curve Q ≡ u1 * _G + u2 * K (mod p)
r and s are the signature values.
K is the signer’s (EOA owner’s) public key.
m is the transaction data that was signed.
G is the elliptic curve generator point.
p is the prime order of the elliptic curve.
Create a transaction data structure, containing nine fields: nonce, gasPrice, gasLimit, to, value, data, chainID, 0, 0.
Produce an RLP-encoded serialized message of the transaction data structure.
Compute the Keccak-256 hash of this serialized message.
Compute the ECDSA signature, signing the hash with the originating EOA’s private key.
Append the ECDSA signature’s computed v, r, and s values to the transaction.
// Load requirements first://// npm init// npm install ethereumjs-tx//// Run with: $ node raw_tx_demo.jsconstethTx=require('ethereumjs-tx');consttxData={nonce:'0x0',gasPrice:'0x09184e72a000',gasLimit:'0x30000',to:'0xb0920c523d582040f2bcb1bd7fb1c7c1ecebdb34',value:'0x00',data:'',v:"0x1c",// Ethereum mainnet chainIDr:0,s:0};tx=newethTx(txData);console.log('RLP-Encoded Tx: 0x'+tx.serialize().toString('hex'))txHash=tx.hash();// This step encodes into RLP and calculates the hashconsole.log('Tx Hash: 0x'+txHash.toString('hex'))// Sign transactionconstprivKey=Buffer.from('91c8360c4cb4b5fac45513a7213f31d4e4a7bfcb4630e9fbf074f42a203ac0b9','hex');tx.sign(privKey);serializedTx=tx.serialize();rawTx='Signed Raw Transaction: 0x'+serializedTx.toString('hex');console.log(rawTx)
Running the example code produces the following results:
$ node raw_tx_demo.js RLP-Encoded Tx: 0xe6808609184e72a0008303000094b0920c523d582040f2bcb1bd7fb1c7c1... Tx Hash: 0xaa7f03f9f4e52fcf69f836a6d2bbc7706580adce0a068ff6525ba337218e6992 Signed Raw Transaction: 0xf866808609184e72a0008303000094b0920c523d582040f2bcb1...
| Chain | Chain ID |
|---|---|
Ethereum mainnet |
1 |
Morden (obsolete), Expanse |
2 |
Ropsten |
3 |
Rinkeby |
4 |
Rootstock mainnet |
30 |
Rootstock testnet |
31 |
Kovan |
42 |
Ethereum Classic mainnet |
61 |
Ethereum Classic testnet |
62 |
Geth private testnets |
1337 |
K1 and K2 are the two possibilities for the signer’s public key.
r-1 is the multiplicative inverse of the signature’s r value.
s is the signature’s s value.
R and R' are the two possibilities for the ephemeral public key Q.
z is the n-lowest bits of the message hash.
G is the elliptic curve generator point.
Create an unsigned transaction on the online computer where the current state of the account, notably the current nonce and funds available, can be retrieved.
Transfer the unsigned transaction to an “air-gapped” offline device for transaction signing, e.g., via a QR code or USB flash drive.
Transmit the signed transaction (back) to an online device for broadcast on the Ethereum blockchain, e.g., via QR code or USB flash drive.