mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 00:58:11 -05:00
feat: support time-based forking (#1128)
This commit is contained in:
@@ -1,810 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"chainId": 5,
|
||||
"homesteadBlock": 0,
|
||||
"daoForkSupport": true,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 1561651,
|
||||
"berlinBlock": 4460644,
|
||||
"londonBlock": 5062605,
|
||||
"terminalTotalDifficulty": 10790000
|
||||
},
|
||||
"nonce": "0x0",
|
||||
"timestamp": "0x5c51a607",
|
||||
"extraData": "0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"gasLimit": "0xa00000",
|
||||
"difficulty": "0x1",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||
"stateRoot": "0x5d6cded585e73c4e322c30c2f782a336316f17dd85a4863b9d838d2d4b8b3008",
|
||||
"alloc": {
|
||||
"0000000000000000000000000000000000000000": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000001": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000002": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000003": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000004": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000005": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000006": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000007": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000008": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000009": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000000a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000000b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000000c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000000d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000000e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000000f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000010": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000011": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000012": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000013": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000014": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000015": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000016": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000017": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000018": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000019": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000001a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000001b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000001c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000001d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000001e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000001f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000020": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000021": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000022": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000023": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000024": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000025": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000026": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000027": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000028": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000029": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000002a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000002b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000002c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000002d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000002e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000002f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000030": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000031": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000032": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000033": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000034": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000035": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000036": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000037": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000038": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000039": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000003a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000003b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000003c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000003d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000003e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000003f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000040": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000041": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000042": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000043": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000044": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000045": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000046": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000047": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000048": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000049": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000004a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000004b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000004c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000004d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000004e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000004f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000050": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000051": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000052": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000053": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000054": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000055": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000056": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000057": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000058": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000059": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000005a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000005b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000005c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000005d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000005e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000005f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000060": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000061": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000062": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000063": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000064": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000065": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000066": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000067": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000068": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000069": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000006a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000006b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000006c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000006d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000006e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000006f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000070": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000071": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000072": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000073": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000074": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000075": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000076": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000077": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000078": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000079": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000007a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000007b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000007c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000007d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000007e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000007f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000080": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000081": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000082": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000083": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000084": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000085": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000086": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000087": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000088": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000089": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000008a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000008b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000008c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000008d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000008e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000008f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000090": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000091": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000092": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000093": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000094": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000095": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000096": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000097": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000098": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"0000000000000000000000000000000000000099": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000009a": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000009b": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000009c": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000009d": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000009e": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"000000000000000000000000000000000000009f": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000a9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000aa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ab": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ac": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ad": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ae": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000af": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000b9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ba": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000bb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000bc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000bd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000be": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000bf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000c9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ca": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000cb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000cc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000cd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ce": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000cf": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000d9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000da": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000db": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000dc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000dd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000de": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000df": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000e9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ea": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000eb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ec": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ed": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ee": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ef": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f0": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f1": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f2": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f3": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f4": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f5": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f6": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f7": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f8": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000f9": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000fa": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000fb": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000fc": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000fd": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000fe": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"00000000000000000000000000000000000000ff": {
|
||||
"balance": "0x1"
|
||||
},
|
||||
"4c2ae482593505f0163cdefc073e81c63cda4107": {
|
||||
"balance": "0x152d02c7e14af6800000"
|
||||
},
|
||||
"a8e8f14732658e4b51e8711931053a8a69baf2b1": {
|
||||
"balance": "0x152d02c7e14af6800000"
|
||||
},
|
||||
"d9a5179f091d85051d3c982785efd1455cec8699": {
|
||||
"balance": "0x84595161401484a000000"
|
||||
},
|
||||
"e0a2bd4258d2768837baa26a28fe71dc079f84c7": {
|
||||
"balance": "0x4a47e3c12448f4ad000000"
|
||||
}
|
||||
},
|
||||
"number": "0x0",
|
||||
"gasUsed": "0x0",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +0,0 @@
|
||||
{
|
||||
"config": {
|
||||
"chainId": 11155111,
|
||||
"homesteadBlock": 0,
|
||||
"daoForkSupport": true,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"muirGlacierBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 0,
|
||||
"terminalTotalDifficulty": 17000000000000000
|
||||
},
|
||||
"nonce": "0x00",
|
||||
"timestamp": "0x6159af19",
|
||||
"extraData": "0x5365706f6c69612c20417468656e732c204174746963612c2047726565636521",
|
||||
"gasLimit": "0x1c9c380",
|
||||
"difficulty": "0x20000",
|
||||
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||
"stateRoot": "0x5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494",
|
||||
"alloc":{
|
||||
"0xa2A6d93439144FFE4D27c9E088dCD8b783946263": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xBc11295936Aa79d594139de1B2e12629414F3BDB": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0x7cF5b79bfe291A67AB02b393E456cCc4c266F753": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xaaec86394441f915bce3e6ab399977e9906f3b69": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xF47CaE1CF79ca6758Bfc787dbD21E6bdBe7112B8": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xd7eDDB78ED295B3C9629240E8924fb8D8874ddD8": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0x8b7F0977Bb4f0fBE7076FA22bC24acA043583F5e": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xe2e2659028143784d557bcec6ff3a0721048880a": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xd9a5179f091d85051d3c982785efd1455cec8699": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0xbeef32ca5b9a198d27B4e02F4c70439fE60356Cf": {"balance": "0xD3C21BCECCEDA1000000"},
|
||||
"0x0000006916a87b82333f4245046623b23794c65c": {"balance": "0x84595161401484A000000"},
|
||||
"0xb21c33de1fab3fa15499c62b59fe0cc3250020d1": {"balance": "0x52B7D2DCC80CD2E4000000"},
|
||||
"0x10F5d45854e038071485AC9e402308cF80D2d2fE": {"balance": "0x52B7D2DCC80CD2E4000000"},
|
||||
"0xd7d76c58b3a519e9fA6Cc4D22dC017259BC49F1E": {"balance": "0x52B7D2DCC80CD2E4000000"},
|
||||
"0x799D329e5f583419167cD722962485926E338F4a": {"balance": "0xDE0B6B3A7640000"}
|
||||
},
|
||||
"number": "0x0",
|
||||
"gasUsed": "0x0",
|
||||
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
}
|
||||
@@ -69,18 +69,18 @@ pub struct Command {
|
||||
#[arg(long, value_name = "SOCKET", value_parser = parse_socket_address, help_heading = "Metrics")]
|
||||
metrics: Option<SocketAddr>,
|
||||
|
||||
/// Set the chain tip manually for testing purposes.
|
||||
///
|
||||
/// NOTE: This is a temporary flag
|
||||
#[arg(long = "debug.tip", help_heading = "Debug")]
|
||||
tip: Option<H256>,
|
||||
|
||||
#[clap(flatten)]
|
||||
network: NetworkOpts,
|
||||
|
||||
#[arg(long, default_value = "any")]
|
||||
nat: NatResolver,
|
||||
|
||||
/// Set the chain tip manually for testing purposes.
|
||||
///
|
||||
/// NOTE: This is a temporary flag
|
||||
#[arg(long = "debug.tip", help_heading = "Debug")]
|
||||
tip: Option<H256>,
|
||||
|
||||
/// Runs the sync only up to the specified block
|
||||
#[arg(long = "debug.max-block", help_heading = "Debug")]
|
||||
max_block: Option<u64>,
|
||||
@@ -214,6 +214,7 @@ impl Command {
|
||||
.add_stages(
|
||||
OnlineStages::new(consensus.clone(), header_downloader, body_downloader).set(
|
||||
TotalDifficultyStage {
|
||||
chain_spec: self.chain.clone(),
|
||||
commit_threshold: stage_conf.total_difficulty.commit_threshold,
|
||||
},
|
||||
),
|
||||
|
||||
@@ -10,8 +10,8 @@ use reth_db::{
|
||||
Error as DbError,
|
||||
};
|
||||
use reth_primitives::{
|
||||
keccak256, Account as RethAccount, Address, ChainSpec, JsonU256, SealedBlock, SealedHeader,
|
||||
StorageEntry, H256, U256,
|
||||
keccak256, Account as RethAccount, Address, ChainSpec, ForkCondition, Hardfork, JsonU256,
|
||||
SealedBlock, SealedHeader, StorageEntry, H256, U256,
|
||||
};
|
||||
use reth_rlp::Decodable;
|
||||
use reth_stages::{stages::ExecutionStage, ExecInput, Stage, StageId, Transaction};
|
||||
@@ -125,7 +125,7 @@ pub async fn run_test(path: PathBuf) -> eyre::Result<TestOutcome> {
|
||||
|
||||
let chain_spec: ChainSpec = suite.network.into();
|
||||
// if paris aka merge is not activated we dont have block rewards;
|
||||
let has_block_reward = chain_spec.paris_status().block_number().is_some();
|
||||
let has_block_reward = !matches!(chain_spec.fork(Hardfork::Paris), ForkCondition::Never);
|
||||
|
||||
// Create db and acquire transaction
|
||||
let db = create_test_rw_db();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Consensus for ethereum network
|
||||
use crate::validation;
|
||||
use reth_interfaces::consensus::{Consensus, Error, ForkchoiceState};
|
||||
use reth_primitives::{BlockNumber, ChainSpec, SealedBlock, SealedHeader};
|
||||
use reth_primitives::{ChainSpec, Hardfork, SealedBlock, SealedHeader, EMPTY_OMMER_ROOT, U256};
|
||||
use tokio::sync::watch;
|
||||
|
||||
use super::BeaconConsensusBuilder;
|
||||
@@ -38,15 +38,41 @@ impl Consensus for BeaconConsensus {
|
||||
self.forkchoice_state_rx.clone()
|
||||
}
|
||||
|
||||
fn validate_header(&self, header: &SealedHeader, parent: &SealedHeader) -> Result<(), Error> {
|
||||
fn pre_validate_header(
|
||||
&self,
|
||||
header: &SealedHeader,
|
||||
parent: &SealedHeader,
|
||||
) -> Result<(), Error> {
|
||||
validation::validate_header_standalone(header, &self.chain_spec)?;
|
||||
validation::validate_header_regarding_parent(parent, header, &self.chain_spec)?;
|
||||
|
||||
if Some(header.number) < self.chain_spec.paris_status().block_number() {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_header(&self, header: &SealedHeader, total_difficulty: U256) -> Result<(), Error> {
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty) {
|
||||
// EIP-3675: Upgrade consensus to Proof-of-Stake:
|
||||
// https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0
|
||||
if header.difficulty != U256::ZERO {
|
||||
return Err(Error::TheMergeDifficultyIsNotZero)
|
||||
}
|
||||
|
||||
if header.nonce != 0 {
|
||||
return Err(Error::TheMergeNonceIsNotZero)
|
||||
}
|
||||
|
||||
if header.ommers_hash != EMPTY_OMMER_ROOT {
|
||||
return Err(Error::TheMergeOmmerRootIsNotEmpty)
|
||||
}
|
||||
|
||||
// mixHash is used instead of difficulty inside EVM
|
||||
// https://eips.ethereum.org/EIPS/eip-4399#using-mixhash-field-instead-of-difficulty
|
||||
} else {
|
||||
// TODO Consensus checks for old blocks:
|
||||
// * difficulty, mix_hash & nonce aka PoW stuff
|
||||
// low priority as syncing is done in reverse order
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -54,7 +80,7 @@ impl Consensus for BeaconConsensus {
|
||||
validation::validate_block_standalone(block)
|
||||
}
|
||||
|
||||
fn has_block_reward(&self, block_num: BlockNumber) -> bool {
|
||||
Some(block_num) < self.chain_spec.paris_status().block_number()
|
||||
fn has_block_reward(&self, total_difficulty: U256) -> bool {
|
||||
self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
use reth_interfaces::{consensus::Error, Result as RethResult};
|
||||
use reth_primitives::{
|
||||
BlockNumber, ChainSpec, Hardfork, Header, SealedBlock, SealedHeader, Transaction,
|
||||
TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy, EMPTY_OMMER_ROOT, U256,
|
||||
TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxLegacy,
|
||||
};
|
||||
use reth_provider::{AccountProvider, HeaderProvider};
|
||||
use std::{
|
||||
@@ -39,30 +39,12 @@ pub fn validate_header_standalone(
|
||||
}
|
||||
|
||||
// Check if base fee is set.
|
||||
if chain_spec.fork_active(Hardfork::London, header.number) && header.base_fee_per_gas.is_none()
|
||||
if chain_spec.fork(Hardfork::London).active_at_block(header.number) &&
|
||||
header.base_fee_per_gas.is_none()
|
||||
{
|
||||
return Err(Error::BaseFeeMissing)
|
||||
}
|
||||
|
||||
// EIP-3675: Upgrade consensus to Proof-of-Stake:
|
||||
// https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0
|
||||
if Some(header.number) >= chain_spec.paris_status().block_number() {
|
||||
if header.difficulty != U256::ZERO {
|
||||
return Err(Error::TheMergeDifficultyIsNotZero)
|
||||
}
|
||||
|
||||
if header.nonce != 0 {
|
||||
return Err(Error::TheMergeNonceIsNotZero)
|
||||
}
|
||||
|
||||
if header.ommers_hash != EMPTY_OMMER_ROOT {
|
||||
return Err(Error::TheMergeOmmerRootIsNotEmpty)
|
||||
}
|
||||
|
||||
// mixHash is used instead of difficulty inside EVM
|
||||
// https://eips.ethereum.org/EIPS/eip-4399#using-mixhash-field-instead-of-difficulty
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -78,7 +60,7 @@ pub fn validate_transaction_regarding_header(
|
||||
let chain_id = match transaction {
|
||||
Transaction::Legacy(TxLegacy { chain_id, .. }) => {
|
||||
// EIP-155: Simple replay attack protection: https://eips.ethereum.org/EIPS/eip-155
|
||||
if chain_spec.fork_active(Hardfork::SpuriousDragon, at_block_number) &&
|
||||
if chain_spec.fork(Hardfork::SpuriousDragon).active_at_block(at_block_number) &&
|
||||
chain_id.is_some()
|
||||
{
|
||||
return Err(Error::TransactionOldLegacyChainId)
|
||||
@@ -87,7 +69,7 @@ pub fn validate_transaction_regarding_header(
|
||||
}
|
||||
Transaction::Eip2930(TxEip2930 { chain_id, .. }) => {
|
||||
// EIP-2930: Optional access lists: https://eips.ethereum.org/EIPS/eip-2930 (New transaction type)
|
||||
if !chain_spec.fork_active(Hardfork::Berlin, at_block_number) {
|
||||
if !chain_spec.fork(Hardfork::Berlin).active_at_block(at_block_number) {
|
||||
return Err(Error::TransactionEip2930Disabled)
|
||||
}
|
||||
Some(*chain_id)
|
||||
@@ -99,7 +81,7 @@ pub fn validate_transaction_regarding_header(
|
||||
..
|
||||
}) => {
|
||||
// EIP-1559: Fee market change for ETH 1.0 chain https://eips.ethereum.org/EIPS/eip-1559
|
||||
if !chain_spec.fork_active(Hardfork::Berlin, at_block_number) {
|
||||
if !chain_spec.fork(Hardfork::Berlin).active_at_block(at_block_number) {
|
||||
return Err(Error::TransactionEip1559Disabled)
|
||||
}
|
||||
|
||||
@@ -259,15 +241,16 @@ pub fn validate_header_regarding_parent(
|
||||
}
|
||||
|
||||
// difficulty check is done by consensus.
|
||||
if chain_spec.paris_status().block_number() > Some(child.number) {
|
||||
// TODO how this needs to be checked? As ice age did increment it by some formula
|
||||
}
|
||||
// TODO(onbjerg): Unsure what the check here is supposed to be, but it should be moved to
|
||||
// [BeaconConsensus]. if chain_spec.paris_status().block_number() > Some(child.number) {
|
||||
// // TODO how this needs to be checked? As ice age did increment it by some formula
|
||||
//}
|
||||
|
||||
let mut parent_gas_limit = parent.gas_limit;
|
||||
|
||||
// By consensus, gas_limit is multiplied by elasticity (*2) on
|
||||
// on exact block that hardfork happens.
|
||||
if chain_spec.fork_block(Hardfork::London) == Some(child.number) {
|
||||
if chain_spec.fork(Hardfork::London).transitions_at_block(child.number) {
|
||||
parent_gas_limit = parent.gas_limit * constants::EIP1559_ELASTICITY_MULTIPLIER;
|
||||
}
|
||||
|
||||
@@ -287,19 +270,20 @@ pub fn validate_header_regarding_parent(
|
||||
}
|
||||
|
||||
// EIP-1559 check base fee
|
||||
if chain_spec.fork_active(Hardfork::London, child.number) {
|
||||
if chain_spec.fork(Hardfork::London).active_at_block(child.number) {
|
||||
let base_fee = child.base_fee_per_gas.ok_or(Error::BaseFeeMissing)?;
|
||||
|
||||
let expected_base_fee = if chain_spec.fork_block(Hardfork::London) == Some(child.number) {
|
||||
constants::EIP1559_INITIAL_BASE_FEE
|
||||
} else {
|
||||
// This BaseFeeMissing will not happen as previous blocks are checked to have them.
|
||||
calculate_next_block_base_fee(
|
||||
parent.gas_used,
|
||||
parent.gas_limit,
|
||||
parent.base_fee_per_gas.ok_or(Error::BaseFeeMissing)?,
|
||||
)
|
||||
};
|
||||
let expected_base_fee =
|
||||
if chain_spec.fork(Hardfork::London).transitions_at_block(child.number) {
|
||||
constants::EIP1559_INITIAL_BASE_FEE
|
||||
} else {
|
||||
// This BaseFeeMissing will not happen as previous blocks are checked to have them.
|
||||
calculate_next_block_base_fee(
|
||||
parent.gas_used,
|
||||
parent.gas_limit,
|
||||
parent.base_fee_per_gas.ok_or(Error::BaseFeeMissing)?,
|
||||
)
|
||||
};
|
||||
if expected_base_fee != base_fee {
|
||||
return Err(Error::BaseFeeDiff { expected: expected_base_fee, got: base_fee })
|
||||
}
|
||||
@@ -367,7 +351,7 @@ mod tests {
|
||||
use reth_interfaces::Result;
|
||||
use reth_primitives::{
|
||||
hex_literal::hex, Account, Address, BlockHash, Bytes, Header, Signature, TransactionKind,
|
||||
TransactionSigned, MAINNET,
|
||||
TransactionSigned, MAINNET, U256,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Reth block execution/validation configuration and constants
|
||||
|
||||
use reth_primitives::{BlockNumber, ChainSpec, Hardfork};
|
||||
use reth_primitives::{ChainSpec, Hardfork, Head};
|
||||
|
||||
/// Two ethereum worth of wei
|
||||
pub const WEI_2ETH: u128 = 2000000000000000000u128;
|
||||
@@ -10,82 +10,147 @@ pub const WEI_3ETH: u128 = 3000000000000000000u128;
|
||||
pub const WEI_5ETH: u128 = 5000000000000000000u128;
|
||||
|
||||
/// return revm_spec from spec configuration.
|
||||
pub fn revm_spec(chain_spec: &ChainSpec, for_block: BlockNumber) -> revm::SpecId {
|
||||
match for_block {
|
||||
b if chain_spec.fork_active(Hardfork::Shanghai, b) => revm::MERGE_EOF,
|
||||
b if Some(b) >= chain_spec.paris_status().block_number() => revm::MERGE,
|
||||
b if chain_spec.fork_active(Hardfork::London, b) => revm::LONDON,
|
||||
b if chain_spec.fork_active(Hardfork::Berlin, b) => revm::BERLIN,
|
||||
b if chain_spec.fork_active(Hardfork::Istanbul, b) => revm::ISTANBUL,
|
||||
b if chain_spec.fork_active(Hardfork::Petersburg, b) => revm::PETERSBURG,
|
||||
b if chain_spec.fork_active(Hardfork::Byzantium, b) => revm::BYZANTIUM,
|
||||
b if chain_spec.fork_active(Hardfork::SpuriousDragon, b) => revm::SPURIOUS_DRAGON,
|
||||
b if chain_spec.fork_active(Hardfork::Tangerine, b) => revm::TANGERINE,
|
||||
b if chain_spec.fork_active(Hardfork::Homestead, b) => revm::HOMESTEAD,
|
||||
b if chain_spec.fork_active(Hardfork::Frontier, b) => revm::FRONTIER,
|
||||
_ => panic!("wrong configuration"),
|
||||
pub fn revm_spec(chain_spec: &ChainSpec, block: Head) -> revm::SpecId {
|
||||
if chain_spec.fork(Hardfork::Shanghai).active_at_head(&block) {
|
||||
revm::MERGE_EOF
|
||||
} else if chain_spec.fork(Hardfork::Paris).active_at_head(&block) {
|
||||
revm::MERGE
|
||||
} else if chain_spec.fork(Hardfork::London).active_at_head(&block) {
|
||||
revm::LONDON
|
||||
} else if chain_spec.fork(Hardfork::Berlin).active_at_head(&block) {
|
||||
revm::BERLIN
|
||||
} else if chain_spec.fork(Hardfork::Istanbul).active_at_head(&block) {
|
||||
revm::ISTANBUL
|
||||
} else if chain_spec.fork(Hardfork::Petersburg).active_at_head(&block) {
|
||||
revm::PETERSBURG
|
||||
} else if chain_spec.fork(Hardfork::Byzantium).active_at_head(&block) {
|
||||
revm::BYZANTIUM
|
||||
} else if chain_spec.fork(Hardfork::SpuriousDragon).active_at_head(&block) {
|
||||
revm::SPURIOUS_DRAGON
|
||||
} else if chain_spec.fork(Hardfork::Tangerine).active_at_head(&block) {
|
||||
revm::TANGERINE
|
||||
} else if chain_spec.fork(Hardfork::Homestead).active_at_head(&block) {
|
||||
revm::HOMESTEAD
|
||||
} else if chain_spec.fork(Hardfork::Frontier).active_at_head(&block) {
|
||||
revm::FRONTIER
|
||||
} else {
|
||||
panic!("wrong configuration")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::config::revm_spec;
|
||||
use reth_primitives::{ChainSpecBuilder, MAINNET};
|
||||
use reth_primitives::{ChainSpecBuilder, Head, MAINNET, U256};
|
||||
#[test]
|
||||
fn test_to_revm_spec() {
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().paris_activated().build(), Head::default()),
|
||||
revm::MERGE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().london_activated().build(), Head::default()),
|
||||
revm::LONDON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().berlin_activated().build(), Head::default()),
|
||||
revm::BERLIN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().istanbul_activated().build(), Head::default()),
|
||||
revm::ISTANBUL
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().petersburg_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().petersburg_activated().build(), Head::default()),
|
||||
revm::PETERSBURG
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().byzantium_activated().build(), Head::default()),
|
||||
revm::BYZANTIUM
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().spurious_dragon_activated().build(), 1),
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().spurious_dragon_activated().build(),
|
||||
Head::default()
|
||||
),
|
||||
revm::SPURIOUS_DRAGON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(), 1),
|
||||
revm_spec(
|
||||
&ChainSpecBuilder::mainnet().tangerine_whistle_activated().build(),
|
||||
Head::default()
|
||||
),
|
||||
revm::TANGERINE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().homestead_activated().build(), Head::default()),
|
||||
revm::HOMESTEAD
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), 1),
|
||||
revm_spec(&ChainSpecBuilder::mainnet().frontier_activated().build(), Head::default()),
|
||||
revm::FRONTIER
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eth_spec() {
|
||||
assert_eq!(revm_spec(&MAINNET, 15537394 + 10), revm::MERGE);
|
||||
assert_eq!(revm_spec(&MAINNET, 15537394 - 10), revm::LONDON);
|
||||
assert_eq!(revm_spec(&MAINNET, 12244000 + 10), revm::BERLIN);
|
||||
assert_eq!(revm_spec(&MAINNET, 12244000 - 10), revm::ISTANBUL);
|
||||
assert_eq!(revm_spec(&MAINNET, 7280000 + 10), revm::PETERSBURG);
|
||||
assert_eq!(revm_spec(&MAINNET, 7280000 - 10), revm::BYZANTIUM);
|
||||
assert_eq!(revm_spec(&MAINNET, 2675000 + 10), revm::SPURIOUS_DRAGON);
|
||||
assert_eq!(revm_spec(&MAINNET, 2675000 - 10), revm::TANGERINE);
|
||||
assert_eq!(revm_spec(&MAINNET, 1150000 + 10), revm::HOMESTEAD);
|
||||
assert_eq!(revm_spec(&MAINNET, 1150000 - 10), revm::FRONTIER);
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&MAINNET,
|
||||
Head {
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_000u128),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
revm::MERGE
|
||||
);
|
||||
// TTD trumps the block number
|
||||
assert_eq!(
|
||||
revm_spec(
|
||||
&MAINNET,
|
||||
Head {
|
||||
number: 15537394 - 10,
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_000u128),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
revm::MERGE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 15537394 - 10, ..Default::default() }),
|
||||
revm::LONDON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 12244000 + 10, ..Default::default() }),
|
||||
revm::BERLIN
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 12244000 - 10, ..Default::default() }),
|
||||
revm::ISTANBUL
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 7280000 + 10, ..Default::default() }),
|
||||
revm::PETERSBURG
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 7280000 - 10, ..Default::default() }),
|
||||
revm::BYZANTIUM
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 2675000 + 10, ..Default::default() }),
|
||||
revm::SPURIOUS_DRAGON
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 2675000 - 10, ..Default::default() }),
|
||||
revm::TANGERINE
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 1150000 + 10, ..Default::default() }),
|
||||
revm::HOMESTEAD
|
||||
);
|
||||
assert_eq!(
|
||||
revm_spec(&MAINNET, Head { number: 1150000 - 10, ..Default::default() }),
|
||||
revm::FRONTIER
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ use crate::{
|
||||
use hashbrown::hash_map::Entry;
|
||||
use reth_interfaces::executor::{BlockExecutor, Error};
|
||||
use reth_primitives::{
|
||||
bloom::logs_bloom, Account, Address, Block, Bloom, ChainSpec, Hardfork, Header, Log, Receipt,
|
||||
TransactionSigned, H160, H256, U256,
|
||||
bloom::logs_bloom, Account, Address, Block, Bloom, ChainSpec, Hardfork, Head, Header, Log,
|
||||
Receipt, TransactionSigned, H160, H256, U256,
|
||||
};
|
||||
use reth_provider::StateProvider;
|
||||
use revm::{
|
||||
@@ -57,8 +57,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn init_block_env(&mut self, header: &Header) {
|
||||
let spec_id = revm_spec(self.chain_spec, header.number);
|
||||
fn init_block_env(&mut self, header: &Header, total_difficulty: U256) {
|
||||
let spec_id = revm_spec(
|
||||
self.chain_spec,
|
||||
Head {
|
||||
number: header.number,
|
||||
timestamp: header.timestamp,
|
||||
total_difficulty,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
self.evm.env.cfg.chain_id = U256::from(self.chain_spec.chain().id());
|
||||
self.evm.env.cfg.spec_id = spec_id;
|
||||
self.evm.env.cfg.perf_all_precompiles_have_balance = false;
|
||||
@@ -192,6 +200,7 @@ where
|
||||
pub fn block_reward_changeset(
|
||||
&mut self,
|
||||
header: &Header,
|
||||
total_difficulty: U256,
|
||||
ommers: &[Header],
|
||||
) -> Result<Option<BTreeMap<H160, AccountInfoChangeSet>>, Error> {
|
||||
// NOTE: Related to Ethereum reward change, for other network this is probably going to be
|
||||
@@ -204,11 +213,14 @@ where
|
||||
// ommer, we raise the block’s beneficiary by an additional 1/32 of the block reward
|
||||
// and the beneficiary of the ommer gets rewarded depending on the blocknumber.
|
||||
// Formally we define the function Ω:
|
||||
match header.number {
|
||||
n if Some(n) >= self.chain_spec.paris_status().block_number() => None,
|
||||
n if Some(n) >= self.chain_spec.fork_block(Hardfork::Petersburg) => Some(WEI_2ETH),
|
||||
n if Some(n) >= self.chain_spec.fork_block(Hardfork::Byzantium) => Some(WEI_3ETH),
|
||||
_ => Some(WEI_5ETH),
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty) {
|
||||
None
|
||||
} else if self.chain_spec.fork(Hardfork::Petersburg).active_at_block(header.number) {
|
||||
Some(WEI_2ETH)
|
||||
} else if self.chain_spec.fork(Hardfork::Byzantium).active_at_block(header.number) {
|
||||
Some(WEI_3ETH)
|
||||
} else {
|
||||
Some(WEI_5ETH)
|
||||
}
|
||||
.map(|reward| -> Result<_, _> {
|
||||
let mut reward_beneficiaries: BTreeMap<H160, u128> = BTreeMap::new();
|
||||
@@ -325,12 +337,13 @@ where
|
||||
fn execute(
|
||||
&mut self,
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
) -> Result<ExecutionResult, Error> {
|
||||
let Block { header, body, ommers } = block;
|
||||
let senders = self.recover_senders(body, senders)?;
|
||||
|
||||
self.init_block_env(header);
|
||||
self.init_block_env(header, total_difficulty);
|
||||
|
||||
let mut cumulative_gas_used = 0;
|
||||
// output of verification
|
||||
@@ -405,9 +418,9 @@ where
|
||||
return Err(Error::BlockGasUsed { got: cumulative_gas_used, expected: header.gas_used })
|
||||
}
|
||||
|
||||
let mut block_reward = self.block_reward_changeset(header, ommers)?;
|
||||
let mut block_reward = self.block_reward_changeset(header, total_difficulty, ommers)?;
|
||||
|
||||
if self.chain_spec.fork_block(Hardfork::Dao) == Some(header.number) {
|
||||
if self.chain_spec.fork(Hardfork::Dao).transitions_at_block(header.number) {
|
||||
let mut irregular_state_changeset = self.dao_fork_changeset()?;
|
||||
irregular_state_changeset.extend(block_reward.take().unwrap_or_default().into_iter());
|
||||
block_reward = Some(irregular_state_changeset);
|
||||
@@ -420,17 +433,19 @@ where
|
||||
/// Execute and verify block
|
||||
pub fn execute_and_verify_receipt<DB: StateProvider>(
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
chain_spec: &ChainSpec,
|
||||
db: &mut SubState<DB>,
|
||||
) -> Result<ExecutionResult, Error> {
|
||||
let execution_result = execute(block, senders, chain_spec, db)?;
|
||||
let execution_result = execute(block, total_difficulty, senders, chain_spec, db)?;
|
||||
|
||||
let receipts_iter = execution_result.changesets.iter().map(|changeset| &changeset.receipt);
|
||||
|
||||
if Some(block.header.number) >= chain_spec.fork_block(Hardfork::Byzantium) {
|
||||
if chain_spec.fork(Hardfork::Byzantium).active_at_block(block.header.number) {
|
||||
verify_receipt(block.header.receipts_root, block.header.logs_bloom, receipts_iter)?;
|
||||
}
|
||||
|
||||
// TODO Before Byzantium, receipts contained state root that would mean that expensive operation
|
||||
// as hashing that is needed for state root got calculated in every transaction
|
||||
// This was replaced with is_success flag.
|
||||
@@ -468,23 +483,23 @@ pub fn verify_receipt<'a>(
|
||||
/// additional TransactionStatechangeset for account that receives the reward.
|
||||
pub fn execute<DB: StateProvider>(
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
chain_spec: &ChainSpec,
|
||||
db: &mut SubState<DB>,
|
||||
) -> Result<ExecutionResult, Error> {
|
||||
let mut executor = Executor::new(chain_spec, db);
|
||||
executor.execute(block, senders)
|
||||
executor.execute(block, total_difficulty, senders)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::revm_wrap::State;
|
||||
use reth_primitives::{
|
||||
hex_literal::hex, keccak256, Account, Address, Bytes, ChainSpecBuilder, SealedBlock,
|
||||
StorageKey, H160, H256, MAINNET, U256,
|
||||
hex_literal::hex, keccak256, Account, Address, Bytes, ChainSpecBuilder, ForkCondition,
|
||||
SealedBlock, StorageKey, H160, H256, MAINNET, U256,
|
||||
};
|
||||
use reth_provider::{AccountProvider, BlockHashProvider, StateProvider};
|
||||
use reth_rlp::Decodable;
|
||||
@@ -598,7 +613,8 @@ mod tests {
|
||||
let mut db = SubState::new(State::new(db));
|
||||
|
||||
// execute chain and verify receipts
|
||||
let out = execute_and_verify_receipt(&block, None, &chain_spec, &mut db).unwrap();
|
||||
let out =
|
||||
execute_and_verify_receipt(&block, U256::ZERO, None, &chain_spec, &mut db).unwrap();
|
||||
|
||||
assert_eq!(out.changesets.len(), 1, "Should executed one transaction");
|
||||
|
||||
@@ -719,13 +735,14 @@ mod tests {
|
||||
|
||||
let chain_spec = ChainSpecBuilder::from(&*MAINNET)
|
||||
.homestead_activated()
|
||||
.with_fork(Hardfork::Dao, 1)
|
||||
.with_fork(Hardfork::Dao, ForkCondition::Block(1))
|
||||
.build();
|
||||
|
||||
let mut db = SubState::new(State::new(db));
|
||||
// execute chain and verify receipts
|
||||
let out = execute_and_verify_receipt(
|
||||
&Block { header, body: vec![], ommers: vec![] },
|
||||
U256::ZERO,
|
||||
None,
|
||||
&chain_spec,
|
||||
&mut db,
|
||||
@@ -813,7 +830,9 @@ mod tests {
|
||||
let mut db = SubState::new(State::new(db));
|
||||
|
||||
// execute chain and verify receipts
|
||||
let out = execute_and_verify_receipt(&block.unseal(), None, &chain_spec, &mut db).unwrap();
|
||||
let out =
|
||||
execute_and_verify_receipt(&block.unseal(), U256::ZERO, None, &chain_spec, &mut db)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(out.changesets.len(), 1, "Should executed one transaction");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use reth_primitives::{BlockHash, BlockNumber, SealedBlock, SealedHeader, H256};
|
||||
use reth_primitives::{BlockHash, BlockNumber, SealedBlock, SealedHeader, H256, U256};
|
||||
use std::fmt::Debug;
|
||||
use tokio::sync::watch::Receiver;
|
||||
|
||||
@@ -13,10 +13,23 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// Get a receiver for the fork choice state
|
||||
fn fork_choice_state(&self) -> Receiver<ForkchoiceState>;
|
||||
|
||||
/// Validate if header is correct and follows consensus specification.
|
||||
/// Validate if the header is correct and follows consensus specification.
|
||||
///
|
||||
/// This is called before properties that are not in the header itself (like total difficulty)
|
||||
/// have been computed.
|
||||
///
|
||||
/// **This should not be called for the genesis block**.
|
||||
fn validate_header(&self, header: &SealedHeader, parent: &SealedHeader) -> Result<(), Error>;
|
||||
fn pre_validate_header(
|
||||
&self,
|
||||
header: &SealedHeader,
|
||||
parent: &SealedHeader,
|
||||
) -> Result<(), Error>;
|
||||
|
||||
/// Validate if the header is correct and follows the consensus specification, including
|
||||
/// computed properties (like total difficulty).
|
||||
///
|
||||
/// Some consensus engines may want to do additional checks here.
|
||||
fn validate_header(&self, header: &SealedHeader, total_difficulty: U256) -> Result<(), Error>;
|
||||
|
||||
/// Validate a block disregarding world state, i.e. things that can be checked before sender
|
||||
/// recovery and execution.
|
||||
@@ -32,7 +45,7 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// This flag is needed as reth's changeset is indexed on transaction level granularity.
|
||||
///
|
||||
/// More info [here](https://github.com/paradigmxyz/reth/issues/237)
|
||||
fn has_block_reward(&self, block_num: BlockNumber) -> bool;
|
||||
fn has_block_reward(&self, total_difficulty: U256) -> bool;
|
||||
}
|
||||
|
||||
/// Consensus Errors
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use reth_primitives::{Address, Block, Bloom, H256};
|
||||
use reth_primitives::{Address, Block, Bloom, H256, U256};
|
||||
use thiserror::Error;
|
||||
|
||||
/// An executor capable of executing a block.
|
||||
@@ -13,7 +13,12 @@ pub trait BlockExecutor<T> {
|
||||
/// provided block's transactions internally. We use this to allow for calculating senders in
|
||||
/// parallel in e.g. staged sync, so that execution can happen without paying for sender
|
||||
/// recovery costs.
|
||||
fn execute(&mut self, block: &Block, senders: Option<Vec<Address>>) -> Result<T, Error>;
|
||||
fn execute(
|
||||
&mut self,
|
||||
block: &Block,
|
||||
total_difficulty: U256,
|
||||
senders: Option<Vec<Address>>,
|
||||
) -> Result<T, Error>;
|
||||
}
|
||||
|
||||
/// BlockExecutor Errors
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::p2p::{download::DownloadClient, error::PeerRequestResult, priority::Priority};
|
||||
use futures::Future;
|
||||
pub use reth_eth_wire::BlockHeaders;
|
||||
use reth_primitives::{BlockHashOrNumber, Header, HeadersDirection, H256, U256};
|
||||
use reth_primitives::{BlockHashOrNumber, Head, Header, HeadersDirection};
|
||||
use std::{fmt::Debug, pin::Pin};
|
||||
|
||||
/// The header request struct to be sent to connected peers, which
|
||||
@@ -43,5 +43,5 @@ pub trait HeadersClient: DownloadClient {
|
||||
/// The status updater for updating the status of the p2p node
|
||||
pub trait StatusUpdater: Send + Sync {
|
||||
/// Updates the status of the p2p node
|
||||
fn update_status(&self, height: u64, hash: H256, total_difficulty: U256);
|
||||
fn update_status(&self, head: Head);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ pub fn validate_header_download(
|
||||
) -> DownloadResult<()> {
|
||||
ensure_parent(header, parent)?;
|
||||
consensus
|
||||
.validate_header(header, parent)
|
||||
.pre_validate_header(header, parent)
|
||||
.map_err(|error| DownloadError::HeaderValidation { hash: parent.hash(), error })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Testing support for headers related interfaces.
|
||||
use crate::{
|
||||
consensus::{self, Consensus},
|
||||
consensus::{self, Consensus, Error},
|
||||
p2p::{
|
||||
download::DownloadClient,
|
||||
error::{DownloadError, DownloadResult, PeerRequestResult, RequestError},
|
||||
@@ -14,8 +14,8 @@ use crate::{
|
||||
use futures::{future, Future, FutureExt, Stream, StreamExt};
|
||||
use reth_eth_wire::BlockHeaders;
|
||||
use reth_primitives::{
|
||||
BlockHash, BlockNumber, Header, HeadersDirection, PeerId, SealedBlock, SealedHeader,
|
||||
WithPeerId, H256,
|
||||
BlockHash, BlockNumber, Head, Header, HeadersDirection, PeerId, SealedBlock, SealedHeader,
|
||||
WithPeerId, H256, U256,
|
||||
};
|
||||
use reth_rpc_types::engine::ForkchoiceState;
|
||||
use std::{
|
||||
@@ -156,7 +156,7 @@ impl Stream for TestDownload {
|
||||
}
|
||||
|
||||
let empty = SealedHeader::default();
|
||||
if let Err(error) = this.consensus.validate_header(&empty, &empty) {
|
||||
if let Err(error) = this.consensus.pre_validate_header(&empty, &empty) {
|
||||
this.done = true;
|
||||
return Poll::Ready(Some(Err(DownloadError::HeaderValidation {
|
||||
hash: empty.hash(),
|
||||
@@ -303,7 +303,7 @@ impl TestConsensus {
|
||||
pub struct TestStatusUpdater;
|
||||
|
||||
impl StatusUpdater for TestStatusUpdater {
|
||||
fn update_status(&self, _height: u64, _hash: H256, _total_difficulty: reth_primitives::U256) {}
|
||||
fn update_status(&self, _: Head) {}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -312,11 +312,19 @@ impl Consensus for TestConsensus {
|
||||
self.channel.1.clone()
|
||||
}
|
||||
|
||||
fn validate_header(
|
||||
fn pre_validate_header(
|
||||
&self,
|
||||
_header: &SealedHeader,
|
||||
_parent: &SealedHeader,
|
||||
) -> Result<(), consensus::Error> {
|
||||
header: &SealedHeader,
|
||||
parent: &SealedHeader,
|
||||
) -> Result<(), Error> {
|
||||
if self.fail_validation() {
|
||||
Err(consensus::Error::BaseFeeMissing)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_header(&self, header: &SealedHeader, total_difficulty: U256) -> Result<(), Error> {
|
||||
if self.fail_validation() {
|
||||
Err(consensus::Error::BaseFeeMissing)
|
||||
} else {
|
||||
@@ -331,7 +339,8 @@ impl Consensus for TestConsensus {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
fn has_block_reward(&self, _block_num: BlockNumber) -> bool {
|
||||
|
||||
fn has_block_reward(&self, _: U256) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ use reth_primitives::{Chain, ForkId, PeerId, H256, U256};
|
||||
/// .total_difficulty(U256::from(100))
|
||||
/// .blockhash(H256::from(MAINNET_GENESIS))
|
||||
/// .genesis(H256::from(MAINNET_GENESIS))
|
||||
/// .forkid(Hardfork::Latest.fork_id(&MAINNET).unwrap())
|
||||
/// .forkid(Hardfork::Paris.fork_id(&MAINNET).unwrap())
|
||||
/// .build();
|
||||
///
|
||||
/// assert_eq!(
|
||||
@@ -32,7 +32,7 @@ use reth_primitives::{Chain, ForkId, PeerId, H256, U256};
|
||||
/// total_difficulty: U256::from(100),
|
||||
/// blockhash: H256::from(MAINNET_GENESIS),
|
||||
/// genesis: H256::from(MAINNET_GENESIS),
|
||||
/// forkid: Hardfork::Latest.fork_id(&MAINNET).unwrap(),
|
||||
/// forkid: Hardfork::Paris.fork_id(&MAINNET).unwrap(),
|
||||
/// }
|
||||
/// );
|
||||
/// ```
|
||||
|
||||
@@ -266,7 +266,7 @@ mod tests {
|
||||
use ethers_core::types::Chain;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use reth_ecies::{stream::ECIESStream, util::pk2id};
|
||||
use reth_primitives::{ForkFilter, H256, U256};
|
||||
use reth_primitives::{ForkFilter, Head, H256, U256};
|
||||
use secp256k1::{SecretKey, SECP256K1};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
use tokio_util::codec::Decoder;
|
||||
@@ -274,7 +274,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn can_handshake() {
|
||||
let genesis = H256::random();
|
||||
let fork_filter = ForkFilter::new(0, genesis, Vec::<u64>::new());
|
||||
let fork_filter = ForkFilter::new(Head::default(), genesis, Vec::new());
|
||||
|
||||
let status = Status {
|
||||
version: EthVersion::Eth67 as u8,
|
||||
@@ -408,7 +408,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let genesis = H256::random();
|
||||
let fork_filter = ForkFilter::new(0, genesis, Vec::<u64>::new());
|
||||
let fork_filter = ForkFilter::new(Head::default(), genesis, Vec::new());
|
||||
|
||||
let status = Status {
|
||||
version: EthVersion::Eth67 as u8,
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use crate::{BlockHashNumber, EthVersion, StatusBuilder};
|
||||
use crate::{EthVersion, StatusBuilder};
|
||||
|
||||
use ethers_core::utils::Genesis;
|
||||
use reth_codecs::derive_arbitrary;
|
||||
use reth_primitives::{
|
||||
constants::EIP1559_INITIAL_BASE_FEE, Chain, ChainSpec, ForkId, Hardfork, Header, H256, MAINNET,
|
||||
U256,
|
||||
};
|
||||
use reth_primitives::{Chain, ChainSpec, ForkId, Hardfork, Head, H256, MAINNET, U256};
|
||||
use reth_rlp::{RlpDecodable, RlpEncodable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{Debug, Display};
|
||||
@@ -47,32 +44,15 @@ impl From<Genesis> for Status {
|
||||
fn from(genesis: Genesis) -> Status {
|
||||
let chain = genesis.config.chain_id;
|
||||
let total_difficulty = genesis.difficulty.into();
|
||||
let mut chainspec = ChainSpec::from(genesis);
|
||||
let mut header = Header::from(chainspec.genesis().clone());
|
||||
|
||||
let hardforks = chainspec.hardforks();
|
||||
|
||||
// set initial base fee depending on eip-1559
|
||||
if Some(&0u64) == hardforks.get(&Hardfork::London) {
|
||||
header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE);
|
||||
}
|
||||
|
||||
// calculate the hash
|
||||
let sealed_header = header.seal();
|
||||
|
||||
// set the new genesis hash after modifying the base fee
|
||||
chainspec.genesis_hash = sealed_header.hash();
|
||||
|
||||
// we need to calculate the fork id AFTER re-setting the genesis hash
|
||||
let forkid = chainspec.fork_id(0);
|
||||
let chainspec = ChainSpec::from(genesis);
|
||||
|
||||
Status {
|
||||
version: EthVersion::Eth67 as u8,
|
||||
chain: Chain::Id(chain),
|
||||
total_difficulty,
|
||||
blockhash: sealed_header.hash(),
|
||||
genesis: sealed_header.hash(),
|
||||
forkid,
|
||||
blockhash: chainspec.genesis_hash(),
|
||||
genesis: chainspec.genesis_hash(),
|
||||
forkid: chainspec.fork_id(&Head::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,20 +64,16 @@ impl Status {
|
||||
}
|
||||
|
||||
/// Create a [`StatusBuilder`] from the given [`ChainSpec`](reth_primitives::ChainSpec) and
|
||||
/// head block number.
|
||||
/// head block.
|
||||
///
|
||||
/// Sets the `chain` and `genesis`, `blockhash`, and `forkid` fields based on the [`ChainSpec`]
|
||||
/// and head.
|
||||
///
|
||||
/// The user should set the `total_difficulty` field if desired. Otherwise, the total
|
||||
/// difficulty will be set to the [`Default`](std::default::Default) implementation for
|
||||
/// [`Status`].
|
||||
pub fn spec_builder(spec: &ChainSpec, head: &BlockHashNumber) -> StatusBuilder {
|
||||
pub fn spec_builder(spec: &ChainSpec, head: &Head) -> StatusBuilder {
|
||||
Self::builder()
|
||||
.chain(spec.chain)
|
||||
.genesis(spec.genesis_hash())
|
||||
.blockhash(head.hash)
|
||||
.forkid(spec.fork_id(head.number))
|
||||
.forkid(spec.fork_id(head))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
NetworkHandle, NetworkManager,
|
||||
};
|
||||
use reth_discv4::{Discv4Config, Discv4ConfigBuilder, DEFAULT_DISCOVERY_PORT};
|
||||
use reth_primitives::{ChainSpec, ForkFilter, NodeRecord, PeerId, MAINNET};
|
||||
use reth_primitives::{ChainSpec, ForkFilter, Head, NodeRecord, PeerId, MAINNET, U256};
|
||||
use reth_provider::{BlockProvider, HeaderProvider};
|
||||
use reth_tasks::TaskExecutor;
|
||||
use secp256k1::{SecretKey, SECP256K1};
|
||||
@@ -27,7 +27,7 @@ mod __reexport {
|
||||
pub use __reexport::*;
|
||||
use reth_dns_discovery::DnsDiscoveryConfig;
|
||||
use reth_ecies::util::pk2id;
|
||||
use reth_eth_wire::{BlockHashNumber, HelloMessage, Status};
|
||||
use reth_eth_wire::{HelloMessage, Status};
|
||||
|
||||
/// Convenience function to create a new random [`SecretKey`]
|
||||
pub fn rng_secret_key() -> SecretKey {
|
||||
@@ -149,7 +149,7 @@ pub struct NetworkConfigBuilder {
|
||||
/// Sets the hello message for the p2p handshake in RLPx
|
||||
hello_message: Option<HelloMessage>,
|
||||
/// Head used to start set for the fork filter and status.
|
||||
head: Option<BlockHashNumber>,
|
||||
head: Option<Head>,
|
||||
}
|
||||
|
||||
// === impl NetworkConfigBuilder ===
|
||||
@@ -304,13 +304,18 @@ impl NetworkConfigBuilder {
|
||||
hello_message.unwrap_or_else(|| HelloMessage::builder(peer_id).build());
|
||||
hello_message.port = listener_addr.port();
|
||||
|
||||
let head = head.unwrap_or(BlockHashNumber { hash: chain_spec.genesis_hash(), number: 0 });
|
||||
let head = head.unwrap_or(Head {
|
||||
hash: chain_spec.genesis_hash(),
|
||||
number: 0,
|
||||
total_difficulty: U256::ZERO,
|
||||
timestamp: 0,
|
||||
});
|
||||
|
||||
// set the status
|
||||
let status = Status::spec_builder(&chain_spec, &head).build();
|
||||
|
||||
// set a fork filter based on the chain spec and head
|
||||
let fork_filter = chain_spec.fork_filter(head.number);
|
||||
let fork_filter = chain_spec.fork_filter(head);
|
||||
|
||||
// If default DNS config is used then we add the known dns network to bootstrap from
|
||||
if let Some(dns_networks) =
|
||||
|
||||
@@ -533,10 +533,8 @@ where
|
||||
NetworkHandleMessage::GetStatus(tx) => {
|
||||
let _ = tx.send(self.status());
|
||||
}
|
||||
NetworkHandleMessage::StatusUpdate { height, hash, total_difficulty } => {
|
||||
if let Some(transition) =
|
||||
self.swarm.sessions_mut().on_status_update(height, hash, total_difficulty)
|
||||
{
|
||||
NetworkHandleMessage::StatusUpdate { head } => {
|
||||
if let Some(transition) = self.swarm.sessions_mut().on_status_update(head) {
|
||||
self.swarm.state_mut().update_fork_id(transition.current);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use reth_net_common::bandwidth_meter::BandwidthMeter;
|
||||
use reth_network_api::{
|
||||
NetworkError, NetworkInfo, NetworkStatus, PeerKind, Peers, PeersInfo, ReputationChangeKind,
|
||||
};
|
||||
use reth_primitives::{NodeRecord, PeerId, TransactionSigned, TxHash, H256, U256};
|
||||
use reth_primitives::{Head, NodeRecord, PeerId, TransactionSigned, TxHash, H256};
|
||||
use std::{
|
||||
net::SocketAddr,
|
||||
sync::{
|
||||
@@ -124,8 +124,8 @@ impl NetworkHandle {
|
||||
}
|
||||
|
||||
/// Update the status of the node.
|
||||
pub fn update_status(&self, height: u64, hash: H256, total_difficulty: U256) {
|
||||
self.send_message(NetworkHandleMessage::StatusUpdate { height, hash, total_difficulty });
|
||||
pub fn update_status(&self, head: Head) {
|
||||
self.send_message(NetworkHandleMessage::StatusUpdate { head });
|
||||
}
|
||||
|
||||
/// Announce a block over devp2p
|
||||
@@ -236,8 +236,8 @@ impl NetworkInfo for NetworkHandle {
|
||||
|
||||
impl StatusUpdater for NetworkHandle {
|
||||
/// Update the status of the node.
|
||||
fn update_status(&self, height: u64, hash: H256, total_difficulty: U256) {
|
||||
self.send_message(NetworkHandleMessage::StatusUpdate { height, hash, total_difficulty });
|
||||
fn update_status(&self, head: Head) {
|
||||
self.send_message(NetworkHandleMessage::StatusUpdate { head });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ pub(crate) enum NetworkHandleMessage {
|
||||
/// Returns the client that can be used to interact with the network.
|
||||
FetchClient(oneshot::Sender<FetchClient>),
|
||||
/// Apply a status update.
|
||||
StatusUpdate { height: u64, hash: H256, total_difficulty: U256 },
|
||||
StatusUpdate { head: Head },
|
||||
/// Get the currenet status
|
||||
GetStatus(oneshot::Sender<NetworkStatus>),
|
||||
/// Get PeerInfo from all the peers
|
||||
|
||||
@@ -21,7 +21,7 @@ use reth_eth_wire::{
|
||||
};
|
||||
use reth_metrics_common::metered_sender::MeteredSender;
|
||||
use reth_net_common::bandwidth_meter::{BandwidthMeter, MeteredStream};
|
||||
use reth_primitives::{ForkFilter, ForkId, ForkTransition, PeerId, H256, U256};
|
||||
use reth_primitives::{ForkFilter, ForkId, ForkTransition, Head, PeerId};
|
||||
use reth_tasks::TaskExecutor;
|
||||
use secp256k1::SecretKey;
|
||||
use std::{
|
||||
@@ -176,15 +176,10 @@ impl SessionManager {
|
||||
///
|
||||
/// If the updated activated another fork, this will return a [`ForkTransition`] and updates the
|
||||
/// active [`ForkId`](ForkId). See also [`ForkFilter::set_head`].
|
||||
pub(crate) fn on_status_update(
|
||||
&mut self,
|
||||
height: u64,
|
||||
hash: H256,
|
||||
total_difficulty: U256,
|
||||
) -> Option<ForkTransition> {
|
||||
self.status.blockhash = hash;
|
||||
self.status.total_difficulty = total_difficulty;
|
||||
self.fork_filter.set_head(height)
|
||||
pub(crate) fn on_status_update(&mut self, head: Head) -> Option<ForkTransition> {
|
||||
self.status.blockhash = head.hash;
|
||||
self.status.total_difficulty = head.total_difficulty;
|
||||
self.fork_filter.set_head(head)
|
||||
}
|
||||
|
||||
/// An incoming TCP connection was received. This starts the authentication process to turn this
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::{fmt, str::FromStr};
|
||||
|
||||
// The chain spec module.
|
||||
mod spec;
|
||||
pub use spec::{ChainSpec, ChainSpecBuilder, ParisStatus, GOERLI, MAINNET, SEPOLIA};
|
||||
pub use spec::{ChainSpec, ChainSpecBuilder, ForkCondition, GOERLI, MAINNET, SEPOLIA};
|
||||
|
||||
// The chain info module.
|
||||
mod info;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,13 @@
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use crate::{BlockNumber, H256};
|
||||
use crate::{BlockNumber, Head, H256};
|
||||
use crc::*;
|
||||
use reth_codecs::derive_arbitrary;
|
||||
use reth_rlp::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
fmt,
|
||||
ops::{Add, AddAssign},
|
||||
@@ -46,9 +47,12 @@ impl From<H256> for ForkHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<BlockNumber> for ForkHash {
|
||||
fn add_assign(&mut self, block: BlockNumber) {
|
||||
let blob = block.to_be_bytes();
|
||||
impl<T> AddAssign<T> for ForkHash
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
fn add_assign(&mut self, v: T) {
|
||||
let blob = v.into().to_be_bytes();
|
||||
let digest = CRC_32_IEEE.digest_with_initial(u32::from_be_bytes(self.0));
|
||||
let value = digest.finalize();
|
||||
let mut digest = CRC_32_IEEE.digest_with_initial(value);
|
||||
@@ -57,14 +61,50 @@ impl AddAssign<BlockNumber> for ForkHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<BlockNumber> for ForkHash {
|
||||
impl<T> Add<T> for ForkHash
|
||||
where
|
||||
T: Into<u64>,
|
||||
{
|
||||
type Output = Self;
|
||||
fn add(mut self, block: BlockNumber) -> Self {
|
||||
fn add(mut self, block: T) -> Self {
|
||||
self += block;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ForkFilterKey {
|
||||
Block(BlockNumber),
|
||||
Time(u64),
|
||||
}
|
||||
|
||||
impl PartialOrd for ForkFilterKey {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ForkFilterKey {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(ForkFilterKey::Block(a), ForkFilterKey::Block(b)) => a.cmp(b),
|
||||
(ForkFilterKey::Time(a), ForkFilterKey::Time(b)) => a.cmp(b),
|
||||
(ForkFilterKey::Block(_), ForkFilterKey::Time(_)) => Ordering::Less,
|
||||
_ => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ForkFilterKey> for u64 {
|
||||
fn from(value: ForkFilterKey) -> Self {
|
||||
match value {
|
||||
ForkFilterKey::Block(block) => block,
|
||||
ForkFilterKey::Time(time) => time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A fork identifier as defined by EIP-2124.
|
||||
/// Serves as the chain compatibility identifier.
|
||||
#[derive_arbitrary(rlp)]
|
||||
@@ -82,10 +122,10 @@ impl Add<BlockNumber> for ForkHash {
|
||||
Deserialize,
|
||||
)]
|
||||
pub struct ForkId {
|
||||
/// CRC32 checksum of the all fork blocks from genesis.
|
||||
/// CRC32 checksum of the all fork blocks and timestamps from genesis.
|
||||
pub hash: ForkHash,
|
||||
/// Next upcoming fork block number, 0 if not yet known.
|
||||
pub next: BlockNumber,
|
||||
/// Next upcoming fork block number or timestamp, 0 if not yet known.
|
||||
pub next: u64,
|
||||
}
|
||||
|
||||
/// Reason for rejecting provided `ForkId`.
|
||||
@@ -115,9 +155,17 @@ pub enum ValidationError {
|
||||
/// compatibility.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ForkFilter {
|
||||
forks: BTreeMap<BlockNumber, ForkHash>,
|
||||
/// The forks in the filter are keyed by `(timestamp, block)`. This ensures that block-based
|
||||
/// forks (`time == 0`) are processed before time-based forks as required by
|
||||
/// [EIP-6122][eip-6122].
|
||||
///
|
||||
/// Time-based forks have their block number set to 0, allowing easy comparisons with a [Head];
|
||||
/// a fork is active if both it's time and block number are less than or equal to [Head].
|
||||
///
|
||||
/// [eip-6122]: https://eips.ethereum.org/EIPS/eip-6122
|
||||
forks: BTreeMap<ForkFilterKey, ForkHash>,
|
||||
|
||||
head: BlockNumber,
|
||||
head: Head,
|
||||
|
||||
cache: Cache,
|
||||
}
|
||||
@@ -125,22 +173,22 @@ pub struct ForkFilter {
|
||||
impl ForkFilter {
|
||||
/// Create the filter from provided head, genesis block hash, past forks and expected future
|
||||
/// forks.
|
||||
pub fn new<F, B>(head: BlockNumber, genesis: H256, forks: F) -> Self
|
||||
pub fn new<F>(head: Head, genesis: H256, forks: F) -> Self
|
||||
where
|
||||
F: IntoIterator<Item = B>,
|
||||
B: Into<BlockNumber>,
|
||||
F: IntoIterator<Item = ForkFilterKey>,
|
||||
{
|
||||
let genesis_fork_hash = ForkHash::from(genesis);
|
||||
let mut forks = forks.into_iter().map(Into::into).collect::<BTreeSet<_>>();
|
||||
forks.remove(&0);
|
||||
let mut forks = forks.into_iter().collect::<BTreeSet<_>>();
|
||||
forks.remove(&ForkFilterKey::Time(0));
|
||||
forks.remove(&ForkFilterKey::Block(0));
|
||||
|
||||
let forks = forks
|
||||
.into_iter()
|
||||
.fold(
|
||||
(BTreeMap::from([(0, genesis_fork_hash)]), genesis_fork_hash),
|
||||
|(mut acc, base_hash), block| {
|
||||
let fork_hash = base_hash + block;
|
||||
acc.insert(block, fork_hash);
|
||||
(BTreeMap::from([(ForkFilterKey::Block(0), genesis_fork_hash)]), genesis_fork_hash),
|
||||
|(mut acc, base_hash), key| {
|
||||
let fork_hash = base_hash + u64::from(key);
|
||||
acc.insert(key, fork_hash);
|
||||
(acc, fork_hash)
|
||||
},
|
||||
)
|
||||
@@ -151,15 +199,19 @@ impl ForkFilter {
|
||||
Self { forks, head, cache }
|
||||
}
|
||||
|
||||
fn set_head_priv(&mut self, head: BlockNumber) -> Option<ForkTransition> {
|
||||
fn set_head_priv(&mut self, head: Head) -> Option<ForkTransition> {
|
||||
let recompute_cache = {
|
||||
if head < self.cache.epoch_start {
|
||||
true
|
||||
} else if let Some(epoch_end) = self.cache.epoch_end {
|
||||
head >= epoch_end
|
||||
} else {
|
||||
false
|
||||
}
|
||||
let head_in_past = match self.cache.epoch_start {
|
||||
ForkFilterKey::Block(epoch_start_block) => head.number < epoch_start_block,
|
||||
ForkFilterKey::Time(epoch_start_time) => head.timestamp < epoch_start_time,
|
||||
};
|
||||
let head_in_future = match self.cache.epoch_end {
|
||||
Some(ForkFilterKey::Block(epoch_end_block)) => head.number >= epoch_end_block,
|
||||
Some(ForkFilterKey::Time(epoch_end_time)) => head.timestamp >= epoch_end_time,
|
||||
None => false,
|
||||
};
|
||||
|
||||
head_in_past || head_in_future
|
||||
};
|
||||
|
||||
let mut transition = None;
|
||||
@@ -181,7 +233,7 @@ impl ForkFilter {
|
||||
/// Set the current head.
|
||||
///
|
||||
/// If the update updates the current [`ForkId`] it returns a [`ForkTransition`]
|
||||
pub fn set_head(&mut self, head: BlockNumber) -> Option<ForkTransition> {
|
||||
pub fn set_head(&mut self, head: Head) -> Option<ForkTransition> {
|
||||
self.set_head_priv(head)
|
||||
}
|
||||
|
||||
@@ -207,8 +259,16 @@ impl ForkFilter {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
// We check if this fork is time-based or block number-based
|
||||
// NOTE: This is a bit hacky but I'm unsure how else we can figure out when to use
|
||||
// timestamp vs when to use block number..
|
||||
let head_block_or_time = match self.cache.epoch_start {
|
||||
ForkFilterKey::Block(_) => self.head.number,
|
||||
ForkFilterKey::Time(_) => self.head.timestamp,
|
||||
};
|
||||
|
||||
//... compare local head to FORK_NEXT.
|
||||
return if self.head >= fork_id.next {
|
||||
return if head_block_or_time >= fork_id.next {
|
||||
// 1a) A remotely announced but remotely not passed block is already passed locally,
|
||||
// disconnect, since the chains are incompatible.
|
||||
Err(ValidationError::LocalIncompatibleOrStale {
|
||||
@@ -225,10 +285,10 @@ impl ForkFilter {
|
||||
let mut it = self.cache.past.iter();
|
||||
while let Some((_, hash)) = it.next() {
|
||||
if *hash == fork_id.hash {
|
||||
// ...and the remote FORK_NEXT matches with the locally following fork block number,
|
||||
// connect.
|
||||
if let Some((actual_fork_block, _)) = it.next() {
|
||||
return if *actual_fork_block == fork_id.next {
|
||||
// ...and the remote FORK_NEXT matches with the locally following fork block number
|
||||
// or timestamp, connect.
|
||||
if let Some((actual_key, _)) = it.next() {
|
||||
return if u64::from(*actual_key) == fork_id.next {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::RemoteStale { local: self.current(), remote: fork_id })
|
||||
@@ -267,28 +327,35 @@ pub struct ForkTransition {
|
||||
struct Cache {
|
||||
// An epoch is a period between forks.
|
||||
// When we progress from one fork to the next one we move to the next epoch.
|
||||
epoch_start: BlockNumber,
|
||||
epoch_end: Option<BlockNumber>,
|
||||
past: Vec<(BlockNumber, ForkHash)>,
|
||||
epoch_start: ForkFilterKey,
|
||||
epoch_end: Option<ForkFilterKey>,
|
||||
past: Vec<(ForkFilterKey, ForkHash)>,
|
||||
future: Vec<ForkHash>,
|
||||
fork_id: ForkId,
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
/// Compute cache.
|
||||
fn compute_cache(forks: &BTreeMap<BlockNumber, ForkHash>, head: BlockNumber) -> Self {
|
||||
fn compute_cache(forks: &BTreeMap<ForkFilterKey, ForkHash>, head: Head) -> Self {
|
||||
let mut past = Vec::with_capacity(forks.len());
|
||||
let mut future = Vec::with_capacity(forks.len());
|
||||
|
||||
let mut epoch_start = 0;
|
||||
let mut epoch_start = ForkFilterKey::Block(0);
|
||||
let mut epoch_end = None;
|
||||
for (block, hash) in forks {
|
||||
if *block <= head {
|
||||
epoch_start = *block;
|
||||
past.push((*block, *hash));
|
||||
for (key, hash) in forks {
|
||||
let active = if let ForkFilterKey::Block(block) = key {
|
||||
*block <= head.number
|
||||
} else if let ForkFilterKey::Time(time) = key {
|
||||
*time <= head.timestamp
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
if active {
|
||||
epoch_start = *key;
|
||||
past.push((*key, *hash));
|
||||
} else {
|
||||
if epoch_end.is_none() {
|
||||
epoch_end = Some(*block);
|
||||
epoch_end = Some(*key);
|
||||
}
|
||||
future.push(*hash);
|
||||
}
|
||||
@@ -296,7 +363,7 @@ impl Cache {
|
||||
|
||||
let fork_id = ForkId {
|
||||
hash: past.last().expect("there is always at least one - genesis - fork hash; qed").1,
|
||||
next: epoch_end.unwrap_or(0),
|
||||
next: epoch_end.unwrap_or(ForkFilterKey::Block(0)).into(),
|
||||
};
|
||||
|
||||
Self { epoch_start, epoch_end, past, future, fork_id }
|
||||
@@ -311,34 +378,40 @@ mod tests {
|
||||
H256(hex!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"));
|
||||
|
||||
// EIP test vectors.
|
||||
|
||||
#[test]
|
||||
fn forkhash() {
|
||||
let mut fork_hash = ForkHash::from(GENESIS_HASH);
|
||||
assert_eq!(fork_hash.0, hex!("fc64ec04"));
|
||||
|
||||
fork_hash += 1_150_000;
|
||||
fork_hash += 1_150_000u64;
|
||||
assert_eq!(fork_hash.0, hex!("97c2c34c"));
|
||||
|
||||
fork_hash += 1_920_000;
|
||||
fork_hash += 1_920_000u64;
|
||||
assert_eq!(fork_hash.0, hex!("91d1f948"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compatibility_check() {
|
||||
let mut filter = ForkFilter::new(
|
||||
0,
|
||||
Head { number: 0, ..Default::default() },
|
||||
GENESIS_HASH,
|
||||
vec![1_150_000u64, 1_920_000, 2_463_000, 2_675_000, 4_370_000, 7_280_000],
|
||||
vec![
|
||||
ForkFilterKey::Block(1_150_000),
|
||||
ForkFilterKey::Block(1_920_000),
|
||||
ForkFilterKey::Block(2_463_000),
|
||||
ForkFilterKey::Block(2_675_000),
|
||||
ForkFilterKey::Block(4_370_000),
|
||||
ForkFilterKey::Block(7_280_000),
|
||||
],
|
||||
);
|
||||
|
||||
// Local is mainnet Petersburg, remote announces the same. No future fork is announced.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("668db0af")), next: 0 }), Ok(()));
|
||||
|
||||
// Local is mainnet Petersburg, remote announces the same. Remote also announces a next fork
|
||||
// at block 0xffffffff, but that is uncertain.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
assert_eq!(
|
||||
filter.validate(ForkId { hash: ForkHash(hex!("668db0af")), next: BlockNumber::MAX }),
|
||||
Ok(())
|
||||
@@ -348,13 +421,13 @@ mod tests {
|
||||
// announces also Byzantium, but it's not yet aware of Petersburg (e.g. non updated
|
||||
// node before the fork). In this case we don't know if Petersburg passed yet or
|
||||
// not.
|
||||
filter.set_head(7_279_999);
|
||||
filter.set_head(Head { number: 7_279_999, ..Default::default() });
|
||||
assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 0 }), Ok(()));
|
||||
|
||||
// Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote
|
||||
// announces also Byzantium, and it's also aware of Petersburg (e.g. updated node
|
||||
// before the fork). We don't know if Petersburg passed yet (will pass) or not.
|
||||
filter.set_head(7_279_999);
|
||||
filter.set_head(Head { number: 7_279_999, ..Default::default() });
|
||||
assert_eq!(
|
||||
filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 7_280_000 }),
|
||||
Ok(())
|
||||
@@ -364,7 +437,7 @@ mod tests {
|
||||
// announces also Byzantium, and it's also aware of some random fork (e.g.
|
||||
// misconfigured Petersburg). As neither forks passed at neither nodes, they may
|
||||
// mismatch, but we still connect for now.
|
||||
filter.set_head(7_279_999);
|
||||
filter.set_head(Head { number: 7_279_999, ..Default::default() });
|
||||
assert_eq!(
|
||||
filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: BlockNumber::MAX }),
|
||||
Ok(())
|
||||
@@ -372,7 +445,7 @@ mod tests {
|
||||
|
||||
// Local is mainnet Petersburg, remote announces Byzantium + knowledge about Petersburg.
|
||||
// Remote is simply out of sync, accept.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
assert_eq!(
|
||||
filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 7_280_000 }),
|
||||
Ok(())
|
||||
@@ -381,25 +454,25 @@ mod tests {
|
||||
// Local is mainnet Petersburg, remote announces Spurious + knowledge about Byzantium.
|
||||
// Remote is definitely out of sync. It may or may not need the Petersburg update,
|
||||
// we don't know yet.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
assert_eq!(
|
||||
filter.validate(ForkId { hash: ForkHash(hex!("3edd5b10")), next: 4_370_000 }),
|
||||
Ok(())
|
||||
);
|
||||
|
||||
// Local is mainnet Byzantium, remote announces Petersburg. Local is out of sync, accept.
|
||||
filter.set_head(7_279_999);
|
||||
filter.set_head(Head { number: 7_279_999, ..Default::default() });
|
||||
assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("668db0af")), next: 0 }), Ok(()));
|
||||
|
||||
// Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg.
|
||||
// Local out of sync. Local also knows about a future fork, but that is uncertain
|
||||
// yet.
|
||||
filter.set_head(4_369_999);
|
||||
filter.set_head(Head { number: 4_369_999, ..Default::default() });
|
||||
assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 0 }), Ok(()));
|
||||
|
||||
// Local is mainnet Petersburg. remote announces Byzantium but is not aware of further
|
||||
// forks. Remote needs software update.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
let remote = ForkId { hash: ForkHash(hex!("a00bc324")), next: 0 };
|
||||
assert_eq!(
|
||||
filter.validate(remote),
|
||||
@@ -408,7 +481,7 @@ mod tests {
|
||||
|
||||
// Local is mainnet Petersburg, and isn't aware of more forks. Remote announces Petersburg +
|
||||
// 0xffffffff. Local needs software update, reject.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
let remote = ForkId { hash: ForkHash(hex!("5cddc0e1")), next: 0 };
|
||||
assert_eq!(
|
||||
filter.validate(remote),
|
||||
@@ -417,7 +490,7 @@ mod tests {
|
||||
|
||||
// Local is mainnet Byzantium, and is aware of Petersburg. Remote announces Petersburg +
|
||||
// 0xffffffff. Local needs software update, reject.
|
||||
filter.set_head(7_279_999);
|
||||
filter.set_head(Head { number: 7_279_999, ..Default::default() });
|
||||
let remote = ForkId { hash: ForkHash(hex!("5cddc0e1")), next: 0 };
|
||||
assert_eq!(
|
||||
filter.validate(remote),
|
||||
@@ -425,7 +498,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// Local is mainnet Petersburg, remote is Rinkeby Petersburg.
|
||||
filter.set_head(7_987_396);
|
||||
filter.set_head(Head { number: 7_987_396, ..Default::default() });
|
||||
let remote = ForkId { hash: ForkHash(hex!("afec6b27")), next: 0 };
|
||||
assert_eq!(
|
||||
filter.validate(remote),
|
||||
@@ -437,7 +510,7 @@ mod tests {
|
||||
// is incompatible.
|
||||
//
|
||||
// This case detects non-upgraded nodes with majority hash power (typical Ropsten mess).
|
||||
filter.set_head(88_888_888);
|
||||
filter.set_head(Head { number: 88_888_888, ..Default::default() });
|
||||
let remote = ForkId { hash: ForkHash(hex!("668db0af")), next: 88_888_888 };
|
||||
assert_eq!(
|
||||
filter.validate(remote),
|
||||
@@ -446,7 +519,7 @@ mod tests {
|
||||
|
||||
// Local is mainnet Byzantium. Remote is also in Byzantium, but announces Gopherium (non
|
||||
// existing fork) at block 7279999, before Petersburg. Local is incompatible.
|
||||
filter.set_head(7_279_999);
|
||||
filter.set_head(Head { number: 7_279_999, ..Default::default() });
|
||||
let remote = ForkId { hash: ForkHash(hex!("a00bc324")), next: 7_279_999 };
|
||||
assert_eq!(
|
||||
filter.validate(remote),
|
||||
@@ -488,40 +561,44 @@ mod tests {
|
||||
let b1 = 1_150_000;
|
||||
let b2 = 1_920_000;
|
||||
|
||||
let h0 = ForkId { hash: ForkHash(hex!("fc64ec04")), next: b1 };
|
||||
let h1 = ForkId { hash: ForkHash(hex!("97c2c34c")), next: b2 };
|
||||
let h0 = ForkId { hash: ForkHash(hex!("fc64ec04")), next: b1.into() };
|
||||
let h1 = ForkId { hash: ForkHash(hex!("97c2c34c")), next: b2.into() };
|
||||
let h2 = ForkId { hash: ForkHash(hex!("91d1f948")), next: 0 };
|
||||
|
||||
let mut fork_filter = ForkFilter::new(0, GENESIS_HASH, vec![b1, b2]);
|
||||
let mut fork_filter = ForkFilter::new(
|
||||
Head { number: 0, ..Default::default() },
|
||||
GENESIS_HASH,
|
||||
vec![ForkFilterKey::Block(b1), ForkFilterKey::Block(b2)],
|
||||
);
|
||||
|
||||
assert!(fork_filter.set_head_priv(0).is_none());
|
||||
assert!(fork_filter.set_head_priv(Head { number: 0, ..Default::default() }).is_none());
|
||||
assert_eq!(fork_filter.current(), h0);
|
||||
|
||||
assert!(fork_filter.set_head_priv(1).is_none());
|
||||
assert!(fork_filter.set_head_priv(Head { number: 1, ..Default::default() }).is_none());
|
||||
assert_eq!(fork_filter.current(), h0);
|
||||
|
||||
assert_eq!(
|
||||
fork_filter.set_head_priv(b1 + 1).unwrap(),
|
||||
fork_filter.set_head_priv(Head { number: b1 + 1, ..Default::default() }).unwrap(),
|
||||
ForkTransition { current: h1, past: h0 }
|
||||
);
|
||||
assert_eq!(fork_filter.current(), h1);
|
||||
|
||||
assert!(fork_filter.set_head_priv(b1).is_none());
|
||||
assert!(fork_filter.set_head_priv(Head { number: b1, ..Default::default() }).is_none());
|
||||
assert_eq!(fork_filter.current(), h1);
|
||||
|
||||
assert_eq!(
|
||||
fork_filter.set_head_priv(b1 - 1).unwrap(),
|
||||
fork_filter.set_head_priv(Head { number: b1 - 1, ..Default::default() }).unwrap(),
|
||||
ForkTransition { current: h0, past: h1 }
|
||||
);
|
||||
assert_eq!(fork_filter.current(), h0);
|
||||
|
||||
assert!(fork_filter.set_head_priv(b1).is_some());
|
||||
assert!(fork_filter.set_head_priv(Head { number: b1, ..Default::default() }).is_some());
|
||||
assert_eq!(fork_filter.current(), h1);
|
||||
|
||||
assert!(fork_filter.set_head_priv(b2 - 1).is_none());
|
||||
assert!(fork_filter.set_head_priv(Head { number: b2 - 1, ..Default::default() }).is_none());
|
||||
assert_eq!(fork_filter.current(), h1);
|
||||
|
||||
assert!(fork_filter.set_head_priv(b2).is_some());
|
||||
assert!(fork_filter.set_head_priv(Head { number: b2, ..Default::default() }).is_some());
|
||||
assert_eq!(fork_filter.current(), h2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@ use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
keccak256,
|
||||
proofs::{genesis_state_root, KeccakHasher, EMPTY_ROOT},
|
||||
proofs::{KeccakHasher, EMPTY_ROOT},
|
||||
utils::serde_helpers::deserialize_stringified_u64,
|
||||
Address, Bytes, Header, H256, KECCAK_EMPTY, U256,
|
||||
Address, Bytes, H256, KECCAK_EMPTY, U256,
|
||||
};
|
||||
use bytes::BytesMut;
|
||||
use ethers_core::utils::GenesisAccount as EthersGenesisAccount;
|
||||
@@ -14,7 +14,7 @@ use triehash::sec_trie_root;
|
||||
|
||||
/// The genesis block specification.
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(rename_all = "camelCase", default)]
|
||||
pub struct Genesis {
|
||||
/// The genesis header nonce.
|
||||
#[serde(deserialize_with = "deserialize_stringified_u64")]
|
||||
@@ -37,22 +37,6 @@ pub struct Genesis {
|
||||
pub alloc: HashMap<Address, GenesisAccount>,
|
||||
}
|
||||
|
||||
impl From<Genesis> for Header {
|
||||
fn from(genesis: Genesis) -> Header {
|
||||
Header {
|
||||
gas_limit: genesis.gas_limit,
|
||||
difficulty: genesis.difficulty,
|
||||
nonce: genesis.nonce,
|
||||
extra_data: genesis.extra_data,
|
||||
state_root: genesis_state_root(genesis.alloc),
|
||||
timestamp: genesis.timestamp,
|
||||
mix_hash: genesis.mix_hash,
|
||||
beneficiary: genesis.coinbase,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An account in the state of the genesis block.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct GenesisAccount {
|
||||
|
||||
@@ -1,77 +1,61 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{ChainSpec, ForkCondition, ForkFilter, ForkId};
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
use crate::{BlockNumber, ChainSpec, ForkFilter, ForkHash, ForkId};
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(
|
||||
Debug, Default, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
/// The name of an Ethereum hardfork.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum Hardfork {
|
||||
/// Frontier.
|
||||
Frontier,
|
||||
/// Homestead.
|
||||
Homestead,
|
||||
/// The DAO fork.
|
||||
Dao,
|
||||
/// Tangerine.
|
||||
Tangerine,
|
||||
/// Spurious Dragon.
|
||||
SpuriousDragon,
|
||||
/// Byzantium.
|
||||
Byzantium,
|
||||
/// Constantinople.
|
||||
Constantinople,
|
||||
/// Petersburg.
|
||||
Petersburg,
|
||||
/// Istanbul.
|
||||
Istanbul,
|
||||
Muirglacier,
|
||||
/// Muir Glacier.
|
||||
MuirGlacier,
|
||||
/// Berlin.
|
||||
Berlin,
|
||||
/// London.
|
||||
London,
|
||||
/// Arrow Glacier.
|
||||
ArrowGlacier,
|
||||
/// Gray Glacier.
|
||||
GrayGlacier,
|
||||
MergeNetsplit,
|
||||
/// Paris.
|
||||
Paris,
|
||||
/// Shanghai.
|
||||
Shanghai,
|
||||
#[default]
|
||||
Latest,
|
||||
}
|
||||
|
||||
impl Hardfork {
|
||||
/// Compute the forkid for the given [`ChainSpec`].
|
||||
///
|
||||
/// This assumes the current hardfork's block number is the current head and uses known future
|
||||
/// hardforks from the [`ChainSpec`] to set the forkid's `next` field.
|
||||
///
|
||||
/// If the hard fork is not present in the [`ChainSpec`] then `None` is returned.
|
||||
pub fn fork_id(&self, chain_spec: &ChainSpec) -> Option<ForkId> {
|
||||
if let Some(fork_block) = chain_spec.fork_block(*self) {
|
||||
let mut curr_forkhash = ForkHash::from(chain_spec.genesis_hash());
|
||||
let mut curr_block_number = 0;
|
||||
|
||||
for (_, b) in chain_spec.forks_iter() {
|
||||
if fork_block >= b {
|
||||
if b != curr_block_number {
|
||||
curr_forkhash += b;
|
||||
curr_block_number = b;
|
||||
}
|
||||
} else {
|
||||
return Some(ForkId { hash: curr_forkhash, next: b })
|
||||
}
|
||||
}
|
||||
Some(ForkId { hash: curr_forkhash, next: 0 })
|
||||
} else {
|
||||
None
|
||||
/// Get the [ForkId] for this hardfork in the given spec, if the fork is activated at any point.
|
||||
pub fn fork_id(&self, spec: &ChainSpec) -> Option<ForkId> {
|
||||
match spec.fork(*self) {
|
||||
ForkCondition::Never => None,
|
||||
_ => Some(spec.fork_id(&spec.fork(*self).satisfy())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a [`ForkFilter`](crate::ForkFilter) for the given hardfork.
|
||||
///
|
||||
/// This assumes the current hardfork's block number is the current head and uses known future
|
||||
/// hardforks from the [`ChainSpec`] to initialize the filter.
|
||||
///
|
||||
/// This returns `None` if the hardfork is not present in the given [`ChainSpec`].
|
||||
pub fn fork_filter(&self, chain_spec: &ChainSpec) -> Option<ForkFilter> {
|
||||
if let Some(fork_block) = chain_spec.fork_block(*self) {
|
||||
let future_forks: Vec<BlockNumber> =
|
||||
chain_spec.forks_iter().filter(|(_, b)| b > &fork_block).map(|(_, b)| b).collect();
|
||||
|
||||
// pass in the chain spec's genesis hash to initialize the fork filter
|
||||
Some(ForkFilter::new(fork_block, chain_spec.genesis_hash(), future_forks))
|
||||
} else {
|
||||
None
|
||||
/// Get the [ForkFilter] for this hardfork in the given spec, if the fork is activated at any
|
||||
/// point.
|
||||
pub fn fork_filter(&self, spec: &ChainSpec) -> Option<ForkFilter> {
|
||||
match spec.fork(*self) {
|
||||
ForkCondition::Never => None,
|
||||
_ => Some(spec.fork_filter(spec.fork(*self).satisfy())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,22 +66,23 @@ impl FromStr for Hardfork {
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
let hardfork = match s.as_str() {
|
||||
"frontier" | "1" => Hardfork::Frontier,
|
||||
"homestead" | "2" => Hardfork::Homestead,
|
||||
"dao" | "3" => Hardfork::Dao,
|
||||
"tangerine" | "4" => Hardfork::Tangerine,
|
||||
"spuriousdragon" | "5" => Hardfork::SpuriousDragon,
|
||||
"byzantium" | "6" => Hardfork::Byzantium,
|
||||
"constantinople" | "7" => Hardfork::Constantinople,
|
||||
"petersburg" | "8" => Hardfork::Petersburg,
|
||||
"istanbul" | "9" => Hardfork::Istanbul,
|
||||
"muirglacier" | "10" => Hardfork::Muirglacier,
|
||||
"berlin" | "11" => Hardfork::Berlin,
|
||||
"london" | "12" => Hardfork::London,
|
||||
"arrowglacier" | "13" => Hardfork::ArrowGlacier,
|
||||
"frontier" => Hardfork::Frontier,
|
||||
"homestead" => Hardfork::Homestead,
|
||||
"dao" => Hardfork::Dao,
|
||||
"tangerine" => Hardfork::Tangerine,
|
||||
"spuriousdragon" => Hardfork::SpuriousDragon,
|
||||
"byzantium" => Hardfork::Byzantium,
|
||||
"constantinople" => Hardfork::Constantinople,
|
||||
"petersburg" => Hardfork::Petersburg,
|
||||
"istanbul" => Hardfork::Istanbul,
|
||||
"muirglacier" => Hardfork::MuirGlacier,
|
||||
"berlin" => Hardfork::Berlin,
|
||||
"london" => Hardfork::London,
|
||||
"arrowglacier" => Hardfork::ArrowGlacier,
|
||||
"grayglacier" => Hardfork::GrayGlacier,
|
||||
"latest" | "14" => Hardfork::Latest,
|
||||
_ => return Err(format!("Unknown hardfork {s}")),
|
||||
"paris" => Hardfork::Paris,
|
||||
"shanghai" => Hardfork::Shanghai,
|
||||
_ => return Err(format!("Unknown hardfork: {s}")),
|
||||
};
|
||||
Ok(hardfork)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,26 @@ use reth_rlp::{length_of_length, Decodable, Encodable};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Describes the current head block.
|
||||
///
|
||||
/// The head block is the highest fully synced block.
|
||||
///
|
||||
/// Note: This is a slimmed down version of [Header], primarily for communicating the highest block
|
||||
/// with the P2P network and the RPC.
|
||||
#[derive(
|
||||
Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize,
|
||||
)]
|
||||
pub struct Head {
|
||||
/// The number of the head block.
|
||||
pub number: BlockNumber,
|
||||
/// The hash of the head block.
|
||||
pub hash: H256,
|
||||
/// The total difficulty of the head block.
|
||||
pub total_difficulty: U256,
|
||||
/// The timestamp of the head block.
|
||||
pub timestamp: u64,
|
||||
}
|
||||
|
||||
/// Block header
|
||||
#[main_codec]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@@ -388,8 +408,8 @@ mod tests {
|
||||
use ethers_core::utils::hex::{self, FromHex};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[test]
|
||||
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||
#[test]
|
||||
fn test_encode_block_header() {
|
||||
let expected = hex::decode("f901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000").unwrap();
|
||||
let header = Header {
|
||||
@@ -411,8 +431,8 @@ mod tests {
|
||||
assert_eq!(header.length(), data.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Test vector from: https://github.com/ethereum/tests/blob/f47bbef4da376a49c8fc3166f09ab8a6d182f765/BlockchainTests/ValidBlocks/bcEIP1559/baseFee.json#L15-L36
|
||||
#[test]
|
||||
fn test_eip1559_block_header_hash() {
|
||||
let expected_hash =
|
||||
H256::from_str("6a251c7c3c5dca7b42407a3752ff48f3bbca1fab7f9868371d9918daf1988d1f")
|
||||
@@ -438,8 +458,8 @@ mod tests {
|
||||
assert_eq!(header.hash_slow(), expected_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||
#[test]
|
||||
fn test_decode_block_header() {
|
||||
let data = hex::decode("f901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000").unwrap();
|
||||
let expected = Header {
|
||||
|
||||
@@ -38,7 +38,7 @@ pub use bits::H512;
|
||||
pub use block::{Block, BlockHashOrNumber, SealedBlock};
|
||||
pub use bloom::Bloom;
|
||||
pub use chain::{
|
||||
Chain, ChainInfo, ChainSpec, ChainSpecBuilder, ParisStatus, GOERLI, MAINNET, SEPOLIA,
|
||||
Chain, ChainInfo, ChainSpec, ChainSpecBuilder, ForkCondition, GOERLI, MAINNET, SEPOLIA,
|
||||
};
|
||||
pub use constants::{
|
||||
EMPTY_OMMER_ROOT, GOERLI_GENESIS, KECCAK_EMPTY, MAINNET_GENESIS, SEPOLIA_GENESIS,
|
||||
@@ -46,7 +46,7 @@ pub use constants::{
|
||||
pub use forkid::{ForkFilter, ForkHash, ForkId, ForkTransition, ValidationError};
|
||||
pub use genesis::{Genesis, GenesisAccount};
|
||||
pub use hardfork::Hardfork;
|
||||
pub use header::{Header, HeadersDirection, SealedHeader};
|
||||
pub use header::{Head, Header, HeadersDirection, SealedHeader};
|
||||
pub use hex_bytes::Bytes;
|
||||
pub use integer_list::IntegerList;
|
||||
pub use jsonu256::JsonU256;
|
||||
|
||||
@@ -74,7 +74,7 @@ pub fn calculate_ommers_root<'a>(ommers: impl Iterator<Item = &'a Header> + Clon
|
||||
|
||||
/// Calculates the root hash for the state, this corresponds to [geth's
|
||||
/// `deriveHash`](https://github.com/ethereum/go-ethereum/blob/6c149fd4ad063f7c24d726a73bc0546badd1bc73/core/genesis.go#L119).
|
||||
pub fn genesis_state_root(genesis_alloc: HashMap<Address, GenesisAccount>) -> H256 {
|
||||
pub fn genesis_state_root(genesis_alloc: &HashMap<Address, GenesisAccount>) -> H256 {
|
||||
let encoded_accounts = genesis_alloc.iter().map(|(address, account)| {
|
||||
let mut acc_rlp = BytesMut::new();
|
||||
account.encode(&mut acc_rlp);
|
||||
@@ -130,7 +130,7 @@ mod tests {
|
||||
#[test]
|
||||
fn check_empty_state_root() {
|
||||
let genesis_alloc = HashMap::new();
|
||||
let root = genesis_state_root(genesis_alloc);
|
||||
let root = genesis_state_root(&genesis_alloc);
|
||||
assert_eq!(root, EMPTY_ROOT);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ mod tests {
|
||||
test_addr,
|
||||
GenesisAccount { nonce: None, balance: U256::MAX, code: None, storage: None },
|
||||
);
|
||||
let root = genesis_state_root(genesis_alloc);
|
||||
let root = genesis_state_root(&genesis_alloc);
|
||||
|
||||
assert_eq!(root, expected_root);
|
||||
}
|
||||
@@ -275,7 +275,7 @@ mod tests {
|
||||
),
|
||||
]);
|
||||
|
||||
let root = genesis_state_root(alloc);
|
||||
let root = genesis_state_root(&alloc);
|
||||
|
||||
assert_eq!(root, expected_root);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use reth_interfaces::consensus::ForkchoiceState;
|
||||
use reth_primitives::{
|
||||
proofs::{self, EMPTY_LIST_HASH},
|
||||
rpc::{BlockId, H256 as EthersH256},
|
||||
ChainSpec, Header, SealedBlock, TransactionSigned, H64, U256,
|
||||
ChainSpec, Hardfork, Header, SealedBlock, TransactionSigned, H64, U256,
|
||||
};
|
||||
use reth_provider::{BlockProvider, HeaderProvider, StateProvider};
|
||||
use reth_rlp::Decodable;
|
||||
@@ -153,12 +153,18 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> EngineApi<Client> {
|
||||
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Syncing))
|
||||
};
|
||||
|
||||
if let Some(parent_td) = self.client.header_td(&parent_hash)? {
|
||||
if Some(parent_td) <= self.chain_spec.paris_status().terminal_total_difficulty() {
|
||||
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid {
|
||||
validation_error: EngineApiError::PayloadPreMerge.to_string(),
|
||||
}))
|
||||
}
|
||||
let parent_td = if let Some(parent_td) = self.client.header_td(&block.parent_hash)? {
|
||||
parent_td
|
||||
} else {
|
||||
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid {
|
||||
validation_error: EngineApiError::PayloadPreMerge.to_string(),
|
||||
}))
|
||||
};
|
||||
|
||||
if !self.chain_spec.fork(Hardfork::Paris).active_at_ttd(parent_td) {
|
||||
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid {
|
||||
validation_error: EngineApiError::PayloadPreMerge.to_string(),
|
||||
}))
|
||||
}
|
||||
|
||||
if block.timestamp <= parent.timestamp {
|
||||
@@ -172,8 +178,10 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> EngineApi<Client> {
|
||||
}
|
||||
|
||||
let mut state_provider = SubState::new(State::new(&*self.client));
|
||||
let total_difficulty = parent_td + block.header.difficulty;
|
||||
match executor::execute_and_verify_receipt(
|
||||
&block.unseal(),
|
||||
total_difficulty,
|
||||
None,
|
||||
&self.chain_spec,
|
||||
&mut state_provider,
|
||||
@@ -238,9 +246,9 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> EngineApi<Client> {
|
||||
|
||||
let merge_terminal_td = self
|
||||
.chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.ok_or(EngineApiError::UnknownMergeTerminalTotalDifficulty)?;
|
||||
.fork(Hardfork::Paris)
|
||||
.ttd()
|
||||
.expect("the engine API should not be running for chains w/o paris");
|
||||
|
||||
// Compare total difficulty values
|
||||
if merge_terminal_td != terminal_total_difficulty {
|
||||
@@ -494,7 +502,7 @@ mod tests {
|
||||
let (result_tx, result_rx) = oneshot::channel();
|
||||
let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| {
|
||||
b.header.difficulty =
|
||||
chain_spec.paris_status().terminal_total_difficulty().unwrap();
|
||||
chain_spec.fork(Hardfork::Paris).ttd().unwrap() - U256::from(1);
|
||||
b
|
||||
});
|
||||
let block = random_block(101, Some(parent.hash()), None, Some(0));
|
||||
@@ -535,7 +543,7 @@ mod tests {
|
||||
let parent = transform_block(random_block(100, None, None, Some(0)), |mut b| {
|
||||
b.header.timestamp = parent_timestamp;
|
||||
b.header.difficulty =
|
||||
chain_spec.paris_status().terminal_total_difficulty().unwrap() + U256::from(1);
|
||||
chain_spec.fork(Hardfork::Paris).ttd().unwrap() + U256::from(1);
|
||||
b
|
||||
});
|
||||
let block =
|
||||
@@ -773,10 +781,7 @@ mod tests {
|
||||
tokio::spawn(engine);
|
||||
|
||||
let transition_config = TransitionConfiguration {
|
||||
terminal_total_difficulty: chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.unwrap() +
|
||||
terminal_total_difficulty: chain_spec.fork(Hardfork::Paris).ttd().unwrap() +
|
||||
U256::from(1),
|
||||
..Default::default()
|
||||
};
|
||||
@@ -792,7 +797,7 @@ mod tests {
|
||||
assert_matches!(
|
||||
result_rx.await,
|
||||
Ok(Err(EngineApiError::TerminalTD { execution, consensus }))
|
||||
if execution == chain_spec.paris_status().terminal_total_difficulty().unwrap()
|
||||
if execution == chain_spec.fork(Hardfork::Paris).ttd().unwrap()
|
||||
&& consensus == U256::from(transition_config.terminal_total_difficulty)
|
||||
);
|
||||
}
|
||||
@@ -818,10 +823,7 @@ mod tests {
|
||||
let execution_terminal_block = random_block(terminal_block_number, None, None, None);
|
||||
|
||||
let transition_config = TransitionConfiguration {
|
||||
terminal_total_difficulty: chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.unwrap(),
|
||||
terminal_total_difficulty: chain_spec.fork(Hardfork::Paris).ttd().unwrap(),
|
||||
terminal_block_hash: consensus_terminal_block.hash(),
|
||||
terminal_block_number: terminal_block_number.into(),
|
||||
};
|
||||
@@ -884,10 +886,7 @@ mod tests {
|
||||
let terminal_block = random_block(terminal_block_number, None, None, None);
|
||||
|
||||
let transition_config = TransitionConfiguration {
|
||||
terminal_total_difficulty: chain_spec
|
||||
.paris_status()
|
||||
.terminal_total_difficulty()
|
||||
.unwrap(),
|
||||
terminal_total_difficulty: chain_spec.fork(Hardfork::Paris).ttd().unwrap(),
|
||||
terminal_block_hash: terminal_block.hash(),
|
||||
terminal_block_number: terminal_block_number.into(),
|
||||
};
|
||||
|
||||
@@ -5,9 +5,7 @@ use reth_db::{
|
||||
tables,
|
||||
transaction::{DbTx, DbTxMut},
|
||||
};
|
||||
use reth_primitives::{
|
||||
constants::EIP1559_INITIAL_BASE_FEE, Account, ChainSpec, Hardfork, Header, H256,
|
||||
};
|
||||
use reth_primitives::{Account, ChainSpec, H256};
|
||||
use std::{path::Path, sync::Arc};
|
||||
use tracing::debug;
|
||||
|
||||
@@ -50,12 +48,7 @@ pub fn init_genesis<DB: Database>(db: Arc<DB>, chain: ChainSpec) -> Result<H256,
|
||||
}
|
||||
|
||||
// Insert header
|
||||
let mut header: Header = genesis.clone().into();
|
||||
|
||||
// set base fee if EIP-1559 is enabled
|
||||
if chain.fork_active(Hardfork::London, 0) {
|
||||
header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE);
|
||||
}
|
||||
let header = chain.genesis_header();
|
||||
|
||||
let hash = header.hash_slow();
|
||||
tx.put::<tables::CanonicalHeaders>(0, hash)?;
|
||||
|
||||
@@ -8,9 +8,7 @@ use reth_network::{
|
||||
NetworkConfig, NetworkManager,
|
||||
};
|
||||
use reth_network_api::Peers;
|
||||
use reth_primitives::{
|
||||
constants::EIP1559_INITIAL_BASE_FEE, ChainSpec, Hardfork, Header, PeerId, SealedHeader,
|
||||
};
|
||||
use reth_primitives::{ChainSpec, PeerId, SealedHeader};
|
||||
use reth_provider::test_utils::NoopProvider;
|
||||
use reth_staged_sync::test_utils::{CliqueGethInstance, CliqueMiddleware};
|
||||
use secp256k1::SecretKey;
|
||||
@@ -97,7 +95,7 @@ async fn init_geth() -> (CliqueGethInstance, ChainSpec) {
|
||||
// === check that we have the same genesis hash ===
|
||||
|
||||
// get the chainspec from the genesis we configured for geth
|
||||
let mut chainspec: ChainSpec = clique
|
||||
let chainspec: ChainSpec = clique
|
||||
.instance
|
||||
.genesis()
|
||||
.clone()
|
||||
@@ -105,21 +103,9 @@ async fn init_geth() -> (CliqueGethInstance, ChainSpec) {
|
||||
.into();
|
||||
let remote_genesis = SealedHeader::from(clique.provider.remote_genesis_block().await.unwrap());
|
||||
|
||||
let mut local_genesis_header = Header::from(chainspec.genesis().clone());
|
||||
|
||||
let hardforks = chainspec.hardforks();
|
||||
|
||||
// set initial base fee depending on eip-1559
|
||||
if let Some(0) = hardforks.get(&Hardfork::London) {
|
||||
local_genesis_header.base_fee_per_gas = Some(EIP1559_INITIAL_BASE_FEE);
|
||||
}
|
||||
|
||||
let local_genesis = local_genesis_header.seal();
|
||||
let local_genesis = chainspec.genesis_header().seal();
|
||||
assert_eq!(local_genesis, remote_genesis, "genesis blocks should match, we computed {local_genesis:#?} but geth computed {remote_genesis:#?}");
|
||||
|
||||
// set the chainspec genesis hash
|
||||
chainspec.genesis_hash = local_genesis.hash();
|
||||
|
||||
// === create many blocks ===
|
||||
|
||||
let nonces = 0..1000u64;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
db::Transaction, exec_or_return, ExecAction, ExecInput, ExecOutput, Stage, StageError, StageId,
|
||||
UnwindInput, UnwindOutput,
|
||||
db::Transaction, exec_or_return, DatabaseIntegrityError, ExecAction, ExecInput, ExecOutput,
|
||||
Stage, StageError, StageId, UnwindInput, UnwindOutput,
|
||||
};
|
||||
use futures_util::TryStreamExt;
|
||||
use reth_db::{
|
||||
@@ -8,7 +8,7 @@ use reth_db::{
|
||||
database::Database,
|
||||
models::{BlockNumHash, StoredBlockBody, StoredBlockOmmers},
|
||||
tables,
|
||||
transaction::DbTxMut,
|
||||
transaction::{DbTx, DbTxMut},
|
||||
};
|
||||
use reth_interfaces::{
|
||||
consensus::Consensus,
|
||||
@@ -81,6 +81,9 @@ impl<DB: Database, D: BodyDownloader> Stage<DB> for BodyStage<D> {
|
||||
// Update the header range on the downloader
|
||||
self.downloader.set_download_range(start_block..end_block + 1)?;
|
||||
|
||||
// Cursor used to get total difficulty
|
||||
let mut td_cursor = tx.cursor_read::<tables::HeaderTD>()?;
|
||||
|
||||
// Cursors used to write bodies, ommers and transactions
|
||||
let mut body_cursor = tx.cursor_write::<tables::BlockBodies>()?;
|
||||
let mut ommers_cursor = tx.cursor_write::<tables::BlockOmmers>()?;
|
||||
@@ -153,7 +156,11 @@ impl<DB: Database, D: BodyDownloader> Stage<DB> for BodyStage<D> {
|
||||
// Increment the transition if the block contains an addition block reward.
|
||||
// If the block does not have a reward, the transition will be the same as the
|
||||
// transition at the last transaction of this block.
|
||||
let has_reward = self.consensus.has_block_reward(numhash.number());
|
||||
let td = td_cursor
|
||||
.seek(numhash)?
|
||||
.ok_or(DatabaseIntegrityError::TotalDifficulty { number: numhash.number() })?
|
||||
.1;
|
||||
let has_reward = self.consensus.has_block_reward(td.into());
|
||||
if has_reward {
|
||||
transition_id += 1;
|
||||
}
|
||||
@@ -505,7 +512,7 @@ mod tests {
|
||||
let start = input.stage_progress.unwrap_or_default();
|
||||
let end = input.previous_stage_progress() + 1;
|
||||
let blocks = random_block_range(start..end, GENESIS_HASH, 0..2);
|
||||
self.tx.insert_headers(blocks.iter().map(|block| &block.header))?;
|
||||
self.tx.insert_headers_with_td(blocks.iter().map(|block| &block.header))?;
|
||||
if let Some(progress) = blocks.first() {
|
||||
// Insert last progress data
|
||||
self.tx.commit(|tx| {
|
||||
@@ -601,6 +608,7 @@ mod tests {
|
||||
self.tx.query(|tx| {
|
||||
// Acquire cursors on body related tables
|
||||
let mut headers_cursor = tx.cursor_read::<tables::Headers>()?;
|
||||
let mut td_cursor = tx.cursor_read::<tables::HeaderTD>()?;
|
||||
let mut bodies_cursor = tx.cursor_read::<tables::BlockBodies>()?;
|
||||
let mut ommers_cursor = tx.cursor_read::<tables::BlockOmmers>()?;
|
||||
let mut block_transition_cursor = tx.cursor_read::<tables::BlockTransitionIndex>()?;
|
||||
@@ -653,7 +661,11 @@ mod tests {
|
||||
}
|
||||
|
||||
// Increment expected id for block reward.
|
||||
if self.consensus.has_block_reward(key.number()) {
|
||||
let td = td_cursor
|
||||
.seek(key)?
|
||||
.expect("Missing TD for header")
|
||||
.1;
|
||||
if self.consensus.has_block_reward(td.into()) {
|
||||
expected_transition_id += 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ pub const EXECUTION: StageId = StageId("Execution");
|
||||
/// Input tables:
|
||||
/// - [tables::CanonicalHeaders] get next block to execute.
|
||||
/// - [tables::Headers] get for revm environment variables.
|
||||
/// - [tables::HeaderTD]
|
||||
/// - [tables::BlockBodies] to get tx number
|
||||
/// - [tables::Transactions] to execute
|
||||
///
|
||||
@@ -92,6 +93,8 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
let mut canonicals = tx.cursor_read::<tables::CanonicalHeaders>()?;
|
||||
// Get header with canonical hashes.
|
||||
let mut headers = tx.cursor_read::<tables::Headers>()?;
|
||||
// Get total difficulty
|
||||
let mut tds = tx.cursor_read::<tables::HeaderTD>()?;
|
||||
// Get bodies with canonical hashes.
|
||||
let mut bodies_cursor = tx.cursor_read::<tables::BlockBodies>()?;
|
||||
// Get ommers with canonical hashes.
|
||||
@@ -110,7 +113,7 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
// Get block headers and bodies from canonical hashes
|
||||
let block_batch = canonical_batch
|
||||
.iter()
|
||||
.map(|key| -> Result<(Header, StoredBlockBody, Vec<Header>), StageError> {
|
||||
.map(|key| -> Result<(Header, U256, StoredBlockBody, Vec<Header>), StageError> {
|
||||
// NOTE: It probably will be faster to fetch all items from one table with cursor,
|
||||
// but to reduce complexity we are using `seek_exact` to skip some
|
||||
// edge cases that can happen.
|
||||
@@ -119,12 +122,15 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
number: key.number(),
|
||||
hash: key.hash(),
|
||||
})?;
|
||||
let (_, td) = tds
|
||||
.seek_exact(*key)?
|
||||
.ok_or(DatabaseIntegrityError::TotalDifficulty { number: key.number() })?;
|
||||
let (_, body) = bodies_cursor
|
||||
.seek_exact(*key)?
|
||||
.ok_or(DatabaseIntegrityError::BlockBody { number: key.number() })?;
|
||||
let (_, stored_ommers) = ommers_cursor.seek_exact(*key)?.unwrap_or_default();
|
||||
|
||||
Ok((header, body, stored_ommers.ommers))
|
||||
Ok((header, td.into(), body, stored_ommers.ommers))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
@@ -133,9 +139,10 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
|
||||
// Fetch transactions, execute them and generate results
|
||||
let mut block_change_patches = Vec::with_capacity(canonical_batch.len());
|
||||
for (header, body, ommers) in block_batch.into_iter() {
|
||||
for (header, td, body, ommers) in block_batch.into_iter() {
|
||||
let block_number = header.number;
|
||||
tracing::trace!(target: "sync::stages::execution", ?block_number, "Execute block.");
|
||||
|
||||
// iterate over all transactions
|
||||
let mut tx_walker = tx_cursor.walk(body.start_tx_id)?;
|
||||
let mut transactions = Vec::with_capacity(body.tx_count as usize);
|
||||
@@ -180,6 +187,7 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
// execute and store output to results
|
||||
reth_executor::executor::execute_and_verify_receipt(
|
||||
&Block { header, body: transactions, ommers },
|
||||
td,
|
||||
Some(signers),
|
||||
&self.chain_spec,
|
||||
&mut state_provider,
|
||||
@@ -196,12 +204,10 @@ impl<DB: Database> Stage<DB> for ExecutionStage {
|
||||
let mut current_transition_id = tx.get_block_transition(last_block)?;
|
||||
info!(target: "sync::stages::execution", current_transition_id, blocks = block_change_patches.len(), "Inserting execution results");
|
||||
|
||||
let spurious_dragon_activation =
|
||||
self.chain_spec.fork_block(Hardfork::SpuriousDragon).unwrap_or_default();
|
||||
|
||||
// apply changes to plain database.
|
||||
for (results, block_number) in block_change_patches.into_iter() {
|
||||
let spurious_dragon_active = block_number >= spurious_dragon_activation;
|
||||
let spurious_dragon_active =
|
||||
self.chain_spec.fork(Hardfork::SpuriousDragon).active_at_block(block_number);
|
||||
// insert state change set
|
||||
for result in results.changesets.into_iter() {
|
||||
for (address, account_change_set) in result.changeset.into_iter() {
|
||||
|
||||
@@ -8,7 +8,8 @@ use reth_db::{
|
||||
tables,
|
||||
transaction::{DbTx, DbTxMut},
|
||||
};
|
||||
use reth_primitives::U256;
|
||||
use reth_interfaces::consensus::Error;
|
||||
use reth_primitives::{ChainSpec, Hardfork, EMPTY_OMMER_ROOT, MAINNET, U256};
|
||||
use tracing::*;
|
||||
|
||||
const TOTAL_DIFFICULTY: StageId = StageId("TotalDifficulty");
|
||||
@@ -20,13 +21,15 @@ const TOTAL_DIFFICULTY: StageId = StageId("TotalDifficulty");
|
||||
/// table.
|
||||
#[derive(Debug)]
|
||||
pub struct TotalDifficultyStage {
|
||||
/// The chain specification.
|
||||
pub chain_spec: ChainSpec,
|
||||
/// The number of table entries to commit at once
|
||||
pub commit_threshold: u64,
|
||||
}
|
||||
|
||||
impl Default for TotalDifficultyStage {
|
||||
fn default() -> Self {
|
||||
Self { commit_threshold: 100_000 }
|
||||
Self { chain_spec: MAINNET.clone(), commit_threshold: 100_000 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +72,30 @@ impl<DB: Database> Stage<DB> for TotalDifficultyStage {
|
||||
for entry in walker {
|
||||
let (key, header) = entry?;
|
||||
td += header.difficulty;
|
||||
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(td) {
|
||||
if header.difficulty != U256::ZERO {
|
||||
return Err(StageError::Validation {
|
||||
block: header.number,
|
||||
error: Error::TheMergeDifficultyIsNotZero,
|
||||
})
|
||||
}
|
||||
|
||||
if header.nonce != 0 {
|
||||
return Err(StageError::Validation {
|
||||
block: header.number,
|
||||
error: Error::TheMergeNonceIsNotZero,
|
||||
})
|
||||
}
|
||||
|
||||
if header.ommers_hash != EMPTY_OMMER_ROOT {
|
||||
return Err(StageError::Validation {
|
||||
block: header.number,
|
||||
error: Error::TheMergeOmmerRootIsNotEmpty,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cursor_td.append(key, td.into())?;
|
||||
}
|
||||
|
||||
@@ -93,7 +120,7 @@ impl<DB: Database> Stage<DB> for TotalDifficultyStage {
|
||||
mod tests {
|
||||
use reth_db::transaction::DbTx;
|
||||
use reth_interfaces::test_utils::generators::{random_header, random_header_range};
|
||||
use reth_primitives::{BlockNumber, SealedHeader};
|
||||
use reth_primitives::{BlockNumber, SealedHeader, MAINNET};
|
||||
|
||||
use super::*;
|
||||
use crate::test_utils::{
|
||||
@@ -162,7 +189,10 @@ mod tests {
|
||||
}
|
||||
|
||||
fn stage(&self) -> Self::S {
|
||||
TotalDifficultyStage { commit_threshold: self.commit_threshold }
|
||||
TotalDifficultyStage {
|
||||
chain_spec: MAINNET.clone(),
|
||||
commit_threshold: self.commit_threshold,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use reth_db::{
|
||||
transaction::{DbTx, DbTxMut},
|
||||
Error as DbError,
|
||||
};
|
||||
use reth_primitives::{BlockNumber, SealedBlock, SealedHeader};
|
||||
use reth_primitives::{BlockNumber, SealedBlock, SealedHeader, U256};
|
||||
use std::{borrow::Borrow, path::Path, sync::Arc};
|
||||
|
||||
use crate::db::Transaction;
|
||||
@@ -197,6 +197,31 @@ impl TestTransaction {
|
||||
})
|
||||
}
|
||||
|
||||
/// Inserts total difficulty of headers into the corresponding tables.
|
||||
///
|
||||
/// Superset functionality of [TestTransaction::insert_headers].
|
||||
pub(crate) fn insert_headers_with_td<'a, I>(&self, headers: I) -> Result<(), DbError>
|
||||
where
|
||||
I: Iterator<Item = &'a SealedHeader>,
|
||||
{
|
||||
self.commit(|tx| {
|
||||
let headers = headers.collect::<Vec<_>>();
|
||||
|
||||
let mut td = U256::ZERO;
|
||||
for header in headers {
|
||||
let key: BlockNumHash = header.num_hash().into();
|
||||
|
||||
td += header.difficulty;
|
||||
tx.put::<tables::HeaderTD>(header.num_hash().into(), td.into())?;
|
||||
tx.put::<tables::CanonicalHeaders>(header.number, header.hash())?;
|
||||
tx.put::<tables::HeaderNumbers>(header.hash(), header.number)?;
|
||||
tx.put::<tables::Headers>(key, header.clone().unseal())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Insert ordered collection of [SealedBlock] into corresponding tables.
|
||||
/// Superset functionality of [TestTransaction::insert_headers].
|
||||
pub fn insert_blocks<'a, I>(&self, blocks: I, tx_offset: Option<u64>) -> Result<(), DbError>
|
||||
|
||||
@@ -530,7 +530,7 @@ mod tests {
|
||||
}
|
||||
tx.commit().unwrap();
|
||||
|
||||
let state_root = genesis_state_root(genesis.alloc);
|
||||
let state_root = genesis_state_root(&genesis.alloc);
|
||||
|
||||
assert_matches!(
|
||||
trie.calculate_root(&tx),
|
||||
|
||||
@@ -4,7 +4,7 @@ use reth_db::{
|
||||
transaction::{DbTx, DbTxMut},
|
||||
};
|
||||
use reth_interfaces::{provider::Error as ProviderError, Result};
|
||||
use reth_primitives::SealedBlock;
|
||||
use reth_primitives::{SealedBlock, U256};
|
||||
|
||||
/// Insert block data into corresponding tables. Used mainly for testing & internal tooling.
|
||||
///
|
||||
@@ -24,6 +24,11 @@ pub fn insert_block<'a, TX: DbTxMut<'a> + DbTx<'a>>(
|
||||
// Put header with canonical hashes.
|
||||
tx.put::<tables::Headers>(block_num_hash, block.header.as_ref().clone())?;
|
||||
tx.put::<tables::HeaderNumbers>(block.hash(), block.number)?;
|
||||
tx.put::<tables::HeaderTD>(
|
||||
block_num_hash,
|
||||
if has_block_reward { U256::ZERO } else { U256::from(58_750_000_000_000_000_000_000u128) }
|
||||
.into(),
|
||||
)?;
|
||||
|
||||
// insert body ommers data
|
||||
tx.put::<tables::BlockOmmers>(
|
||||
|
||||
Reference in New Issue
Block a user