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