feat: support time-based forking (#1128)

This commit is contained in:
Bjerg
2023-02-06 21:55:41 +01:00
committed by GitHub
parent 3605e00428
commit 02a6aec3fb
38 changed files with 1204 additions and 28330 deletions

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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,
},
),

View File

@@ -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();

View File

@@ -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)
}
}

View File

@@ -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::*;

View File

@@ -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
);
}
}

View File

@@ -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 blocks 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");

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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(())
}

View File

@@ -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
}
}

View File

@@ -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(),
/// }
/// );
/// ```

View File

@@ -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,

View File

@@ -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))
}
}

View File

@@ -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) =

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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(),
};

View File

@@ -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)?;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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,
}
}
}

View File

@@ -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>

View File

@@ -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),

View File

@@ -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>(