forked from mirror/go-ethereum
all: implement EIP-1559 (#22837)
This is the initial implementation of EIP-1559 in packages core/types and core. Mining, RPC, etc. will be added in subsequent commits. Co-authored-by: Marius van der Wijden <m.vanderwijden@live.de> Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com> Co-authored-by: Felix Lange <fjl@twurst.com>revert-23120-drop-eth-65
parent
14bc6e5130
commit
94451c2788
@ -1,23 +0,0 @@ |
|||||||
{ |
|
||||||
"root": "f4157bb27bcb1d1a63001434a249a80948f2e9fe1f53d551244c1dae826b5b23", |
|
||||||
"accounts": { |
|
||||||
"0x8a8eafb1cf62bfbeb1741769dae1a9dd47996192": { |
|
||||||
"balance": "4276951709", |
|
||||||
"nonce": 1, |
|
||||||
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", |
|
||||||
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" |
|
||||||
}, |
|
||||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
|
||||||
"balance": "6916764286133345652", |
|
||||||
"nonce": 172, |
|
||||||
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", |
|
||||||
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" |
|
||||||
}, |
|
||||||
"0xc94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
|
||||||
"balance": "42500", |
|
||||||
"nonce": 0, |
|
||||||
"root": "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", |
|
||||||
"codeHash": "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,23 @@ |
|||||||
|
{ |
||||||
|
"0x1111111111111111111111111111111111111111" : { |
||||||
|
"balance" : "0x010000000000", |
||||||
|
"code" : "0xfe", |
||||||
|
"nonce" : "0x01", |
||||||
|
"storage" : { |
||||||
|
} |
||||||
|
}, |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { |
||||||
|
"balance" : "0x010000000000", |
||||||
|
"code" : "0x", |
||||||
|
"nonce" : "0x01", |
||||||
|
"storage" : { |
||||||
|
} |
||||||
|
}, |
||||||
|
"0xd02d72e067e77158444ef2020ff2d325f929b363" : { |
||||||
|
"balance" : "0x01000000000000", |
||||||
|
"code" : "0x", |
||||||
|
"nonce" : "0x01", |
||||||
|
"storage" : { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
{ |
||||||
|
"currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", |
||||||
|
"currentDifficulty" : "0x020000", |
||||||
|
"currentNumber" : "0x01", |
||||||
|
"currentTimestamp" : "0x079e", |
||||||
|
"previousHash" : "0xcb23ee65a163121f640673b41788ee94633941405f95009999b502eedfbbfd4f", |
||||||
|
"currentGasLimit" : "0x40000000", |
||||||
|
"currentBaseFee" : "0x036b", |
||||||
|
"blockHashes" : { |
||||||
|
"0" : "0xcb23ee65a163121f640673b41788ee94633941405f95009999b502eedfbbfd4f" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
## EIP-1559 testing |
||||||
|
|
||||||
|
This test contains testcases for EIP-1559, which were reported by Ori as misbehaving. |
||||||
|
|
||||||
|
``` |
||||||
|
[user@work evm]$ dir=./testdata/10 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout 2>&1 |
||||||
|
INFO [05-09|22:11:59.436] rejected tx index=3 hash=db07bf..ede1e8 from=0xd02d72E067e77158444ef2020Ff2d325f929B363 error="gas limit reached" |
||||||
|
``` |
||||||
|
Output: |
||||||
|
```json |
||||||
|
{ |
||||||
|
"alloc": { |
||||||
|
"0x1111111111111111111111111111111111111111": { |
||||||
|
"code": "0xfe", |
||||||
|
"balance": "0x10000000000", |
||||||
|
"nonce": "0x1" |
||||||
|
}, |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
||||||
|
"balance": "0x10000000000", |
||||||
|
"nonce": "0x1" |
||||||
|
}, |
||||||
|
"0xd02d72e067e77158444ef2020ff2d325f929b363": { |
||||||
|
"balance": "0xff5beffffc95", |
||||||
|
"nonce": "0x4" |
||||||
|
} |
||||||
|
}, |
||||||
|
"result": { |
||||||
|
"stateRoot": "0xf91a7ec08e4bfea88719aab34deabb000c86902360532b52afa9599d41f2bb8b", |
||||||
|
"txRoot": "0xda925f2306a52fa24c15d5cd212d736ee016415fd8dd0c45fd368de7917d64bb", |
||||||
|
"receiptRoot": "0x439a25f7fc424c10fb1f89800e4aa1df74156b137239d9ac3eaa7c911c353cd5", |
||||||
|
"logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", |
||||||
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"receipts": [ |
||||||
|
{ |
||||||
|
"type": "0x2", |
||||||
|
"root": "0x", |
||||||
|
"status": "0x0", |
||||||
|
"cumulativeGasUsed": "0x10000001", |
||||||
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"logs": null, |
||||||
|
"transactionHash": "0x88980f6efcc5358d9c359663e7b9414722d430497637340ea056b076bc206701", |
||||||
|
"contractAddress": "0x0000000000000000000000000000000000000000", |
||||||
|
"gasUsed": "0x10000001", |
||||||
|
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"transactionIndex": "0x0" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "0x2", |
||||||
|
"root": "0x", |
||||||
|
"status": "0x0", |
||||||
|
"cumulativeGasUsed": "0x20000001", |
||||||
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"logs": null, |
||||||
|
"transactionHash": "0xd7bf3886f4e2aef74d525ae072c680f3846f550254401b67cbfda4a233757582", |
||||||
|
"contractAddress": "0x0000000000000000000000000000000000000000", |
||||||
|
"gasUsed": "0x10000000", |
||||||
|
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"transactionIndex": "0x1" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"type": "0x2", |
||||||
|
"root": "0x", |
||||||
|
"status": "0x0", |
||||||
|
"cumulativeGasUsed": "0x30000001", |
||||||
|
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"logs": null, |
||||||
|
"transactionHash": "0x50308296760f01f1eeec7500e9e73cad67469249b1f59e9a9f55e6625a4923db", |
||||||
|
"contractAddress": "0x0000000000000000000000000000000000000000", |
||||||
|
"gasUsed": "0x10000000", |
||||||
|
"blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", |
||||||
|
"transactionIndex": "0x2" |
||||||
|
} |
||||||
|
], |
||||||
|
"rejected": [ |
||||||
|
3 |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
@ -0,0 +1,70 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"input" : "0x", |
||||||
|
"gas" : "0x10000001", |
||||||
|
"nonce" : "0x1", |
||||||
|
"to" : "0x1111111111111111111111111111111111111111", |
||||||
|
"value" : "0x0", |
||||||
|
"v" : "0x0", |
||||||
|
"r" : "0x7a45f00bcde9036b026cdf1628b023cd8a31a95c62b5e4dbbee2fa7debe668fb", |
||||||
|
"s" : "0x3cc9d6f2cd00a045b0263f2d6dad7d60938d5d13d061af4969f95928aa934d4a", |
||||||
|
"secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", |
||||||
|
"chainId" : "0x1", |
||||||
|
"type" : "0x2", |
||||||
|
"feeCap" : "0xfa0", |
||||||
|
"tip" : "0x0", |
||||||
|
"accessList" : [ |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"input" : "0x", |
||||||
|
"gas" : "0x10000000", |
||||||
|
"nonce" : "0x2", |
||||||
|
"to" : "0x1111111111111111111111111111111111111111", |
||||||
|
"value" : "0x0", |
||||||
|
"v" : "0x0", |
||||||
|
"r" : "0x4c564b94b0281a8210eeec2dd1fe2e16ff1c1903a8c3a1078d735d7f8208b2af", |
||||||
|
"s" : "0x56432b2593e6de95db1cb997b7385217aca03f1615327e231734446b39f266d", |
||||||
|
"secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", |
||||||
|
"chainId" : "0x1", |
||||||
|
"type" : "0x2", |
||||||
|
"feeCap" : "0xfa0", |
||||||
|
"tip" : "0x0", |
||||||
|
"accessList" : [ |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"input" : "0x", |
||||||
|
"gas" : "0x10000000", |
||||||
|
"nonce" : "0x3", |
||||||
|
"to" : "0x1111111111111111111111111111111111111111", |
||||||
|
"value" : "0x0", |
||||||
|
"v" : "0x0", |
||||||
|
"r" : "0x2ed2ef52f924f59d4a21e1f2a50d3b1109303ce5e32334a7ece9b46f4fbc2a57", |
||||||
|
"s" : "0x2980257129cbd3da987226f323d50ba3975a834d165e0681f991b75615605c44", |
||||||
|
"secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", |
||||||
|
"chainId" : "0x1", |
||||||
|
"type" : "0x2", |
||||||
|
"feeCap" : "0xfa0", |
||||||
|
"tip" : "0x0", |
||||||
|
"accessList" : [ |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
"input" : "0x", |
||||||
|
"gas" : "0x10000000", |
||||||
|
"nonce" : "0x4", |
||||||
|
"to" : "0x1111111111111111111111111111111111111111", |
||||||
|
"value" : "0x0", |
||||||
|
"v" : "0x0", |
||||||
|
"r" : "0x5df7d7f8f8e15b36fc9f189cacb625040fad10398d08fc90812595922a2c49b2", |
||||||
|
"s" : "0x565fc1803f77a84d754ffe3c5363ab54a8d93a06ea1bb9d4c73c73a282b35917", |
||||||
|
"secretKey" : "0x41f6e321b31e72173f8ff2e292359e1862f24fba42fe6f97efaf641980eff298", |
||||||
|
"chainId" : "0x1", |
||||||
|
"type" : "0x2", |
||||||
|
"feeCap" : "0xfa0", |
||||||
|
"tip" : "0x0", |
||||||
|
"accessList" : [ |
||||||
|
] |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,25 @@ |
|||||||
|
{ |
||||||
|
"0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : { |
||||||
|
"balance" : "0x0de0b6b3a7640000", |
||||||
|
"code" : "0x61ffff5060046000f3", |
||||||
|
"nonce" : "0x01", |
||||||
|
"storage" : { |
||||||
|
} |
||||||
|
}, |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { |
||||||
|
"balance" : "0x0de0b6b3a7640000", |
||||||
|
"code" : "0x", |
||||||
|
"nonce" : "0x00", |
||||||
|
"storage" : { |
||||||
|
"0x00" : "0x00" |
||||||
|
} |
||||||
|
}, |
||||||
|
"0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { |
||||||
|
"balance" : "0x00", |
||||||
|
"code" : "0x6001600055", |
||||||
|
"nonce" : "0x00", |
||||||
|
"storage" : { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,12 @@ |
|||||||
|
{ |
||||||
|
"currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", |
||||||
|
"currentDifficulty" : "0x020000", |
||||||
|
"currentNumber" : "0x01", |
||||||
|
"currentTimestamp" : "0x03e8", |
||||||
|
"previousHash" : "0xfda4419b3660e99f37e536dae1ab081c180136bb38c837a93e93d9aab58553b2", |
||||||
|
"currentGasLimit" : "0x0f4240", |
||||||
|
"blockHashes" : { |
||||||
|
"0" : "0xfda4419b3660e99f37e536dae1ab081c180136bb38c837a93e93d9aab58553b2" |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,13 @@ |
|||||||
|
## Test missing basefee |
||||||
|
|
||||||
|
In this test, the `currentBaseFee` is missing from the env portion. |
||||||
|
On a live blockchain, the basefee is present in the header, and verified as part of header validation. |
||||||
|
|
||||||
|
In `evm t8n`, we don't have blocks, so it needs to be added in the `env`instead. |
||||||
|
|
||||||
|
When it's missing, an error is expected. |
||||||
|
|
||||||
|
``` |
||||||
|
dir=./testdata/11 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout --output.result=stdout 2>&1>/dev/null |
||||||
|
ERROR(3): EIP-1559 config but missing 'currentBaseFee' in env section |
||||||
|
``` |
@ -0,0 +1,14 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"input" : "0x38600060013960015160005560006000f3", |
||||||
|
"gas" : "0x61a80", |
||||||
|
"gasPrice" : "0x1", |
||||||
|
"nonce" : "0x0", |
||||||
|
"value" : "0x186a0", |
||||||
|
"v" : "0x1c", |
||||||
|
"r" : "0x2e1391fd903387f1cc2b51df083805fb4bbb0d4710a2cdf4a044d191ff7be63e", |
||||||
|
"s" : "0x7f10a933c42ab74927db02b1db009e923d9d2ab24ac24d63c399f2fe5d9c9b22", |
||||||
|
"secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" |
||||||
|
} |
||||||
|
] |
||||||
|
|
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"0x000000000000000000000000000000000000aaaa": { |
||||||
|
"balance": "0x03", |
||||||
|
"code": "0x58585454", |
||||||
|
"nonce": "0x1" |
||||||
|
}, |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
||||||
|
"balance": "0x100000000000000", |
||||||
|
"nonce": "0x00" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", |
||||||
|
"currentDifficulty": "0x20000", |
||||||
|
"currentGasTarget": "0x1000000000", |
||||||
|
"currentBaseFee": "0x3B9ACA00", |
||||||
|
"currentNumber": "0x1000000", |
||||||
|
"currentTimestamp": "0x04" |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
## EIP-1559 testing |
||||||
|
|
||||||
|
This test contains testcases for EIP-1559, which uses an new transaction type and has a new block parameter. |
||||||
|
|
||||||
|
### Prestate |
||||||
|
|
||||||
|
The alloc portion contains one contract (`0x000000000000000000000000000000000000aaaa`), containing the |
||||||
|
following code: `0x58585454`: `PC; PC; SLOAD; SLOAD`. |
||||||
|
|
||||||
|
Essentialy, this contract does `SLOAD(0)` and `SLOAD(1)`. |
||||||
|
|
||||||
|
The alloc also contains some funds on `0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b`. |
||||||
|
|
||||||
|
## Transactions |
||||||
|
|
||||||
|
There are two transactions, each invokes the contract above. |
||||||
|
|
||||||
|
1. EIP-1559 ACL-transaction, which contains the `0x0` slot for `0xaaaa` |
||||||
|
2. Legacy transaction |
||||||
|
|
||||||
|
## Execution |
||||||
|
|
||||||
|
Running it yields: |
||||||
|
``` |
||||||
|
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --trace && cat trace-* | grep SLOAD |
||||||
|
{"pc":2,"op":84,"gas":"0x48c28","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD |
||||||
|
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} |
||||||
|
{"pc":3,"op":84,"gas":"0x483f4","gasCost":"0x64","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnDa |
||||||
|
ta":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} |
||||||
|
{"pc":2,"op":84,"gas":"0x49cf4","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x1"],"returnStack":null,"returnD |
||||||
|
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} |
||||||
|
{"pc":3,"op":84,"gas":"0x494c0","gasCost":"0x834","memory":"0x","memSize":0,"stack":["0x0","0x0"],"returnStack":null,"returnD |
||||||
|
ata":"0x","depth":1,"refund":0,"opName":"SLOAD","error":""} |
||||||
|
``` |
||||||
|
|
||||||
|
We can also get the post-alloc: |
||||||
|
``` |
||||||
|
$ dir=./testdata/9 && ./evm t8n --state.fork=London --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout |
||||||
|
{ |
||||||
|
"alloc": { |
||||||
|
"0x000000000000000000000000000000000000aaaa": { |
||||||
|
"code": "0x58585454", |
||||||
|
"balance": "0x3", |
||||||
|
"nonce": "0x1" |
||||||
|
}, |
||||||
|
"0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba": { |
||||||
|
"balance": "0xbfc02677a000" |
||||||
|
}, |
||||||
|
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { |
||||||
|
"balance": "0xff104fcfea7800", |
||||||
|
"nonce": "0x2" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
If we try to execute it on older rules: |
||||||
|
``` |
||||||
|
dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs.json --input.env=$dir/env.json --output.alloc=stdout |
||||||
|
ERROR(10): Failed signing transactions: ERROR(10): Tx 0: failed to sign tx: transaction type not supported |
||||||
|
``` |
||||||
|
|
||||||
|
It fails, due to the `evm t8n` cannot sign them in with the given signer. We can bypass that, however, |
||||||
|
by feeding it presigned transactions, located in `txs_signed.json`. |
||||||
|
|
||||||
|
``` |
||||||
|
dir=./testdata/9 && ./evm t8n --state.fork=Berlin --input.alloc=$dir/alloc.json --input.txs=$dir/txs_signed.json --input.env=$dir/env.json |
||||||
|
INFO [05-07|12:28:42.072] rejected tx index=0 hash=b4821e..536819 error="transaction type not supported" |
||||||
|
INFO [05-07|12:28:42.072] rejected tx index=1 hash=a9c6c6..fa4036 from=0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B error="nonce too high: address 0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B, tx: 1 state: 0" |
||||||
|
INFO [05-07|12:28:42.073] Wrote file file=alloc.json |
||||||
|
INFO [05-07|12:28:42.073] Wrote file file=result.json |
||||||
|
``` |
||||||
|
|
||||||
|
Number `0` is not applicable, and therefore number `1` has wrong nonce, and both are rejected. |
||||||
|
|
@ -0,0 +1,37 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"gas": "0x4ef00", |
||||||
|
"tip": "0x2", |
||||||
|
"feeCap": "0x12A05F200", |
||||||
|
"chainId": "0x1", |
||||||
|
"input": "0x", |
||||||
|
"nonce": "0x0", |
||||||
|
"to": "0x000000000000000000000000000000000000aaaa", |
||||||
|
"value": "0x0", |
||||||
|
"type" : "0x2", |
||||||
|
"accessList": [ |
||||||
|
{"address": "0x000000000000000000000000000000000000aaaa", |
||||||
|
"storageKeys": [ |
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000000" |
||||||
|
] |
||||||
|
} |
||||||
|
], |
||||||
|
"v": "0x0", |
||||||
|
"r": "0x0", |
||||||
|
"s": "0x0", |
||||||
|
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"gas": "0x4ef00", |
||||||
|
"gasPrice": "0x12A05F200", |
||||||
|
"chainId": "0x1", |
||||||
|
"input": "0x", |
||||||
|
"nonce": "0x1", |
||||||
|
"to": "0x000000000000000000000000000000000000aaaa", |
||||||
|
"value": "0x0", |
||||||
|
"v": "0x0", |
||||||
|
"r": "0x0", |
||||||
|
"s": "0x0", |
||||||
|
"secretKey": "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,93 @@ |
|||||||
|
// Copyright 2021 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package misc |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"math/big" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common" |
||||||
|
"github.com/ethereum/go-ethereum/common/math" |
||||||
|
"github.com/ethereum/go-ethereum/core/types" |
||||||
|
"github.com/ethereum/go-ethereum/params" |
||||||
|
) |
||||||
|
|
||||||
|
// VerifyEip1559Header verifies some header attributes which were changed in EIP-1559,
|
||||||
|
// - gas limit check
|
||||||
|
// - basefee check
|
||||||
|
func VerifyEip1559Header(config *params.ChainConfig, parent, header *types.Header) error { |
||||||
|
// Verify that the gas limit remains within allowed bounds
|
||||||
|
parentGasLimit := parent.GasLimit |
||||||
|
if !config.IsLondon(parent.Number) { |
||||||
|
parentGasLimit = parent.GasLimit * params.ElasticityMultiplier |
||||||
|
} |
||||||
|
if err := VerifyGaslimit(parentGasLimit, header.GasLimit); err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
// Verify the header is not malformed
|
||||||
|
if header.BaseFee == nil { |
||||||
|
return fmt.Errorf("header is missing baseFee") |
||||||
|
} |
||||||
|
// Verify the baseFee is correct based on the parent header.
|
||||||
|
expectedBaseFee := CalcBaseFee(config, parent) |
||||||
|
if header.BaseFee.Cmp(expectedBaseFee) != 0 { |
||||||
|
return fmt.Errorf("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d", |
||||||
|
expectedBaseFee, header.BaseFee, parent.BaseFee, parent.GasUsed) |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// CalcBaseFee calculates the basefee of the header.
|
||||||
|
func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { |
||||||
|
// If the current block is the first EIP-1559 block, return the InitialBaseFee.
|
||||||
|
if !config.IsLondon(parent.Number) { |
||||||
|
return new(big.Int).SetUint64(params.InitialBaseFee) |
||||||
|
} |
||||||
|
|
||||||
|
var ( |
||||||
|
parentGasTarget = parent.GasLimit / params.ElasticityMultiplier |
||||||
|
parentGasTargetBig = new(big.Int).SetUint64(parentGasTarget) |
||||||
|
baseFeeChangeDenominator = new(big.Int).SetUint64(params.BaseFeeChangeDenominator) |
||||||
|
) |
||||||
|
// If the parent gasUsed is the same as the target, the baseFee remains unchanged.
|
||||||
|
if parent.GasUsed == parentGasTarget { |
||||||
|
return new(big.Int).Set(parent.BaseFee) |
||||||
|
} |
||||||
|
if parent.GasUsed > parentGasTarget { |
||||||
|
// If the parent block used more gas than its target, the baseFee should increase.
|
||||||
|
gasUsedDelta := new(big.Int).SetUint64(parent.GasUsed - parentGasTarget) |
||||||
|
x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) |
||||||
|
y := x.Div(x, parentGasTargetBig) |
||||||
|
baseFeeDelta := math.BigMax( |
||||||
|
x.Div(y, baseFeeChangeDenominator), |
||||||
|
common.Big1, |
||||||
|
) |
||||||
|
|
||||||
|
return x.Add(parent.BaseFee, baseFeeDelta) |
||||||
|
} else { |
||||||
|
// Otherwise if the parent block used less gas than its target, the baseFee should decrease.
|
||||||
|
gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parent.GasUsed) |
||||||
|
x := new(big.Int).Mul(parent.BaseFee, gasUsedDelta) |
||||||
|
y := x.Div(x, parentGasTargetBig) |
||||||
|
baseFeeDelta := x.Div(y, baseFeeChangeDenominator) |
||||||
|
|
||||||
|
return math.BigMax( |
||||||
|
x.Sub(parent.BaseFee, baseFeeDelta), |
||||||
|
common.Big0, |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,133 @@ |
|||||||
|
// Copyright 2021 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package misc |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/big" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common" |
||||||
|
"github.com/ethereum/go-ethereum/core/types" |
||||||
|
"github.com/ethereum/go-ethereum/params" |
||||||
|
) |
||||||
|
|
||||||
|
// copyConfig does a _shallow_ copy of a given config. Safe to set new values, but
|
||||||
|
// do not use e.g. SetInt() on the numbers. For testing only
|
||||||
|
func copyConfig(original *params.ChainConfig) *params.ChainConfig { |
||||||
|
return ¶ms.ChainConfig{ |
||||||
|
ChainID: original.ChainID, |
||||||
|
HomesteadBlock: original.HomesteadBlock, |
||||||
|
DAOForkBlock: original.DAOForkBlock, |
||||||
|
DAOForkSupport: original.DAOForkSupport, |
||||||
|
EIP150Block: original.EIP150Block, |
||||||
|
EIP150Hash: original.EIP150Hash, |
||||||
|
EIP155Block: original.EIP155Block, |
||||||
|
EIP158Block: original.EIP158Block, |
||||||
|
ByzantiumBlock: original.ByzantiumBlock, |
||||||
|
ConstantinopleBlock: original.ConstantinopleBlock, |
||||||
|
PetersburgBlock: original.PetersburgBlock, |
||||||
|
IstanbulBlock: original.IstanbulBlock, |
||||||
|
MuirGlacierBlock: original.MuirGlacierBlock, |
||||||
|
BerlinBlock: original.BerlinBlock, |
||||||
|
LondonBlock: original.LondonBlock, |
||||||
|
EWASMBlock: original.EWASMBlock, |
||||||
|
CatalystBlock: original.CatalystBlock, |
||||||
|
Ethash: original.Ethash, |
||||||
|
Clique: original.Clique, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func config() *params.ChainConfig { |
||||||
|
config := copyConfig(params.TestChainConfig) |
||||||
|
config.LondonBlock = big.NewInt(5) |
||||||
|
return config |
||||||
|
} |
||||||
|
|
||||||
|
// TestBlockGasLimits tests the gasLimit checks for blocks both across
|
||||||
|
// the EIP-1559 boundary and post-1559 blocks
|
||||||
|
func TestBlockGasLimits(t *testing.T) { |
||||||
|
initial := new(big.Int).SetUint64(params.InitialBaseFee) |
||||||
|
|
||||||
|
for i, tc := range []struct { |
||||||
|
pGasLimit uint64 |
||||||
|
pNum int64 |
||||||
|
gasLimit uint64 |
||||||
|
ok bool |
||||||
|
}{ |
||||||
|
// Transitions from non-london to london
|
||||||
|
{10000000, 4, 20000000, true}, // No change
|
||||||
|
{10000000, 4, 20019530, true}, // Upper limit
|
||||||
|
{10000000, 4, 20019531, false}, // Upper +1
|
||||||
|
{10000000, 4, 19980470, true}, // Lower limit
|
||||||
|
{10000000, 4, 19980469, false}, // Lower limit -1
|
||||||
|
// London to London
|
||||||
|
{20000000, 5, 20000000, true}, |
||||||
|
{20000000, 5, 20019530, true}, // Upper limit
|
||||||
|
{20000000, 5, 20019531, false}, // Upper limit +1
|
||||||
|
{20000000, 5, 19980470, true}, // Lower limit
|
||||||
|
{20000000, 5, 19980469, false}, // Lower limit -1
|
||||||
|
{40000000, 5, 40039061, true}, // Upper limit
|
||||||
|
{40000000, 5, 40039062, false}, // Upper limit +1
|
||||||
|
{40000000, 5, 39960939, true}, // lower limit
|
||||||
|
{40000000, 5, 39960938, false}, // Lower limit -1
|
||||||
|
} { |
||||||
|
parent := &types.Header{ |
||||||
|
GasUsed: tc.pGasLimit / 2, |
||||||
|
GasLimit: tc.pGasLimit, |
||||||
|
BaseFee: initial, |
||||||
|
Number: big.NewInt(tc.pNum), |
||||||
|
} |
||||||
|
header := &types.Header{ |
||||||
|
GasUsed: tc.gasLimit / 2, |
||||||
|
GasLimit: tc.gasLimit, |
||||||
|
BaseFee: initial, |
||||||
|
Number: big.NewInt(tc.pNum + 1), |
||||||
|
} |
||||||
|
err := VerifyEip1559Header(config(), parent, header) |
||||||
|
if tc.ok && err != nil { |
||||||
|
t.Errorf("test %d: Expected valid header: %s", i, err) |
||||||
|
} |
||||||
|
if !tc.ok && err == nil { |
||||||
|
t.Errorf("test %d: Expected invalid header", i) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TestCalcBaseFee assumes all blocks are 1559-blocks
|
||||||
|
func TestCalcBaseFee(t *testing.T) { |
||||||
|
tests := []struct { |
||||||
|
parentBaseFee int64 |
||||||
|
parentGasLimit uint64 |
||||||
|
parentGasUsed uint64 |
||||||
|
expectedBaseFee int64 |
||||||
|
}{ |
||||||
|
{params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target
|
||||||
|
{params.InitialBaseFee, 20000000, 9000000, 987500000}, // usage below target
|
||||||
|
{params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target
|
||||||
|
} |
||||||
|
for i, test := range tests { |
||||||
|
parent := &types.Header{ |
||||||
|
Number: common.Big32, |
||||||
|
GasLimit: test.parentGasLimit, |
||||||
|
GasUsed: test.parentGasUsed, |
||||||
|
BaseFee: big.NewInt(test.parentBaseFee), |
||||||
|
} |
||||||
|
if have, want := CalcBaseFee(config(), parent), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { |
||||||
|
t.Errorf("test %d: have %d want %d, ", i, have, want) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
// Copyright 2021 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package misc |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/params" |
||||||
|
) |
||||||
|
|
||||||
|
// VerifyGaslimit verifies the header gas limit according increase/decrease
|
||||||
|
// in relation to the parent gas limit.
|
||||||
|
func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error { |
||||||
|
// Verify that the gas limit remains within allowed bounds
|
||||||
|
diff := int64(parentGasLimit) - int64(headerGasLimit) |
||||||
|
if diff < 0 { |
||||||
|
diff *= -1 |
||||||
|
} |
||||||
|
limit := parentGasLimit / params.GasLimitBoundDivisor |
||||||
|
if uint64(diff) >= limit { |
||||||
|
return fmt.Errorf("invalid gas limit: have %d, want %d +-= %d", headerGasLimit, parentGasLimit, limit-1) |
||||||
|
} |
||||||
|
if headerGasLimit < params.MinGasLimit { |
||||||
|
return errors.New("invalid gas limit below 5000") |
||||||
|
} |
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
// Copyright 2021 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package types |
||||||
|
|
||||||
|
import ( |
||||||
|
"math/big" |
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common" |
||||||
|
) |
||||||
|
|
||||||
|
type DynamicFeeTx struct { |
||||||
|
ChainID *big.Int |
||||||
|
Nonce uint64 |
||||||
|
Tip *big.Int |
||||||
|
FeeCap *big.Int |
||||||
|
Gas uint64 |
||||||
|
To *common.Address `rlp:"nil"` // nil means contract creation
|
||||||
|
Value *big.Int |
||||||
|
Data []byte |
||||||
|
AccessList AccessList |
||||||
|
|
||||||
|
// Signature values
|
||||||
|
V *big.Int `json:"v" gencodec:"required"` |
||||||
|
R *big.Int `json:"r" gencodec:"required"` |
||||||
|
S *big.Int `json:"s" gencodec:"required"` |
||||||
|
} |
||||||
|
|
||||||
|
// copy creates a deep copy of the transaction data and initializes all fields.
|
||||||
|
func (tx *DynamicFeeTx) copy() TxData { |
||||||
|
cpy := &DynamicFeeTx{ |
||||||
|
Nonce: tx.Nonce, |
||||||
|
To: tx.To, // TODO: copy pointed-to address
|
||||||
|
Data: common.CopyBytes(tx.Data), |
||||||
|
Gas: tx.Gas, |
||||||
|
// These are copied below.
|
||||||
|
AccessList: make(AccessList, len(tx.AccessList)), |
||||||
|
Value: new(big.Int), |
||||||
|
ChainID: new(big.Int), |
||||||
|
Tip: new(big.Int), |
||||||
|
FeeCap: new(big.Int), |
||||||
|
V: new(big.Int), |
||||||
|
R: new(big.Int), |
||||||
|
S: new(big.Int), |
||||||
|
} |
||||||
|
copy(cpy.AccessList, tx.AccessList) |
||||||
|
if tx.Value != nil { |
||||||
|
cpy.Value.Set(tx.Value) |
||||||
|
} |
||||||
|
if tx.ChainID != nil { |
||||||
|
cpy.ChainID.Set(tx.ChainID) |
||||||
|
} |
||||||
|
if tx.Tip != nil { |
||||||
|
cpy.Tip.Set(tx.Tip) |
||||||
|
} |
||||||
|
if tx.FeeCap != nil { |
||||||
|
cpy.FeeCap.Set(tx.FeeCap) |
||||||
|
} |
||||||
|
if tx.V != nil { |
||||||
|
cpy.V.Set(tx.V) |
||||||
|
} |
||||||
|
if tx.R != nil { |
||||||
|
cpy.R.Set(tx.R) |
||||||
|
} |
||||||
|
if tx.S != nil { |
||||||
|
cpy.S.Set(tx.S) |
||||||
|
} |
||||||
|
return cpy |
||||||
|
} |
||||||
|
|
||||||
|
// accessors for innerTx.
|
||||||
|
func (tx *DynamicFeeTx) txType() byte { return DynamicFeeTxType } |
||||||
|
func (tx *DynamicFeeTx) chainID() *big.Int { return tx.ChainID } |
||||||
|
func (tx *DynamicFeeTx) protected() bool { return true } |
||||||
|
func (tx *DynamicFeeTx) accessList() AccessList { return tx.AccessList } |
||||||
|
func (tx *DynamicFeeTx) data() []byte { return tx.Data } |
||||||
|
func (tx *DynamicFeeTx) gas() uint64 { return tx.Gas } |
||||||
|
func (tx *DynamicFeeTx) feeCap() *big.Int { return tx.FeeCap } |
||||||
|
func (tx *DynamicFeeTx) tip() *big.Int { return tx.Tip } |
||||||
|
func (tx *DynamicFeeTx) gasPrice() *big.Int { return tx.FeeCap } |
||||||
|
func (tx *DynamicFeeTx) value() *big.Int { return tx.Value } |
||||||
|
func (tx *DynamicFeeTx) nonce() uint64 { return tx.Nonce } |
||||||
|
func (tx *DynamicFeeTx) to() *common.Address { return tx.To } |
||||||
|
|
||||||
|
func (tx *DynamicFeeTx) rawSignatureValues() (v, r, s *big.Int) { |
||||||
|
return tx.V, tx.R, tx.S |
||||||
|
} |
||||||
|
|
||||||
|
func (tx *DynamicFeeTx) setSignatureValues(chainID, v, r, s *big.Int) { |
||||||
|
tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s |
||||||
|
} |
Loading…
Reference in new issue