diff --git a/src/Nethermind/Chains/beverlyhills.json b/src/Nethermind/Chains/beverlyhills.json new file mode 100644 index 00000000000..1af2bda45ae --- /dev/null +++ b/src/Nethermind/Chains/beverlyhills.json @@ -0,0 +1,886 @@ +{ + "name": "Beverly Hills", + "dataDir": "bevHills", + "engine": { + "Ethash": { + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "networkID" : "0x16062", + "eip140Transition": "0x0", + "eip145Transition": "0x0", + "eip150Transition": "0x0", + "eip155Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0", + "eip1014Transition": "0x0", + "eip1052Transition": "0x0", + "eip1283Transition": "0x0", + "eip1283DisableTransition": "0x0", + "eip152Transition": "0x0", + "eip1108Transition": "0x0", + "eip1344Transition": "0x0", + "eip1884Transition": "0x0", + "eip2028Transition": "0x0", + "eip2200Transition": "0x0", + "eip2315Transition": "0x0", + "eip2537Transition": "0x0", + "eip2565Transition": "0x0", + "eip2929Transition": "0x0", + "eip2930Transition": "0x0", + "verkleTransition": "0x0", + "eip1559Transition": "0x0", + "eip3198Transition": "0x0", + "eip3529Transition": "0x0", + "eip3541Transition": "0x0", + "verkleTreeTransitionTimestamp": "0x0" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x1234", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x01", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "1676038202", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x17D7840" + }, + "nodes": [ + "enode://7fa827135276f77e6ee35be78689c24901695e53f784280214805a06cf59cbded2fae9dcec064f07e8817c1c2c11aeb8b80061aa0ebb0ca9ebb5dda648367542@188.166.72.218:30303", + "enode://9fc1e1d72dacb752e021c485216d576284628c83b0b731734e4fe1c7bdf271f679cf3350404c9c30f94401195da5aa3bd4cde345ece43cf9fc6aa007e3030e1f@167.71.70.196:30303" + ], + "accounts": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0x6976650c43E63cb1E2f88312a8E57678b323dF36": { + "balance": "1000000000000000000000000000" + }, + "0x02E4650436d2dCa3308eb4d62B0A4a056a01b2Ec": { + "balance": "1000000000000000000000000000" + }, + "0xDCdaB38e9106D9Fd56d468D1E5044F0a59F231df": { + "balance": "1000000000000000000000000000" + }, + "0x950e6058D70C778b1F28B91559B55feB5B9be819": { + "balance": "1000000000000000000000000000" + }, + "0x24C32bd9715979A114bb5842126d3BEA2F1347B3": { + "balance": "1000000000000000000000000000" + }, + "0xA9500ed21AA63Af1aF82433C8ffa7bE23D6F3029": { + "balance": "1000000000000000000000000000" + } + } +} diff --git a/src/Nethermind/Chains/condrieu.json b/src/Nethermind/Chains/condrieu.json new file mode 100644 index 00000000000..4e51bbdda58 --- /dev/null +++ b/src/Nethermind/Chains/condrieu.json @@ -0,0 +1,114 @@ +{ + "name": "Kaustinen", + "dataDir": "Kaustinen", + "engine": { + "Ethash": { + "params": { + "minimumDifficulty": "0x20000", + "difficultyBoundDivisor": "0x800", + "durationLimit": "0xd", + "blockReward": { + "0x0": "0x1BC16D674EC80000" + }, + "homesteadTransition": "0x0", + "eip100bTransition": "0x0", + "difficultyBombDelays": {} + } + } + }, + "params": { + "gasLimitBoundDivisor": "0x0400", + "accountStartNonce": "0x0", + "networkID" : "0x10F2C", + "eip140Transition": "0x0", + "eip145Transition": "0x0", + "eip150Transition": "0x0", + "eip155Transition": "0x0", + "eip160Transition": "0x0", + "eip161abcTransition": "0x0", + "eip161dTransition": "0x0", + "eip211Transition": "0x0", + "eip214Transition": "0x0", + "eip658Transition": "0x0", + "eip1014Transition": "0x0", + "eip1052Transition": "0x0", + "eip1283Transition": "0x0", + "eip1283DisableTransition": "0x0", + "eip152Transition": "0x0", + "eip1108Transition": "0x0", + "eip1344Transition": "0x0", + "eip1884Transition": "0x0", + "eip2028Transition": "0x0", + "eip2200Transition": "0x0", + "eip2315Transition": "0x0", + "eip2537Transition": "0x0", + "eip2565Transition": "0x0", + "eip2929Transition": "0x0", + "eip2930Transition": "0x0", + "verkleTransition": "0x0", + "eip1559Transition": "0x0", + "eip3198Transition": "0x0", + "eip3529Transition": "0x0", + "eip3541Transition": "0x0", + "verkleTreeTransitionTimestamp": "0x0" + }, + "genesis": { + "seal": { + "ethereum": { + "nonce": "0x56", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + }, + "difficulty": "0x01", + "author": "0x0000000000000000000000000000000000000000", + "timestamp": "1674759342", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x2fefd8" + }, + "nodes": [ + "enode://3da5fa6fb683a747a7258f93880ec5a28128e0c9a6272d9b0fa5aa27d182a6088b0d53f5fed214d5922d75220a6f31b56232273d48ded990db69e027fae8acfd@178.62.227.218:30303" + ], + "accounts": { + "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134": { + "balance": "10000000000000000000000000" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + } + } +} diff --git a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs index 11a45512572..9863213c1de 100644 --- a/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs +++ b/src/Nethermind/Nethermind.AccountAbstraction.Test/UserOperationTracerTests.cs @@ -20,7 +20,8 @@ namespace Nethermind.AccountAbstraction.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class UserOperationTracerTests : VirtualMachineTestsBase { [TestCase(Instruction.GASPRICE, false)] @@ -246,5 +247,8 @@ public void Should_allow_gas_only_if_followed_by_call(Instruction instruction, b } protected override long BlockNumber { get; } = MainnetSpecProvider.LondonBlockNumber; + public UserOperationTracerTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs index 3f846b5634a..3ec2ee6182d 100644 --- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs +++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs @@ -21,6 +21,8 @@ using Nethermind.State; using Nethermind.Trie.Pruning; using Nethermind.TxPool; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; namespace Nethermind.Api { @@ -42,6 +44,8 @@ public interface IApiWithBlockchain : IApiWithStores, IBlockchainBridgeFactory IUnclesValidator? UnclesValidator { get; set; } IHeaderValidator? HeaderValidator { get; set; } IManualBlockProductionTrigger ManualBlockProductionTrigger { get; } + VerkleStateStore VerkleTrieStore { get; set; } + ReadOnlyVerkleStateStore ReadOnlyVerkleTrieStore { get; set; } IReadOnlyTrieStore? ReadOnlyTrieStore { get; set; } IRewardCalculatorSource? RewardCalculatorSource { get; set; } ISealer? Sealer { get; set; } diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs index 01d004c26c4..1e66560c3e8 100644 --- a/src/Nethermind/Nethermind.Api/NethermindApi.cs +++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs @@ -57,6 +57,8 @@ using Nethermind.State.Snap; using Nethermind.Synchronization.SnapSync; using Nethermind.Synchronization.Blocks; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; namespace Nethermind.Api { @@ -74,9 +76,19 @@ public IBlockchainBridge CreateBlockchainBridge() { ReadOnlyBlockTree readOnlyTree = BlockTree.AsReadOnly(); LazyInitializer.EnsureInitialized(ref _readOnlyDbProvider, () => new ReadOnlyDbProvider(DbProvider, false)); + IReadOnlyTxProcessorSourceExt readOnlyTxProcessingEnv; + switch (SpecProvider.GenesisSpec.VerkleTreeEnabled) + { + case true: + // TODO: reuse the same trie cache here + readOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv(_readOnlyDbProvider, ReadOnlyVerkleTrieStore, readOnlyTree, SpecProvider, LogManager); + break; + case false: + // TODO: reuse the same trie cache here + readOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv(_readOnlyDbProvider, ReadOnlyTrieStore, readOnlyTree, SpecProvider, LogManager); + break; + } - // TODO: reuse the same trie cache here - IReadOnlyTxProcessorSourceExt readOnlyTxProcessingEnv = new ReadOnlyTxProcessingEnv(_readOnlyDbProvider, ReadOnlyTrieStore, readOnlyTree, SpecProvider, LogManager); IMiningConfig miningConfig = ConfigProvider.GetConfig(); IBlocksConfig blocksConfig = ConfigProvider.GetConfig(); @@ -126,6 +138,8 @@ public IBlockchainBridge CreateBlockchainBridge() public IManualBlockProductionTrigger ManualBlockProductionTrigger { get; set; } = new BuildBlocksWhenRequested(); + public VerkleStateStore VerkleTrieStore { get; set; } + public ReadOnlyVerkleStateStore ReadOnlyVerkleTrieStore { get; set; } public IIPResolver? IpResolver { get; set; } public IJsonSerializer EthereumJsonSerializer { get; set; } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs index ad651f16a92..b5ad5cf6af6 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs @@ -108,5 +108,88 @@ public void Test() autoResetEvent.WaitOne(1000).Should().BeTrue("1"); blockTree.Head.Number.Should().Be(1); } + + [Test] + public void TestVerkle() + { + ISpecProvider specProvider = MainnetSpecProvider.Instance; + DbProvider dbProvider = new(DbModeHint.Mem); + dbProvider.RegisterDb(DbNames.BlockInfos, new MemDb()); + dbProvider.RegisterDb(DbNames.Blocks, new MemDb()); + dbProvider.RegisterDb(DbNames.Headers, new MemDb()); + dbProvider.RegisterDb(DbNames.State, new MemDb()); + dbProvider.RegisterDb(DbNames.Code, new MemDb()); + dbProvider.RegisterDb(DbNames.Metadata, new MemDb()); + dbProvider.RegisterDb(DbNames.Leaf, new MemDb()); + dbProvider.RegisterDb(DbNames.Branch, new MemDb()); + dbProvider.RegisterDb(DbNames.Stem, new MemDb()); + dbProvider.RegisterDb(DbNames.ForwardDiff, new MemDb()); + dbProvider.RegisterDb(DbNames.ReverseDiff, new MemDb()); + dbProvider.RegisterDb(DbNames.StateRootToBlock, new MemDb()); + + BlockTree blockTree = new( + dbProvider, + new ChainLevelInfoRepository(dbProvider), + specProvider, + NullBloomStorage.Instance, + LimboLogs.Instance); + VerkleStateTree stateTree = new VerkleStateTree(dbProvider); + VerkleStateReader stateReader = new(stateTree, dbProvider.GetDb(DbNames.Code), LimboLogs.Instance); + VerkleWorldState worldState = new VerkleWorldState(stateTree, dbProvider.RegisteredDbs[DbNames.Code], LimboLogs.Instance); + BlockhashProvider blockhashProvider = new(blockTree, LimboLogs.Instance); + VirtualMachine virtualMachine = new( + blockhashProvider, + specProvider, + LimboLogs.Instance); + TransactionProcessor txProcessor = new( + specProvider, + worldState, + virtualMachine, + LimboLogs.Instance); + BlockProcessor blockProcessor = new( + specProvider, + Always.Valid, + NoBlockRewards.Instance, + new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, new VerkleWorldState(stateTree, dbProvider.RegisteredDbs[DbNames.Code], LimboLogs.Instance)), + worldState, + NullReceiptStorage.Instance, + NullWitnessCollector.Instance, + LimboLogs.Instance); + BlockchainProcessor blockchainProcessor = new( + blockTree, + blockProcessor, + NullRecoveryStep.Instance, + stateReader, + LimboLogs.Instance, + BlockchainProcessor.Options.Default); + BuildBlocksWhenRequested trigger = new(); + ManualTimestamper timestamper = new ManualTimestamper(); + DevBlockProducer devBlockProducer = new( + EmptyTxSource.Instance, + blockchainProcessor, + worldState, + blockTree, + trigger, + timestamper, + specProvider, + new BlocksConfig(), + LimboLogs.Instance); + + blockchainProcessor.Start(); + devBlockProducer.Start(); + ProducedBlockSuggester suggester = new ProducedBlockSuggester(blockTree, devBlockProducer); + + AutoResetEvent autoResetEvent = new(false); + + blockTree.NewHeadBlock += (s, e) => autoResetEvent.Set(); + blockTree.SuggestBlock(Build.A.Block.Genesis.TestObject); + + autoResetEvent.WaitOne(1000).Should().BeTrue("genesis"); + + trigger.BuildBlock(); + autoResetEvent.WaitOne(1000).Should().BeTrue("1"); + blockTree.Head.Number.Should().Be(1); + } + } } diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs index 12693cfd75a..4e01751214d 100644 --- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs +++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionSelectorTests.cs @@ -155,9 +155,7 @@ public void Proper_transactions_selected(ProperTransactionsSelectedTestCase test MemDb stateDb = new(); MemDb codeDb = new(); TrieStore trieStore = new(stateDb, LimboLogs.Instance); - StateProvider stateProvider = new(trieStore, codeDb, LimboLogs.Instance); - StateReader stateReader = - new(new TrieStore(stateDb, LimboLogs.Instance), codeDb, LimboLogs.Instance); + IWorldState stateProvider = new WorldState(trieStore, codeDb, LimboLogs.Instance); ISpecProvider specProvider = Substitute.For(); void SetAccountStates(IEnumerable
missingAddresses) diff --git a/src/Nethermind/Nethermind.Blockchain/TrieStoreBoundaryWatcher.cs b/src/Nethermind/Nethermind.Blockchain/TrieStoreBoundaryWatcher.cs index 8aebd45a381..797b3f0751d 100644 --- a/src/Nethermind/Nethermind.Blockchain/TrieStoreBoundaryWatcher.cs +++ b/src/Nethermind/Nethermind.Blockchain/TrieStoreBoundaryWatcher.cs @@ -13,11 +13,11 @@ namespace Nethermind.Blockchain /// public class TrieStoreBoundaryWatcher : IDisposable { - private readonly ITrieStore _trieStore; + private readonly IStoreWithReorgBoundary _trieStore; private readonly IBlockTree _blockTree; private readonly ILogger _logger; - public TrieStoreBoundaryWatcher(ITrieStore trieStore, IBlockTree blockTree, ILogManager logManager) + public TrieStoreBoundaryWatcher(IStoreWithReorgBoundary trieStore, IBlockTree blockTree, ILogManager logManager) { _trieStore = trieStore; _blockTree = blockTree; diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/EthashDifficultyCalculator.cs b/src/Nethermind/Nethermind.Consensus.Ethash/EthashDifficultyCalculator.cs index 963eed34c42..ee2112e1eaf 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/EthashDifficultyCalculator.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/EthashDifficultyCalculator.cs @@ -24,7 +24,7 @@ public EthashDifficultyCalculator(ISpecProvider specProvider) _specProvider = specProvider; } - private const long OfGenesisBlock = 131_072; + private const long OfGenesisBlock = 5000; public UInt256 Calculate(BlockHeader header, BlockHeader parent) => Calculate(parent.Difficulty, diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs index cead007cece..51b391ee616 100644 --- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs +++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs @@ -65,7 +65,7 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd if (logger.IsWarn) logger.Warn("Starting Neth Dev block producer & sealer"); - IReadOnlyTxProcessorSource producerEnv = new ReadOnlyTxProcessingEnv(readOnlyDbProvider, getFromApi.ReadOnlyTrieStore, readOnlyBlockTree, getFromApi.SpecProvider, getFromApi.LogManager); + IReadOnlyTxProcessorSource producerEnv = new ReadOnlyTxProcessingEnv(readOnlyDbProvider, getFromApi.ReadOnlyVerkleTrieStore, readOnlyBlockTree, getFromApi.SpecProvider, getFromApi.LogManager); BlockProcessor producerProcessor = new( getFromApi!.SpecProvider, @@ -85,16 +85,14 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd getFromApi.LogManager, BlockchainProcessor.Options.NoReceipts); - DefaultBlockProductionTrigger = new BuildBlocksRegularly(TimeSpan.FromMilliseconds(200)) - .IfPoolIsNotEmpty(getFromApi.TxPool) - .Or(getFromApi.ManualBlockProductionTrigger); + DefaultBlockProductionTrigger = getFromApi.ManualBlockProductionTrigger; IBlockProducer blockProducer = new DevBlockProducer( additionalTxSource.Then(txPoolTxSource).ServeTxsOneByOne(), producerChainProcessor, producerEnv.WorldState, getFromApi.BlockTree, - blockProductionTrigger ?? DefaultBlockProductionTrigger, + DefaultBlockProductionTrigger, getFromApi.Timestamper, getFromApi.SpecProvider, getFromApi.Config(), diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs index 941afa98bbb..26e4d167158 100644 --- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs +++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs @@ -12,6 +12,8 @@ using Nethermind.Logging; using Nethermind.State; using Nethermind.Trie.Pruning; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -36,6 +38,16 @@ public ReadOnlyTxProcessingEnv( { } + public ReadOnlyTxProcessingEnv( + IDbProvider? dbProvider, + ReadOnlyVerkleStateStore? trieStore, + IBlockTree? blockTree, + ISpecProvider? specProvider, + ILogManager? logManager) + : this(dbProvider?.AsReadOnly(false), trieStore, blockTree?.AsReadOnly(), specProvider, logManager) + { + } + public ReadOnlyTxProcessingEnv( IReadOnlyDbProvider? readOnlyDbProvider, IReadOnlyTrieStore? readOnlyTrieStore, @@ -57,6 +69,27 @@ public ReadOnlyTxProcessingEnv( TransactionProcessor = new TransactionProcessor(specProvider, WorldState, Machine, logManager); } + public ReadOnlyTxProcessingEnv( + IReadOnlyDbProvider? readOnlyDbProvider, + ReadOnlyVerkleStateStore? readOnlyTrieStore, + IReadOnlyBlockTree? readOnlyBlockTree, + ISpecProvider? specProvider, + ILogManager? logManager) + { + if (specProvider is null) throw new ArgumentNullException(nameof(specProvider)); + + ReadOnlyDb codeDb = readOnlyDbProvider.CodeDb.AsReadOnly(true); + + StateReader = new VerkleStateReader(new VerkleStateTree(readOnlyTrieStore), codeDb, logManager); + WorldState = new VerkleWorldState(new VerkleStateTree(readOnlyTrieStore), codeDb, logManager); + + BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree)); + BlockhashProvider = new BlockhashProvider(BlockTree, logManager); + + Machine = new VirtualMachine(BlockhashProvider, specProvider, logManager); + TransactionProcessor = new TransactionProcessor(specProvider, WorldState, Machine, logManager); + } + public IReadOnlyTransactionProcessor Build(Keccak stateRoot) => new ReadOnlyTransactionProcessor(TransactionProcessor, WorldState, stateRoot); } } diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs index 332c0eed1db..a9f78af2c40 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs @@ -233,7 +233,7 @@ protected bool TrySetState(Keccak? parentStateRoot) { bool HasState(Keccak stateRoot) { - RootCheckVisitor visitor = new(); + RootCheckVisitor visitor = new RootCheckVisitor(); StateProvider.Accept(visitor, stateRoot); return visitor.HasRoot; } diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs index 2dacba1db23..c62b0d3c8b0 100644 --- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs +++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using Nethermind.Blockchain; using Nethermind.Blockchain.Receipts; using Nethermind.Config; @@ -16,6 +17,8 @@ using Nethermind.State; using Nethermind.Trie.Pruning; using Nethermind.TxPool; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; namespace Nethermind.Consensus.Producers { @@ -24,6 +27,7 @@ public class BlockProducerEnvFactory : IBlockProducerEnvFactory protected readonly IDbProvider _dbProvider; protected readonly IBlockTree _blockTree; protected readonly IReadOnlyTrieStore _readOnlyTrieStore; + protected readonly ReadOnlyVerkleStateStore _readOnlyVerkleTrieStore; protected readonly ISpecProvider _specProvider; protected readonly IBlockValidator _blockValidator; protected readonly IRewardCalculatorSource _rewardCalculatorSource; @@ -33,6 +37,7 @@ public class BlockProducerEnvFactory : IBlockProducerEnvFactory protected readonly ITransactionComparerProvider _transactionComparerProvider; protected readonly IBlocksConfig _blocksConfig; protected readonly ILogManager _logManager; + protected readonly TreeType _treeType; public IBlockTransactionsExecutorFactory TransactionsExecutorFactory { get; set; } @@ -62,6 +67,38 @@ public BlockProducerEnvFactory( _transactionComparerProvider = transactionComparerProvider; _blocksConfig = blocksConfig; _logManager = logManager; + _treeType = TreeType.MerkleTree; + + TransactionsExecutorFactory = new BlockProducerTransactionsExecutorFactory(specProvider, logManager); + } + + public BlockProducerEnvFactory( + IDbProvider dbProvider, + IBlockTree blockTree, + ReadOnlyVerkleStateStore readOnlyTrieStore, + ISpecProvider specProvider, + IBlockValidator blockValidator, + IRewardCalculatorSource rewardCalculatorSource, + IReceiptStorage receiptStorage, + IBlockPreprocessorStep blockPreprocessorStep, + ITxPool txPool, + ITransactionComparerProvider transactionComparerProvider, + IBlocksConfig blocksConfig, + ILogManager logManager) + { + _dbProvider = dbProvider; + _blockTree = blockTree; + _readOnlyVerkleTrieStore = readOnlyTrieStore; + _specProvider = specProvider; + _blockValidator = blockValidator; + _rewardCalculatorSource = rewardCalculatorSource; + _receiptStorage = receiptStorage; + _blockPreprocessorStep = blockPreprocessorStep; + _txPool = txPool; + _transactionComparerProvider = transactionComparerProvider; + _blocksConfig = blocksConfig; + _logManager = logManager; + _treeType = TreeType.VerkleTree; TransactionsExecutorFactory = new BlockProducerTransactionsExecutorFactory(specProvider, logManager); } @@ -106,8 +143,16 @@ public virtual BlockProducerEnv Create(ITxSource? additionalTxSource = null) }; } - protected virtual IReadOnlyTxProcessorSource CreateReadonlyTxProcessingEnv(ReadOnlyDbProvider readOnlyDbProvider, ReadOnlyBlockTree readOnlyBlockTree) => - new ReadOnlyTxProcessingEnv(readOnlyDbProvider, _readOnlyTrieStore, readOnlyBlockTree, _specProvider, _logManager); + protected virtual IReadOnlyTxProcessorSource CreateReadonlyTxProcessingEnv(ReadOnlyDbProvider readOnlyDbProvider, ReadOnlyBlockTree readOnlyBlockTree) + { + return _treeType switch + { + TreeType.MerkleTree => new ReadOnlyTxProcessingEnv(readOnlyDbProvider, _readOnlyTrieStore, readOnlyBlockTree, _specProvider, _logManager), + TreeType.VerkleTree => new ReadOnlyTxProcessingEnv(readOnlyDbProvider, _readOnlyVerkleTrieStore, readOnlyBlockTree, _specProvider, _logManager), + _ => throw new ArgumentOutOfRangeException() + }; + } + protected virtual ITxSource CreateTxSourceForProducer( ITxSource? additionalTxSource, diff --git a/src/Nethermind/Nethermind.Core/Account.cs b/src/Nethermind/Nethermind.Core/Account.cs index f09d1e9ef56..dbdc1753aef 100644 --- a/src/Nethermind/Nethermind.Core/Account.cs +++ b/src/Nethermind/Nethermind.Core/Account.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System.Collections.Generic; +using System.Linq; using Nethermind.Core.Crypto; using Nethermind.Int256; @@ -104,7 +105,7 @@ private Account(in UInt256 nonce, in UInt256 balance, Keccak storageRoot, Keccak public UInt256 Nonce { get; } public UInt256 Balance { get; } - public UInt256 CodeSize { get; } + public UInt256 CodeSize { get; set; } public UInt256 Version { get; } public Keccak StorageRoot { get; } public Keccak CodeHash { get; } @@ -127,24 +128,28 @@ public Account WithChangedStorageRoot(Keccak newStorageRoot) return new(Nonce, Balance, newStorageRoot, CodeHash, IsTotallyEmpty && newStorageRoot == Keccak.EmptyTreeHash); } - public Account WithChangedCodeHash(Keccak newCodeHash) + public Account WithChangedCodeHash(Keccak newCodeHash, byte[]? code = null) { // TODO: does the code and codeHash match? - return new(Nonce, Balance, StorageRoot, newCodeHash, IsTotallyEmpty && newCodeHash == Keccak.OfAnEmptyString); + return new(Nonce, Balance, StorageRoot, newCodeHash, IsTotallyEmpty && newCodeHash == Keccak.OfAnEmptyString) + { + Code = code, + CodeSize = new UInt256((ulong) (code?.Length ?? 0)) + }; } public Dictionary ToVerkleDict() { Dictionary dict = new Dictionary(); - dict[0] = Version.ToBigEndian(); - dict[1] = Balance.ToBigEndian(); - dict[2] = Nonce.ToBigEndian(); + dict[0] = Version.ToLittleEndian(); + dict[1] = Balance.ToLittleEndian(); + dict[2] = Nonce.ToLittleEndian(); dict[3] = CodeHash.Bytes; - dict[4] = CodeSize.ToBigEndian(); + if(!CodeHash.Bytes.SequenceEqual(Keccak.OfAnEmptyString.Bytes)) + dict[4] = CodeSize.ToLittleEndian(); return dict; - } } } diff --git a/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs b/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs index b215e408639..c0dceb48566 100644 --- a/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs +++ b/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs @@ -14,8 +14,20 @@ namespace Nethermind.Core.Collections /// Due to snapshots is not supported. public class JournalSet : IReadOnlySet, ICollection, IJournal { - private readonly List _items = new(); - private readonly HashSet _set = new(); + private readonly List _items; + private readonly HashSet _set; + + public JournalSet(IEqualityComparer comparer) + { + _items = new List(); + _set = new HashSet(comparer); + } + + public JournalSet() + { + _items = new List(); + _set = new HashSet(); + } public int TakeSnapshot() => Position; private int Position => Count - 1; diff --git a/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs index 4230c89b29e..58750bd892c 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/EnumerableExtensions.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; namespace Nethermind.Core.Extensions { @@ -11,5 +12,14 @@ public static class EnumerableExtensions { public static ISet AsSet(this IEnumerable enumerable) => enumerable is ISet set ? set : enumerable.ToHashSet(); + + public static string ToString(this IEnumerable enumerable) + { + StringBuilder builder = new StringBuilder(); + builder.Append('['); + builder.AppendJoin(", ", enumerable); + builder.Append(']'); + return builder.ToString(); + } } } diff --git a/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs b/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs index a1867c8bf92..c670e434e6f 100644 --- a/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs +++ b/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs @@ -36,6 +36,13 @@ public static byte[] ToByteArray(this int value) return bytes; } + public static byte[] ToByteArrayLittleEndian(this int value) + { + byte[] bytes = new byte[sizeof(int)]; + BinaryPrimitives.WriteInt32LittleEndian(bytes, value); + return bytes; + } + public static byte[] ToBigEndianByteArray(this int value) { byte[] bytes = BitConverter.GetBytes(value); diff --git a/src/Nethermind/Nethermind.Core/IVerkleWitness.cs b/src/Nethermind/Nethermind.Core/IVerkleWitness.cs index c235d5a5612..bfdcdd0c74c 100644 --- a/src/Nethermind/Nethermind.Core/IVerkleWitness.cs +++ b/src/Nethermind/Nethermind.Core/IVerkleWitness.cs @@ -26,8 +26,6 @@ public interface IVerkleWitness : IJournal public long AccessCompleteAccount(Address address, bool isWrite = false); - public long AccessAccount(Address address, bool[] bitVector, bool isWrite = false); - public long AccessKey(byte[] key, bool isWrite = false); - public long AccessForTransaction(Address originAddress, Address destinationAddress, bool isValueTransfer); + public long AccessForProofOfAbsence(Address address); } diff --git a/src/Nethermind/Nethermind.Crypto/EthereumEcdsa.cs b/src/Nethermind/Nethermind.Crypto/EthereumEcdsa.cs index 7d4fda2a752..0e080776760 100644 --- a/src/Nethermind/Nethermind.Crypto/EthereumEcdsa.cs +++ b/src/Nethermind/Nethermind.Crypto/EthereumEcdsa.cs @@ -61,7 +61,7 @@ public void Sign(PrivateKey privateKey, Transaction tx, bool isEip155Enabled) } /// - /// + /// /// /// /// @@ -73,7 +73,7 @@ public bool Verify(Address sender, Transaction tx) } /// - /// + /// /// /// /// diff --git a/src/Nethermind/Nethermind.Db/IDbProvider.cs b/src/Nethermind/Nethermind.Db/IDbProvider.cs index 1bef207ee44..78aeb2875d9 100644 --- a/src/Nethermind/Nethermind.Db/IDbProvider.cs +++ b/src/Nethermind/Nethermind.Db/IDbProvider.cs @@ -36,6 +36,11 @@ public interface IDbProvider : IDisposable public IDb StemDb => GetDb(DbNames.Stem); public IDb BranchDb => GetDb(DbNames.Branch); + public IDb ForwardDiff => GetDb(DbNames.ForwardDiff); + public IDb ReverseDiff => GetDb(DbNames.ReverseDiff); + + public IDb StateRootToBlocks => GetDb(DbNames.StateRootToBlock); + T GetDb(string dbName) where T : class, IDb; void RegisterDb(string dbName, T db) where T : class, IDb; diff --git a/src/Nethermind/Nethermind.Evm.Test/BytecodeBuilderExtensionsTests.cs b/src/Nethermind/Nethermind.Evm.Test/BytecodeBuilderExtensionsTests.cs index 490162e882c..3618e1c963d 100644 --- a/src/Nethermind/Nethermind.Evm.Test/BytecodeBuilderExtensionsTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/BytecodeBuilderExtensionsTests.cs @@ -26,6 +26,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class BytecodeBuilderExtensionsTests : VirtualMachineTestsBase { public class TestCase @@ -56,7 +58,7 @@ static bool HasDigit(Instruction opcode, Instruction[] treatLikeSuffexedOpcode, return true; } - // we check if opcode has a digit at its end + // we check if opcode has a digit at its end bool hasDigits = false; int i = opcodeAsString.Length - 1; while (i > 0) @@ -133,7 +135,7 @@ public static IEnumerable opcodes_with_0_arg() //we get MethodInfo of the function representing the opcode var method = GetFluentOpcodeFunction(opcode); - //we handle the cases requiring a byte differentiator + //we handle the cases requiring a byte differentiator initBytecode = opcode switch { >= Instruction.SWAP1 and <= Instruction.SWAP16 => (Prepare)method.Invoke(null, new object[] { initBytecode, (byte)(opcode - Instruction.SWAP1 + 1) }), @@ -626,5 +628,8 @@ public void code_emited_by_fluent_is_same_as_expected([ValueSource(nameof(Fluent { test.FluentCodes.Should().BeEquivalentTo(test.ResultCodes, test.Description); } + public BytecodeBuilderExtensionsTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/CallDataCopyTests.cs b/src/Nethermind/Nethermind.Evm.Test/CallDataCopyTests.cs index 7ab2e83f5dd..dc8955eb89f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/CallDataCopyTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/CallDataCopyTests.cs @@ -6,6 +6,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class CallDataCopyTests : VirtualMachineTestsBase { [Test] @@ -21,5 +23,8 @@ public void Ranges() TestAllTracerWithOutput result = Execute(code); result.Error.Should().BeNull(); } + public CallDataCopyTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/CmpTests.cs b/src/Nethermind/Nethermind.Evm.Test/CmpTests.cs index cb6fc2b5bfd..26d201e45da 100644 --- a/src/Nethermind/Nethermind.Evm.Test/CmpTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/CmpTests.cs @@ -9,9 +9,11 @@ namespace Nethermind.Evm.Test { - [TestFixture(true)] - [TestFixture(false)] [Parallelizable(ParallelScope.Self)] + [TestFixture(true, VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(true, VirtualMachineTestsStateProvider.VerkleTrie)] + [TestFixture(false, VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(false, VirtualMachineTestsStateProvider.VerkleTrie)] public class CmpTests : VirtualMachineTestsBase { private readonly bool _simdDisabled; @@ -22,7 +24,7 @@ private void AssertEip1014(Address address, byte[] code) AssertCodeHash(address, Keccak.Compute(code)); } - public CmpTests(bool simdDisabled) + public CmpTests(bool simdDisabled, VirtualMachineTestsStateProvider stateProvider): base(stateProvider) { _simdDisabled = simdDisabled; } diff --git a/src/Nethermind/Nethermind.Evm.Test/CoinbaseTests.cs b/src/Nethermind/Nethermind.Evm.Test/CoinbaseTests.cs index fbead389dd6..78de258f9ee 100644 --- a/src/Nethermind/Nethermind.Evm.Test/CoinbaseTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/CoinbaseTests.cs @@ -8,7 +8,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class CoinbaseTests : VirtualMachineTestsBase { protected override long BlockNumber => RinkebySpecProvider.SpuriousDragonBlockNumber; @@ -55,5 +56,8 @@ public void When_author_no_set_coinbase_return_beneficiary() AssertStorage(0, TestItem.AddressB); } + public CoinbaseTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs index 7ffab7e5121..4738491408b 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1014Tests.cs @@ -15,7 +15,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip1014Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.ConstantinopleFixBlockNumber; @@ -110,8 +111,14 @@ public void Test_out_of_gas_existing_account_with_storage() WorldState.Commit(Spec); WorldState.CommitTree(0); - Keccak storageRoot = WorldState.GetAccount(expectedAddress).StorageRoot; - storageRoot.Should().NotBe(PatriciaTree.EmptyTreeHash); + WorldState.Get(new StorageCell(expectedAddress, 1)).Should().BeEquivalentTo(new byte[] { 1, 2, 3, 4, 5 }); + + Keccak storageRoot = Keccak.EmptyTreeHash; + if (_stateProvider == VirtualMachineTestsStateProvider.MerkleTrie) + { + storageRoot = WorldState.GetAccount(expectedAddress).StorageRoot; + storageRoot.Should().NotBe(PatriciaTree.EmptyTreeHash); + } WorldState.CreateAccount(TestItem.AddressC, 1.Ether()); @@ -125,7 +132,7 @@ public void Test_out_of_gas_existing_account_with_storage() WorldState.GetAccount(expectedAddress).Should().NotBeNull(); WorldState.GetAccount(expectedAddress).Balance.Should().Be(1.Ether()); - WorldState.GetAccount(expectedAddress).StorageRoot.Should().Be(storageRoot); + if(_stateProvider == VirtualMachineTestsStateProvider.MerkleTrie) WorldState.GetAccount(expectedAddress).StorageRoot.Should().Be(storageRoot); AssertEip1014(expectedAddress, Array.Empty()); } @@ -191,5 +198,8 @@ public void Examples_from_eip_spec_are_executed_correctly(string addressHex, str AssertEip1014(expectedAddress, deployedCode); // Assert.AreEqual(gas, trace.Entries.Single(e => e.Operation == Instruction.CREATE2.ToString()).GasCost); } + public Eip1014Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs index 72ba0559cf5..4a96dc80f1c 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1052Tests.cs @@ -14,7 +14,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip1052Tests : VirtualMachineTestsBase { protected override long BlockNumber => RopstenSpecProvider.ConstantinopleBlockNumber; @@ -133,6 +134,8 @@ public void Addresses_are_trimmed_properly() [Test] public void Self_destructed_returns_zero() { + // verkle trees does not support deletions + if(_stateProvider is VirtualMachineTestsStateProvider.VerkleTrie) return; byte[] selfDestructCode = Prepare.EvmCode .PushData(Recipient) .Op(Instruction.SELFDESTRUCT).Done; @@ -155,6 +158,8 @@ public void Self_destructed_returns_zero() [Test] public void Self_destructed_and_reverted_returns_code_hash() { + // verkle trees does not support deletions + if(_stateProvider is VirtualMachineTestsStateProvider.VerkleTrie) return; byte[] callAndRevertCode = Prepare.EvmCode .Call(TestItem.AddressD, 50000) .Op(Instruction.REVERT).Done; @@ -184,6 +189,8 @@ public void Self_destructed_and_reverted_returns_code_hash() [Test] public void Empty_account_that_would_be_cleared_returns_zero() { + // verkle trees does not support deletions + if(_stateProvider is VirtualMachineTestsStateProvider.VerkleTrie) return; WorldState.CreateAccount(TestItem.AddressC, 0.Ether()); byte[] code = Prepare.EvmCode @@ -278,5 +285,8 @@ public void Create_returns_code_hash() Execute(code); AssertStorage(0, deployedCodeHash); } + public Eip1052Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1108Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1108Tests.cs index 7e5a9d98e66..a4a726e9c63 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1108Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1108Tests.cs @@ -7,7 +7,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip1108Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.IstanbulBlockNumber + _blockNumberAdjustment; @@ -88,5 +89,8 @@ public void Test_pairing_after_istanbul() Assert.AreEqual(StatusCode.Success, result.StatusCode); AssertGas(result, 21000 + 6 * 12 + 7 * 3 + GasCostOf.CallEip150 + 45000L + 34000L); } + public Eip1108Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs index d06bb8ecdc9..9e891ad855a 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1153Tests.cs @@ -14,6 +14,8 @@ namespace Nethermind.Evm.Test /// /// Tests functionality of Transient Storage /// + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] internal class Eip1153Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.GrayGlacierBlockNumber; @@ -820,5 +822,8 @@ public void tload_from_static_reentrant_call(Instruction callType, int expectedR Assert.AreEqual(expectedResult, (int)result.ReturnValue.ToUInt256()); } + public Eip1153Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs index 4016e4338b0..b37447fe2ae 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1283Tests.cs @@ -11,7 +11,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip1283Tests : VirtualMachineTestsBase { protected override long BlockNumber => RopstenSpecProvider.ConstantinopleBlockNumber; @@ -44,5 +45,8 @@ public void Test(string codeHex, long gasUsed, long refund, byte originalValue) TestAllTracerWithOutput receipt = Execute(Bytes.FromHexString(codeHex)); AssertGas(receipt, gasUsed + GasCostOf.Transaction - Math.Min((gasUsed + GasCostOf.Transaction) / 2, refund)); } + public Eip1283Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs index 44ca4eb7d3f..6473c0d5720 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1344Tests.cs @@ -10,7 +10,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip1344Tests : VirtualMachineTestsBase { private void Test(ulong chainId) @@ -37,6 +38,9 @@ public void given_custom_0_network_chain_id_opcode_puts_expected_value_onto_the_ { Test(SpecProvider.ChainId); } + public Custom0(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } private class Custom32000 : Eip1344Tests @@ -49,6 +53,9 @@ public void given_custom_custom_32000_network_chain_id_opcode_puts_expected_valu { Test(SpecProvider.ChainId); } + public Custom32000(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } private class Goerli : Eip1344Tests @@ -61,6 +68,9 @@ public void given_goerli_network_chain_id_opcode_puts_expected_value_onto_the_st { Test(SpecProvider.ChainId); } + public Goerli(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } private class Mainnet : Eip1344Tests @@ -73,6 +83,9 @@ public void given_mainnet_network_chain_id_opcode_puts_expected_value_onto_the_s { Test(SpecProvider.ChainId); } + public Mainnet(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } private class Rinkeby : Eip1344Tests @@ -85,6 +98,9 @@ public void given_rinkeby_network_chain_id_opcode_puts_expected_value_onto_the_s { Test(SpecProvider.ChainId); } + public Rinkeby(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } private class Ropsten : Eip1344Tests @@ -97,6 +113,13 @@ public void given_ropsten_network_chain_id_opcode_puts_expected_value_onto_the_s { Test(SpecProvider.ChainId); } + public Ropsten(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } + } + + public Eip1344Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs index 89b3c99cdff..c3499e9e9a9 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip145Tests.cs @@ -9,7 +9,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip145Tests : VirtualMachineTestsBase { protected override long BlockNumber => RopstenSpecProvider.ConstantinopleBlockNumber; @@ -114,5 +115,8 @@ public void Arithmetic_shift_right(string a, string b, string result) TestAllTracerWithOutput receipt = Execute(code); AssertEip145(receipt, result); } + public Eip145Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs index df62eee5606..f65cd926f04 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip152Tests.cs @@ -8,6 +8,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip152Tests : VirtualMachineTestsBase { private const int InputLength = 213; @@ -38,5 +40,8 @@ public void after_istanbul() TestAllTracerWithOutput result = Execute(code); Assert.AreEqual(StatusCode.Success, result.StatusCode); } + public Eip152Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs index 086a29e8abe..abd736dd317 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip1884Tests.cs @@ -13,6 +13,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip1884Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.IstanbulBlockNumber; @@ -136,5 +138,8 @@ public void just_before_istanbul_sload_cost_is_increased() TestAllTracerWithOutput result = Execute(BlockNumber - 1, 100000, code); AssertGas(result, 21000 + 2 * GasCostOf.VeryLow + GasCostOf.SLoadEip150); } + public Eip1884Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs index 440ee62151a..f9436d6d0e9 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2028Tests.cs @@ -11,7 +11,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip2028Tests : VirtualMachineTestsBase { private class AfterIstanbul : Eip2028Tests @@ -34,6 +35,9 @@ public void zero_transaction_data_cost_should_be_4() long cost = IntrinsicGasCalculator.Calculate(transaction, Spec); cost.Should().Be(GasCostOf.Transaction + GasCostOf.TxDataZero); } + public AfterIstanbul(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } private class BeforeIstanbul : Eip2028Tests @@ -56,6 +60,13 @@ public void zero_transaction_data_cost_should_be_4() long cost = IntrinsicGasCalculator.Calculate(transaction, Spec); cost.Should().Be(GasCostOf.Transaction + GasCostOf.TxDataZero); } + public BeforeIstanbul(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } + } + + public Eip2028Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2200Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2200Tests.cs index 7ef6dfc2fce..8fceb91367e 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip2200Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2200Tests.cs @@ -11,7 +11,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip2200Tests : VirtualMachineTestsBase { protected override long BlockNumber => RopstenSpecProvider.IstanbulBlockNumber; @@ -96,5 +97,8 @@ public void Test_when_gas_just_below_stipend(string codeHex, long gasUsed, long TestAllTracerWithOutput receipt = Execute(BlockNumber, 21000 + gasUsed + (2299 - 800), Bytes.FromHexString(codeHex)); Assert.AreEqual(0, receipt.StatusCode); } + public Eip2200Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2315Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2315Tests.cs index 412d3bee50d..ab54d8b304d 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip2315Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2315Tests.cs @@ -10,6 +10,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip2315Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.BerlinBlockNumber; @@ -101,5 +103,8 @@ public void Error_on_walk_into_the_subroutine() result.StatusCode.Should().Be(0); result.Error.Should().Be(EvmExceptionType.BadInstruction.ToString()); } + public Eip2315Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip2929Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip2929Tests.cs index d41cd3392b9..c3e05e0cf3f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip2929Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip2929Tests.cs @@ -13,6 +13,8 @@ namespace Nethermind.Evm.Test /// /// https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a /// + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip2929Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.BerlinBlockNumber; @@ -80,5 +82,8 @@ protected override TestAllTracerWithOutput CreateTracer() tracer.IsTracingAccess = false; return tracer; } + public Eip2929Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3198BaseFeeTests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3198BaseFeeTests.cs index 392f3d024db..a26b83e72b1 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3198BaseFeeTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3198BaseFeeTests.cs @@ -15,6 +15,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip3198BaseFeeTests : VirtualMachineTestsBase { @@ -63,5 +65,8 @@ public void Base_fee_opcode_should_return_expected_results(bool eip3198Enabled, AssertStorage((UInt256)0, (UInt256)0); } } + public Eip3198BaseFeeTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3529RefundsTests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3529RefundsTests.cs index 383bf32aacf..563e7da1e64 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3529RefundsTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3529RefundsTests.cs @@ -23,6 +23,8 @@ namespace Nethermind.Evm.Test { // Vitalik Buterin, Martin Swende, "EIP-3529: Reduction in refunds [DRAFT]," Ethereum Improvement Proposals, no. 3529, April 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3529. + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip3529Tests : VirtualMachineTestsBase { @@ -178,5 +180,8 @@ public void After_3529_self_destruct_has_zero_refund(bool eip3529Enabled) Assert.AreEqual(expectedRefund, tracer.Refund); AssertGas(tracer, gasUsedByTx3 + GasCostOf.Transaction - Math.Min((gasUsedByTx3 + GasCostOf.Transaction) / (eip3529Enabled ? RefundHelper.MaxRefundQuotientEIP3529 : RefundHelper.MaxRefundQuotient), expectedRefund)); } + public Eip3529Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3541Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3541Tests.cs index 477128560df..a9379937356 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3541Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3541Tests.cs @@ -19,6 +19,8 @@ namespace Nethermind.Evm.Test { // Alex Beregszaszi, Paweł Bylica, Andrei Maiboroda, Alexey Akhunov, Christian Reitwiessner, Martin Swende, "EIP-3541: Reject new contracts starting with the 0xEF byte," Ethereum Improvement Proposals, no. 3541, March 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3541. + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip3541Tests : VirtualMachineTestsBase { @@ -112,5 +114,8 @@ void DeployCodeAndAssertTx(string code, bool eip3541Enabled, ContractDeployment Assert.AreEqual(withoutAnyInvalidCodeErrors, tracer.ReportedActionErrors.All(x => x != EvmExceptionType.InvalidCode), $"Code {code}, Context {context}"); } + public Eip3541Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3588Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3588Tests.cs index 69905794e16..0ec5a85a47d 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3588Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3588Tests.cs @@ -19,7 +19,8 @@ namespace Nethermind.Evm.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip3855Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.GrayGlacierBlockNumber; @@ -72,5 +73,8 @@ public void Test_Eip3855_should_fail(int repeat, bool isShanghai) receipt.Error.Should().Be(EvmExceptionType.BadInstruction.ToString()); } } + public Eip3855Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3651Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3651Tests.cs index 06875c31fb5..945444dab3a 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3651Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3651Tests.cs @@ -14,6 +14,8 @@ namespace Nethermind.Evm.Test /// /// https://gist.github.com/holiman/174548cad102096858583c6fbbb0649a /// + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip3651Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.GrayGlacierBlockNumber; @@ -53,5 +55,8 @@ protected override TestAllTracerWithOutput CreateTracer() return tracer; } + public Eip3651Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs index cd6d7a7e807..d8970b11ac2 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Eip3860Tests.cs @@ -12,6 +12,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Eip3860Tests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.GrayGlacierBlockNumber; @@ -114,5 +116,8 @@ protected TestAllTracerWithOutput PrepExecuteCreateTransaction(ulong timestamp, return tracer; } + public Eip3860Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/ExtCodeCopyTests.cs b/src/Nethermind/Nethermind.Evm.Test/ExtCodeCopyTests.cs index e9b633b58ad..a176852c886 100644 --- a/src/Nethermind/Nethermind.Evm.Test/ExtCodeCopyTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/ExtCodeCopyTests.cs @@ -6,6 +6,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class ExtCodeCopyTests : VirtualMachineTestsBase { [Test] @@ -22,5 +24,8 @@ public void Ranges() TestAllTracerWithOutput result = Execute(code); result.Error.Should().BeNull(); } + public ExtCodeCopyTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs b/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs index 263fb7d0b62..e507348114c 100644 --- a/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/GasPriceExtractorTests.cs @@ -13,7 +13,8 @@ namespace Nethermind.Evm.Test { [Explicit("Failing on MacOS GitHub Actions with stack overflow")] - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class GasPriceExtractorTests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.IstanbulBlockNumber; @@ -129,5 +130,8 @@ private static Rlp BuildHeader() Rlp rlp = decoder.Encode(blockHeader); return rlp; } + public GasPriceExtractorTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/GtTests.cs b/src/Nethermind/Nethermind.Evm.Test/GtTests.cs index a4adfbb25bf..477188c0dab 100644 --- a/src/Nethermind/Nethermind.Evm.Test/GtTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/GtTests.cs @@ -6,6 +6,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class GtTests : VirtualMachineTestsBase { [TestCase(0, 0, 0)] @@ -27,5 +29,8 @@ public void Gt(int a, int b, int res) _ = Execute(code); AssertStorage(UInt256.Zero, res); } + public GtTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/InvalidOpcodeTests.cs b/src/Nethermind/Nethermind.Evm.Test/InvalidOpcodeTests.cs index 9eb83a4e04c..ea7b8ba0af0 100644 --- a/src/Nethermind/Nethermind.Evm.Test/InvalidOpcodeTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/InvalidOpcodeTests.cs @@ -12,8 +12,9 @@ namespace Nethermind.Evm.Test { - [TestFixture] [Parallelizable(ParallelScope.Self)] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class InvalidOpcodeTests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.ConstantinopleFixBlockNumber; @@ -175,5 +176,8 @@ public void Test(long blockNumber, ulong? timestamp = null) } } } + public InvalidOpcodeTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj b/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj index d9a87d7058d..1e9c3f64412 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj +++ b/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj @@ -21,6 +21,7 @@ + diff --git a/src/Nethermind/Nethermind.Evm.Test/SDivTests.cs b/src/Nethermind/Nethermind.Evm.Test/SDivTests.cs index df7b5bf30c9..b79e6cfc7ca 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SDivTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SDivTests.cs @@ -8,6 +8,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class SDivTests : VirtualMachineTestsBase { [Test] @@ -37,5 +39,8 @@ public void Representations() Assert.AreEqual(a, b); } + public SDivTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/SModTests.cs b/src/Nethermind/Nethermind.Evm.Test/SModTests.cs index 17b2f524b65..8bfb903cfea 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SModTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SModTests.cs @@ -6,6 +6,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class SModTests : VirtualMachineTestsBase { [TestCase(1, 1, 0)] @@ -51,5 +53,8 @@ public void Test_for_a_equals_int256_dot_min(int b, int res) AssertStorage(UInt256.Zero, res); } + public SModTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/SgtTests.cs b/src/Nethermind/Nethermind.Evm.Test/SgtTests.cs index 57f48b5e79a..153cdaf6e31 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SgtTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SgtTests.cs @@ -6,6 +6,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class SgtTests : VirtualMachineTestsBase { [TestCase(1, 1, 0)] @@ -32,5 +34,8 @@ public void Sgt(int a, int b, int res) _ = Execute(code); AssertStorage(UInt256.Zero, res); } + public SgtTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Sha3Tests.cs b/src/Nethermind/Nethermind.Evm.Test/Sha3Tests.cs index 4c2a92f2fb4..d9d1878ea5f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Sha3Tests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Sha3Tests.cs @@ -8,8 +8,9 @@ namespace Nethermind.Evm.Test { - [TestFixture] [Parallelizable(ParallelScope.All)] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class Sha3Tests : VirtualMachineTestsBase { protected override long BlockNumber => RinkebySpecProvider.ConstantinopleFixBlockNumber; @@ -43,5 +44,8 @@ public void Spin_sha3() AssertGas(receipt, 8000000); } + public Sha3Tests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/SignExtTests.cs b/src/Nethermind/Nethermind.Evm.Test/SignExtTests.cs index e26b2c5b86c..096d10def22 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SignExtTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SignExtTests.cs @@ -7,6 +7,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class SignExtTests : VirtualMachineTestsBase { [Test] @@ -50,5 +52,8 @@ public void Sign_ext_underflow() TestAllTracerWithOutput res = Execute(code); res.Error.Should().Be(EvmExceptionType.StackUnderflow.ToString()); } + public SignExtTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs b/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs index bb2ef6058a2..3f08b36151f 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs @@ -10,9 +10,11 @@ namespace Nethermind.Evm.Test { - [TestFixture(true)] - [TestFixture(false)] [Parallelizable(ParallelScope.Self)] + [TestFixture(true, VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(true, VirtualMachineTestsStateProvider.VerkleTrie)] + [TestFixture(false, VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(false, VirtualMachineTestsStateProvider.VerkleTrie)] public class SimdTests : VirtualMachineTestsBase { private readonly bool _simdDisabled; @@ -23,7 +25,7 @@ private void AssertEip1014(Address address, byte[] code) AssertCodeHash(address, Keccak.Compute(code)); } - public SimdTests(bool simdDisabled) + public SimdTests(bool simdDisabled, VirtualMachineTestsStateProvider stateProvider): base(stateProvider) { _simdDisabled = simdDisabled; } diff --git a/src/Nethermind/Nethermind.Evm.Test/SltTests.cs b/src/Nethermind/Nethermind.Evm.Test/SltTests.cs index 3e62d281eda..3cd7314bcc9 100644 --- a/src/Nethermind/Nethermind.Evm.Test/SltTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/SltTests.cs @@ -6,6 +6,8 @@ namespace Nethermind.Evm.Test { + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class SltTests : VirtualMachineTestsBase { [TestCase(1, 1, 0)] @@ -32,5 +34,8 @@ public void Slt(int a, int b, int res) _ = Execute(code); AssertStorage(UInt256.Zero, res); } + public SltTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs b/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs index 65c8891207f..5964afdb3e8 100644 --- a/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/StorageAndSelfDestructTests.cs @@ -18,6 +18,8 @@ namespace Nethermind.Evm.Test { [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class StorageAndSelfDestructTests : VirtualMachineTestsBase { protected override long BlockNumber => MainnetSpecProvider.MuirGlacierBlockNumber; @@ -397,5 +399,8 @@ public void Destroy_restore_store_different_cells_previously_existing() _processor.Execute(tx4, block.Header, tracer); AssertStorage(new StorageCell(deploymentAddress, 7), 0); } + public StorageAndSelfDestructTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/AccessTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/AccessTxTracerTests.cs index c629865ca24..214a9fdba2a 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/AccessTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/AccessTxTracerTests.cs @@ -15,7 +15,8 @@ namespace Nethermind.Evm.Test.Tracing { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class AccessTxTracerTests : VirtualMachineTestsBase { [Test] @@ -68,5 +69,8 @@ public void Records_get_correct_accessed_keys() _processor.Execute(transaction, block.Header, tracer); return (tracer, block, transaction); } + public AccessTxTracerTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxTracerTests.cs index 1d48296fade..3c74759b5e5 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/GethLikeTxTracerTests.cs @@ -13,6 +13,8 @@ namespace Nethermind.Evm.Test.Tracing { [TestFixture] [Parallelizable(ParallelScope.Self)] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class GethLikeTxTracerTests : VirtualMachineTestsBase { [Test] @@ -373,5 +375,8 @@ public void Can_trace_memory() Assert.AreEqual(SampleHexData1.PadLeft(64, '0'), trace.Entries[6].Memory[0], "entry[6][0]"); Assert.AreEqual(SampleHexData2.PadLeft(64, '0'), trace.Entries[6].Memory[1], "entry[6][1]"); } + public GethLikeTxTracerTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs index a507a7f1fa1..bb40cef3482 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ParityLikeTxTracerTests.cs @@ -16,7 +16,8 @@ namespace Nethermind.Evm.Test.Tracing { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class ParityLikeTxTracerTests : VirtualMachineTestsBase { [Test] @@ -180,14 +181,10 @@ public void Action_input_is_set() [Test] public void Action_value_is_set() { - byte[] code = Prepare.EvmCode - .PushData(SampleHexData1) - .Done; - - byte[] input = Bytes.FromHexString(SampleHexData2); + byte[] input = Bytes.FromHexString("0xf66000603a55fe7f71d2cd8574f77ac1416d9809fdb706b0993ca14719aea4af2791bfe60a5f6b2c6040527f18d12bfc602492b3bb48802356dc8744afade08d17777ab745be005aae2021286060527f46270cafa421d1e9c7e7237fdd348252ca0b8d7ba185bf6c1a1e0eaab4619e3d6080527f676c98d6bb8a61a243f04ad3"); UInt256 value = 1.Ether(); - (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(input, value, code); + (ParityLikeTxTrace trace, Block block, Transaction tx) = ExecuteAndTraceParityCall(input, value, Array.Empty()); Assert.AreEqual(value, trace.Action.Value); } @@ -855,5 +852,8 @@ public void Is_tracing_rewards_only_when_rewards_trace_type_selected() _processor.Execute(transaction, block.Header, tracer); return (tracer.BuildResult(), block, transaction); } + public ParityLikeTxTracerTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } } } diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs index dbf6cc2c6b5..bec961d4a41 100644 --- a/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/ProofTxTracerTests.cs @@ -9,14 +9,16 @@ namespace Nethermind.Evm.Test.Tracing { - [TestFixture(true)] - [TestFixture(false)] + [TestFixture(true, VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(true, VirtualMachineTestsStateProvider.VerkleTrie)] + [TestFixture(false, VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(false, VirtualMachineTestsStateProvider.VerkleTrie)] [Parallelizable(ParallelScope.Self)] public class ProofTxTracerTests : VirtualMachineTestsBase { private readonly bool _treatSystemAccountDifferently; - public ProofTxTracerTests(bool treatSystemAccountDifferently) + public ProofTxTracerTests(bool treatSystemAccountDifferently, VirtualMachineTestsStateProvider stateProviderType): base(stateProviderType) { _treatSystemAccountDifferently = treatSystemAccountDifferently; } diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs index 6d7fd13e8bb..ca0c21ec4c2 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTests.cs @@ -14,8 +14,13 @@ namespace Nethermind.Evm.Test { [TestFixture] [Parallelizable(ParallelScope.Self)] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class VirtualMachineTests : VirtualMachineTestsBase { + public VirtualMachineTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } [Test] public void Stop() { diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs index 871ff1039b4..f48a56aa154 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs @@ -18,12 +18,21 @@ using Nethermind.Logging; using Nethermind.State; using Nethermind.Trie.Pruning; +using Nethermind.Verkle; using NUnit.Framework; namespace Nethermind.Evm.Test { public class VirtualMachineTestsBase { + protected readonly VirtualMachineTestsStateProvider _stateProvider; + + public enum VirtualMachineTestsStateProvider + { + MerkleTrie, + VerkleTrie + } + protected const string SampleHexData1 = "a01234"; protected const string SampleHexData2 = "b15678"; protected const string HexZero = "00"; @@ -31,7 +40,6 @@ public class VirtualMachineTestsBase private IEthereumEcdsa _ethereumEcdsa; protected ITransactionProcessor _processor; - private IDb _stateDb; protected VirtualMachine Machine { get; private set; } protected IWorldState WorldState { get; private set; } @@ -55,14 +63,28 @@ protected virtual ILogManager GetLogManager() return LimboLogs.Instance; } + public VirtualMachineTestsBase(VirtualMachineTestsStateProvider stateProvider) + { + _stateProvider = stateProvider; + } + [SetUp] public virtual void Setup() { ILogManager logManager = GetLogManager(); IDb codeDb = new MemDb(); - _stateDb = new MemDb(); - WorldState = new WorldState(new TrieStore(_stateDb, logManager), codeDb, logManager); + MemDb stateDb = new MemDb(); + if (_stateProvider == VirtualMachineTestsStateProvider.MerkleTrie) + { + WorldState = new WorldState(new TrieStore(stateDb, logManager), codeDb, logManager); + } + else + { + IDbProvider provider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + WorldState = new VerkleWorldState(new VerkleStateTree(provider), codeDb, logManager); + } + _ethereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, logManager); IBlockhashProvider blockhashProvider = TestBlockhashProvider.Instance; Machine = new VirtualMachine(blockhashProvider, SpecProvider, logManager); diff --git a/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs b/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs index 4b9747b7c85..40136fee603 100644 --- a/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs +++ b/src/Nethermind/Nethermind.Evm.Test/VmCodeDepositTests.cs @@ -13,8 +13,14 @@ namespace Nethermind.Evm.Test { [TestFixture] [Parallelizable(ParallelScope.Self)] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class VmCodeDepositTests : VirtualMachineTestsBase { + public VmCodeDepositTests(VirtualMachineTestsStateProvider stateProvider) : base(stateProvider) + { + } + private long _blockNumber = MainnetSpecProvider.ByzantiumBlockNumber; protected override long BlockNumber => _blockNumber; diff --git a/src/Nethermind/Nethermind.Evm/EvmState.cs b/src/Nethermind/Nethermind.Evm/EvmState.cs index ee3f2b67269..704b6ea795d 100644 --- a/src/Nethermind/Nethermind.Evm/EvmState.cs +++ b/src/Nethermind/Nethermind.Evm/EvmState.cs @@ -157,8 +157,7 @@ public EvmState( false, null, isContinuation, - false, - new VerkleWitness()) + false) { GasAvailable = gasAvailable; Env = env; @@ -182,8 +181,7 @@ public EvmState( false, null, isContinuation, - false, - verkleWitness) + false) { GasAvailable = gasAvailable; Env = env; @@ -200,35 +198,7 @@ internal EvmState( bool isStatic, EvmState? stateForAccessLists, bool isContinuation, - bool isCreateOnPreExistingAccount) : - this(gasAvailable, - env, - executionType, - isTopLevel, - snapshot, - outputDestination, - outputLength, - isStatic, - stateForAccessLists, - isContinuation, - isCreateOnPreExistingAccount, - new VerkleWitness() - ) - { } - - internal EvmState( - long gasAvailable, - ExecutionEnvironment env, - ExecutionType executionType, - bool isTopLevel, - Snapshot snapshot, - long outputDestination, - long outputLength, - bool isStatic, - EvmState? stateForAccessLists, - bool isContinuation, - bool isCreateOnPreExistingAccount, - IVerkleWitness verkleWitness) + bool isCreateOnPreExistingAccount) { if (isTopLevel && isContinuation) { @@ -246,7 +216,6 @@ internal EvmState( IsStatic = isStatic; IsContinuation = isContinuation; IsCreateOnPreExistingAccount = isCreateOnPreExistingAccount; - _verkleWitness = verkleWitness; if (stateForAccessLists is not null) { // if we are sub-call, then we use the main collection for this transaction @@ -263,7 +232,7 @@ internal EvmState( _accessedStorageCells = new JournalSet(); _destroyList = new JournalSet
(); _logs = new JournalCollection(); - _verkleWitness = new VerkleWitness(); + _verkleWitness = env.VerkleWitness; } _accessedAddressesSnapshot = _accessedAddresses.TakeSnapshot(); diff --git a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs index 59406ddacf9..085c3258acc 100644 --- a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs +++ b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs @@ -52,6 +52,11 @@ public struct ExecutionEnvironment /// public CodeInfo CodeInfo { get; set; } + /// + /// Parsed bytecode for the current call. + /// + public IVerkleWitness VerkleWitness { get; set; } + /// If we call TX -> DELEGATECALL -> CALL -> STATICCALL then the call depth would be 3. public int CallDepth { get; set; } } diff --git a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs index fa8a2f58e85..a8aa9c9ab9f 100644 --- a/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs +++ b/src/Nethermind/Nethermind.Evm/TransactionProcessing/TransactionProcessor.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Linq; +using Microsoft.IdentityModel.Tokens; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Specs; @@ -14,7 +15,6 @@ using Nethermind.Logging; using Nethermind.Specs; using Nethermind.State; -using Nethermind.Trie.Pruning; using Transaction = Nethermind.Core.Transaction; namespace Nethermind.Evm.TransactionProcessing @@ -123,12 +123,13 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra // restore is CallAndRestore - previous call, we will restore state after the execution bool restore = (executionOptions & ExecutionOptions.Restore) == ExecutionOptions.Restore; bool noValidation = (executionOptions & ExecutionOptions.NoValidation) == ExecutionOptions.NoValidation; - // commit - is for standard execute, we will commit thee state after execution + // commit - is for standard execute, we will commit the state after execution bool commit = (executionOptions & ExecutionOptions.Commit) == ExecutionOptions.Commit || eip658NotEnabled; - //!commit - is for build up during block production, we won't commit state after each transaction to support rollbacks - //we commit only after all block is constructed + // !commit - is for build up during block production, we won't commit state after each transaction to support rollbacks + // we commit only after all block is constructed bool notSystemTransaction = !transaction.IsSystem(); bool deleteCallerAccount = false; + VerkleWitness witness = new VerkleWitness(); if (!notSystemTransaction) { @@ -152,7 +153,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra byte[] data = transaction.IsMessageCall ? transaction.Data : Array.Empty(); Address? caller = transaction.SenderAddress; - if (_logger.IsTrace) _logger.Trace($"Executing tx {transaction.Hash}"); + _logger.Info($"Executing tx {transaction.Hash}"); if (caller is null) { @@ -161,6 +162,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra return; } + // TODO: do we need to check Intrinsic Gas before this? if (!noValidation && _worldState.IsInvalidContractSender(spec, caller)) { TraceLogInvalidTx(transaction, "SENDER_IS_CONTRACT"); @@ -188,7 +190,9 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra } long intrinsicGas = IntrinsicGasCalculator.Calculate(transaction, spec); - if (_logger.IsTrace) _logger.Trace($"Intrinsic gas calculated for {transaction.Hash}: " + intrinsicGas); + _logger.Info($"Intrinsic gas calculated for {transaction.Hash}: {intrinsicGas}"); + if (spec.IsVerkleTreeEipEnabled) intrinsicGas += witness.AccessForTransaction(caller, transaction.To!, !transaction.Value.IsZero); + _logger.Info($"Intrinsic gas calculated for {transaction.Hash}: {intrinsicGas}"); if (notSystemTransaction) { @@ -218,8 +222,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra if (caller != transaction.SenderAddress) { - if (_logger.IsWarn) - _logger.Warn( + _logger.Info( $"TX recovery issue fixed - tx was coming with sender {caller} and the now it recovers to {transaction.SenderAddress}"); caller = transaction.SenderAddress; } @@ -228,7 +231,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra TraceLogInvalidTx(transaction, $"SENDER_ACCOUNT_DOES_NOT_EXIST {caller}"); if (!commit || noValidation || effectiveGasPrice == UInt256.Zero) { - deleteCallerAccount = !commit || restore; + deleteCallerAccount = (!commit || restore) && !spec.IsVerkleTreeEipEnabled; _worldState.CreateAccount(caller, UInt256.Zero); } } @@ -297,34 +300,42 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra if (transaction.IsContractCreation) { // if transaction is a contract creation then recipient address is the contract deployment address - Address contractAddress = recipient; - PrepareAccountForContractDeployment(contractAddress!, spec); - } + if (spec.IsVerkleTreeEipEnabled) + { + long gasContractCreationInit = witness.AccessForContractCreationInit(recipient, !transaction.Value.IsZero); + if (unspentGas < gasContractCreationInit) + { + TraceLogInvalidTx(transaction, + $"INSUFFICIENT_GAS: UNSPENT_GAS = {unspentGas}"); + QuickFail(transaction, block, txTracer, eip658NotEnabled, "insufficient unspent gas"); + return; + } + unspentGas -= gasContractCreationInit; + } - if (recipient is null) - { - // this transaction is not a contract creation so it should have the recipient known and not null - throw new InvalidDataException("Recipient has not been resolved properly before tx execution"); + PrepareAccountForContractDeployment(recipient!, spec); } - recipientOrNull = recipient; + recipientOrNull = recipient ?? throw new InvalidDataException("Recipient has not been resolved properly before tx execution"); - ExecutionEnvironment env = new(); - env.TxExecutionContext = new TxExecutionContext(block, caller, effectiveGasPrice); - env.Value = value; - env.TransferValue = value; - env.Caller = caller; - env.CodeSource = recipient; - env.ExecutingAccount = recipient; - env.InputData = data ?? Array.Empty(); - env.CodeInfo = machineCode is null - ? _virtualMachine.GetCachedCodeInfo(_worldState, recipient, spec) - : new CodeInfo(machineCode); + ExecutionEnvironment env = new ExecutionEnvironment + { + TxExecutionContext = new TxExecutionContext(block, caller, effectiveGasPrice), + Value = value, + TransferValue = value, + Caller = caller, + CodeSource = recipient, + ExecutingAccount = recipient, + InputData = data ?? Array.Empty(), + CodeInfo = machineCode is null + ? _virtualMachine.GetCachedCodeInfo(_worldState, recipient, spec) + : new CodeInfo(machineCode), + VerkleWitness = witness + }; ExecutionType executionType = transaction.IsContractCreation ? ExecutionType.Create : ExecutionType.Transaction; - using (EvmState state = - new(unspentGas, env, executionType, true, snapshot, false)) + using (EvmState state = new EvmState(unspentGas, env, executionType, true, snapshot, false)) { if (spec.UseTxAccessLists) { @@ -344,6 +355,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra substate = _virtualMachine.Run(state, _worldState, txTracer); unspentGas = state.GasAvailable; + _logger.Info($"Gas unspent Run: {unspentGas}"); if (txTracer.IsTracingAccess) { @@ -353,7 +365,7 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra if (substate.ShouldRevert || substate.IsError) { - if (_logger.IsTrace) _logger.Trace("Restoring state from before transaction"); + _logger.Info("Restoring state from before transaction"); _worldState.Restore(snapshot); } else @@ -378,11 +390,19 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra _worldState.InsertCode(recipient, substate.Output, spec); unspentGas -= codeDepositGasCost; } + // TODO: when contract creation completed - AccessContractCreated + if (spec.IsVerkleTreeEipEnabled) + { + unspentGas -= witness.AccessContractCreated(recipient); + } } + if (spec.IsVerkleTreeEipEnabled && !substate.DestroyList.IsNullOrEmpty()) + throw new NotSupportedException("DestroyList should be empty for Verkle Trees"); + foreach (Address toBeDestroyed in substate.DestroyList) { - if (_logger.IsTrace) _logger.Trace($"Destroying account {toBeDestroyed}"); + _logger.Info($"Destroying account {toBeDestroyed}"); _worldState.ClearStorage(toBeDestroyed); _worldState.DeleteAccount(toBeDestroyed); if (txTracer.IsTracingRefunds) txTracer.ReportRefund(RefundOf.Destroy(spec.IsEip3529Enabled)); @@ -391,16 +411,18 @@ private void Execute(Transaction transaction, BlockHeader block, ITxTracer txTra statusCode = StatusCode.Success; } + + _logger.Info($"Gas unspent Run: {unspentGas}"); spentGas = Refund(gasLimit, unspentGas, substate, caller, effectiveGasPrice, spec); } catch (Exception ex) when ( ex is EvmException || ex is OverflowException) // TODO: OverflowException? still needed? hope not { - if (_logger.IsTrace) _logger.Trace($"EVM EXCEPTION: {ex.GetType().Name}"); + _logger.Info($"EVM EXCEPTION: {ex.GetType().Name}"); _worldState.Restore(snapshot); } - if (_logger.IsTrace) _logger.Trace("Gas spent: " + spentGas); + _logger.Info($"Gas spent: {spentGas}"); Address gasBeneficiary = block.GasBeneficiary; bool gasBeneficiaryNotDestroyed = substate?.DestroyList.Contains(gasBeneficiary) != true; @@ -505,22 +527,19 @@ private void PrepareAccountForContractDeployment(Address contractAddress, IRelea // (but this would generally be a hash collision) if (codeIsNotEmpty || accountNonceIsNotZero) { - if (_logger.IsTrace) - { - _logger.Trace($"Contract collision at {contractAddress}"); - } + _logger.Info($"Contract collision at {contractAddress}"); - throw new TransactionCollisionException(); + throw new TransactionCollisionException(); } // we clean any existing storage (in case of a previously called self destruct) - _worldState.UpdateStorageRoot(contractAddress, Keccak.EmptyTreeHash); + // _worldState.UpdateStorageRoot(contractAddress, Keccak.EmptyTreeHash); } } private void TraceLogInvalidTx(Transaction transaction, string reason) { - if (_logger.IsTrace) _logger.Trace($"Invalid tx {transaction.Hash} ({reason})"); + _logger.Info($"Invalid tx {transaction.Hash} ({reason})"); } private long Refund(long gasLimit, long unspentGas, TransactionSubstate substate, Address sender, @@ -535,8 +554,7 @@ private long Refund(long gasLimit, long unspentGas, TransactionSubstate substate : RefundHelper.CalculateClaimableRefund(spentGas, substate.Refund + substate.DestroyList.Count * RefundOf.Destroy(spec.IsEip3529Enabled), spec); - if (_logger.IsTrace) - _logger.Trace("Refunding unused gas of " + unspentGas + " and refund of " + refund); + _logger.Info($"Refunding unused gas of {unspentGas} and refund of {refund}"); _worldState.AddToBalance(sender, (ulong)(unspentGas + refund) * gasPrice, spec); spentGas -= refund; } diff --git a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs index fcf3435ac27..991f7ebe9ce 100644 --- a/src/Nethermind/Nethermind.Evm/VirtualMachine.cs +++ b/src/Nethermind/Nethermind.Evm/VirtualMachine.cs @@ -6,6 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using FastEnumUtility; using Nethermind.Core; using Nethermind.Core.Caching; using Nethermind.Core.Crypto; @@ -252,7 +253,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer { currentState.GasAvailable -= gasAvailableForCodeDeposit; worldState.Restore(previousState.Snapshot); - if (!previousState.IsCreateOnPreExistingAccount) + if (!previousState.IsCreateOnPreExistingAccount && _worldState is WorldState) { _worldState.DeleteAccount(callCodeOwner); } @@ -315,7 +316,7 @@ public TransactionSubstate Run(EvmState state, IWorldState worldState, ITxTracer } catch (Exception ex) when (ex is EvmException or OverflowException) { - if (_logger.IsTrace) _logger.Trace($"exception ({ex.GetType().Name}) in {currentState.ExecutionType} at depth {currentState.Env.CallDepth} - restoring snapshot"); + _logger.Info($"exception ({ex.GetType().Name}) in {currentState.ExecutionType} at depth {currentState.Env.CallDepth} - restoring snapshot"); _worldState.Restore(currentState.Snapshot); @@ -448,29 +449,75 @@ private static void UpdateGasUp(long refund, ref long gasAvailable) gasAvailable += refund; } - private bool ChargeAccountAccessGas(ref long gasAvailable, EvmState vmState, Address address, IReleaseSpec spec, bool chargeForWarm = true) + private bool ChargeAccountAccessGas(ref long gasAvailable, EvmState vmState, Address address, IReleaseSpec spec, bool chargeForWarm = true, bool valueTransfer = false, Instruction opCode = Instruction.STOP) { - // Console.WriteLine($"Accessing {address}"); - + _logger.Info($"GasAvailable: {gasAvailable} Instruction: {opCode.ToName()}"); bool result = true; - if (spec.UseHotAndColdStorage) + if (spec.IsVerkleTreeEipEnabled) { - if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list + bool isAddressPreCompile = address.IsPrecompile(spec); + switch (opCode) { - vmState.WarmUp(address); - } + case Instruction.BALANCE: + { + result = UpdateGas(vmState.VerkleTreeWitness.AccessBalance(address), ref gasAvailable); + break; + } + case Instruction.EXTCODESIZE: + case Instruction.EXTCODECOPY: + case Instruction.SELFDESTRUCT: + case Instruction.CALL: + case Instruction.CALLCODE: + case Instruction.DELEGATECALL: + case Instruction.STATICCALL: + { + if (!isAddressPreCompile) + { + result = UpdateGas(vmState.VerkleTreeWitness.AccessForCodeOpCodes(address), ref gasAvailable); + if (!result) + { + break; + } + } - if (vmState.IsCold(address) && !address.IsPrecompile(spec)) - { - result = UpdateGas(GasCostOf.ColdAccountAccess, ref gasAvailable); - vmState.WarmUp(address); - } - else if (chargeForWarm) - { - result = UpdateGas(GasCostOf.WarmStateRead, ref gasAvailable); + if (valueTransfer) + { + result = UpdateGas( + vmState.VerkleTreeWitness.AccessBalance(address), ref gasAvailable); + } + break; + } + case Instruction.EXTCODEHASH: + { + result = UpdateGas( + vmState.VerkleTreeWitness.AccessCodeHash(address), ref gasAvailable); + break; + } + default: + { + throw new ArgumentOutOfRangeException(nameof(opCode), opCode, null); + } } + _logger.Info($"GasNowAvailable: {gasAvailable} Instruction: {opCode.ToName()}"); + return result; } + if (!spec.UseHotAndColdStorage) return true; + if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list + { + vmState.WarmUp(address); + } + + + if (vmState.IsCold(address) && !address.IsPrecompile(spec)) + { + result = UpdateGas(GasCostOf.ColdAccountAccess, ref gasAvailable); + vmState.WarmUp(address); + } + else if (chargeForWarm) + { + result = UpdateGas(GasCostOf.WarmStateRead, ref gasAvailable); + } return result; } @@ -487,26 +534,30 @@ private bool ChargeStorageAccessGas( StorageAccessType storageAccessType, IReleaseSpec spec) { - // Console.WriteLine($"Accessing {storageCell} {storageAccessType}"); + _logger.Info($"Accessing {storageCell} {storageAccessType}"); bool result = true; - if (spec.UseHotAndColdStorage) + if (spec.IsVerkleTreeEipEnabled) { - if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list - { - vmState.WarmUp(storageCell); - } + if (!UpdateGas( + vmState.VerkleTreeWitness.AccessStorage(storageCell.Address, storageCell.Index, + storageAccessType == StorageAccessType.SSTORE), ref gasAvailable)) return false; + } + if (!spec.UseHotAndColdStorage) return true; + if (_txTracer.IsTracingAccess) // when tracing access we want cost as if it was warmed up from access list + { + vmState.WarmUp(storageCell); + } - if (vmState.IsCold(storageCell)) - { - result = UpdateGas(GasCostOf.ColdSLoad, ref gasAvailable); - vmState.WarmUp(storageCell); - } - else if (storageAccessType == StorageAccessType.SLOAD) - { - // we do not charge for WARM_STORAGE_READ_COST in SSTORE scenario - result = UpdateGas(GasCostOf.WarmStateRead, ref gasAvailable); - } + if (vmState.IsCold(storageCell)) + { + result = UpdateGas(GasCostOf.ColdSLoad, ref gasAvailable); + vmState.WarmUp(storageCell); + } + else if (storageAccessType == StorageAccessType.SLOAD) + { + // we do not charge for WARM_STORAGE_READ_COST in SSTORE scenario + result = UpdateGas(GasCostOf.WarmStateRead, ref gasAvailable); } return result; @@ -572,7 +623,7 @@ private CallResult ExecutePrecompile(EvmState state, IReleaseSpec spec) } catch (Exception exception) { - if (_logger.IsDebug) _logger.Error($"Precompiled contract ({precompile.GetType()}) execution exception", exception); + _logger.Error($"Precompiled contract ({precompile.GetType()}) execution exception", exception); CallResult callResult = new(Array.Empty(), false, true); return callResult; } @@ -585,11 +636,31 @@ private CallResult ExecuteCall(EvmState vmState, byte[]? previousCallResult, Zer bool traceOpcodes = _txTracer.IsTracingInstructions; ExecutionEnvironment env = vmState.Env; TxExecutionContext txCtx = env.TxExecutionContext; + vmState.InitStacks(); + EvmStack stack = new EvmStack(vmState.DataStack.AsSpan(), vmState.DataStackHead, _txTracer); + long gasAvailable = vmState.GasAvailable; + int programCounter = vmState.ProgramCounter; + Span code = env.CodeInfo.MachineCode.AsSpan(); if (!vmState.IsContinuation) { if (!_worldState.AccountExists(env.ExecutingAccount)) { + // TODO: completely and definitely wrong - just to be similar to geth + if (spec.IsVerkleTreeEipEnabled && vmState.ExecutionType == ExecutionType.Transaction) + { + _logger.Info($"Transfer Value {env.TransferValue} {env.TransferValue.IsZero}"); + if (env.TransferValue.IsZero) + { + long gasProofOfAbsence = vmState.VerkleTreeWitness.AccessForProofOfAbsence(env.Caller); + _logger.Info($"Gas Proof of Absence {gasProofOfAbsence}"); + if (!UpdateGas(gasProofOfAbsence, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + } _worldState.CreateAccount(env.ExecutingAccount, env.TransferValue); } else @@ -605,15 +676,10 @@ private CallResult ExecuteCall(EvmState vmState, byte[]? previousCallResult, Zer if (vmState.Env.CodeInfo.MachineCode.Length == 0) { + UpdateCurrentState(vmState, programCounter, gasAvailable, stack.Head); return CallResult.Empty; } - vmState.InitStacks(); - EvmStack stack = new(vmState.DataStack.AsSpan(), vmState.DataStackHead, _txTracer); - long gasAvailable = vmState.GasAvailable; - int programCounter = vmState.ProgramCounter; - Span code = env.CodeInfo.MachineCode.AsSpan(); - static void UpdateCurrentState(EvmState state, in int pc, in long gas, in int stackHead) { @@ -721,10 +787,46 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) // if(_txTracer.IsTracingInstructions) _txTracer.ReportMemoryChange((long)localPreviousDest, previousCallOutput); } + byte CalculateChunkIdFromPc(int pc) + { + int chunkId = pc / 31; + _logger.Info($"Counter: {pc} ChunkID: {chunkId}"); + return (byte)chunkId; + } + + // byte CalculateChunkIdFrom256(UInt256 pc) + // { + // UInt256 chunkId = pc / 31; + // _logger.Info($"Counter: {pc} ChunkID: {chunkId}"); + // return (byte)chunkId; + // } + + + + + _logger.Info($"Code: {code.ToHexString()}"); while (programCounter < code.Length) { + + _logger.Info($"Gas Available Current: {gasAvailable}"); + if (spec.IsVerkleTreeEipEnabled) + { + if (vmState.ExecutionType is ExecutionType.Create or ExecutionType.Create2) + { + _logger.Info("Dont Charge Witness Cost in Create or Create2 InitCode"); + } + else + { + long gas = vmState.VerkleTreeWitness.AccessCodeChunk(vmState.To, CalculateChunkIdFromPc(programCounter), false); + if (!UpdateGas(gas, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + } Instruction instruction = (Instruction)code[programCounter]; - // Console.WriteLine(instruction); + _logger.Info($"Instruction: {instruction.ToName()}"); if (traceOpcodes) { StartInstructionTrace(instruction, stack); @@ -1317,7 +1419,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) } Address address = stack.PopAddress(); - if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) + if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec, opCode: instruction)) { EndInstructionTraceError(EvmExceptionType.OutOfGas); return CallResult.OutOfGasException; @@ -1441,6 +1543,27 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) ZeroPaddedSpan codeSlice = code.SliceWithZeroPadding(src, (int)length); vmState.Memory.Save(in dest, codeSlice); if (_txTracer.IsTracingInstructions) _txTracer.ReportMemoryChange((long)dest, codeSlice); + + if (spec.IsVerkleTreeEipEnabled) + { + // TODO: modify - add the chunk that gets jumped when PUSH32 is called. + if (src > length) + { + src = length; + } + var startChunkId = CalculateChunkIdFromPc((int)src); + var endChunkId = CalculateChunkIdFromPc((int)src + codeSlice.Length); + + for (byte ch= startChunkId; ch <= endChunkId; ch++) + { + long gas = vmState.VerkleTreeWitness.AccessCodeChunk(vmState.To, ch, false); + if (!UpdateGas(gas, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + } } break; @@ -1467,7 +1590,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) } Address address = stack.PopAddress(); - if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) + if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec, opCode: instruction)) { EndInstructionTraceError(EvmExceptionType.OutOfGas); return CallResult.OutOfGasException; @@ -1493,7 +1616,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) return CallResult.OutOfGasException; } - if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) + if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec, opCode: instruction)) { EndInstructionTraceError(EvmExceptionType.OutOfGas); return CallResult.OutOfGasException; @@ -1510,8 +1633,28 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) { _txTracer.ReportMemoryChange((long)dest, callDataSlice); } - } + if (spec.IsVerkleTreeEipEnabled) + { + // TODO: modify - add the chunk that gets jumped when PUSH32 is called. + if (src > length) + { + src = length; + } + var startChunkId = CalculateChunkIdFromPc((int)src); + var endChunkId = CalculateChunkIdFromPc((int)src + callDataSlice.Length); + + for (byte ch= startChunkId; ch <= endChunkId; ch++) + { + long gas = vmState.VerkleTreeWitness.AccessCodeChunk(address, ch, false); + if (!UpdateGas(gas, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + } + } break; } case Instruction.RETURNDATASIZE: @@ -1846,7 +1989,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) newValue = new byte[] { 0 }; } - StorageCell storageCell = new(env.ExecutingAccount, storageIndex); + StorageCell storageCell = new StorageCell(env.ExecutingAccount, storageIndex); if (!ChargeStorageAccessGas( ref gasAvailable, @@ -1860,7 +2003,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) } Span currentValue = _worldState.Get(storageCell); - // Console.WriteLine($"current: {currentValue.ToHexString()} newValue {newValue.ToHexString()}"); + Console.WriteLine($"current: {currentValue.ToHexString()} newValue {newValue.ToHexString()}"); bool currentIsZero = currentValue.IsZero(); bool newSameAsCurrent = (newIsZero && currentIsZero) || Bytes.AreEqual(currentValue, newValue); @@ -1899,10 +2042,22 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) { Span originalValue = _worldState.GetOriginal(storageCell); bool originalIsZero = originalValue.IsZero(); + _logger.Info($"{EnumerableExtensions.ToString(originalValue.ToArray())}"); + _logger.Info($"{EnumerableExtensions.ToString(currentValue.ToArray())}"); + _logger.Info($"{originalIsZero}"); + _logger.Info($"{currentIsZero}"); - bool currentSameAsOriginal = Bytes.AreEqual(originalValue, currentValue); + bool currentSameAsOriginal = originalValue.WithoutLeadingZeros().SequenceEqual(currentValue.WithoutLeadingZeros()); + if (originalValue.Length == 0 && currentIsZero) + { + currentSameAsOriginal = true; + } + _logger.Info($"{currentSameAsOriginal}"); if (currentSameAsOriginal) { + _logger.Info("currentSameAsOriginal"); + _logger.Info($"{originalIsZero}"); + _logger.Info($"{currentIsZero}"); if (currentIsZero) { if (!UpdateGas(GasCostOf.SSet, ref gasAvailable)) @@ -2177,6 +2332,17 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) } programCounter++; + + if (spec.IsVerkleTreeEipEnabled && programCounterInt % 31 == 0) + { + // TODO: modify - add the chunk that gets jumped when PUSH32 is called. + long gas = vmState.VerkleTreeWitness.AccessCodeChunk(vmState.To, CalculateChunkIdFromPc(programCounter), false); + if (!UpdateGas(gas, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } break; } case Instruction.PUSH2: @@ -2224,6 +2390,23 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) stack.PushLeftPaddedBytes(code.Slice(programCounterInt, usedFromCode), length); programCounter += length; + + if (spec.IsVerkleTreeEipEnabled) + { + // TODO: modify - add the chunk that gets jumped when PUSH32 is called. + var startChunkId = CalculateChunkIdFromPc(programCounterInt + 1); + var endChunkId = CalculateChunkIdFromPc(programCounterInt + usedFromCode); + + for (byte ch= startChunkId; ch <= endChunkId; ch++) + { + long gas = vmState.VerkleTreeWitness.AccessCodeChunk(vmState.To, ch, false); + if (!UpdateGas(gas, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + } break; } case Instruction.DUP1: @@ -2357,8 +2540,8 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) } long gasCost = GasCostOf.Create + - (spec.IsEip3860Enabled ? GasCostOf.InitCodeWord * EvmPooledMemory.Div32Ceiling(initCodeLength) : 0) + - (instruction == Instruction.CREATE2 ? GasCostOf.Sha3Word * EvmPooledMemory.Div32Ceiling(initCodeLength) : 0); + (spec.IsEip3860Enabled ? GasCostOf.InitCodeWord * EvmPooledMemory.Div32Ceiling(initCodeLength) : 0) + + (instruction == Instruction.CREATE2 ? GasCostOf.Sha3Word * EvmPooledMemory.Div32Ceiling(initCodeLength) : 0); if (!UpdateGas(gasCost, ref gasAvailable)) { @@ -2366,6 +2549,8 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) return CallResult.OutOfGasException; } + + UpdateMemoryCost(in memoryPositionOfInitCode, initCodeLength); // TODO: copy pasted from CALL / DELEGATECALL, need to move it outside? @@ -2410,6 +2595,17 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) ? ContractAddress.From(env.ExecutingAccount, _worldState.GetNonce(env.ExecutingAccount)) : ContractAddress.From(env.ExecutingAccount, salt, initCode); + if (spec.IsVerkleTreeEipEnabled) + { + long gasWitness = vmState.VerkleTreeWitness.AccessForContractCreationInit(contractAddress, !vmState.Env.Value.IsZero); + if (!UpdateGas(gasWitness, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + + if (spec.UseHotAndColdStorage) { // EIP-2929 assumes that warm-up cost is included in the costs of CREATE and CREATE2 @@ -2424,19 +2620,22 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) if (accountExists && (GetCachedCodeInfo(_worldState, contractAddress, spec).MachineCode.Length != 0 || _worldState.GetNonce(contractAddress) != 0)) { /* we get the snapshot before this as there is a possibility with that we will touch an empty account and remove it even if the REVERT operation follows */ - if (isTrace) _logger.Trace($"Contract collision at {contractAddress}"); + _logger.Info($"Contract collision at {contractAddress}"); _returnDataBuffer = Array.Empty(); stack.PushZero(); break; } - if (accountExists) - { - _worldState.UpdateStorageRoot(contractAddress, Keccak.EmptyTreeHash); - } - else if (_worldState.IsDeadAccount(contractAddress)) + if (_worldState is WorldState) { - _worldState.ClearStorage(contractAddress); + if (accountExists) + { + _worldState.UpdateStorageRoot(contractAddress, Keccak.EmptyTreeHash); + } + else if (_worldState.IsDeadAccount(contractAddress)) + { + _worldState.ClearStorage(contractAddress); + } } _worldState.SubtractFromBalance(env.ExecutingAccount, value, spec); @@ -2464,6 +2663,17 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) false, accountExists); + // TODO - modify - when create finishes - call the AccessContractCreated + if (spec.IsVerkleTreeEipEnabled) + { + long gasWitness = vmState.VerkleTreeWitness.AccessContractCreated(contractAddress); + if (!UpdateGas(gasWitness, ref gasAvailable)) + { + EndInstructionTraceError(EvmExceptionType.OutOfGas); + return CallResult.OutOfGasException; + } + } + UpdateCurrentState(vmState, programCounter, gasAvailable, stack.Head); return new CallResult(callState); } @@ -2497,7 +2707,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) Address codeSource = stack.PopAddress(); // Console.WriteLine($"CALLIN {codeSource}"); - if (!ChargeAccountAccessGas(ref gasAvailable, vmState, codeSource, spec)) + if (!ChargeAccountAccessGas(ref gasAvailable, vmState, codeSource, spec, opCode: instruction)) { EndInstructionTraceError(EvmExceptionType.OutOfGas); return CallResult.OutOfGasException; @@ -2532,14 +2742,11 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) Address caller = instruction == Instruction.DELEGATECALL ? env.Caller : env.ExecutingAccount; Address target = instruction == Instruction.CALL || instruction == Instruction.STATICCALL ? codeSource : env.ExecutingAccount; - if (isTrace) - { - _logger.Trace($"caller {caller}"); - _logger.Trace($"code source {codeSource}"); - _logger.Trace($"target {target}"); - _logger.Trace($"value {callValue}"); - _logger.Trace($"transfer value {transferValue}"); - } + _logger.Info($"caller {caller}"); + _logger.Info($"code source {codeSource}"); + _logger.Info($"target {target}"); + _logger.Info($"value {callValue}"); + _logger.Info($"transfer value {transferValue}"); long gasExtra = 0L; @@ -2601,7 +2808,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) _txTracer.ReportMemoryChange(dataOffset, memoryTrace.Span); } - if (isTrace) _logger.Trace("FAIL - call depth"); + _logger.Info("FAIL - call depth"); if (_txTracer.IsTracingInstructions) _txTracer.ReportOperationRemainingGas(gasAvailable); if (_txTracer.IsTracingInstructions) _txTracer.ReportOperationError(EvmExceptionType.NotEnoughBalance); @@ -2626,7 +2833,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) callEnv.InputData = callData; callEnv.CodeInfo = GetCachedCodeInfo(_worldState, codeSource, spec); - if (isTrace) _logger.Trace($"Tx call gas {gasLimitUl}"); + _logger.Info($"Tx call gas {gasLimitUl}"); if (outputLength == 0) { // TODO: when output length is 0 outputOffset can have any value really @@ -2698,13 +2905,15 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) Metrics.SelfDestructs++; Address inheritor = stack.PopAddress(); - if (!ChargeAccountAccessGas(ref gasAvailable, vmState, inheritor, spec, false)) + if (!ChargeAccountAccessGas(ref gasAvailable, vmState, inheritor, spec, false, opCode: instruction)) { EndInstructionTraceError(EvmExceptionType.OutOfGas); return CallResult.OutOfGasException; } - vmState.DestroyList.Add(env.ExecutingAccount); + // TODO: replace this by EIP-4758 + if(!spec.IsVerkleTreeEipEnabled) + vmState.DestroyList.Add(env.ExecutingAccount); UInt256 ownerBalance = _worldState.GetBalance(env.ExecutingAccount); if (_txTracer.IsTracingActions) _txTracer.ReportSelfDestruct(env.ExecutingAccount, ownerBalance, inheritor); @@ -2852,7 +3061,7 @@ void UpdateMemoryCost(in UInt256 position, in UInt256 length) } Address address = stack.PopAddress(); - if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec)) + if (!ChargeAccountAccessGas(ref gasAvailable, vmState, address, spec, opCode: instruction)) { EndInstructionTraceError(EvmExceptionType.OutOfGas); return CallResult.OutOfGasException; diff --git a/src/Nethermind/Nethermind.GitBook/docs b/src/Nethermind/Nethermind.GitBook/docs index 69c39b19019..5ca6560fea8 160000 --- a/src/Nethermind/Nethermind.GitBook/docs +++ b/src/Nethermind/Nethermind.GitBook/docs @@ -1 +1 @@ -Subproject commit 69c39b190197ffd4a98873ce99758c1168edccff +Subproject commit 5ca6560fea86ddba3addf8c47a4dad68d9ec5e95 diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockProducer.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockProducer.cs index 9373eb5a3bf..d483c057bdf 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockProducer.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockProducer.cs @@ -33,18 +33,37 @@ public async Task Execute(CancellationToken _) protected virtual async Task BuildProducer() { - _api.BlockProducerEnvFactory = new BlockProducerEnvFactory(_api.DbProvider!, - _api.BlockTree!, - _api.ReadOnlyTrieStore!, - _api.SpecProvider!, - _api.BlockValidator!, - _api.RewardCalculatorSource!, - _api.ReceiptStorage!, - _api.BlockPreprocessor, - _api.TxPool!, - _api.TransactionComparerProvider!, - _api.Config(), - _api.LogManager); + + if (_api.SpecProvider != null && _api.SpecProvider.GenesisSpec.VerkleTreeEnabled) + { + _api.BlockProducerEnvFactory = new BlockProducerEnvFactory(_api.DbProvider!, + _api.BlockTree!, + _api.ReadOnlyVerkleTrieStore!, + _api.SpecProvider!, + _api.BlockValidator!, + _api.RewardCalculatorSource!, + _api.ReceiptStorage!, + _api.BlockPreprocessor, + _api.TxPool!, + _api.TransactionComparerProvider!, + _api.Config(), + _api.LogManager); + } + else + { + _api.BlockProducerEnvFactory = new BlockProducerEnvFactory(_api.DbProvider!, + _api.BlockTree!, + _api.ReadOnlyTrieStore!, + _api.SpecProvider!, + _api.BlockValidator!, + _api.RewardCalculatorSource!, + _api.ReceiptStorage!, + _api.BlockPreprocessor, + _api.TxPool!, + _api.TransactionComparerProvider!, + _api.Config(), + _api.LogManager); + } if (_api.ChainSpec is null) throw new StepDependencyException(nameof(_api.ChainSpec)); IConsensusPlugin? consensusPlugin = _api.GetConsensusPlugin(); diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs index d649d8f8eca..156cde63958 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeBlockchain.cs @@ -21,7 +21,6 @@ using Nethermind.Core.Attributes; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; -using Nethermind.Crypto; using Nethermind.Db; using Nethermind.Db.FullPruning; using Nethermind.Evm; @@ -39,6 +38,8 @@ using Nethermind.Trie; using Nethermind.Trie.Pruning; using Nethermind.TxPool; +using Nethermind.Verkle.Tree; +using Nethermind.Verkle.Tree.VerkleDb; using Nethermind.Wallet; namespace Nethermind.Init.Steps @@ -99,60 +100,72 @@ private Task InitBlockchain() witnessCollector = setApi.WitnessCollector = NullWitnessCollector.Instance; setApi.WitnessRepository = NullWitnessCollector.Instance; } + ReadOnlyDbProvider readOnly = new(getApi.DbProvider, false); - CachingStore cachedStateDb = getApi.DbProvider.StateDb - .Cached(Trie.MemoryAllowance.TrieNodeCacheCount); - setApi.MainStateDbWithCache = cachedStateDb; + IWorldState worldState; + IStateReader stateReader; IKeyValueStore codeDb = getApi.DbProvider.CodeDb .WitnessedBy(witnessCollector); - TrieStore trieStore; - IKeyValueStoreWithBatching stateWitnessedBy = setApi.MainStateDbWithCache.WitnessedBy(witnessCollector); - if (pruningConfig.Mode.IsMemory()) + if (!getApi.SpecProvider.GenesisSpec.VerkleTreeEnabled) { - IPersistenceStrategy persistenceStrategy = Persist.IfBlockOlderThan(pruningConfig.PersistenceInterval); // TODO: this should be based on time - if (pruningConfig.Mode.IsFull()) + TrieStore trieStore; + CachingStore cachedStateDb = getApi.DbProvider.StateDb + .Cached(Trie.MemoryAllowance.TrieNodeCacheCount); + setApi.MainStateDbWithCache = cachedStateDb; + ; + + IKeyValueStoreWithBatching stateWitnessedBy = setApi.MainStateDbWithCache.WitnessedBy(witnessCollector); + if (pruningConfig.Mode.IsMemory()) { - PruningTriggerPersistenceStrategy triggerPersistenceStrategy = new((IFullPruningDb)getApi.DbProvider!.StateDb, getApi.BlockTree!, getApi.LogManager); - getApi.DisposeStack.Push(triggerPersistenceStrategy); - persistenceStrategy = persistenceStrategy.Or(triggerPersistenceStrategy); - } + IPersistenceStrategy persistenceStrategy = Persist.IfBlockOlderThan(pruningConfig.PersistenceInterval); // TODO: this should be based on time + if (pruningConfig.Mode.IsFull()) + { + PruningTriggerPersistenceStrategy triggerPersistenceStrategy = new((IFullPruningDb)getApi.DbProvider!.StateDb, getApi.BlockTree!, getApi.LogManager); + getApi.DisposeStack.Push(triggerPersistenceStrategy); + persistenceStrategy = persistenceStrategy.Or(triggerPersistenceStrategy); + } - setApi.TrieStore = trieStore = new TrieStore( - stateWitnessedBy, - Prune.WhenCacheReaches(pruningConfig.CacheMb.MB()), // TODO: memory hint should define this - persistenceStrategy, - getApi.LogManager); + setApi.TrieStore = trieStore = new TrieStore( + stateWitnessedBy, + Prune.WhenCacheReaches(pruningConfig.CacheMb.MB()), // TODO: memory hint should define this + persistenceStrategy, + getApi.LogManager); - if (pruningConfig.Mode.IsFull()) - { - IFullPruningDb fullPruningDb = (IFullPruningDb)getApi.DbProvider!.StateDb; - fullPruningDb.PruningStarted += (_, args) => + if (pruningConfig.Mode.IsFull()) { - cachedStateDb.PersistCache(args.Context); - trieStore.PersistCache(args.Context, args.Context.CancellationTokenSource.Token); - }; + IFullPruningDb fullPruningDb = (IFullPruningDb)getApi.DbProvider!.StateDb; + fullPruningDb.PruningStarted += (_, args) => + { + cachedStateDb.PersistCache(args.Context); + trieStore.PersistCache(args.Context, args.Context.CancellationTokenSource.Token); + }; + } + } + else + { + setApi.TrieStore = trieStore = new TrieStore( + stateWitnessedBy, + No.Pruning, + Persist.EveryBlock, + getApi.LogManager); } + ITrieStore readOnlyTrieStore = setApi.ReadOnlyTrieStore = trieStore.AsReadOnly(cachedStateDb); + worldState = setApi.WorldState = new WorldState(trieStore, codeDb, getApi.LogManager); + stateReader = setApi.StateReader = new StateReader(readOnlyTrieStore, readOnly.GetDb(DbNames.Code), getApi.LogManager); + + TrieStoreBoundaryWatcher trieStoreBoundaryWatcher = new TrieStoreBoundaryWatcher(trieStore, _api.BlockTree!, _api.LogManager); + getApi.DisposeStack.Push(trieStoreBoundaryWatcher); + getApi.DisposeStack.Push(trieStore); } else { - setApi.TrieStore = trieStore = new TrieStore( - stateWitnessedBy, - No.Pruning, - Persist.EveryBlock, - getApi.LogManager); - } - - TrieStoreBoundaryWatcher trieStoreBoundaryWatcher = new(trieStore, _api.BlockTree!, _api.LogManager); - getApi.DisposeStack.Push(trieStoreBoundaryWatcher); - getApi.DisposeStack.Push(trieStore); - - ITrieStore readOnlyTrieStore = setApi.ReadOnlyTrieStore = trieStore.AsReadOnly(cachedStateDb); - IWorldState worldState = setApi.WorldState = new WorldState(trieStore, codeDb, getApi.LogManager); + VerkleStateStore verkleStateStore = setApi.VerkleTrieStore = new VerkleStateStore(getApi.DbProvider); + ReadOnlyVerkleStateStore readOnlyVerkleStateStore = setApi.ReadOnlyVerkleTrieStore = verkleStateStore.AsReadOnly(new VerkleMemoryDb()); - ReadOnlyDbProvider readOnly = new(getApi.DbProvider, false); - - IStateReader stateReader = setApi.StateReader = new StateReader(readOnlyTrieStore, readOnly.GetDb(DbNames.Code), getApi.LogManager); + worldState = setApi.WorldState = new VerkleWorldState(new VerkleStateTree(verkleStateStore), codeDb, getApi.LogManager); + stateReader = setApi.StateReader = new VerkleStateReader(new VerkleStateTree(readOnlyVerkleStateStore), codeDb, getApi.LogManager); + } setApi.TransactionComparerProvider = new TransactionComparerProvider(getApi.SpecProvider!, getApi.BlockTree.AsReadOnly()); setApi.ChainHeadStateProvider = new ChainHeadReadOnlyStateProvider(getApi.BlockTree, stateReader); @@ -343,7 +356,7 @@ protected virtual BlockProcessor CreateBlockProcessor() _api.SpecProvider, _api.BlockValidator, _api.RewardCalculatorSource.Get(_api.TransactionProcessor!), - new BlockProcessor.BlockValidationTransactionsExecutor(_api.TransactionProcessor, new WorldState(_api.TrieStore, _api.DbProvider!.CodeDb, _api.LogManager)), + new BlockProcessor.BlockValidationTransactionsExecutor(_api.TransactionProcessor, _api.WorldState!), _api.WorldState, _api.ReceiptStorage, _api.WitnessCollector, diff --git a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs index ad1e49c0841..47431b7df9c 100644 --- a/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs +++ b/src/Nethermind/Nethermind.Init/Steps/InitializeNetwork.cs @@ -104,16 +104,18 @@ private async Task Initialize(CancellationToken cancellationToken) ProgressTracker progressTracker = new(_api.BlockTree!, _api.DbProvider.StateDb, _api.LogManager); _api.SnapProvider = new SnapProvider(progressTracker, _api.DbProvider, _api.LogManager); - SyncProgressResolver syncProgressResolver = new( - _api.BlockTree!, - _api.ReceiptStorage!, - _api.DbProvider.StateDb, - _api.ReadOnlyTrieStore!, - progressTracker, - _syncConfig, - _api.LogManager); + switch (_api.SpecProvider!.GenesisSpec.VerkleTreeEnabled) + { + case true: + _api.SyncProgressResolver = new SyncProgressResolver(_api.BlockTree!, _api.ReceiptStorage!, _api.ReadOnlyVerkleTrieStore!, progressTracker, _syncConfig, _api.LogManager); + break; + case false: + _api.SyncProgressResolver = new SyncProgressResolver(_api.BlockTree!, _api.ReceiptStorage!, _api.ReadOnlyTrieStore!, progressTracker, _syncConfig, _api.LogManager); + break; + } + + - _api.SyncProgressResolver = syncProgressResolver; _api.BetterPeerStrategy = new TotalDifficultyBetterPeerStrategy(_api.LogManager); int maxPeersCount = _networkConfig.ActivePeersMaxCount; @@ -131,7 +133,7 @@ private async Task Initialize(CancellationToken cancellationToken) await plugin.InitSynchronization(); } - _api.SyncModeSelector ??= CreateMultiSyncModeSelector(syncProgressResolver); + _api.SyncModeSelector ??= CreateMultiSyncModeSelector(_api.SyncProgressResolver); _api.DisposeStack.Push(_api.SyncModeSelector); _api.Pivot ??= new Pivot(_syncConfig); @@ -269,7 +271,7 @@ await StartDiscovery().ContinueWith(initDiscoveryTask => ThisNodeInfo.AddInfo("Node address :", $"{_api.Enode.Address} (do not use as an account)"); } - protected virtual MultiSyncModeSelector CreateMultiSyncModeSelector(SyncProgressResolver syncProgressResolver) + protected virtual MultiSyncModeSelector CreateMultiSyncModeSelector(ISyncProgressResolver syncProgressResolver) => new(syncProgressResolver, _api.SyncPeerPool!, _syncConfig, No.BeaconSync, _api.BetterPeerStrategy!, _api.LogManager, _api.ChainSpec?.SealEngineType == SealEngineType.Clique); private Task StartDiscovery() diff --git a/src/Nethermind/Nethermind.Init/Steps/LoadGenesisBlock.cs b/src/Nethermind/Nethermind.Init/Steps/LoadGenesisBlock.cs index ea64368dabd..dc71525a422 100644 --- a/src/Nethermind/Nethermind.Init/Steps/LoadGenesisBlock.cs +++ b/src/Nethermind/Nethermind.Init/Steps/LoadGenesisBlock.cs @@ -8,6 +8,7 @@ using Nethermind.Blockchain; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Logging; using Nethermind.State; @@ -41,6 +42,7 @@ public async Task Execute(CancellationToken _) { Load(); } + Console.WriteLine($"GenesisRootState: {_api.BlockTree.Genesis?.StateRoot?.Bytes.ToHexString()}"); ValidateGenesisHash(expectedGenesisHash); diff --git a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs index 157dea9cc5f..fa90b3b2ee0 100644 --- a/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs +++ b/src/Nethermind/Nethermind.Init/Steps/RegisterRpcModules.cs @@ -92,21 +92,9 @@ public virtual async Task Execute(CancellationToken cancellationToken) if (_api.ReceiptStorage is null) throw new StepDependencyException(nameof(_api.ReceiptStorage)); if (_api.GasPriceOracle is null) throw new StepDependencyException(nameof(_api.GasPriceOracle)); if (_api.EthSyncingInfo is null) throw new StepDependencyException(nameof(_api.EthSyncingInfo)); - if (_api.ReadOnlyTrieStore is null) throw new StepDependencyException(nameof(_api.ReadOnlyTrieStore)); + // if (_api.ReadOnlyTrieStore is null) throw new StepDependencyException(nameof(_api.ReadOnlyTrieStore)); - EthModuleFactory ethModuleFactory = new( - _api.TxPool, - _api.TxSender, - _api.Wallet, - _api.BlockTree, - rpcConfig, - _api.LogManager, - _api.StateReader, - _api, - _api.SpecProvider, - _api.ReceiptStorage, - _api.GasPriceOracle, - _api.EthSyncingInfo); + EthModuleFactory ethModuleFactory = new EthModuleFactory(_api.TxPool, _api.TxSender, _api.Wallet, _api.BlockTree, rpcConfig, _api.LogManager, _api.StateReader, _api, _api.SpecProvider, _api.ReceiptStorage, _api.GasPriceOracle, _api.EthSyncingInfo); rpcModuleProvider.RegisterBounded(ethModuleFactory, rpcConfig.EthModuleConcurrentInstances ?? Environment.ProcessorCount, rpcConfig.Timeout); @@ -118,36 +106,27 @@ public virtual async Task Execute(CancellationToken cancellationToken) if (_api.PeerPool is null) throw new StepDependencyException(nameof(_api.PeerPool)); if (_api.WitnessRepository is null) throw new StepDependencyException(nameof(_api.WitnessRepository)); - ProofModuleFactory proofModuleFactory = new(_api.DbProvider, _api.BlockTree, _api.ReadOnlyTrieStore, _api.BlockPreprocessor, _api.ReceiptFinder, _api.SpecProvider, _api.LogManager); + ProofModuleFactory proofModuleFactory = _api.SpecProvider.GenesisSpec.VerkleTreeEnabled switch + { + true => new ProofModuleFactory(_api.DbProvider, _api.BlockTree, _api.ReadOnlyVerkleTrieStore, _api.BlockPreprocessor, _api.ReceiptFinder, _api.SpecProvider, _api.LogManager), + false => new ProofModuleFactory(_api.DbProvider, _api.BlockTree, _api.ReadOnlyTrieStore!, _api.BlockPreprocessor, _api.ReceiptFinder, _api.SpecProvider, _api.LogManager), + }; rpcModuleProvider.RegisterBounded(proofModuleFactory, 2, rpcConfig.Timeout); - DebugModuleFactory debugModuleFactory = new( - _api.DbProvider, - _api.BlockTree, - rpcConfig, - _api.BlockValidator, - _api.BlockPreprocessor, - _api.RewardCalculatorSource, - _api.ReceiptStorage, - new ReceiptMigration(_api), - _api.ReadOnlyTrieStore, - _api.ConfigProvider, - _api.SpecProvider, - _api.SyncModeSelector, - _api.LogManager); + DebugModuleFactory debugModuleFactory = _api.SpecProvider.GenesisSpec.VerkleTreeEnabled switch + { + true => new DebugModuleFactory(_api.DbProvider, _api.BlockTree, rpcConfig, _api.BlockValidator, _api.BlockPreprocessor, _api.RewardCalculatorSource, _api.ReceiptStorage, new ReceiptMigration(_api), _api.ReadOnlyVerkleTrieStore, + _api.ConfigProvider, _api.SpecProvider, _api.SyncModeSelector, _api.LogManager), + false => new DebugModuleFactory(_api.DbProvider, _api.BlockTree, rpcConfig, _api.BlockValidator, _api.BlockPreprocessor, _api.RewardCalculatorSource, _api.ReceiptStorage, new ReceiptMigration(_api), _api.ReadOnlyTrieStore!, + _api.ConfigProvider, _api.SpecProvider, _api.SyncModeSelector, _api.LogManager), + }; rpcModuleProvider.RegisterBoundedByCpuCount(debugModuleFactory, rpcConfig.Timeout); - TraceModuleFactory traceModuleFactory = new( - _api.DbProvider, - _api.BlockTree, - _api.ReadOnlyTrieStore, - rpcConfig, - _api.BlockPreprocessor, - _api.RewardCalculatorSource, - _api.ReceiptStorage, - _api.SpecProvider, - _api.LogManager); - + TraceModuleFactory traceModuleFactory = _api.SpecProvider.GenesisSpec.VerkleTreeEnabled switch + { + true => new TraceModuleFactory(_api.DbProvider, _api.BlockTree, _api.ReadOnlyVerkleTrieStore, rpcConfig, _api.BlockPreprocessor, _api.RewardCalculatorSource, _api.ReceiptStorage, _api.SpecProvider, _api.LogManager), + false => new TraceModuleFactory(_api.DbProvider, _api.BlockTree, _api.ReadOnlyTrieStore!, rpcConfig, _api.BlockPreprocessor, _api.RewardCalculatorSource, _api.ReceiptStorage, _api.SpecProvider, _api.LogManager), + }; rpcModuleProvider.RegisterBoundedByCpuCount(traceModuleFactory, rpcConfig.Timeout); if (_api.EthereumEcdsa is null) throw new StepDependencyException(nameof(_api.EthereumEcdsa)); diff --git a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs index c03044502c0..125bd2566d3 100644 --- a/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs +++ b/src/Nethermind/Nethermind.JsonRpc.Test/Modules/Proof/ProofRpcModuleTests.cs @@ -27,14 +27,20 @@ using NUnit.Framework; using System.Threading.Tasks; using Nethermind.Consensus.Processing; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; +using Nethermind.Verkle.Tree.VerkleDb; using NSubstitute; namespace Nethermind.JsonRpc.Test.Modules.Proof { [Parallelizable(ParallelScope.None)] - [TestFixture(true, true)] - [TestFixture(true, false)] - [TestFixture(false, false)] + [TestFixture(true, true, TreeType.VerkleTree)] + [TestFixture(true, false, TreeType.VerkleTree)] + [TestFixture(false, false, TreeType.VerkleTree)] + [TestFixture(true, true, TreeType.MerkleTree)] + [TestFixture(true, false, TreeType.MerkleTree)] + [TestFixture(false, false, TreeType.MerkleTree)] public class ProofRpcModuleTests { private readonly bool _createSystemAccount; @@ -43,11 +49,13 @@ public class ProofRpcModuleTests private IBlockTree _blockTree; private IDbProvider _dbProvider; private TestSpecProvider _specProvider; + private TreeType _treeType; - public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice) + public ProofRpcModuleTests(bool createSystemAccount, bool useNonZeroGasPrice, TreeType treeType) { _createSystemAccount = createSystemAccount; _useNonZeroGasPrice = useNonZeroGasPrice; + _treeType = treeType; } [SetUp] @@ -57,15 +65,14 @@ public async Task Setup() _specProvider = new TestSpecProvider(London.Instance); _blockTree = Build.A.BlockTree().WithTransactions(receiptStorage, _specProvider).OfChainLength(10).TestObject; _dbProvider = await TestMemDbProvider.InitAsync(); - - ProofModuleFactory moduleFactory = new( - _dbProvider, - _blockTree, - new TrieStore(_dbProvider.StateDb, LimboLogs.Instance).AsReadOnly(), - new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), - receiptStorage, - _specProvider, - LimboLogs.Instance); + ProofModuleFactory moduleFactory = _treeType switch + { + TreeType.MerkleTree => new(_dbProvider, _blockTree, new TrieStore(_dbProvider.StateDb, LimboLogs.Instance).AsReadOnly(), + new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), receiptStorage, _specProvider, LimboLogs.Instance), + TreeType.VerkleTree => new(_dbProvider, _blockTree, new VerkleStateStore(_dbProvider).AsReadOnly(new VerkleMemoryDb()), + new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), receiptStorage, _specProvider, LimboLogs.Instance), + _ => throw new ArgumentOutOfRangeException() + }; _proofRpcModule = moduleFactory.Create(); } @@ -203,14 +210,14 @@ public void Get_receipt_when_block_has_few_receipts(bool withHeader, string expe _receiptFinder.Get(Arg.Any()).Returns(receipts); _receiptFinder.FindBlockHash(Arg.Any()).Returns(_blockTree.FindBlock(1).Hash); - ProofModuleFactory moduleFactory = new ProofModuleFactory( - _dbProvider, - _blockTree, - new TrieStore(_dbProvider.StateDb, LimboLogs.Instance).AsReadOnly(), - new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), - _receiptFinder, - _specProvider, - LimboLogs.Instance); + ProofModuleFactory moduleFactory = _treeType switch + { + TreeType.MerkleTree => new(_dbProvider, _blockTree, new TrieStore(_dbProvider.StateDb, LimboLogs.Instance).AsReadOnly(), + new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), _receiptFinder, _specProvider, LimboLogs.Instance), + TreeType.VerkleTree => new(_dbProvider, _blockTree, new VerkleStateStore(_dbProvider).AsReadOnly(new VerkleMemoryDb()), + new CompositeBlockPreprocessorStep(new RecoverSignatures(new EthereumEcdsa(ChainId.Mainnet, LimboLogs.Instance), NullTxPool.Instance, _specProvider, LimboLogs.Instance)), _receiptFinder, _specProvider, LimboLogs.Instance), + _ => throw new ArgumentOutOfRangeException() + }; _proofRpcModule = moduleFactory.Create(); ReceiptWithProof receiptWithProof = _proofRpcModule.proof_getTransactionReceipt(txHash, withHeader).Data; diff --git a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs index 13f6f12387a..52698e6c217 100644 --- a/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs +++ b/src/Nethermind/Nethermind.JsonRpc/IJsonRpcConfig.cs @@ -48,7 +48,7 @@ public interface IJsonRpcConfig : IConfig [ConfigItem( Description = "Defines which RPC modules should be enabled. Built in modules are: Admin, Baseline, Clique, Consensus, Db, Debug, Deposit, Erc20, Eth, Evm, Health Mev, NdmConsumer, NdmProvider, Net, Nft, Parity, Personal, Proof, Subscribe, Trace, TxPool, Vault, Web3.", - DefaultValue = "[Eth, Subscribe, Trace, TxPool, Web3, Personal, Proof, Net, Parity, Health, Rpc]")] + DefaultValue = "[Eth, Subscribe, Trace, TxPool, Web3, Personal, Proof, Net, Parity, Health, Rpc, Evm]")] string[] EnabledModules { get; set; } [ConfigItem( diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs index de0f5817f69..eac08327222 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/DebugModule/DebugModuleFactory.cs @@ -18,6 +18,8 @@ using Nethermind.State; using Nethermind.Synchronization.ParallelSync; using Nethermind.Trie.Pruning; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; using Newtonsoft.Json; namespace Nethermind.JsonRpc.Modules.DebugModule @@ -30,6 +32,7 @@ public class DebugModuleFactory : ModuleFactoryBase private readonly IReceiptStorage _receiptStorage; private readonly IReceiptsMigration _receiptsMigration; private readonly IReadOnlyTrieStore _trieStore; + private readonly ReadOnlyVerkleStateStore _verkleTrieStore; private readonly IConfigProvider _configProvider; private readonly ISpecProvider _specProvider; private readonly ILogManager _logManager; @@ -38,6 +41,7 @@ public class DebugModuleFactory : ModuleFactoryBase private readonly IReadOnlyBlockTree _blockTree; private readonly ISyncModeSelector _syncModeSelector; private ILogger _logger; + protected readonly TreeType _treeType; public DebugModuleFactory( IDbProvider dbProvider, @@ -68,11 +72,50 @@ public DebugModuleFactory( _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector)); _logger = logManager.GetClassLogger(); + _treeType = TreeType.MerkleTree; + } + + public DebugModuleFactory( + IDbProvider dbProvider, + IBlockTree blockTree, + IJsonRpcConfig jsonRpcConfig, + IBlockValidator blockValidator, + IBlockPreprocessorStep recoveryStep, + IRewardCalculatorSource rewardCalculator, + IReceiptStorage receiptStorage, + IReceiptsMigration receiptsMigration, + ReadOnlyVerkleStateStore trieStore, + IConfigProvider configProvider, + ISpecProvider specProvider, + ISyncModeSelector syncModeSelector, + ILogManager logManager) + { + _dbProvider = dbProvider.AsReadOnly(false); + _blockTree = blockTree.AsReadOnly(); + _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); + _blockValidator = blockValidator ?? throw new ArgumentNullException(nameof(blockValidator)); + _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep)); + _rewardCalculatorSource = rewardCalculator ?? throw new ArgumentNullException(nameof(rewardCalculator)); + _receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage)); + _receiptsMigration = receiptsMigration ?? throw new ArgumentNullException(nameof(receiptsMigration)); + _verkleTrieStore = (trieStore ?? throw new ArgumentNullException(nameof(trieStore))); + _configProvider = configProvider ?? throw new ArgumentNullException(nameof(configProvider)); + _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); + _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector)); + _logger = logManager.GetClassLogger(); + _treeType = TreeType.VerkleTree; } public override IDebugRpcModule Create() { - IReadOnlyTxProcessorSourceExt txEnv = new ReadOnlyTxProcessingEnv(_dbProvider, _trieStore, _blockTree, _specProvider, _logManager); + + IReadOnlyTxProcessorSourceExt txEnv = _treeType switch + { + TreeType.MerkleTree => new ReadOnlyTxProcessingEnv(_dbProvider, _trieStore, _blockTree, _specProvider, _logManager), + TreeType.VerkleTree => new ReadOnlyTxProcessingEnv(_dbProvider, _verkleTrieStore, _blockTree, _specProvider, _logManager), + _ => throw new ArgumentOutOfRangeException() + }; ChangeableTransactionProcessorAdapter transactionProcessorAdapter = new(txEnv.TransactionProcessor); BlockProcessor.BlockValidationTransactionsExecutor transactionsExecutor = new(transactionProcessorAdapter, txEnv.WorldState); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs index f2efe61e76e..454f7289163 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/ModuleType.cs @@ -79,6 +79,7 @@ public static class ModuleType Parity, Health, Rpc, + Evm }; public static IEnumerable DefaultEngineModules { get; } = new List() diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs index cd3cf047cdb..0bf321bee4d 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Proof/ProofModuleFactory.cs @@ -14,7 +14,10 @@ using Nethermind.Db; using Nethermind.JsonRpc.Data; using Nethermind.Logging; +using Nethermind.State; using Nethermind.Trie.Pruning; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; using Newtonsoft.Json; namespace Nethermind.JsonRpc.Modules.Proof @@ -28,6 +31,8 @@ public class ProofModuleFactory : ModuleFactoryBase private readonly IReadOnlyBlockTree _blockTree; private readonly ReadOnlyDbProvider _dbProvider; private readonly IReadOnlyTrieStore _trieStore; + private readonly ReadOnlyVerkleStateStore _verkleTrieStore; + protected readonly TreeType _treeType; public ProofModuleFactory( IDbProvider dbProvider, @@ -45,11 +50,36 @@ public ProofModuleFactory( _dbProvider = dbProvider.AsReadOnly(false); _blockTree = blockTree.AsReadOnly(); _trieStore = trieStore; + _treeType = TreeType.MerkleTree; + } + + public ProofModuleFactory( + IDbProvider dbProvider, + IBlockTree blockTree, + ReadOnlyVerkleStateStore trieStore, + IBlockPreprocessorStep recoveryStep, + IReceiptFinder receiptFinder, + ISpecProvider specProvider, + ILogManager logManager) + { + _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); + _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep)); + _receiptFinder = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); + _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + _dbProvider = dbProvider.AsReadOnly(false); + _blockTree = blockTree.AsReadOnly(); + _verkleTrieStore = trieStore; + _treeType = TreeType.VerkleTree; } public override IProofRpcModule Create() { - IReadOnlyTxProcessorSourceExt txProcessingEnv = new ReadOnlyTxProcessingEnv(_dbProvider, _trieStore, _blockTree, _specProvider, _logManager); + IReadOnlyTxProcessorSourceExt txProcessingEnv = _treeType switch + { + TreeType.MerkleTree => new ReadOnlyTxProcessingEnv(_dbProvider, _trieStore, _blockTree, _specProvider, _logManager), + TreeType.VerkleTree => new ReadOnlyTxProcessingEnv(_dbProvider, _verkleTrieStore, _blockTree, _specProvider, _logManager), + _ => throw new ArgumentOutOfRangeException() + }; ReadOnlyChainProcessingEnv chainProcessingEnv = new( txProcessingEnv, Always.Valid, _recoveryStep, NoBlockRewards.Instance, new InMemoryReceiptStorage(), _dbProvider, _specProvider, _logManager); diff --git a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs index e40505df3a0..eab5f5713a7 100644 --- a/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs +++ b/src/Nethermind/Nethermind.JsonRpc/Modules/Trace/TraceModuleFactory.cs @@ -15,6 +15,8 @@ using Nethermind.Logging; using Nethermind.State; using Nethermind.Trie.Pruning; +using Nethermind.Verkle; +using Nethermind.Verkle.Tree; using Newtonsoft.Json; namespace Nethermind.JsonRpc.Modules.Trace @@ -24,12 +26,14 @@ public class TraceModuleFactory : ModuleFactoryBase private readonly ReadOnlyDbProvider _dbProvider; private readonly IReadOnlyBlockTree _blockTree; private readonly IReadOnlyTrieStore _trieNodeResolver; + private readonly ReadOnlyVerkleStateStore _verkleTrieStore; private readonly IJsonRpcConfig _jsonRpcConfig; private readonly IReceiptStorage _receiptStorage; private readonly ISpecProvider _specProvider; private readonly ILogManager _logManager; private readonly IBlockPreprocessorStep _recoveryStep; private readonly IRewardCalculatorSource _rewardCalculatorSource; + protected readonly TreeType _treeType; public TraceModuleFactory( IDbProvider dbProvider, @@ -52,11 +56,42 @@ public TraceModuleFactory( _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); logManager.GetClassLogger(); + _treeType = TreeType.MerkleTree; + } + + public TraceModuleFactory( + IDbProvider dbProvider, + IBlockTree blockTree, + ReadOnlyVerkleStateStore trieNodeResolver, + IJsonRpcConfig jsonRpcConfig, + IBlockPreprocessorStep recoveryStep, + IRewardCalculatorSource rewardCalculatorSource, + IReceiptStorage receiptFinder, + ISpecProvider specProvider, + ILogManager logManager) + { + _dbProvider = dbProvider.AsReadOnly(false); + _blockTree = blockTree.AsReadOnly(); + _verkleTrieStore = trieNodeResolver; + _jsonRpcConfig = jsonRpcConfig ?? throw new ArgumentNullException(nameof(jsonRpcConfig)); + _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep)); + _rewardCalculatorSource = rewardCalculatorSource ?? throw new ArgumentNullException(nameof(rewardCalculatorSource)); + _receiptStorage = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); + _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); + _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); + logManager.GetClassLogger(); + _treeType = TreeType.VerkleTree; } public override ITraceRpcModule Create() { - IReadOnlyTxProcessorSourceExt txProcessingEnv = new ReadOnlyTxProcessingEnv(_dbProvider, _trieNodeResolver, _blockTree, _specProvider, _logManager); + + IReadOnlyTxProcessorSourceExt txProcessingEnv = _treeType switch + { + TreeType.MerkleTree => new ReadOnlyTxProcessingEnv(_dbProvider, _trieNodeResolver, _blockTree, _specProvider, _logManager), + TreeType.VerkleTree => new ReadOnlyTxProcessingEnv(_dbProvider, _verkleTrieStore, _blockTree, _specProvider, _logManager), + _ => throw new ArgumentOutOfRangeException() + }; IRewardCalculator rewardCalculator = _rewardCalculatorSource.Get(txProcessingEnv.TransactionProcessor); diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs index 6a5829acdd6..d6a0416ba09 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/Synchronization/BeaconHeadersSyncTests.cs @@ -108,7 +108,6 @@ public MultiSyncModeSelector Selector SyncProgressResolver syncProgressResolver = new( BlockTree, NullReceiptStorage.Instance, - stateDb, new TrieStore(stateDb, LimboLogs.Instance), progressTracker, SyncConfig, diff --git a/src/Nethermind/Nethermind.Merge.Plugin/IMergeConfig.cs b/src/Nethermind/Nethermind.Merge.Plugin/IMergeConfig.cs index 93329c18d3d..35207a5d075 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/IMergeConfig.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/IMergeConfig.cs @@ -12,7 +12,7 @@ public interface IMergeConfig : IConfig { [ConfigItem( Description = "Defines whether the Merge plugin is enabled bundles are allowed.", - DefaultValue = "true")] + DefaultValue = "false")] bool Enabled { get; set; } [ConfigItem(Description = "Final total difficulty is total difficulty of the last PoW block. FinalTotalDifficulty >= TerminalTotalDifficulty.", DefaultValue = "null")] diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergeConfig.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergeConfig.cs index bc86d6fa22c..27b9007f390 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergeConfig.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergeConfig.cs @@ -7,7 +7,7 @@ namespace Nethermind.Merge.Plugin { public class MergeConfig : IMergeConfig { - public bool Enabled { get; set; } = true; + public bool Enabled { get; set; } = false; public string? FinalTotalDifficulty { get; set; } diff --git a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs index f66300af163..5e3be2c82d8 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/MergePlugin.BlockProducer.cs @@ -39,7 +39,7 @@ public virtual async Task InitBlockProducer(IConsensusPlugin con if (_api.ReceiptStorage is null) throw new ArgumentNullException(nameof(_api.ReceiptStorage)); if (_api.TxPool is null) throw new ArgumentNullException(nameof(_api.TxPool)); if (_api.DbProvider is null) throw new ArgumentNullException(nameof(_api.DbProvider)); - if (_api.ReadOnlyTrieStore is null) throw new ArgumentNullException(nameof(_api.ReadOnlyTrieStore)); + // if (_api.ReadOnlyTrieStore is null) throw new ArgumentNullException(nameof(_api.ReadOnlyTrieStore)); if (_api.BlockchainProcessor is null) throw new ArgumentNullException(nameof(_api.BlockchainProcessor)); if (_api.HeaderValidator is null) throw new ArgumentNullException(nameof(_api.HeaderValidator)); if (_mergeBlockProductionPolicy is null) throw new ArgumentNullException(nameof(_mergeBlockProductionPolicy)); diff --git a/src/Nethermind/Nethermind.Runner/configs/BeverlyHills.cfg b/src/Nethermind/Nethermind.Runner/configs/BeverlyHills.cfg new file mode 100644 index 00000000000..211021fdbeb --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/configs/BeverlyHills.cfg @@ -0,0 +1,33 @@ +{ + "Init": { + "ChainSpecPath": "chainspec/beverlyhills.json", + "BaseDbPath": "nethermind_db/beverlyhills", + "LogFileName": "beverlyhills.logs.txt", + }, + "Sync": { + "NetworkingEnabled": true, + "SynchronizationEnabled": true + }, + "JsonRpc": { + "Enabled": true, + "Port": 8545 + }, + "EthStats": { + "Server": "wss://ethstats.net/api" + }, + "Metrics": { + "NodeName": "Mainnet" + }, + "JsonRpc": { + "Enabled": true, + "Timeout": 20000, + "Host": "127.0.0.1", + "Port": 8545, + "AdditionalRpcUrls": [ + "http://localhost:8551|http;ws|net;eth;subscribe;engine;web3;client" + ] + }, + "Merge": { + "Enabled": true + } +} diff --git a/src/Nethermind/Nethermind.Runner/configs/condrieu.cfg b/src/Nethermind/Nethermind.Runner/configs/condrieu.cfg new file mode 100644 index 00000000000..1f8c20c457f --- /dev/null +++ b/src/Nethermind/Nethermind.Runner/configs/condrieu.cfg @@ -0,0 +1,33 @@ +{ + "Init": { + "ChainSpecPath": "chainspec/condrieu.json", + "BaseDbPath": "nethermind_db/condrieu", + "LogFileName": "condrieu.logs.txt", + }, + "Sync": { + "NetworkingEnabled": true, + "SynchronizationEnabled": true + }, + "JsonRpc": { + "Enabled": true, + "Port": 8545 + }, + "EthStats": { + "Server": "wss://ethstats.net/api" + }, + "Metrics": { + "NodeName": "Mainnet" + }, + "JsonRpc": { + "Enabled": true, + "Timeout": 20000, + "Host": "127.0.0.1", + "Port": 8545, + "AdditionalRpcUrls": [ + "http://localhost:8551|http;ws|net;eth;subscribe;engine;web3;client" + ] + }, + "Merge": { + "Enabled": true + } +} diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs index c1a101995b1..ac9ab317ba6 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/HeaderDecoder.cs @@ -77,30 +77,30 @@ public class HeaderDecoder : IRlpValueDecoder, IRlpStreamDecoder= VerkleTreeTransitionTimestamp) - { - blockHeader.VerkleProof = decoderContext.DecodeByteArray(); - if (blockHeader.VerkleProof.IsZero()) - { - blockHeader.VerkleProof = null; - } - - int verkleWitnessSequenceLength = decoderContext.ReadSequenceLength(); - int verkleWitnessCheck = decoderContext.Position + verkleWitnessSequenceLength; - blockHeader.VerkleWitnesses = new(); - while (decoderContext.Position < verkleWitnessCheck) - { - int witnessSequenceLength = decoderContext.ReadSequenceLength(); - int witnessCheck = decoderContext.Position + witnessSequenceLength; - blockHeader.VerkleWitnesses.Add(new[] { decoderContext.DecodeByteArray(), decoderContext.DecodeByteArray() }); - decoderContext.Check(witnessCheck); - } - decoderContext.Check(verkleWitnessCheck); - if (blockHeader.VerkleWitnesses.Capacity == 0) - { - blockHeader.VerkleWitnesses = null; - } - } + // if (blockHeader.Timestamp >= VerkleTreeTransitionTimestamp) + // { + // blockHeader.VerkleProof = decoderContext.DecodeByteArray(); + // if (blockHeader.VerkleProof.IsZero()) + // { + // blockHeader.VerkleProof = null; + // } + // + // int verkleWitnessSequenceLength = decoderContext.ReadSequenceLength(); + // int verkleWitnessCheck = decoderContext.Position + verkleWitnessSequenceLength; + // blockHeader.VerkleWitnesses = new(); + // while (decoderContext.Position < verkleWitnessCheck) + // { + // int witnessSequenceLength = decoderContext.ReadSequenceLength(); + // int witnessCheck = decoderContext.Position + witnessSequenceLength; + // blockHeader.VerkleWitnesses.Add(new[] { decoderContext.DecodeByteArray(), decoderContext.DecodeByteArray() }); + // decoderContext.Check(witnessCheck); + // } + // decoderContext.Check(verkleWitnessCheck); + // if (blockHeader.VerkleWitnesses.Capacity == 0) + // { + // blockHeader.VerkleWitnesses = null; + // } + // } if ((rlpBehaviors & RlpBehaviors.AllowExtraData) != RlpBehaviors.AllowExtraData) { @@ -170,30 +170,30 @@ public class HeaderDecoder : IRlpValueDecoder, IRlpStreamDecoder= VerkleTreeTransitionTimestamp) - { - blockHeader.VerkleProof = rlpStream.DecodeByteArray(); - if (blockHeader.VerkleProof.IsZero()) - { - blockHeader.VerkleProof = null; - } - - int verkleWitnessSequenceLength = rlpStream.ReadSequenceLength(); - int verkleWitnessCheck = rlpStream.Position + verkleWitnessSequenceLength; - blockHeader.VerkleWitnesses = new(); - while (rlpStream.Position < verkleWitnessCheck) - { - int witnessSequenceLength = rlpStream.ReadSequenceLength(); - int witnessCheck = rlpStream.Position + witnessSequenceLength; - blockHeader.VerkleWitnesses.Add(new[] { rlpStream.DecodeByteArray(), rlpStream.DecodeByteArray() }); - rlpStream.Check(witnessCheck); - } - rlpStream.Check(verkleWitnessCheck); - if (blockHeader.VerkleWitnesses.Capacity == 0) - { - blockHeader.VerkleWitnesses = null; - } - } + // if (blockHeader.Timestamp >= VerkleTreeTransitionTimestamp) + // { + // blockHeader.VerkleProof = rlpStream.DecodeByteArray(); + // if (blockHeader.VerkleProof.IsZero()) + // { + // blockHeader.VerkleProof = null; + // } + // + // int verkleWitnessSequenceLength = rlpStream.ReadSequenceLength(); + // int verkleWitnessCheck = rlpStream.Position + verkleWitnessSequenceLength; + // blockHeader.VerkleWitnesses = new(); + // while (rlpStream.Position < verkleWitnessCheck) + // { + // int witnessSequenceLength = rlpStream.ReadSequenceLength(); + // int witnessCheck = rlpStream.Position + witnessSequenceLength; + // blockHeader.VerkleWitnesses.Add(new[] { rlpStream.DecodeByteArray(), rlpStream.DecodeByteArray() }); + // rlpStream.Check(witnessCheck); + // } + // rlpStream.Check(verkleWitnessCheck); + // if (blockHeader.VerkleWitnesses.Capacity == 0) + // { + // blockHeader.VerkleWitnesses = null; + // } + // } if ((rlpBehaviors & RlpBehaviors.AllowExtraData) != RlpBehaviors.AllowExtraData) { @@ -247,28 +247,28 @@ public void Encode(RlpStream rlpStream, BlockHeader? header, RlpBehaviors rlpBeh rlpStream.Encode(header.BaseFeePerGas); } - if (header.Timestamp >= VerkleTreeTransitionTimestamp) - { - // do i need to check here if the verkle witness exists? and if no witness, then does the proof exist? - // ANS: yes, add a null proof maybe? - if (header.VerkleProof == null) - { - rlpStream.EncodeEmptyByteArray(); - rlpStream.EncodeNullObject(); - } - else - { - rlpStream.Encode(header.VerkleProof); - // assumption here that if proof is not null then the witness is not null - rlpStream.StartSequence(GetWitnessLength(header, rlpBehaviors)); - foreach (var witness in header.VerkleWitnesses) - { - rlpStream.StartSequence(Rlp.LengthOf(witness[0]) + Rlp.LengthOf(witness[1])); - rlpStream.Encode(witness[0]); - rlpStream.Encode(witness[1]); - } - } - } + // if (header.Timestamp >= VerkleTreeTransitionTimestamp) + // { + // // do i need to check here if the verkle witness exists? and if no witness, then does the proof exist? + // // ANS: yes, add a null proof maybe? + // if (header.VerkleProof == null) + // { + // rlpStream.EncodeEmptyByteArray(); + // rlpStream.EncodeNullObject(); + // } + // else + // { + // rlpStream.Encode(header.VerkleProof); + // // assumption here that if proof is not null then the witness is not null + // rlpStream.StartSequence(GetWitnessLength(header, rlpBehaviors)); + // foreach (var witness in header.VerkleWitnesses) + // { + // rlpStream.StartSequence(Rlp.LengthOf(witness[0]) + Rlp.LengthOf(witness[1])); + // rlpStream.Encode(witness[0]); + // rlpStream.Encode(witness[1]); + // } + // } + // } } public Rlp Encode(BlockHeader? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) @@ -306,9 +306,9 @@ private static int GetContentLength(BlockHeader? item, RlpBehaviors rlpBehaviors + Rlp.LengthOf(item.GasUsed) + Rlp.LengthOf(item.Timestamp) + Rlp.LengthOf(item.ExtraData) - + (item.Number < Eip1559TransitionBlock ? 0 : Rlp.LengthOf(item.BaseFeePerGas)) - + (item.Timestamp < VerkleTreeTransitionTimestamp ? 0 : Rlp.LengthOf(item.VerkleProof)) - + (item.Timestamp < VerkleTreeTransitionTimestamp ? 0 : Rlp.LengthOfSequence(GetWitnessLength(item, rlpBehaviors))); + + (item.Number < Eip1559TransitionBlock ? 0 : Rlp.LengthOf(item.BaseFeePerGas)); + // + (item.Timestamp < VerkleTreeTransitionTimestamp ? 0 : Rlp.LengthOf(item.VerkleProof)) + // + (item.Timestamp < VerkleTreeTransitionTimestamp ? 0 : Rlp.LengthOfSequence(GetWitnessLength(item, rlpBehaviors))); if (notForSealing) { diff --git a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs index 47663fc8e68..993259dad33 100644 --- a/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs +++ b/src/Nethermind/Nethermind.Specs.Test/ChainSpecStyle/ChainSpecBasedSpecProviderTests.cs @@ -585,6 +585,7 @@ public void Eip_transitions_loaded_correctly() Eip3855TransitionTimestamp = 1000000012, Eip3860TransitionTimestamp = 1000000012, Eip1153TransitionTimestamp = 1000000024, + VerkleTreeTransitionTimestamp = 1000000030, } }; @@ -611,6 +612,7 @@ void TestTransitions(ForkActivation activation, Action changes) r.Eip1559TransitionBlock = 15590L; r.IsTimeAdjustmentPostOlympic = true; r.MaximumUncleCount = 2; + r.VerkleTreeTransitionTimeStamp = 1000000030; }); TestTransitions((ForkActivation)1L, r => diff --git a/src/Nethermind/Nethermind.State.Test/Nethermind.State.Test.csproj b/src/Nethermind/Nethermind.State.Test/Nethermind.State.Test.csproj index 12dfccd9569..ec4feb1d6f2 100644 --- a/src/Nethermind/Nethermind.State.Test/Nethermind.State.Test.csproj +++ b/src/Nethermind/Nethermind.State.Test/Nethermind.State.Test.csproj @@ -20,6 +20,7 @@ + diff --git a/src/Nethermind/Nethermind.State.Test/VerkleTreeTests.cs b/src/Nethermind/Nethermind.State.Test/VerkleTreeTests.cs new file mode 100644 index 00000000000..c946ece42a9 --- /dev/null +++ b/src/Nethermind/Nethermind.State.Test/VerkleTreeTests.cs @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using FluentAssertions; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Core.Test.Builders; +using Nethermind.Db; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.State; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; +using Nethermind.Verkle; +using NUnit.Framework; + +namespace Nethermind.Store.Test; + +[TestFixture, Parallelizable(ParallelScope.All)] +public class VerkleTreeTests +{ + [Test] + public void Create_commit_change_balance_get() + { + Account account = new(1); + IDbProvider dbProvider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + VerkleStateTree stateTree = new VerkleStateTree(dbProvider); + stateTree.Set(TestItem.AddressA, account); + stateTree.Flush(0); + + account = account.WithChangedBalance(2); + stateTree.Set(TestItem.AddressA, account); + stateTree.Flush(0); + + Account accountRestored = stateTree.Get(TestItem.AddressA); + Assert.AreEqual((UInt256)2, accountRestored.Balance); + } + + [Test] + public void Create_create_commit_change_balance_get() + { + Account account = new(1); + IDbProvider dbProvider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + VerkleStateTree stateTree = new VerkleStateTree(dbProvider); + stateTree.Set(TestItem.AddressA, account); + stateTree.Set(TestItem.AddressB, account); + stateTree.Flush(0); + + account = account.WithChangedBalance(2); + stateTree.Set(TestItem.AddressA, account); + stateTree.Flush(0); + + Account accountRestored = stateTree.Get(TestItem.AddressA); + Assert.AreEqual((UInt256)2, accountRestored.Balance); + } + + [Test] + public void TestGenesis() + { + Account account = new(1); + IDbProvider dbProvider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + VerkleStateTree stateTree = new VerkleStateTree(dbProvider); + stateTree.Set(new Address("0x0000000000000000000000000000000000000000"), account); + stateTree.Flush(0); + Console.WriteLine(EnumerableExtensions.ToString(stateTree.RootHash)); + } + + // [Test] + // public void Create_commit_reset_change_balance_get() + // { + // Account account = new(1); + // IDbProvider dbProvider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + // VerkleStateTree stateTree = new VerkleStateTree(dbProvider); + // stateTree.Set(TestItem.AddressA, account); + // stateTree.Flush(0); + // + // Keccak rootHash = new Keccak(stateTree.RootHash); + // + // stateTree.Get(TestItem.AddressA); + // account = account.WithChangedBalance(2); + // stateTree.Set(TestItem.AddressA, account); + // stateTree.Flush(0); + // } + // + // [TestCase(true, false)] + // [TestCase(false, true)] + // public void Commit_with_skip_root_should_skip_root(bool skipRoot, bool hasRoot) + // { + // MemDb db = new(); + // TrieStore trieStore = new TrieStore(db, LimboLogs.Instance); + // Account account = new(1); + // + // IDbProvider dbProvider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + // VerkleStateTree stateTree = new VerkleStateTree(dbProvider); + // stateTree.Set(TestItem.AddressA, account); + // stateTree.UpdateRootHash(); + // Keccak stateRoot = stateTree.RootHash; + // stateTree.Flush(0, skipRoot); + // + // if (hasRoot) + // { + // trieStore.LoadRlp(stateRoot).Length.Should().BeGreaterThan(0); + // } + // else + // { + // trieStore.Invoking(ts => ts.LoadRlp(stateRoot)).Should().Throw(); + // } + // } +} diff --git a/src/Nethermind/Nethermind.State.Test/VerkleWitnessAccessCostTest.cs b/src/Nethermind/Nethermind.State.Test/VerkleWitnessAccessCostTest.cs new file mode 100644 index 00000000000..befc36703c1 --- /dev/null +++ b/src/Nethermind/Nethermind.State.Test/VerkleWitnessAccessCostTest.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Core.Test.Builders; +using Nethermind.State; +using NUnit.Framework; + +namespace Nethermind.Store.Test; + +public class VerkleWitnessAccessCostTest +{ + + [Test] + public void TestAccessForTransaction() + { + VerkleWitness calculator = new VerkleWitness(); + long gas = calculator.AccessForTransaction(TestItem.AddressA, TestItem.AddressB, false); + Console.WriteLine(gas); + } + + [Test] + public void TestAccessForTransactionWithValue() + { + VerkleWitness calculator = new VerkleWitness(); + long gas = calculator.AccessForTransaction(TestItem.AddressA, TestItem.AddressB, true); + Console.WriteLine(gas); + } +} diff --git a/src/Nethermind/Nethermind.State/IStateReader.cs b/src/Nethermind/Nethermind.State/IStateReader.cs index f3e3352f8f9..34f21b84a9b 100644 --- a/src/Nethermind/Nethermind.State/IStateReader.cs +++ b/src/Nethermind/Nethermind.State/IStateReader.cs @@ -13,6 +13,7 @@ public interface IStateReader Account? GetAccount(Keccak stateRoot, Address address); byte[]? GetStorage(Keccak storageRoot, in UInt256 index); + byte[]? GetStorage(Address address, in UInt256 index); byte[]? GetCode(Keccak codeHash); diff --git a/src/Nethermind/Nethermind.State/Nethermind.State.csproj b/src/Nethermind/Nethermind.State/Nethermind.State.csproj index c29b2129d94..6c67fdfe122 100644 --- a/src/Nethermind/Nethermind.State/Nethermind.State.csproj +++ b/src/Nethermind/Nethermind.State/Nethermind.State.csproj @@ -16,6 +16,6 @@ - + diff --git a/src/Nethermind/Nethermind.State/StateReader.cs b/src/Nethermind/Nethermind.State/StateReader.cs index 22e71220c70..8d72530c47b 100644 --- a/src/Nethermind/Nethermind.State/StateReader.cs +++ b/src/Nethermind/Nethermind.State/StateReader.cs @@ -43,6 +43,11 @@ public byte[] GetStorage(Keccak storageRoot, in UInt256 index) Metrics.StorageTreeReads++; return _storage.Get(index, storageRoot); } + public byte[]? GetStorage(Address address, in UInt256 index) + { + Account account = _state.Get(address); + return GetStorage(account.StorageRoot, index); + } public UInt256 GetBalance(Keccak stateRoot, Address address) { diff --git a/src/Nethermind/Nethermind.State/StateStore.cs b/src/Nethermind/Nethermind.State/StateStore.cs new file mode 100644 index 00000000000..e5ffb5e9b49 --- /dev/null +++ b/src/Nethermind/Nethermind.State/StateStore.cs @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Logging; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; + +namespace Nethermind.State; + +public class StateStore +{ + private StateTree _tree; + private ITrieStore _trieStore; + private readonly IKeyValueStore _codeDb; + private ILogManager _logManager; + + public Keccak RootHash + { + get => GetStateRoot(); + set => MoveToStateRoot(value); + } + + public StateStore(ITrieStore? trieStore, IKeyValueStore? codeDb, ILogManager? logManager) + { + _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager)); + _trieStore = trieStore ?? throw new ArgumentNullException(nameof(trieStore)); + _tree = new StateTree(trieStore, logManager); + _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); + } + + public Account? GetState(Address address) => _tree.Get(address); + + public void SetState(Address address, Account? account) => _tree.Set(address, account); + + public StorageTree GetOrCreateStorage(Address address) => new StorageTree(_trieStore, GetStorageRoot(address), _logManager); + + private Keccak GetStorageRoot(Address address) + { + Account? account = GetState(address); + if (account is null) + { + throw new InvalidOperationException($"Account {address} is null when accessing storage root"); + } + return account.StorageRoot; + } + + public void SetStorage(StorageCell storageCell, byte[] value) + { + StorageTree tree = GetOrCreateStorage(storageCell.Address); + tree.Set(storageCell.Index, value); + } + + public byte[] GetStorage(StorageCell storageCell) + { + StorageTree tree = GetOrCreateStorage(storageCell.Address); + return tree.Get(storageCell.Index); + } + + public void Commit(long blockNumber) + { + _tree.Commit(blockNumber); + } + + public string Dump() + { + TreeDumper dumper = new TreeDumper(); + _tree.Accept(dumper, RootHash); + return dumper.ToString(); + } + + public TrieStats CollectStats() + { + TrieStatsCollector collector = new(_codeDb, _logManager); + _tree.Accept(collector, RootHash, new VisitingOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }); + return collector.Stats; + } + + public void MoveToStateRoot(Keccak stateRoot) + { + _tree.RootHash = stateRoot; + } + + public void UpdateRootHash() + { + _tree.UpdateRootHash(); + } + + public Keccak GetStateRoot() + { + return _tree.RootHash; + } + + public StorageTree ClearStorage(Address address) => new StorageTree(_trieStore, Keccak.EmptyTreeHash, _logManager); + + public void Accept(ITreeVisitor visitor, Keccak rootHash, VisitingOptions? visitingOptions = null) + { + _tree.Accept(visitor, rootHash, visitingOptions); + } + +} diff --git a/src/Nethermind/Nethermind.State/TreeType.cs b/src/Nethermind/Nethermind.State/TreeType.cs new file mode 100644 index 00000000000..b69eb05bff3 --- /dev/null +++ b/src/Nethermind/Nethermind.State/TreeType.cs @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.State; + +public enum TreeType +{ + MerkleTree = 0, + VerkleTree = 1 +} diff --git a/src/Nethermind/Nethermind.State/VerklePersistentStorageProvider.cs b/src/Nethermind/Nethermind.State/VerklePersistentStorageProvider.cs index 513516d246c..93612cdce0d 100644 --- a/src/Nethermind/Nethermind.State/VerklePersistentStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/VerklePersistentStorageProvider.cs @@ -9,13 +9,13 @@ using Nethermind.Core.Extensions; using Nethermind.Core.Resettables; using Nethermind.Logging; -using Nethermind.Verkle; +using Nethermind.Verkle.Tree; namespace Nethermind.State; public class VerklePersistentStorageProvider: PartialStorageProviderBase { - private readonly VerkleTree _verkleTree; + private readonly VerkleStateTree _verkleTree; private readonly ILogManager? _logManager; /// /// EIP-1283 @@ -23,7 +23,7 @@ public class VerklePersistentStorageProvider: PartialStorageProviderBase private readonly ResettableDictionary _originalValues = new ResettableDictionary(); private readonly ResettableHashSet _committedThisRound = new ResettableHashSet(); - public VerklePersistentStorageProvider(VerkleTree tree, ILogManager? logManager) + public VerklePersistentStorageProvider(VerkleStateTree tree, ILogManager? logManager) : base(logManager) { _verkleTree = tree; @@ -151,6 +151,10 @@ protected override void CommitCore(IStorageTracer tracer) Db.Metrics.StorageTreeWrites++; byte[]? key = AccountHeader.GetTreeKeyForStorageSlot(change.StorageCell.Address.Bytes, change.StorageCell.Index); +#if DEBUG + Console.WriteLine("K: " + EnumerableExtensions.ToString(key)); + Console.WriteLine("V: " + EnumerableExtensions.ToString(change.Value)); +#endif _verkleTree.Insert(key, change.Value); if (isTracing) { diff --git a/src/Nethermind/Nethermind.State/VerkleStateReader.cs b/src/Nethermind/Nethermind.State/VerkleStateReader.cs new file mode 100644 index 00000000000..0d97116bb5b --- /dev/null +++ b/src/Nethermind/Nethermind.State/VerkleStateReader.cs @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Db; +using Nethermind.Int256; +using Nethermind.Logging; +using Nethermind.Trie; +using Metrics = Nethermind.Db.Metrics; + +namespace Nethermind.State; + +public class VerkleStateReader : IStateReader +{ + private readonly IKeyValueStore _codeDb; + private readonly ILogger _logger; + private readonly VerkleStateTree _state; + + public VerkleStateReader(VerkleStateTree verkleTree, IKeyValueStore? codeDb, ILogManager? logManager) + { + _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); + _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); + _state = verkleTree; + } + + public Account? GetAccount(Keccak stateRoot, Address address) + { + return GetState(stateRoot, address); + } + + public byte[] GetStorage(Address address, in UInt256 index) + { + return _state.Get(address, index); + } + + public byte[] GetStorage(Keccak storageRoot, in UInt256 index) + { + throw new NotImplementedException(); + } + + public UInt256 GetBalance(Keccak stateRoot, Address address) + { + return GetState(stateRoot, address)?.Balance ?? UInt256.Zero; + } + + public byte[]? GetCode(Keccak codeHash) + { + if (codeHash == Keccak.OfAnEmptyString) + { + return Array.Empty(); + } + + return _codeDb[codeHash.Bytes]; + } + + public void RunTreeVisitor(ITreeVisitor treeVisitor, Keccak rootHash, VisitingOptions? visitingOptions = null) + { + _state.Accept(treeVisitor, rootHash, visitingOptions); + } + + public byte[] GetCode(Keccak stateRoot, Address address) + { + Account? account = GetState(stateRoot, address); + return account is null ? Array.Empty() : GetCode(account.CodeHash); + } + + private Account? GetState(Keccak stateRoot, Address address) + { + if (stateRoot == Keccak.EmptyTreeHash) + { + return null; + } + + Metrics.StateTreeReads++; + Account? account = _state.Get(address, stateRoot); + return account; + } +} diff --git a/src/Nethermind/Nethermind.State/VerkleStateTree.cs b/src/Nethermind/Nethermind.State/VerkleStateTree.cs new file mode 100644 index 00000000000..bfa618397a4 --- /dev/null +++ b/src/Nethermind/Nethermind.State/VerkleStateTree.cs @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System; +using System.Diagnostics; +using System.Linq; +using Nethermind.Core; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Db; +using Nethermind.Int256; +using Nethermind.Serialization.Rlp; +using Nethermind.Verkle.Tree; + +namespace Nethermind.State; + +public class VerkleStateTree: VerkleTree +{ + + public VerkleStateTree(IDbProvider dbProvider) : base(dbProvider) + { + } + + public VerkleStateTree(IVerkleStore stateStore) : base(stateStore) + { + } + + [DebuggerStepThrough] + public Account? Get(Address address, Keccak? rootHash = null) + { + Span key = new byte[32]; + byte[]? headerTreeKey = AccountHeader.GetTreeKeyPrefixAccount(address.Bytes); + headerTreeKey.CopyTo(key); + key[31] = AccountHeader.Version; + UInt256 version = new UInt256((Get(key.ToArray()) ?? Array.Empty()).ToArray()); + key[31] = AccountHeader.Balance; + UInt256 balance = new UInt256((Get(key.ToArray()) ?? Array.Empty()).ToArray()); + key[31] = AccountHeader.Nonce; + UInt256 nonce = new UInt256((Get(key.ToArray()) ?? Array.Empty()).ToArray()); + key[31] = AccountHeader.CodeHash; + byte[]? codeHash = (Get(key.ToArray()) ?? Keccak.OfAnEmptyString.Bytes).ToArray(); + key[31] = AccountHeader.CodeSize; + UInt256 codeSize = new UInt256((Get(key.ToArray()) ?? Array.Empty()).ToArray()); + + return new Account(balance, nonce, new Keccak(codeHash), codeSize, version); + } + + public void Set(Address address, Account? account) + { + byte[]? headerTreeKey = AccountHeader.GetTreeKeyPrefixAccount(address.Bytes); + if (account != null) InsertStemBatch(headerTreeKey[..31], account.ToVerkleDict()); + } + + public byte[] Get(Address address, in UInt256 index, Keccak? storageRoot = null) + { + byte[]? key = AccountHeader.GetTreeKeyForStorageSlot(address.Bytes, index).ToArray(); + return (Get(key) ?? Array.Empty()).ToArray(); + } + + public void Set(Address address, in UInt256 index, byte[] value) + { + byte[] key = AccountHeader.GetTreeKeyForStorageSlot(address.Bytes, index).ToArray(); + Insert(key, value); + } +} diff --git a/src/Nethermind/Nethermind.State/VerkleStorageProvider.cs b/src/Nethermind/Nethermind.State/VerkleStorageProvider.cs index a5213e15371..2c325385abb 100644 --- a/src/Nethermind/Nethermind.State/VerkleStorageProvider.cs +++ b/src/Nethermind/Nethermind.State/VerkleStorageProvider.cs @@ -1,9 +1,10 @@ // SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System.Diagnostics; using Nethermind.Core; using Nethermind.Logging; -using Nethermind.Verkle; +using Nethermind.Verkle.Tree; namespace Nethermind.State; @@ -12,7 +13,7 @@ public class VerkleStorageProvider : IStorageProvider private readonly VerklePersistentStorageProvider _persistentStorageProvider; private readonly VerkleTransientStorageProvider _transientStorageProvider; - public VerkleStorageProvider(VerkleTree tree, ILogManager? logManager) + public VerkleStorageProvider(VerkleStateTree tree, ILogManager? logManager) { _persistentStorageProvider = new VerklePersistentStorageProvider(tree, logManager); _transientStorageProvider = new VerkleTransientStorageProvider(logManager); @@ -75,11 +76,13 @@ public void Restore(Snapshot.Storage snapshot) public void Set(StorageCell storageCell, byte[] newValue) { + Debug.Assert(newValue.Length == 32); _persistentStorageProvider.Set(storageCell, newValue); } public void SetTransientState(StorageCell storageCell, byte[] newValue) { + Debug.Assert(newValue.Length == 32); _transientStorageProvider.Set(storageCell, newValue); } diff --git a/src/Nethermind/Nethermind.State/VerkleWitness.cs b/src/Nethermind/Nethermind.State/VerkleWitness.cs index 16bef3bd8be..2993f2e1f38 100644 --- a/src/Nethermind/Nethermind.State/VerkleWitness.cs +++ b/src/Nethermind/Nethermind.State/VerkleWitness.cs @@ -1,45 +1,55 @@ // SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only +using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Nethermind.Core; using Nethermind.Core.Collections; +using Nethermind.Core.Extensions; using Nethermind.Int256; -using Nethermind.Trie; +using Nethermind.Logging; +using Nethermind.Verkle.Tree; namespace Nethermind.State; // TODO: this can be definitely optimized by caching the keys from StateProvider - because for every access we // already calculate keys in StateProvider - or we maintain pre images? -public class VerkleWitness : IVerkleWitness +public struct VerkleWitness : IVerkleWitness { - // const int VersionLeafKey = 0; - // const int BalanceLeafKey = 1; - // const int NonceLeafKey = 2; - // const int CodeKeccakLeafKey = 3; - // const int CodeSizeLeafKey = 4; + private ILogger _logger = SimpleConsoleLogger.Instance; + [Flags] + private enum AccountHeaderAccess + { + Version = 1, + Balance = 2, + Nonce = 4, + CodeHash = 8, + CodeSize = 16 + } + private readonly JournalSet _accessedSubtrees; private readonly JournalSet _accessedLeaves; private readonly JournalSet _modifiedSubtrees; private readonly JournalSet _modifiedLeaves; // TODO: add these in GasPrices List - public const long WitnessChunkRead = 200; // verkle-trie - public const long WitnessChunkWrite = 500; // verkle-trie - public const long WitnessChunkFill = 6200; // verkle-trie - public const long WitnessBranchRead = 1900; // verkle-trie - public const long WitnessBranchWrite = 3000; // verkle-trie + private const long WitnessChunkRead = 200; // verkle-trie + private const long WitnessChunkWrite = 500; // verkle-trie + private const long WitnessChunkFill = 6200; // verkle-trie + private const long WitnessBranchRead = 1900; // verkle-trie + private const long WitnessBranchWrite = 3000; // verkle-trie - private readonly Dictionary _snapshots = new(); - private int NextSnapshot = 0; + private readonly Dictionary _snapshots = new Dictionary(); + private int NextSnapshot; public VerkleWitness() { - _accessedSubtrees = new JournalSet(); - _accessedLeaves = new JournalSet(); - _modifiedLeaves = new JournalSet(); - _modifiedSubtrees = new JournalSet(); + _accessedSubtrees = new JournalSet(Bytes.EqualityComparer); + _accessedLeaves = new JournalSet(Bytes.EqualityComparer); + _modifiedLeaves = new JournalSet(Bytes.EqualityComparer); + _modifiedSubtrees = new JournalSet(Bytes.EqualityComparer); } /// /// When a non-precompile address is the target of a CALL, CALLCODE, @@ -51,10 +61,9 @@ public VerkleWitness() /// public long AccessForCodeOpCodes(Address caller) { - // (address, 0, VERSION_LEAF_KEY) - // (address, 0, CODE_SIZE_LEAF_KEY) - bool[] accountAccess = { true, false, false, false, true }; - return AccessAccount(caller, accountAccess); + long gas = AccessAccount(caller, AccountHeaderAccess.Version | AccountHeaderAccess.CodeSize); + _logger.Info($"AccessForCodeOpCodes: {caller.Bytes.ToHexString()} {gas}"); + return gas; } /// @@ -67,14 +76,13 @@ public long AccessForCodeOpCodes(Address caller) /// /// /// - /// /// public long AccessValueTransfer(Address caller, Address callee) { - // (caller_address, 0, BALANCE_LEAF_KEY) - // (callee_address, 0, BALANCE_LEAF_KEY) - bool[] accountAccess = { false, true, false, false, false }; - return AccessAccount(caller, accountAccess, true) + AccessAccount(callee, accountAccess, true); + + var gas = AccessAccount(caller, AccountHeaderAccess.Balance, true) + AccessAccount(callee, AccountHeaderAccess.Balance, true); + _logger.Info($"AccessForCodeOpCodes: {caller.Bytes.ToHexString()} {gas}"); + return gas; } /// @@ -85,15 +93,12 @@ public long AccessValueTransfer(Address caller, Address callee) /// public long AccessForContractCreationInit(Address contractAddress, bool isValueTransfer) { - // (contract_address, 0, VERSION_LEAF_KEY) - // (contract_address, 0, NONCE_LEAF_KEY) - bool[] accountAccess = { true, false, true, false, false }; - if (isValueTransfer) - { - // (contract_address, 0, BALANCE_LEAF_KEY) - accountAccess[1] = true; - } - return AccessAccount(contractAddress, accountAccess, true); + long gas = isValueTransfer + ? AccessAccount(contractAddress, AccountHeaderAccess.Version | AccountHeaderAccess.Nonce | AccountHeaderAccess.Balance | AccountHeaderAccess.CodeHash, true) + : AccessAccount(contractAddress, AccountHeaderAccess.Version | AccountHeaderAccess.Nonce | AccountHeaderAccess.CodeHash, true); + _logger.Info($"AccessForContractCreationInit: {contractAddress.Bytes.ToHexString()} {isValueTransfer} {gas}"); + + return gas; } /// @@ -103,12 +108,10 @@ public long AccessForContractCreationInit(Address contractAddress, bool isValueT /// public long AccessContractCreated(Address contractAddress) { - // (contract_address, 0, VERSION_LEAF_KEY) - // (contract_address, 0, NONCE_LEAF_KEY) - // (contract_address, 0, BALANCE_LEAF_KEY) - // (contract_address, 0, CODE_KECCAK_LEAF_KEY) - // (contract_address, 0, CODE_SIZE_LEAF_KEY) - return AccessCompleteAccount(contractAddress, true); + + var gas = AccessCompleteAccount(contractAddress, true); + _logger.Info($"AccessContractCreated: {contractAddress.Bytes.ToHexString()} {gas}"); + return gas; } /// @@ -118,9 +121,10 @@ public long AccessContractCreated(Address contractAddress) /// public long AccessBalance(Address address) { - // (address, 0, BALANCE_LEAF_KEY) - bool[] accountAccess = { false, true, false, false, false }; - return AccessAccount(address, accountAccess); + + var gas = AccessAccount(address, AccountHeaderAccess.Balance); + _logger.Info($"AccessBalance: {address.Bytes.ToHexString()} {gas}"); + return gas; } /// @@ -131,8 +135,9 @@ public long AccessBalance(Address address) public long AccessCodeHash(Address address) { - bool[] accountAccess = { false, false, false, true, false }; - return AccessAccount(address, accountAccess); + var gas = AccessAccount(address, AccountHeaderAccess.CodeHash); + _logger.Info($"AccessCodeHash: {address.Bytes.ToHexString()} {gas}"); + return gas; } /// @@ -145,7 +150,9 @@ public long AccessCodeHash(Address address) /// public long AccessStorage(Address address, UInt256 key, bool isWrite) { - return AccessKey(VerkleUtils.GetTreeKeyForStorageSlot(address, key), isWrite); + var gas = AccessKey(AccountHeader.GetTreeKeyForStorageSlot(address.Bytes, key), isWrite); + _logger.Info($"AccessStorage: {address.Bytes.ToHexString()} {key.ToBigEndian().ToHexString()} {isWrite} {gas}"); + return gas; } /// @@ -157,7 +164,11 @@ public long AccessStorage(Address address, UInt256 key, bool isWrite) /// public long AccessCodeChunk(Address address, byte chunkId, bool isWrite) { - return AccessKey(VerkleUtils.GetTreeKeyForCodeChunk(address, chunkId), isWrite); + var key = AccountHeader.GetTreeKeyForCodeChunk(address.Bytes, chunkId); + _logger.Info($"AccessCodeChunkKey: {EnumerableExtensions.ToString(key)}"); + var gas = AccessKey(key, isWrite); + _logger.Info($"AccessCodeChunk: {address.Bytes.ToHexString()} {chunkId} {isWrite} {gas}"); + return gas; } /// @@ -166,25 +177,35 @@ public long AccessCodeChunk(Address address, byte chunkId, bool isWrite) /// /// /// - /// /// - public long AccessForTransaction(Address originAddress, Address destinationAddress, bool isValueTransfer) + public long AccessForTransaction(Address originAddress, Address? destinationAddress, bool isValueTransfer) { - long gasCost = AccessCompleteAccount(originAddress) + AccessCompleteAccount(destinationAddress); + // TODO: does not seem right - not upto spec + long gasCost = AccessAccount(originAddress, AccountHeaderAccess.Version | AccountHeaderAccess.Balance | AccountHeaderAccess.Nonce) + + (destinationAddress == null ? 0: AccessCompleteAccount(destinationAddress)); // when you are executing a transaction, you are writing to the nonce of the origin address - bool[] accountAccess = { false, false, true, false, false }; - gasCost += AccessAccount(originAddress, accountAccess, true); + gasCost += AccessAccount(originAddress, AccountHeaderAccess.Nonce, true); if (isValueTransfer) { // when you are executing a transaction with value transfer, // you are writing to the balance of the origin and destination address gasCost += AccessValueTransfer(originAddress, destinationAddress); } - + else + { + gasCost += AccessAccount(originAddress, AccountHeaderAccess.Balance, true); + } + _logger.Info($"AccessForTransaction: {originAddress.Bytes.ToHexString()} {destinationAddress?.Bytes.ToHexString()} {isValueTransfer} {gasCost}"); return gasCost; } + public long AccessForProofOfAbsence(Address address) + { + long gas = AccessCompleteAccount(address); + _logger.Info($"AccessForProofOfAbsence: {address.Bytes.ToHexString()} {gas}"); + return gas; + } /// /// When you have to access the complete account @@ -194,80 +215,79 @@ public long AccessForTransaction(Address originAddress, Address destinationAddre /// public long AccessCompleteAccount(Address address, bool isWrite = false) { - bool[] accountAccess = { true, true, true, true, true }; - return AccessAccount(address, accountAccess, isWrite); + + var gas = AccessAccount(address, + AccountHeaderAccess.Version | AccountHeaderAccess.Balance | AccountHeaderAccess.Nonce | AccountHeaderAccess.CodeHash | AccountHeaderAccess.CodeSize, + isWrite); + _logger.Info($"AccessCompleteAccount: {address.Bytes.ToHexString()} {isWrite} {gas}"); + return gas; } /// /// When you have to access the certain keys for the account - /// you can specify the keys you want to access using the bitVector. - /// set the bits to true if you want to access the key. - /// bitVector[0] for VersionLeafKey - /// bitVector[1] for BalanceLeafKey - /// bitVector[2] for NonceLeafKey - /// bitVector[3] for CodeKeccakLeafKey - /// bitVector[4] for CodeSizeLeafKey + /// you can specify the keys you want to access using the AccountHeaderAccess. /// /// - /// + /// /// /// - public long AccessAccount(Address address, bool[] bitVector, bool isWrite = false) + private long AccessAccount(Address address, AccountHeaderAccess accessOptions, bool isWrite = false) { long gasUsed = 0; - for (int i = 0; i < bitVector.Length; i++) - { - if (bitVector[i]) - { - gasUsed += AccessKey(VerkleUtils.GetTreeKey(address, UInt256.Zero, (byte)i), isWrite); - } - } - + if ((accessOptions & AccountHeaderAccess.Version) == AccountHeaderAccess.Version) gasUsed += AccessKey(AccountHeader.GetTreeKey(address.Bytes, UInt256.Zero, AccountHeader.Version), isWrite); + if ((accessOptions & AccountHeaderAccess.Balance) == AccountHeaderAccess.Balance) gasUsed += AccessKey(AccountHeader.GetTreeKey(address.Bytes, UInt256.Zero, AccountHeader.Balance), isWrite); + if ((accessOptions & AccountHeaderAccess.Nonce) == AccountHeaderAccess.Nonce) gasUsed += AccessKey(AccountHeader.GetTreeKey(address.Bytes, UInt256.Zero, AccountHeader.Nonce), isWrite); + if ((accessOptions & AccountHeaderAccess.CodeHash) == AccountHeaderAccess.CodeHash) gasUsed += AccessKey(AccountHeader.GetTreeKey(address.Bytes, UInt256.Zero, AccountHeader.CodeHash), isWrite); + if ((accessOptions & AccountHeaderAccess.CodeSize) == AccountHeaderAccess.CodeSize) gasUsed += AccessKey(AccountHeader.GetTreeKey(address.Bytes, UInt256.Zero, AccountHeader.CodeSize), isWrite); + _logger.Info($"AccessAccount: {address.Bytes.ToHexString()} {accessOptions} {isWrite} {gasUsed}"); return gasUsed; } - public long AccessKey(byte[] key, bool isWrite = false) + private long AccessKey(byte[] key, bool isWrite = false, bool leafExist = false) { + Debug.Assert(key.Length == 32); bool newSubTreeAccess = false; - bool newSubTreeWrite = false; bool newLeafAccess = false; - bool newLeafWrite = false; + + bool newSubTreeUpdate = false; + bool newLeafUpdate = false; + bool newLeafFill = false; - if (!_accessedLeaves.Contains((key))) + + if (_accessedLeaves.Add((key))) { newLeafAccess = true; - _accessedLeaves.Add((key)); } - if (!_accessedSubtrees.Add(key[..31])) + if (_accessedSubtrees.Add(key[..31])) { newSubTreeAccess = true; - _accessedSubtrees.Add(key[..31]); } - if (isWrite) + long accessCost = + (newLeafAccess ? WitnessChunkRead : 0) + + (newSubTreeAccess ? WitnessBranchRead : 0); + if (!isWrite) + return accessCost; + + if (_modifiedLeaves.Add((key))) { - if (!_modifiedLeaves.Contains((key))) - { - newLeafWrite = true; - _modifiedLeaves.Add((key)); - // are we just writing or filling the chunk? - implement the difference - } - - if (!_modifiedSubtrees.Add(key[..31])) - { - newSubTreeWrite = true; - _modifiedSubtrees.Add(key[..31]); - } + // newLeafFill = !leafExist; + newLeafUpdate = true; } - return (newLeafAccess ? WitnessChunkRead : 0) + - (newLeafWrite ? WitnessChunkWrite : 0) + - (newLeafFill ? WitnessChunkFill : 0) + - (newSubTreeAccess ? WitnessBranchRead : 0) + - (newSubTreeWrite ? WitnessBranchWrite : 0); + if (_modifiedSubtrees.Add(key[..31])) + { + newSubTreeUpdate = true; + } + long writeCost = + (newLeafUpdate ? WitnessChunkWrite : 0) + + (newLeafFill ? WitnessChunkFill : 0) + + (newSubTreeUpdate ? WitnessBranchWrite : 0); + + return writeCost + accessCost; } public byte[][] GetAccessedKeys() @@ -286,9 +306,8 @@ public int TakeSnapshot() public void Restore(int snapshot) { - int[] Snapshot = _snapshots[snapshot]; - _accessedSubtrees.Restore(Snapshot[0]); - _accessedLeaves.Restore(Snapshot[1]); + int[] witnessSnapshot = _snapshots[snapshot]; + _accessedSubtrees.Restore(witnessSnapshot[0]); + _accessedLeaves.Restore(witnessSnapshot[1]); } - } diff --git a/src/Nethermind/Nethermind.State/VerkleWorldState.cs b/src/Nethermind/Nethermind.State/VerkleWorldState.cs index 714a9dae8a6..76f48993710 100644 --- a/src/Nethermind/Nethermind.State/VerkleWorldState.cs +++ b/src/Nethermind/Nethermind.State/VerkleWorldState.cs @@ -6,13 +6,14 @@ using System.Linq; using Nethermind.Core; using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Core.Resettables; using Nethermind.Core.Specs; using Nethermind.Int256; using Nethermind.Logging; using Nethermind.State.Witnesses; using Nethermind.Trie; -using Nethermind.Verkle; +using Nethermind.Verkle.Tree; namespace Nethermind.State; @@ -30,10 +31,10 @@ public class VerkleWorldState: IWorldState private Change?[] _changes = new Change?[StartCapacity]; private int _currentPosition = Resettable.EmptyPosition; - private readonly VerkleTree _tree; + private readonly VerkleStateTree _tree; private readonly IStorageProvider _storageProvider; - public VerkleWorldState(VerkleTree verkleTree, IKeyValueStore? codeDb, ILogManager? logManager) + public VerkleWorldState(VerkleStateTree verkleTree, IKeyValueStore? codeDb, ILogManager? logManager) { _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); @@ -43,7 +44,7 @@ public VerkleWorldState(VerkleTree verkleTree, IKeyValueStore? codeDb, ILogManag public void Accept(ITreeVisitor? visitor, Keccak? stateRoot, VisitingOptions? visitingOptions = null) { - throw new NotImplementedException(); + _tree.Accept(visitor, stateRoot, visitingOptions); } public void RecalculateStateRoot() @@ -55,7 +56,7 @@ public void RecalculateStateRoot() public Keccak StateRoot { get => new Keccak(_tree.RootHash); - set => throw new InvalidOperationException(); + set => _tree.RootHash = value.Bytes; } @@ -131,7 +132,7 @@ public void InsertCode(Address address, ReadOnlyMemory code, IReleaseSpec if (account.CodeHash != codeHash) { if (_logger.IsTrace) _logger.Trace($" Update {address} C {account.CodeHash} -> {codeHash}"); - Account changedAccount = account.WithChangedCodeHash(codeHash); + Account changedAccount = account.WithChangedCodeHash(codeHash, _codeDb[codeHash.Bytes]); PushUpdate(address, changedAccount); } else if (releaseSpec.IsEip158Enabled && !isGenesis) @@ -382,7 +383,9 @@ private void ReportChanges(IStateTracer stateTracer, Dictionary()).ToArray()); + IEnumerable? versionVal = _tree.Get(headerTreeKey); + if (versionVal is null) return null; + UInt256 version = new UInt256((versionVal ?? Array.Empty()).ToArray()); headerTreeKey[31] = AccountHeader.Balance; UInt256 balance = new UInt256((_tree.Get(headerTreeKey) ?? Array.Empty()).ToArray()); headerTreeKey[31] = AccountHeader.Nonce; @@ -400,7 +403,20 @@ private void SetState(Address address, Account? account) Db.Metrics.StateTreeWrites++; byte[]? headerTreeKey = AccountHeader.GetTreeKeyPrefixAccount(address.Bytes); - if (account != null) _tree.InsertStemBatch(headerTreeKey, account.ToVerkleDict()); + if (account != null) _tree.InsertStemBatch(headerTreeKey.AsSpan()[..31], account.ToVerkleDict()); + if (account!.Code is null) return; + UInt256 chunkId = 0; + CodeChunkEnumerator codeEnumerator = new CodeChunkEnumerator(account.Code); + while (codeEnumerator.TryGetNextChunk(out byte[] chunk)) + { + byte[]? key = AccountHeader.GetTreeKeyForCodeChunk(address.Bytes, chunkId); +#if DEBUG + Console.WriteLine("K: " + EnumerableExtensions.ToString(key)); + Console.WriteLine("V: " + EnumerableExtensions.ToString(chunk)); +#endif + _tree.Insert(key, chunk); + chunkId += 1; + } } private readonly HashSet
_readsForTracing = new HashSet
(); @@ -489,19 +505,19 @@ public byte[] GetOriginal(StorageCell storageCell) } public byte[] Get(StorageCell storageCell) { - return _storageProvider.Get(storageCell); + return _storageProvider.Get(storageCell).WithoutLeadingZeros().ToArray(); } public void Set(StorageCell storageCell, byte[] newValue) { - _storageProvider.Set(storageCell, newValue); + _storageProvider.Set(storageCell, newValue.PadLeft(32)); } public byte[] GetTransientState(StorageCell storageCell) { - return _storageProvider.GetTransientState(storageCell); + return _storageProvider.GetTransientState(storageCell).WithoutLeadingZeros().ToArray(); } public void SetTransientState(StorageCell storageCell, byte[] newValue) { - _storageProvider.SetTransientState(storageCell, newValue); + _storageProvider.SetTransientState(storageCell, newValue.PadLeft(32)); } public void Reset() { diff --git a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs index 29349f2fec9..33a842062cf 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/BlockDownloaderTests.cs @@ -945,7 +945,6 @@ public virtual IBlockTree BlockTree new SyncProgressResolver( BlockTree, ReceiptStorage, - _stateDb, new TrieStore(_stateDb, LimboLogs.Instance), ProgressTracker, syncConfig, diff --git a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs index 206df0a7a40..894b7cd798b 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/OldStyleFullSynchronizerTests.cs @@ -60,7 +60,6 @@ public async Task Setup() SyncProgressResolver resolver = new( _blockTree, _receiptStorage, - _stateDb, trieStore, progressTracker, syncConfig, diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs index 3ef79b813e8..2be528c1de2 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncProgressResolverTests.cs @@ -31,7 +31,7 @@ public void Header_block_is_0_when_no_header_was_suggested() syncConfig.PivotNumber = "1"; ProgressTracker progressTracker = new(blockTree, stateDb, LimboLogs.Instance); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); blockTree.BestSuggestedHeader.Returns((BlockHeader)null); Assert.AreEqual(0, syncProgressResolver.FindBestHeader()); } @@ -46,7 +46,7 @@ public void Best_block_is_0_when_no_block_was_suggested() syncConfig.PivotNumber = "1"; ProgressTracker progressTracker = new(blockTree, stateDb, LimboLogs.Instance); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); blockTree.BestSuggestedBody.Returns((Block)null); Assert.AreEqual(0, syncProgressResolver.FindBestFullBlock()); } @@ -61,7 +61,7 @@ public void Best_state_is_head_when_there_are_no_suggested_blocks() syncConfig.PivotNumber = "1"; ProgressTracker progressTracker = new(blockTree, stateDb, LimboLogs.Instance); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, new TrieStore(stateDb, LimboLogs.Instance), progressTracker, syncConfig, LimboLogs.Instance); var head = Build.A.Block.WithHeader(Build.A.BlockHeader.WithNumber(5).WithStateRoot(TestItem.KeccakA).TestObject).TestObject; blockTree.Head.Returns(head); blockTree.BestSuggestedHeader.Returns(head.Header); @@ -79,7 +79,7 @@ public void Best_state_is_suggested_if_there_is_suggested_block_with_state() syncConfig.PivotNumber = "1"; ProgressTracker progressTracker = new(blockTree, stateDb, LimboLogs.Instance); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, new TrieStore(stateDb, LimboLogs.Instance), progressTracker, syncConfig, LimboLogs.Instance); var head = Build.A.Block.WithHeader(Build.A.BlockHeader.WithNumber(5).WithStateRoot(TestItem.KeccakA).TestObject).TestObject; var suggested = Build.A.BlockHeader.WithNumber(6).WithStateRoot(TestItem.KeccakB).TestObject; blockTree.Head.Returns(head); @@ -100,7 +100,7 @@ public void Best_state_is_head_if_there_is_suggested_block_without_state() syncConfig.PivotNumber = "1"; ProgressTracker progressTracker = new(blockTree, stateDb, LimboLogs.Instance); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, new TrieStore(stateDb, LimboLogs.Instance), progressTracker, syncConfig, LimboLogs.Instance); var head = Build.A.Block.WithHeader(Build.A.BlockHeader.WithNumber(5).WithStateRoot(TestItem.KeccakA).TestObject).TestObject; var suggested = Build.A.BlockHeader.WithNumber(6).WithStateRoot(TestItem.KeccakB).TestObject; blockTree.Head.Returns(head); @@ -122,7 +122,7 @@ public void Is_fast_block_finished_returns_true_when_no_fast_block_sync_is_used( syncConfig.PivotNumber = "1"; ProgressTracker progressTracker = new(blockTree, stateDb, LimboLogs.Instance); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); Assert.True(syncProgressResolver.IsFastBlocksHeadersFinished()); Assert.True(syncProgressResolver.IsFastBlocksBodiesFinished()); Assert.True(syncProgressResolver.IsFastBlocksReceiptsFinished()); @@ -143,7 +143,7 @@ public void Is_fast_block_headers_finished_returns_false_when_headers_not_downlo blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(2).WithStateRoot(TestItem.KeccakA).TestObject); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); Assert.False(syncProgressResolver.IsFastBlocksHeadersFinished()); } @@ -163,7 +163,7 @@ public void Is_fast_block_bodies_finished_returns_false_when_blocks_not_download blockTree.LowestInsertedHeader.Returns(Build.A.BlockHeader.WithNumber(1).WithStateRoot(TestItem.KeccakA).TestObject); blockTree.LowestInsertedBodyNumber.Returns(2); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); Assert.False(syncProgressResolver.IsFastBlocksBodiesFinished()); } @@ -185,7 +185,7 @@ public void Is_fast_block_receipts_finished_returns_false_when_receipts_not_down receiptStorage.LowestInsertedReceiptBlockNumber.Returns(2); SyncProgressResolver syncProgressResolver = new( - blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); Assert.False(syncProgressResolver.IsFastBlocksReceiptsFinished()); } @@ -206,7 +206,7 @@ public void Is_fast_block_bodies_finished_returns_true_when_bodies_not_downloade blockTree.LowestInsertedBodyNumber.Returns(2); receiptStorage.LowestInsertedReceiptBlockNumber.Returns(1); - SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + SyncProgressResolver syncProgressResolver = new(blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); Assert.True(syncProgressResolver.IsFastBlocksBodiesFinished()); } @@ -228,7 +228,7 @@ public void Is_fast_block_receipts_finished_returns_true_when_receipts_not_downl receiptStorage.LowestInsertedReceiptBlockNumber.Returns(2); SyncProgressResolver syncProgressResolver = new( - blockTree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, LimboLogs.Instance); + blockTree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, LimboLogs.Instance); Assert.True(syncProgressResolver.IsFastBlocksReceiptsFinished()); } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs index b662b34c0a3..8910534dbc4 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncThreadTests.cs @@ -348,7 +348,7 @@ private SyncTestContext CreateSyncManager(int index) SnapProvider snapProvider = new(progressTracker, dbProvider, LimboLogs.Instance); SyncProgressResolver resolver = new( - tree, receiptStorage, stateDb, NullTrieNodeResolver.Instance, progressTracker, syncConfig, logManager); + tree, receiptStorage, NullTrieStore.Instance, progressTracker, syncConfig, logManager); TotalDifficultyBetterPeerStrategy bestPeerStrategy = new(LimboLogs.Instance); MultiSyncModeSelector selector = new(resolver, syncPeerPool, syncConfig, No.BeaconSync, bestPeerStrategy, logManager); Pivot pivot = new(syncConfig); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 741c6a35e27..99f09acba84 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -325,7 +325,6 @@ ISyncConfig GetSyncConfig() => SyncProgressResolver syncProgressResolver = new( BlockTree, NullReceiptStorage.Instance, - stateDb, trieStore, progressTracker, syncConfig, diff --git a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs index 8d214c4d221..d1aa0c25346 100644 --- a/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs +++ b/src/Nethermind/Nethermind.Synchronization/ParallelSync/SyncProgressResolver.cs @@ -7,13 +7,10 @@ using Nethermind.Blockchain.Synchronization; using Nethermind.Core; using Nethermind.Core.Crypto; -using Nethermind.Db; using Nethermind.Int256; using Nethermind.Logging; -using Nethermind.State.Snap; using Nethermind.Synchronization.SnapSync; using Nethermind.Trie; -using Nethermind.Trie.Pruning; namespace Nethermind.Synchronization.ParallelSync { @@ -26,8 +23,7 @@ public class SyncProgressResolver : ISyncProgressResolver private readonly IBlockTree _blockTree; private readonly IReceiptStorage _receiptStorage; - private readonly IDb _stateDb; - private readonly ITrieNodeResolver _trieNodeResolver; + private readonly ISyncTrieStore _trieNodeResolver; private readonly ProgressTracker _progressTracker; private readonly ISyncConfig _syncConfig; @@ -39,8 +35,7 @@ public class SyncProgressResolver : ISyncProgressResolver public SyncProgressResolver(IBlockTree blockTree, IReceiptStorage receiptStorage, - IDb stateDb, - ITrieNodeResolver trieNodeResolver, + ISyncTrieStore trieNodeResolver, ProgressTracker progressTracker, ISyncConfig syncConfig, ILogManager logManager) @@ -48,7 +43,6 @@ public SyncProgressResolver(IBlockTree blockTree, _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager)); _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); _receiptStorage = receiptStorage ?? throw new ArgumentNullException(nameof(receiptStorage)); - _stateDb = stateDb ?? throw new ArgumentNullException(nameof(stateDb)); _trieNodeResolver = trieNodeResolver ?? throw new ArgumentNullException(nameof(trieNodeResolver)); _progressTracker = progressTracker ?? throw new ArgumentNullException(nameof(progressTracker)); _syncConfig = syncConfig ?? throw new ArgumentNullException(nameof(syncConfig)); @@ -57,24 +51,6 @@ public SyncProgressResolver(IBlockTree blockTree, _receiptsBarrier = _syncConfig.AncientReceiptsBarrierCalc; } - private bool IsFullySynced(Keccak stateRoot) - { - if (stateRoot == Keccak.EmptyTreeHash) - { - return true; - } - - TrieNode trieNode = _trieNodeResolver.FindCachedOrUnknown(stateRoot); - bool stateRootIsInMemory = trieNode.NodeType != NodeType.Unknown; - // We check whether one of below happened: - // 1) the block has been processed but not yet persisted (pruning) OR - // 2) the block has been persisted and removed from cache already OR - // 3) the full block state has been synced in the state nodes sync (fast sync) - // In 2) and 3) the state root will be saved in the database. - // In fast sync we never save the state root unless all the descendant nodes have been stored in the DB. - return stateRootIsInMemory || _stateDb.Get(stateRoot) is not null; - } - public long FindBestFullState() { // so the full state can be in a few places but there are some best guesses @@ -117,7 +93,7 @@ private long SearchForFullState(BlockHeader startHeader) break; } - if (IsFullySynced(startHeader.StateRoot!)) + if (_trieNodeResolver.IsFullySynced(startHeader.StateRoot!)) { bestFullState = startHeader.Number; break; diff --git a/src/Nethermind/Nethermind.Synchronization/SyncServer.cs b/src/Nethermind/Nethermind.Synchronization/SyncServer.cs index e9b66e919af..20ca71014a7 100644 --- a/src/Nethermind/Nethermind.Synchronization/SyncServer.cs +++ b/src/Nethermind/Nethermind.Synchronization/SyncServer.cs @@ -40,7 +40,7 @@ public class SyncServer : ISyncServer private readonly IReceiptFinder _receiptFinder; private readonly IBlockValidator _blockValidator; private readonly ISealValidator _sealValidator; - private readonly IReadOnlyKeyValueStore _stateDb; + private readonly IReadOnlyKeyValueStore? _stateDb; private readonly IReadOnlyKeyValueStore _codeDb; private readonly IWitnessRepository _witnessRepository; private readonly IGossipPolicy _gossipPolicy; @@ -78,7 +78,7 @@ public SyncServer( _pool = pool ?? throw new ArgumentNullException(nameof(pool)); _syncModeSelector = syncModeSelector ?? throw new ArgumentNullException(nameof(syncModeSelector)); _sealValidator = sealValidator ?? throw new ArgumentNullException(nameof(sealValidator)); - _stateDb = stateDb ?? throw new ArgumentNullException(nameof(stateDb)); + _stateDb = stateDb; _codeDb = codeDb ?? throw new ArgumentNullException(nameof(codeDb)); _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree)); _receiptFinder = receiptFinder ?? throw new ArgumentNullException(nameof(receiptFinder)); diff --git a/src/Nethermind/Nethermind.Trie/ISyncTrieStore.cs b/src/Nethermind/Nethermind.Trie/ISyncTrieStore.cs new file mode 100644 index 00000000000..220fd081561 --- /dev/null +++ b/src/Nethermind/Nethermind.Trie/ISyncTrieStore.cs @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Crypto; + +namespace Nethermind.Trie; + +public interface ISyncTrieStore +{ + bool IsFullySynced(Keccak stateRoot); +} diff --git a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs index c05cace316c..21a7a21b16a 100644 --- a/src/Nethermind/Nethermind.Trie/PatriciaTree.cs +++ b/src/Nethermind/Nethermind.Trie/PatriciaTree.cs @@ -987,7 +987,7 @@ public void Accept(ITreeVisitor visitor, Keccak rootHash, VisitingOptions? visit if (rootHash is null) throw new ArgumentNullException(nameof(rootHash)); visitingOptions ??= VisitingOptions.Default; - using TrieVisitContext trieVisitContext = new() + using TrieVisitContext trieVisitContext = new TrieVisitContext { // hacky but other solutions are not much better, something nicer would require a bit of thinking // we introduced a notion of an account on the visit context level which should have no knowledge of account really diff --git a/src/Nethermind/Nethermind.Trie/Pruning/ITrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/ITrieStore.cs index a98e3559299..e9b83148caa 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/ITrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/ITrieStore.cs @@ -7,7 +7,7 @@ namespace Nethermind.Trie.Pruning { - public interface ITrieStore : ITrieNodeResolver, IReadOnlyKeyValueStore, IDisposable + public interface ITrieStore : ITrieNodeResolver, IStoreWithReorgBoundary, IReadOnlyKeyValueStore, ISyncTrieStore, IDisposable { void CommitNode(long blockNumber, NodeCommitInfo nodeCommitInfo); @@ -16,7 +16,10 @@ public interface ITrieStore : ITrieNodeResolver, IReadOnlyKeyValueStore, IDispos bool IsPersisted(Keccak keccak); IReadOnlyTrieStore AsReadOnly(IKeyValueStore? keyValueStore); + } + public interface IStoreWithReorgBoundary + { event EventHandler? ReorgBoundaryReached; } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/NullTrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/NullTrieStore.cs index e1b5203009a..d85d77e266b 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/NullTrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/NullTrieStore.cs @@ -45,5 +45,6 @@ public byte[] LoadRlp(Keccak hash) public void Dispose() { } public byte[]? this[byte[] key] => null; + public bool IsFullySynced(Keccak stateRoot) => false; } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/ReadOnlyTrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/ReadOnlyTrieStore.cs index 4ba2d2fd4bf..93a5e3564eb 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/ReadOnlyTrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/ReadOnlyTrieStore.cs @@ -48,5 +48,6 @@ public event EventHandler ReorgBoundaryReached public void Dispose() { } public byte[]? this[byte[] key] => _trieStore[key]; + public bool IsFullySynced(Keccak stateRoot) => _trieStore.IsFullySynced(stateRoot); } } diff --git a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs index ab42a23e449..5c6b7878dff 100644 --- a/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs +++ b/src/Nethermind/Nethermind.Trie/Pruning/TrieStore.cs @@ -831,5 +831,16 @@ public byte[]? this[byte[] key] ? trieNode.FullRlp : _currentBatch?[key] ?? _keyValueStore[key]; } + public bool IsFullySynced(Keccak stateRoot) + { + if (stateRoot == Keccak.EmptyTreeHash) + { + return true; + } + + TrieNode trieNode = FindCachedOrUnknown(stateRoot); + bool stateRootIsInMemory = trieNode.NodeType != NodeType.Unknown; + return stateRootIsInMemory || _keyValueStore[stateRoot.Bytes] is not null; + } } } diff --git a/src/Nethermind/Nethermind.Trie/VerkleUtils.cs b/src/Nethermind/Nethermind.Trie/VerkleUtils.cs deleted file mode 100644 index 925afa2677e..00000000000 --- a/src/Nethermind/Nethermind.Trie/VerkleUtils.cs +++ /dev/null @@ -1,222 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited -// SPDX-License-Identifier: LGPL-3.0-only - -using System; -using Nethermind.Core; -using Nethermind.Int256; - -namespace Nethermind.Trie; - -public static class PedersenHash -{ - public static byte[] CalculatePedersenHash(Span keyPrefix) - { - throw new ArgumentException(); - } -} - -public static unsafe class VerkleUtils -{ - public const int VersionLeafKey = 0; - public const int BalanceLeafKey = 1; - public const int NonceLeafKey = 2; - public const int CodeKeccakLeafKey = 3; - public const int CodeSizeLeafKey = 4; - - const int MainStorageOffsetExponent = 31; - - static readonly UInt256 HeaderStorageOffset = 64; - static readonly UInt256 CodeOffset = 128; - static readonly UInt256 VerkleNodeWidth = 256; - - static readonly UInt256 MainStorageOffsetBase = 256; - static readonly UInt256 MainStorageOffset = MainStorageOffsetBase << MainStorageOffsetExponent; - - public static byte[] GetTreeKeyPrefix(Address address, UInt256 treeIndex) - { - // allocate the array on stack - Span keyPrefix = stackalloc byte[64]; - // first 12 bytes are '0' padding to convert 12 byte address -> 32 bytes - // Span cursor = keyPrefix.Slice(12); - Span cursor = keyPrefix.Slice(0); - address.Bytes.CopyTo(cursor); - // copy the address to the remaining 20 bytes - - //TODO: correct this when geth corrects it, it should be left padded and not right - // cursor = cursor.Slice(20); - cursor = cursor.Slice(32); - // copy the tree index to the remaining 32 bytes - treeIndex.ToBigEndian(cursor); - byte[] prefix = PedersenHash.CalculatePedersenHash(keyPrefix); - prefix[31] = 0; - return prefix; - } - - public static byte[] GetTreeKeyPrefixAccount(Address address) => GetTreeKeyPrefix(address, 0); - - public static byte[] GetTreeKey(Address address, UInt256 treeIndex, byte subIndexBytes) - { - byte[] treeKeyPrefix = GetTreeKeyPrefix(address, treeIndex); - treeKeyPrefix[31] = subIndexBytes; - return treeKeyPrefix; - } - - public static byte[] GetTreeKeyForVersion(Address address) => GetTreeKey(address, UInt256.Zero, VersionLeafKey); - public static byte[] GetTreeKeyForBalance(Address address) => GetTreeKey(address, UInt256.Zero, BalanceLeafKey); - public static byte[] GetTreeKeyForNonce(Address address) => GetTreeKey(address, UInt256.Zero, NonceLeafKey); - public static byte[] GetTreeKeyForCodeKeccak(Address address) => GetTreeKey(address, UInt256.Zero, CodeKeccakLeafKey); - public static byte[] GetTreeKeyForCodeSize(Address address) => GetTreeKey(address, UInt256.Zero, CodeSizeLeafKey); - - public static byte[] GetTreeKeyForCodeChunk(Address address, UInt256 chunk) - { - UInt256 chunkOffset = CodeOffset + chunk; - - UInt256 treeIndex = chunkOffset / VerkleNodeWidth; - - UInt256.Mod(chunkOffset, VerkleNodeWidth, out UInt256 subIndex); - return GetTreeKey(address, treeIndex, subIndex.ToBigEndian()[31]); - } - - public static byte[] GetTreeKeyForStorageSlot(Address address, UInt256 storageKey) - { - UInt256 pos; - - if (storageKey < CodeOffset - HeaderStorageOffset) - { - pos = HeaderStorageOffset + storageKey; - } - else - { - pos = MainStorageOffset + storageKey; - } - - UInt256 treeIndex = pos / VerkleNodeWidth; - - UInt256.Mod(pos, VerkleNodeWidth, out UInt256 subIndex); - return GetTreeKey(address, treeIndex, subIndex.ToBigEndian()[31]); - } - - - public static void FillTreeAndSubIndexForChunk(UInt256 chunkId, ref Span subIndexBytes, out UInt256 treeIndex) - { - UInt256 chunkOffset = CodeOffset + chunkId; - treeIndex = chunkOffset / VerkleNodeWidth; - UInt256.Mod(chunkOffset, VerkleNodeWidth, out UInt256 subIndex); - subIndex.ToBigEndian(subIndexBytes); - } - - public ref struct CodeChunkEnumerator - { - const byte PushOffset = 95; - const byte Push1 = PushOffset + 1; - const byte Push32 = PushOffset + 32; - - private Span _code; - private byte _rollingOverPushLength = 0; - private readonly byte[] _bufferChunk = new byte[32]; - private readonly Span _bufferChunkCodePart; - - public CodeChunkEnumerator(Span code) - { - _code = code; - _bufferChunkCodePart = _bufferChunk.AsSpan().Slice(1); - } - - // Try get next chunk - public bool TryGetNextChunk(out byte[] chunk) - { - chunk = _bufferChunk; - - // we don't have chunks left - if (_code.IsEmpty) - { - return false; - } - - // we don't have full chunk - if (_code.Length < 31) - { - // need to have trailing zeroes - _bufferChunkCodePart.Fill(0); - - // set number of push bytes - _bufferChunk[0] = _rollingOverPushLength; - - // copy main bytes - _code.CopyTo(_bufferChunkCodePart); - - // we are done - _code = Span.Empty; - } - else - { - // fill up chunk to store - - // get current chunk of code - Span currentChunk = _code.Slice(0, 31); - - // copy main bytes - currentChunk.CopyTo(_bufferChunkCodePart); - - switch (_rollingOverPushLength) - { - case 32 or 31: // all bytes are roll over - - // set number of push bytes - _bufferChunk[0] = 31; - - // if 32, then we will roll over with 1 to even next chunk - _rollingOverPushLength -= 31; - break; - default: - // set number of push bytes - _bufferChunk[0] = _rollingOverPushLength; - _rollingOverPushLength = 0; - - // check if we have a push instruction in remaining code - // ignore the bytes we rolled over, they are not instructions - for (int i = _bufferChunk[0]; i < 31;) - { - byte instruction = currentChunk[i]; - i++; - if (instruction is >= Push1 and <= Push32) - { - // we calculate data to ignore in code - i += instruction - PushOffset; - - // check if we rolled over the chunk - _rollingOverPushLength = (byte)Math.Max(i - 31, 0); - } - } - - break; - } - - // move to next chunk - _code = _code.Slice(31); - } - - return true; - } - } - - public static byte[,] To2D(byte[][] jagged) - { - byte[,] keys = new byte[jagged.Length, 32]; - unsafe - { - for (int i = 0; i < jagged.Length; i++) - { - fixed (byte* pInKey = jagged[i]) - { - fixed (byte* pOutKey = &keys[i, 0]) - { - Buffer.MemoryCopy(pInKey, pOutKey, 32, 32); - } - } - } - } - - return keys; - } - -} diff --git a/src/Nethermind/Nethermind.Trie/VisitContext.cs b/src/Nethermind/Nethermind.Trie/VisitContext.cs index 49eb15a9713..ce8b3a95415 100644 --- a/src/Nethermind/Nethermind.Trie/VisitContext.cs +++ b/src/Nethermind/Nethermind.Trie/VisitContext.cs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LGPL-3.0-only using System; +using System.Collections.Generic; using System.Threading; namespace Nethermind.Trie @@ -11,15 +12,31 @@ public class TrieVisitContext : IDisposable private SemaphoreSlim? _semaphore; private readonly int _maxDegreeOfParallelism = 1; - public int Level { get; internal set; } + public int Level { get; set; } public bool IsStorage { get; internal set; } public int? BranchChildIndex { get; internal set; } public bool ExpectAccounts { get; init; } + public bool KeepTrackOfAbsolutePath { get; init; } + + private List? _absolutePathIndex; + + public List AbsolutePathIndex => _absolutePathIndex ??= new List(); + public int MaxDegreeOfParallelism { get => _maxDegreeOfParallelism; - internal init => _maxDegreeOfParallelism = value == 0 ? Environment.ProcessorCount : value; + init => _maxDegreeOfParallelism = value == 0 ? Environment.ProcessorCount : value; + } + + public AbsolutePathStruct AbsolutePathNext(byte[] path) + { + return new AbsolutePathStruct(!KeepTrackOfAbsolutePath ? null : AbsolutePathIndex, path); + } + + public AbsolutePathStruct AbsolutePathNext(byte path) + { + return new AbsolutePathStruct(!KeepTrackOfAbsolutePath ? null : AbsolutePathIndex, path); } public SemaphoreSlim Semaphore @@ -43,4 +60,31 @@ public void Dispose() _semaphore?.Dispose(); } } + + + public readonly ref struct AbsolutePathStruct + { + public AbsolutePathStruct(List? absolutePath, IReadOnlyCollection? path) + { + _absolutePath = absolutePath; + _pathLength = path!.Count; + _absolutePath?.AddRange(path!); + } + + public AbsolutePathStruct(List? absolutePath, byte path) + { + _absolutePath = absolutePath; + _pathLength = 1; + _absolutePath?.Add(path); + } + + private readonly List? _absolutePath; + private readonly int _pathLength; + + public void Dispose() + { + if (_pathLength > 0) + _absolutePath?.RemoveRange(_absolutePath.Count - _pathLength, _pathLength); + } + } } diff --git a/src/Nethermind/Nethermind.TxPool.Test/Nethermind.TxPool.Test.csproj b/src/Nethermind/Nethermind.TxPool.Test/Nethermind.TxPool.Test.csproj index 835864e8ea5..912dcb672d8 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/Nethermind.TxPool.Test.csproj +++ b/src/Nethermind/Nethermind.TxPool.Test/Nethermind.TxPool.Test.csproj @@ -17,6 +17,7 @@ + diff --git a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs index fe59bdc0605..04d564f79c2 100644 --- a/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs +++ b/src/Nethermind/Nethermind.TxPool.Test/TxPoolTests.cs @@ -30,14 +30,29 @@ using Nethermind.State; using Nethermind.Trie.Pruning; using Nethermind.TxPool.Filters; +using Nethermind.Verkle; using NSubstitute; using NUnit.Framework; namespace Nethermind.TxPool.Test { - [TestFixture] + [TestFixture(VirtualMachineTestsStateProvider.MerkleTrie)] + [TestFixture(VirtualMachineTestsStateProvider.VerkleTrie)] public class TxPoolTests { + private readonly VirtualMachineTestsStateProvider _stateProviderType; + + public enum VirtualMachineTestsStateProvider + { + MerkleTrie, + VerkleTrie + } + + public TxPoolTests(VirtualMachineTestsStateProvider stateProvider) + { + _stateProviderType = stateProvider; + } + private ILogManager _logManager; private IEthereumEcdsa _ethereumEcdsa; private ISpecProvider _specProvider; @@ -53,9 +68,20 @@ public void Setup() _logManager = LimboLogs.Instance; _specProvider = RopstenSpecProvider.Instance; _ethereumEcdsa = new EthereumEcdsa(_specProvider.ChainId, _logManager); - var trieStore = new TrieStore(new MemDb(), _logManager); - var codeDb = new MemDb(); - _stateProvider = new WorldState(trieStore, codeDb, _logManager); + + if (_stateProviderType == VirtualMachineTestsStateProvider.MerkleTrie) + { + var trieStore = new TrieStore(new MemDb(), _logManager); + var codeDb = new MemDb(); + _stateProvider = new WorldState(trieStore, codeDb, _logManager); + } + else + { + var codeDb = new MemDb(); + IDbProvider provider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null); + _stateProvider = new VerkleWorldState(new VerkleStateTree(provider), codeDb, _logManager); + } + _blockTree = Substitute.For(); Block block = Build.A.Block.WithNumber(0).TestObject; _blockTree.Head.Returns(block); diff --git a/src/Nethermind/Nethermind.Verkle.Proofs.Test/IPATests.cs b/src/Nethermind/Nethermind.Verkle.Proofs.Test/IPATests.cs new file mode 100644 index 00000000000..08656025540 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs.Test/IPATests.cs @@ -0,0 +1,94 @@ +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Polynomial; + + +namespace Nethermind.Verkle.Proofs.Test +{ + public class IpaTests + { + private readonly FrE[] _poly = + { + FrE.SetElement(1), FrE.SetElement(2), FrE.SetElement(3), FrE.SetElement(4), FrE.SetElement(5), FrE.SetElement(6), FrE.SetElement(7), FrE.SetElement(8), FrE.SetElement(9), FrE.SetElement(10), FrE.SetElement(11), FrE.SetElement(12), FrE.SetElement(13), + FrE.SetElement(14), FrE.SetElement(15), FrE.SetElement(16), FrE.SetElement(17), FrE.SetElement(18), FrE.SetElement(19), FrE.SetElement(20), FrE.SetElement(21), FrE.SetElement(22), FrE.SetElement(23), FrE.SetElement(24), FrE.SetElement(25), FrE.SetElement(26), + FrE.SetElement(27), FrE.SetElement(28), FrE.SetElement(29), FrE.SetElement(30), FrE.SetElement(31), FrE.SetElement(32) + }; + + + [Test] + public void TestBasicIpaProof() + { + FrE[] domain = new FrE[256]; + for (int i = 0; i < 256; i++) + { + domain[i] = FrE.SetElement(i); + } + + PreComputeWeights weights = PreComputeWeights.Init(); + + List lagrangePoly = new List(); + + for (int i = 0; i < 8; i++) + { + lagrangePoly.AddRange(_poly); + } + + CRS crs = CRS.Instance; + Banderwagon commitment = crs.Commit(lagrangePoly.ToArray()); + + Assert.That(Convert.ToHexString(commitment.ToBytes()).ToLower() + .SequenceEqual("1b9dff8f5ebbac250d291dfe90e36283a227c64b113c37f1bfb9e7a743cdb128")); + + Transcript proverTranscript = new Transcript("test"); + + FrE inputPoint = FrE.SetElement(2101); + FrE[] b = weights.BarycentricFormulaConstants(inputPoint); + IpaProverQuery query = new IpaProverQuery(lagrangePoly.ToArray(), commitment, inputPoint, b); + + List cache = new List(); + foreach (FrE i in lagrangePoly) + { + cache.AddRange(i.ToBytes().ToArray()); + } + cache.AddRange(commitment.ToBytes()); + cache.AddRange(inputPoint.ToBytes().ToArray()); + foreach (FrE i in b) + { + cache.AddRange(i.ToBytes().ToArray()); + } + + (FrE outputPoint, IpaProofStruct proof) = Ipa.MakeIpaProof(crs, proverTranscript, query); + FrE pChallenge = proverTranscript.ChallengeScalar("state"); + + Assert.That(Convert.ToHexString(pChallenge.ToBytes()).ToLower() + .SequenceEqual("0a81881cbfd7d7197a54ebd67ed6a68b5867f3c783706675b34ece43e85e7306")); + + Transcript verifierTranscript = new Transcript("test"); + + IpaVerifierQuery queryX = new IpaVerifierQuery(commitment, inputPoint, b, outputPoint, proof); + + bool ok = Ipa.CheckIpaProof(crs, verifierTranscript, queryX); + + Assert.That(ok); + } + + [Test] + public void TestInnerProduct() + { + FrE[] a = + { + FrE.SetElement(1), FrE.SetElement(2), FrE.SetElement(3), FrE.SetElement(4), FrE.SetElement(5) + }; + + FrE[] b = + { + FrE.SetElement(10), FrE.SetElement(12), FrE.SetElement(13), FrE.SetElement(14), FrE.SetElement(15) + }; + + FrE expectedResult = FrE.SetElement(204); + + FrE gotResult = Ipa.InnerProduct(a, b); + Assert.That(gotResult, Is.EqualTo(expectedResult)); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs.Test/MultiProofTests.cs b/src/Nethermind/Nethermind.Verkle.Proofs.Test/MultiProofTests.cs new file mode 100644 index 00000000000..03785c166e3 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs.Test/MultiProofTests.cs @@ -0,0 +1,168 @@ +using Nethermind.Core.Extensions; +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Polynomial; + +namespace Nethermind.Verkle.Proofs.Test +{ + public class MultiProofTests + { + private readonly FrE[] _poly = + { + FrE.SetElement(1), FrE.SetElement(2), FrE.SetElement(3), FrE.SetElement(4), FrE.SetElement(5), FrE.SetElement(6), FrE.SetElement(7), FrE.SetElement(8), FrE.SetElement(9), FrE.SetElement(10), FrE.SetElement(11), FrE.SetElement(12), FrE.SetElement(13), + FrE.SetElement(14), FrE.SetElement(15), FrE.SetElement(16), FrE.SetElement(17), FrE.SetElement(18), FrE.SetElement(19), FrE.SetElement(20), FrE.SetElement(21), FrE.SetElement(22), FrE.SetElement(23), FrE.SetElement(24), FrE.SetElement(25), FrE.SetElement(26), + FrE.SetElement(27), FrE.SetElement(28), FrE.SetElement(29), FrE.SetElement(30), FrE.SetElement(31), FrE.SetElement(32) + }; + + [Test] + public void TestBasicMultiProof() + { + List polyEvalA = new List(); + List polyEvalB = new List(); + + for (int i = 0; i < 8; i++) + { + polyEvalA.AddRange(_poly); + polyEvalB.AddRange(_poly.Reverse()); + } + CRS crs = CRS.Instance; + Banderwagon cA = crs.Commit(polyEvalA.ToArray()); + Banderwagon cB = crs.Commit(polyEvalB.ToArray()); + + FrE[] zs = + { + FrE.Zero, FrE.Zero + }; + FrE[] ys = + { + FrE.SetElement(1), FrE.SetElement(32) + }; + FrE[][] fs = + { + polyEvalA.ToArray(), polyEvalB.ToArray() + }; + + Banderwagon[] cs = + { + cA, cB + }; + + + VerkleProverQuery queryA = new VerkleProverQuery(new LagrangeBasis(fs[0]), cs[0], zs[0], ys[0]); + VerkleProverQuery queryB = new VerkleProverQuery(new LagrangeBasis(fs[1]), cs[1], zs[1], ys[1]); + + MultiProof multiproof = new MultiProof(crs, PreComputeWeights.Init()); + + Transcript proverTranscript = new Transcript("test"); + VerkleProverQuery[] queries = + { + queryA, queryB + }; + VerkleProofStruct proof = multiproof.MakeMultiProof(proverTranscript, new List(queries)); + FrE pChallenge = proverTranscript.ChallengeScalar("state"); + + Assert.IsTrue(Convert.ToHexString(pChallenge.ToBytes()).ToLower() + .SequenceEqual("eee8a80357ff74b766eba39db90797d022e8d6dee426ded71234241be504d519")); + + Transcript verifierTranscript = new Transcript("test"); + VerkleVerifierQuery queryAx = new VerkleVerifierQuery(cs[0], zs[0], ys[0]); + VerkleVerifierQuery queryBx = new VerkleVerifierQuery(cs[1], zs[1], ys[1]); + + VerkleVerifierQuery[] queriesX = + { + queryAx, queryBx + }; + bool ok = multiproof.CheckMultiProof(verifierTranscript, queriesX, proof); + Assert.That(ok, Is.True); + + FrE vChallenge = verifierTranscript.ChallengeScalar("state"); + Assert.That(vChallenge, Is.EqualTo(pChallenge)); + } + + [Test] + public void TestMultiProofConsistency() + { + FrE[] polyA = TestPoly256(new ulong[] + { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 + } + ); + + FrE[] polyB = TestPoly256(new ulong[] + { + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 + } + ); + + Transcript proverTranscript = new Transcript("test"); + + CRS cfg = CRS.Instance; + + Banderwagon commA = cfg.Commit(polyA); + Banderwagon commB = cfg.Commit(polyB); + + var one = FrE.One; + var thirtyTwo = FrE.SetElement(32); + + VerkleProverQuery queryA = new VerkleProverQuery(new LagrangeBasis(polyA), commA, FrE.SetElement(0), one); + VerkleProverQuery queryB = new VerkleProverQuery(new LagrangeBasis(polyB), commB, FrE.SetElement(0), thirtyTwo); + + MultiProof multiproof = new MultiProof(cfg, PreComputeWeights.Init()); + List queries = new List + { + queryA, + queryB + }; + + VerkleProofStruct proof = multiproof.MakeMultiProof(proverTranscript, queries); + FrE pChallenge = proverTranscript.ChallengeScalar("state"); + + string pChallengeExcepted = "eee8a80357ff74b766eba39db90797d022e8d6dee426ded71234241be504d519"; + Assert.IsTrue(pChallenge.ToBytes().ToHexString().SequenceEqual(pChallengeExcepted)); + + string expectedProof = + "4f53588244efaf07a370ee3f9c467f933eed360d4fbf7a19dfc8bc49b67df4711bf1d0a720717cd6a8c75f1a668cb7cbdd63b48c676b89a7aee4298e71bd7" + + "f4013d7657146aa9736817da47051ed6a45fc7b5a61d00eb23e5df82a7f285cc10e67d444e91618465ca68d8ae4f2c916d1942201b7e2aae491ef0f809867" + + "d00e83468fb7f9af9b42ede76c1e90d89dd789ff22eb09e8b1d062d8a58b6f88b3cbe80136fc68331178cd45a1df9496ded092d976911b5244b85bc3de41e" + + "844ec194256b39aeee4ea55538a36139211e9910ad6b7a74e75d45b869d0a67aa4bf600930a5f760dfb8e4df9938d1f47b743d71c78ba8585e3b80aba26d2" + + "4b1f50b36fa1458e79d54c05f58049245392bc3e2b5c5f9a1b99d43ed112ca82b201fb143d401741713188e47f1d6682b0bf496a5d4182836121efff0fd3b" + + "030fc6bfb5e21d6314a200963fe75cb856d444a813426b2084dfdc49dca2e649cb9da8bcb47859a4c629e97898e3547c591e39764110a224150d579c33fb7" + + "4fa5eb96427036899c04154feab5344873d36a53a5baefd78c132be419f3f3a8dd8f60f72eb78dd5f43c53226f5ceb68947da3e19a750d760fb31fa8d4c7f" + + "53bfef11c4b89158aa56b1f4395430e16a3128f88e234ce1df7ef865f2d2c4975e8c82225f578310c31fd41d265fd530cbfa2b8895b228a510b806c31dff3" + + "b1fa5c08bffad443d567ed0e628febdd22775776e0cc9cebcaea9c6df9279a5d91dd0ee5e7a0434e989a160005321c97026cb559f71db23360105460d959b" + + "cdf74bee22c4ad8805a1d497507"; + + Assert.IsTrue(proof.Encode().ToHexString().SequenceEqual(expectedProof)); + } + + private static FrE[] TestPoly256(ulong[] polynomial) + { + FrE[] poly = new FrE[256]; + for (int i = 0; i < 256; i++) + { + poly[i] = FrE.Zero; + } + + for (int i = 0; i < polynomial.Length; i++) + { + poly[i] = FrE.SetElement(polynomial[i]); + } + + return poly; + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs.Test/Nethermind.Verkle.Proofs.Test.csproj b/src/Nethermind/Nethermind.Verkle.Proofs.Test/Nethermind.Verkle.Proofs.Test.csproj new file mode 100644 index 00000000000..202e1c32a49 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs.Test/Nethermind.Verkle.Proofs.Test.csproj @@ -0,0 +1,25 @@ + + + + net7.0 + enable + enable + + false + + Verkle.Proofs.Test + + + + + + + + + + + + + + + diff --git a/src/Nethermind/Nethermind.Verkle.Proofs.Test/TranscriptTests.cs b/src/Nethermind/Nethermind.Verkle.Proofs.Test/TranscriptTests.cs new file mode 100644 index 00000000000..52ea820bed9 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs.Test/TranscriptTests.cs @@ -0,0 +1,99 @@ +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; + +namespace Nethermind.Verkle.Proofs.Test +{ + public class TranscriptTests + { + [Test] + public void TestProverVerifierConsistency() + { + Banderwagon point = Banderwagon.Generator(); + Random random = new Random(); + byte[] data = new byte[32]; + random.NextBytes(data); + FrE scalar = new FrE(data); + + Transcript proverTranscript = new Transcript("protocol_name"); + + proverTranscript.AppendPoint(point, "D"); + proverTranscript.DomainSep("sub_protocol_name"); + proverTranscript.AppendScalar(scalar, "r"); + + FrE proverQ = proverTranscript.ChallengeScalar("q"); + + Transcript verifierTranscript = new Transcript("protocol_name"); + + verifierTranscript.AppendPoint(point, "D"); + verifierTranscript.DomainSep("sub_protocol_name"); + verifierTranscript.AppendScalar(scalar, "r"); + + FrE verifierQ = verifierTranscript.ChallengeScalar("q"); + + Assert.That(proverQ, Is.EqualTo(verifierQ)); + } + + [Test] + public void TestVector0() + { + Transcript transcript = new Transcript("foo"); + FrE firstChallenge = transcript.ChallengeScalar("f"); + FrE secondChallenge = transcript.ChallengeScalar("f"); + Assert.IsTrue(!firstChallenge.Equals(secondChallenge)); + } + + [Test] + public void TestVector1() + { + Transcript transcript = new Transcript("simple_protocol"); + FrE challenge = transcript.ChallengeScalar("simple_challenge"); + Assert.That(Convert.ToHexString(challenge.ToBytes()).ToLower() + .SequenceEqual("c2aa02607cbdf5595f00ee0dd94a2bbff0bed6a2bf8452ada9011eadb538d003")); + } + + [Test] + public void TestVector2() + { + Transcript transcript = new Transcript("simple_protocol"); + FrE scalar = FrE.SetElement(5); + + transcript.AppendScalar(scalar, "five"); + transcript.AppendScalar(scalar, "five again"); + + FrE challenge = transcript.ChallengeScalar("simple_challenge"); + Assert.That(Convert.ToHexString(challenge.ToBytes()).ToLower() + .SequenceEqual("498732b694a8ae1622d4a9347535be589e4aee6999ffc0181d13fe9e4d037b0b"), Is.True); + } + + [Test] + public void TestVector3() + { + Transcript transcript = new Transcript("simple_protocol"); + FrE minusOne = FrE.SetElement(-1); + FrE one = FrE.SetElement(1); + transcript.AppendScalar(minusOne, "-1"); + transcript.DomainSep("separate me"); + transcript.AppendScalar(minusOne, "-1 again"); + transcript.DomainSep("separate me again"); + transcript.AppendScalar(one, "now 1"); + + FrE challenge = transcript.ChallengeScalar("simple_challenge"); + Assert.That(Convert.ToHexString(challenge.ToBytes()).ToLower() + .SequenceEqual("14f59938e9e9b1389e74311a464f45d3d88d8ac96adf1c1129ac466de088d618"), Is.True); + } + + [Test] + public void TestVector4() + { + Transcript transcript = new Transcript("simple_protocol"); + + Banderwagon generator = Banderwagon.Generator(); + + transcript.AppendPoint(generator, "generator"); + FrE challenge = transcript.ChallengeScalar("simple_challenge"); + + Assert.That(Convert.ToHexString(challenge.ToBytes()).ToLower() + .SequenceEqual("8c2dafe7c0aabfa9ed542bb2cbf0568399ae794fc44fdfd7dff6cc0e6144921c"), Is.True); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs.Test/Usings.cs b/src/Nethermind/Nethermind.Verkle.Proofs.Test/Usings.cs new file mode 100644 index 00000000000..324456763af --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs.Test/Usings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; diff --git a/src/Nethermind/Nethermind.Verkle.Proofs/IPA.cs b/src/Nethermind/Nethermind.Verkle.Proofs/IPA.cs new file mode 100644 index 00000000000..afc2d55df60 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs/IPA.cs @@ -0,0 +1,226 @@ +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; + +namespace Nethermind.Verkle.Proofs +{ + public static class Ipa + { + private static Banderwagon VarBaseCommit(FrE[] values, Banderwagon[] elements) + { + return Banderwagon.MSM(elements, values); + } + + public static FrE InnerProduct(IEnumerable a, IEnumerable b) + { + FrE result = FrE.SetElement(); + + foreach ((FrE aI, FrE bI) in a.Zip(b)) + { + FrE.MultiplyMod(aI, bI, out FrE term); + result += term; + } + + return result; + } + + public static (FrE Y, IpaProofStruct Proof) MakeIpaProof(CRS crs, Transcript transcript, + IpaProverQuery query) + { + transcript.DomainSep("ipa"); + + int n = query._polynomial.Length; + int m = n / 2; + FrE[] a = query._polynomial; + FrE[] b = query._pointEvaluations; + FrE y = InnerProduct(a, b); + + IpaProofStruct ipaProof = new IpaProofStruct(new List(), FrE.Zero, new List()); + + transcript.AppendPoint(query._commitment, "C"u8.ToArray()); + transcript.AppendScalar(query._point, "input point"u8.ToArray()); + transcript.AppendScalar(y, "output point"u8.ToArray()); + FrE w = transcript.ChallengeScalar("w"u8.ToArray()); + + Banderwagon q = crs.BasisQ * w; + + Banderwagon[] currentBasis = crs.BasisG; + + while (n > 1) + { + FrE[] aL = a[..m]; + FrE[] aR = a[m..]; + FrE[] bL = b[..m]; + FrE[] bR = b[m..]; + FrE zL = InnerProduct(aR, bL); + FrE zR = InnerProduct(aL, bR); + + Banderwagon cL = VarBaseCommit(aR, currentBasis[..m]) + q * zL; + Banderwagon cR = VarBaseCommit(aL, currentBasis[m..]) + q * zR; + + ipaProof._l.Add(cL); + ipaProof._r.Add(cR); + + transcript.AppendPoint(cL, "L"u8.ToArray()); + transcript.AppendPoint(cR, "R"u8.ToArray()); + FrE x = transcript.ChallengeScalar("x"u8.ToArray()); + + FrE.Inverse(x, out FrE xInv); + + a = new FrE[aL.Length]; + int i = 0; + foreach ((FrE v1, FrE v2) in aL.Zip(aR)) + { + a[i] = v1 + x * v2; + i++; + } + + b = new FrE[aL.Length]; + i = 0; + foreach ((FrE v1, FrE v2) in bL.Zip(bR)) + { + b[i] = v1 + xInv * v2; + i++; + } + + Banderwagon[] currentBasisN = new Banderwagon[m]; + i = 0; + foreach ((Banderwagon v1, Banderwagon v2) in currentBasis[..m].Zip(currentBasis[m..])) + { + currentBasisN[i] = v1 + v2 * xInv; + i++; + } + + currentBasis = currentBasisN; + n = m; + m = n / 2; + } + + ipaProof._a = a[0]; + + return (y, ipaProof); + } + + public static bool CheckIpaProof(CRS crs, Transcript transcript, + IpaVerifierQuery query) + { + transcript.DomainSep("ipa"u8.ToArray()); + + int n = query._pointEvaluations.Length; + int m = n / 2; + + + Banderwagon c = query._commitment; + FrE z = query._point; + FrE[] b = query._pointEvaluations; + IpaProofStruct ipaProof = query._ipaProof; + FrE y = query._outputPoint; + + transcript.AppendPoint(c, "C"u8.ToArray()); + transcript.AppendScalar(z, "input point"u8.ToArray()); + transcript.AppendScalar(y, "output point"u8.ToArray()); + FrE w = transcript.ChallengeScalar("w"u8.ToArray()); + + Banderwagon q = crs.BasisQ * w; + + Banderwagon currentCommitment = c + q * y; + + int i = 0; + List xs = new List(); + List xInvList = new List(); + + + while (n > 1) + { + Banderwagon cL = ipaProof._l[i]; + Banderwagon cR = ipaProof._r[i]; + + transcript.AppendPoint(cL, "L"u8.ToArray()); + transcript.AppendPoint(cR, "R"u8.ToArray()); + FrE x = transcript.ChallengeScalar("x"u8.ToArray()); + + FrE.Inverse(in x, out FrE xInv); + + xs.Add(x); + xInvList.Add(xInv); + + currentCommitment = currentCommitment + cL * x + cR * xInv; + n = m; + m = n / 2; + i += 1; + } + + Banderwagon[] currentBasis = crs.BasisG; + + for (int j = 0; j < xs.Count; j++) + { + (Banderwagon[] gL, Banderwagon[] gR) = SplitPoints(currentBasis); + (FrE[] bL, FrE[] bR) = SplitScalars(b); + + FrE xInv = xInvList[j]; + + b = FoldScalars(bL, bR, xInv); + currentBasis = FoldPoints(gL, gR, xInv); + + } + + if (b.Length != currentBasis.Length) + throw new Exception(); + + if (b.Length != 1) + throw new Exception(); + FrE b0 = b[0]; + Banderwagon g0 = currentBasis[0]; + + Banderwagon gotCommitment = g0 * ipaProof._a + q * (ipaProof._a * b0); + + return currentCommitment == gotCommitment; + } + + private static (T[] firstHalf, T[] secondHalf) SplitListInHalf(T[] x) + { + if (x.Length % 2 != 0) + throw new Exception(); + + int mid = x.Length / 2; + return (x[..mid], x[mid..]); + } + + private static (Banderwagon[] firstHalf, Banderwagon[] secondHalf) SplitPoints(Banderwagon[] x) + { + return SplitListInHalf(x); + } + + private static (FrE[] firstHalf, FrE[] secondHalf) SplitScalars(FrE[] x) + { + return SplitListInHalf(x); + } + + private static FrE[] FoldScalars(IReadOnlyList a, IReadOnlyList b, FrE foldingChallenge) + { + if (a.Count != b.Count) + throw new Exception(); + + FrE[] result = new FrE[a.Count]; + for (int i = 0; i < a.Count; i++) + { + result[i] = a[i] + b[i] * foldingChallenge; + } + + return result; + } + + private static Banderwagon[] FoldPoints(IReadOnlyList a, IReadOnlyList b, FrE foldingChallenge) + { + if (a.Count != b.Count) + throw new Exception(); + + Banderwagon[] result = new Banderwagon[a.Count]; + for (int i = 0; i < a.Count; i++) + { + result[i] = a[i] + b[i] * foldingChallenge; + } + + return result; + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs/MultiProof.cs b/src/Nethermind/Nethermind.Verkle.Proofs/MultiProof.cs new file mode 100644 index 00000000000..0218edd18c8 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs/MultiProof.cs @@ -0,0 +1,170 @@ +using System.ComponentModel; +using System.Security.Cryptography; +using Nethermind.Core.Extensions; +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Polynomial; + +namespace Nethermind.Verkle.Proofs +{ + public class MultiProof + { + private readonly CRS _crs; + private readonly PreComputeWeights _preComp; + + public MultiProof(CRS cRs, PreComputeWeights preComp) + { + _preComp = preComp; + _crs = cRs; + } + + public VerkleProofStruct MakeMultiProof(Transcript transcript, List queries) + { + int domainSize = _preComp._domain.Length; + + // create transcript for multiproof + transcript.DomainSep("multiproof"); + foreach (VerkleProverQuery query in queries) + { + transcript.AppendPoint(query._nodeCommitPoint, "C"); + transcript.AppendScalar(query._childIndex, "z"); + transcript.AppendScalar(query._childHash, "y"); + } + FrE r = transcript.ChallengeScalar("r"); + + FrE[] g = new FrE[domainSize]; + for (int i = 0; i < domainSize; i++) + { + g[i] = FrE.Zero; + } + + FrE powerOfR = FrE.One; + + foreach (VerkleProverQuery query in queries) + { + LagrangeBasis f = query._childHashPoly; + FrE index = query._childIndex; + FrE[] quotient = Quotient.ComputeQuotientInsideDomain(_preComp, f, index); + + for (int i = 0; i < quotient.Length; i++) + { + g[i] += powerOfR * quotient[i]; + } + + powerOfR *= r; + } + + Banderwagon d = _crs.Commit(g); + transcript.AppendPoint(d, "D"); + FrE t = transcript.ChallengeScalar("t"); + + FrE[] h = new FrE[domainSize]; + for (int i = 0; i < domainSize; i++) + { + h[i] = FrE.Zero; + } + + powerOfR = FrE.One; + + foreach (VerkleProverQuery query in queries) + { + int index = query._childIndex.ToBytes()[0]; + FrE.Inverse(t - _preComp._domain[index], out FrE denominatorInv); + LagrangeBasis f = query._childHashPoly; + for (int i = 0; i < f.Evaluations.Length; i++) + { + h[i] += powerOfR * f.Evaluations[i] * denominatorInv; + } + powerOfR *= r; + } + + FrE[] hMinusG = new FrE[domainSize]; + for (int i = 0; i < domainSize; i++) + { + hMinusG[i] = h[i] - g[i]; + } + + Banderwagon e = _crs.Commit(h); + transcript.AppendPoint(e, "E"); + + Banderwagon ipaCommitment = e - d; + FrE[] inputPointVector = _preComp.BarycentricFormulaConstants(t); + IpaProverQuery pQuery = new IpaProverQuery(hMinusG, ipaCommitment, + t, inputPointVector); + + (FrE _, IpaProofStruct ipaProof) = Ipa.MakeIpaProof(_crs, transcript, pQuery); + + return new VerkleProofStruct(ipaProof, d); + + } + + public bool CheckMultiProof(Transcript transcript, VerkleVerifierQuery[] queries, VerkleProofStruct proof) + { + transcript.DomainSep("multiproof"); + Banderwagon d = proof._d; + IpaProofStruct ipaIpaProof = proof._ipaProof; + foreach (VerkleVerifierQuery query in queries) + { + transcript.AppendPoint(query._nodeCommitPoint, "C"); + transcript.AppendScalar(query._childIndex, "z"); + transcript.AppendScalar(query._childHash, "y"); + } + + FrE r = transcript.ChallengeScalar("r"); + + transcript.AppendPoint(d, "D"); + FrE t = transcript.ChallengeScalar("t"); + + Dictionary eCoefficients = new Dictionary(); + FrE g2OfT = FrE.Zero; + FrE powerOfR = FrE.One; + + Dictionary cBySerialized = new Dictionary(); + + foreach (VerkleVerifierQuery query in queries) + { + Banderwagon c = query._nodeCommitPoint; + int z = query._childIndex.ToBytes()[0]; + FrE y = query._childHash; + FrE eCoefficient = powerOfR / t - _preComp._domain[z]; + byte[] cSerialized = c.ToBytes(); + cBySerialized[cSerialized] = c; + if (!eCoefficients.ContainsKey(cSerialized)) + { + eCoefficients[cSerialized] = eCoefficient; + } + else + { + eCoefficients[cSerialized] += eCoefficient; + } + + g2OfT += eCoefficient * y; + + powerOfR *= r; + } + + Banderwagon[] elems = new Banderwagon[eCoefficients.Count]; + for (int i = 0; i < eCoefficients.Count; i++) + { + elems[i] = cBySerialized[eCoefficients.Keys.ToArray()[i]]; + } + + Banderwagon e = VarBaseCommit(eCoefficients.Values.ToArray(), elems); + transcript.AppendPoint(e, "E"); + + FrE yO = g2OfT; + Banderwagon ipaCommitment = e - d; + FrE[] inputPointVector = _preComp.BarycentricFormulaConstants(t); + + IpaVerifierQuery queryX = new IpaVerifierQuery(ipaCommitment, t, + inputPointVector, yO, ipaIpaProof); + + return Ipa.CheckIpaProof(_crs, transcript, queryX); + } + + private static Banderwagon VarBaseCommit(FrE[] values, Banderwagon[] elements) + { + return Banderwagon.MSM(elements, values); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs/Nethermind.Verkle.Proofs.csproj b/src/Nethermind/Nethermind.Verkle.Proofs/Nethermind.Verkle.Proofs.csproj new file mode 100644 index 00000000000..7a6d9cac07a --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs/Nethermind.Verkle.Proofs.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Nethermind/Nethermind.Verkle.Proofs/Quotient.cs b/src/Nethermind/Nethermind.Verkle.Proofs/Quotient.cs new file mode 100644 index 00000000000..3bb69e4ac0d --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs/Quotient.cs @@ -0,0 +1,56 @@ +using Nethermind.Core.Extensions; +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Polynomial; + +namespace Nethermind.Verkle.Proofs +{ + public static class Quotient + { + public static FrE[] ComputeQuotientInsideDomain(PreComputeWeights preComp, LagrangeBasis f, + FrE index) + { + int domainSize = f.Evaluations.Length; + + FrE[] inverses = preComp._domainInv; + FrE[] aPrimeDomain = preComp._aPrimeDomain; + FrE[] aPrimeDomainInv = preComp._aPrimeDomainInv; + + int indexI = index.ToBytes()[0]; + + FrE[] q = new FrE[domainSize]; + for (int i = 0; i < domainSize; i++) + { + q[i] = FrE.Zero; + } + FrE y = f.Evaluations[indexI]; + + + for (int i = 0; i < domainSize; i++) + { + if (i == indexI) continue; + q[i] = (f.Evaluations[i] - y) * inverses[(i - indexI) < 0 ? (inverses.Length + (i - indexI)): (i - indexI)]; + q[indexI] += (f.Evaluations[i] - y) * inverses[(indexI - i) < 0 ? (inverses.Length + indexI - i) : (indexI - i)] * aPrimeDomain[indexI] * + aPrimeDomainInv[i]; + } + + return q; + } + + public static FrE[] ComputeQuotientOutsideDomain(PreComputeWeights preComp, LagrangeBasis f, FrE z, + FrE y) + { + FrE[] domain = preComp._domain; + int domainSize = domain.Length; + + FrE[] q = new FrE[domainSize]; + for (int i = 0; i < domainSize; i++) + { + FrE x = f.Evaluations[i] - y; + FrE zz = domain[i] - z; + q[i] = x / zz; + } + + return q; + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs/Structures.cs b/src/Nethermind/Nethermind.Verkle.Proofs/Structures.cs new file mode 100644 index 00000000000..46a2461e531 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs/Structures.cs @@ -0,0 +1,161 @@ +// Copyright 2022 Demerzel Solutions Limited +// Licensed under Apache-2.0.For full terms, see LICENSE in the project root. + +using System.Text; +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Polynomial; +using Nethermind.Core.Extensions; + +namespace Nethermind.Verkle.Proofs +{ + public struct IpaProverQuery + { + public readonly FrE[] _polynomial; + public readonly Banderwagon _commitment; + public FrE _point; + public readonly FrE[] _pointEvaluations; + + public IpaProverQuery(FrE[] polynomial, Banderwagon commitment, FrE point, + FrE[] pointEvaluations) + { + _polynomial = polynomial; + _commitment = commitment; + _point = point; + _pointEvaluations = pointEvaluations; + } + } + + public struct IpaProofStruct + { + public readonly List _l; + public FrE _a; + public readonly List _r; + + public IpaProofStruct(List l, FrE a, List r) + { + _l = l; + _a = a; + _r = r; + } + + public byte[] Encode() + { + List encoded = new List(); + + foreach (Banderwagon l in _l) + { + encoded.AddRange(l.ToBytesLittleEndian().Reverse().ToArray()); + } + + foreach (Banderwagon r in _r) + { + encoded.AddRange(r.ToBytesLittleEndian().Reverse().ToArray()); + } + + encoded.AddRange(_a.ToBytes().ToArray()); + + return encoded.ToArray(); + } + + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("\n#[_l]#\n"); + foreach (Banderwagon l in _l) + { + stringBuilder.AppendJoin(", ", l.ToBytesLittleEndian().Reverse().ToArray()); + stringBuilder.Append('\n'); + } + stringBuilder.Append("\n#[_a]#\n"); + stringBuilder.AppendJoin(", ", _a.ToBytes().ToArray()); + stringBuilder.Append("\n#[_r]#\n"); + foreach (Banderwagon l in _r) + { + stringBuilder.AppendJoin(", ", l.ToBytesLittleEndian().Reverse().ToArray()); + stringBuilder.Append('\n'); + } + return stringBuilder.ToString(); + } + } + + public struct IpaVerifierQuery + { + public readonly Banderwagon _commitment; + public FrE _point; + public readonly FrE[] _pointEvaluations; + public FrE _outputPoint; + public IpaProofStruct _ipaProof; + + public IpaVerifierQuery(Banderwagon commitment, FrE point, FrE[] pointEvaluations, FrE outputPoint, IpaProofStruct ipaProof) + { + _commitment = commitment; + _point = point; + _pointEvaluations = pointEvaluations; + _outputPoint = outputPoint; + _ipaProof = ipaProof; + } + } + + public struct VerkleProofStruct + { + public IpaProofStruct _ipaProof; + public readonly Banderwagon _d; + + public VerkleProofStruct(IpaProofStruct ipaProof, Banderwagon d) + { + _ipaProof = ipaProof; + _d = d; + } + + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("\n##[IPA Proof]##\n"); + stringBuilder.Append(_ipaProof.ToString()); + stringBuilder.Append("\n##[_d]##\n"); + stringBuilder.AppendJoin(", ", _d.ToBytesLittleEndian().Reverse().ToArray()); + return stringBuilder.ToString(); + } + + public byte[] Encode() + { + List encoded = new List(); + + encoded.AddRange(_d.ToBytesLittleEndian().Reverse().ToArray()); + encoded.AddRange(_ipaProof.Encode()); + + return encoded.ToArray(); + } + } + + public struct VerkleProverQuery + { + public readonly LagrangeBasis _childHashPoly; + public readonly Banderwagon _nodeCommitPoint; + public FrE _childIndex; + public FrE _childHash; + + public VerkleProverQuery(LagrangeBasis childHashPoly, Banderwagon nodeCommitPoint, FrE childIndex, FrE childHash) + { + _childHashPoly = childHashPoly; + _nodeCommitPoint = nodeCommitPoint; + _childIndex = childIndex; + _childHash = childHash; + } + } + + public struct VerkleVerifierQuery + { + public readonly Banderwagon _nodeCommitPoint; + public FrE _childIndex; + public FrE _childHash; + + public VerkleVerifierQuery(Banderwagon nodeCommitPoint, FrE childIndex, FrE childHash) + { + _nodeCommitPoint = nodeCommitPoint; + _childIndex = childIndex; + _childHash = childHash; + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Proofs/Transcript.cs b/src/Nethermind/Nethermind.Verkle.Proofs/Transcript.cs new file mode 100644 index 00000000000..1395279493f --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Proofs/Transcript.cs @@ -0,0 +1,80 @@ +using System.Security.Cryptography; +using System.Text; +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; + +namespace Nethermind.Verkle.Proofs +{ + public class Transcript + { + public List CurrentHash = new List(); + + public Transcript(IEnumerable label) + { + CurrentHash.AddRange(label); + } + + public Transcript(string label) + { + CurrentHash.AddRange(Encoding.ASCII.GetBytes(label)); + } + + public static FrE ByteToField(byte[] bytes) + { + return FrE.FromBytesReduced(bytes); + } + + public void AppendBytes(IEnumerable message, IEnumerable label) + { + CurrentHash.AddRange(label); + CurrentHash.AddRange(message); + } + + public void AppendBytes(string message, string label) + { + AppendBytes(Encoding.ASCII.GetBytes(message), Encoding.ASCII.GetBytes(label)); + } + + public void AppendScalar(FrE scalar, IEnumerable label) + { + AppendBytes(scalar.ToBytes().ToArray(), label); + } + public void AppendScalar(FrE scalar, string label) + { + AppendScalar(scalar, Encoding.ASCII.GetBytes(label)); + } + + public void AppendPoint(Banderwagon point, byte[] label) + { + AppendBytes(point.ToBytes(), label); + } + public void AppendPoint(Banderwagon point, string label) + { + AppendPoint(point, Encoding.ASCII.GetBytes(label)); + } + + public FrE ChallengeScalar(byte[] label) + { + DomainSep(label); + byte[] hash = SHA256.Create().ComputeHash(CurrentHash.ToArray()); + FrE challenge = ByteToField(hash); + CurrentHash = new List(); + + AppendScalar(challenge, label); + return challenge; + } + public FrE ChallengeScalar(string label) + { + return ChallengeScalar(Encoding.ASCII.GetBytes(label)); + } + + public void DomainSep(byte[] label) + { + CurrentHash.AddRange(label); + } + public void DomainSep(string label) + { + DomainSep(Encoding.ASCII.GetBytes(label)); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Test/AccountHeaderTests.cs b/src/Nethermind/Nethermind.Verkle.Test/AccountHeaderTests.cs index d447d0d09d1..6e5d9acf074 100644 --- a/src/Nethermind/Nethermind.Verkle.Test/AccountHeaderTests.cs +++ b/src/Nethermind/Nethermind.Verkle.Test/AccountHeaderTests.cs @@ -1,4 +1,8 @@ using FluentAssertions; +using Nethermind.Core.Extensions; +using Nethermind.Int256; +using Nethermind.Verkle.Tree; +using Nethermind.Verkle.Utils; using NUnit.Framework; namespace Nethermind.Verkle.Test; @@ -6,11 +10,30 @@ namespace Nethermind.Verkle.Test; [TestFixture] public class AccountHeaderTests { + + [Test] + public void TestGetTreeKey() + { + Span addr = new byte[32]; + for (int i = 0; i < 16; i++) + { + addr[1 + 2 * i] = 255; + } + + UInt256 n = 1; + n = n << 129; + n = n + 3; + byte[] key = PedersenHash.Hash(addr, n); + key[31] = 1; + + key.ToHexString().Should().BeEquivalentTo("f42f932f43faf5d14b292b9009c45c28da61dbf66e20dbedc2e02dfd64ff5a01"); + } + [Test] public void SetAccountWithCode() { byte[] code = { 1, 2, 3, 4 }; - AccountHeader.CodeChunkEnumerator codeEnumerator = new AccountHeader.CodeChunkEnumerator(code); + CodeChunkEnumerator codeEnumerator = new CodeChunkEnumerator(code); codeEnumerator.TryGetNextChunk(out byte[] value); value.Should().NotBeNull(); @@ -24,7 +47,7 @@ public void SetAccountWithCode() public void SetAccountWithCodePushOpcodes() { byte[] code1 = { 97, 1, 2, 3, 4 }; - AccountHeader.CodeChunkEnumerator codeEnumerator = new AccountHeader.CodeChunkEnumerator(code1); + CodeChunkEnumerator codeEnumerator = new CodeChunkEnumerator(code1); codeEnumerator.TryGetNextChunk(out byte[] value); value.Should().NotBeNull(); @@ -46,7 +69,7 @@ public void SetAccountWithCodePushOpcodes() 4, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45 }; - codeEnumerator = new AccountHeader.CodeChunkEnumerator(code2); + codeEnumerator = new CodeChunkEnumerator(code2); codeEnumerator.TryGetNextChunk(out value); value.Should().NotBeNull(); @@ -82,7 +105,7 @@ public void SetCodeEdgeCases1() { 1, 62, 63, 64, 65 }; - AccountHeader.CodeChunkEnumerator codeEnumerator = new AccountHeader.CodeChunkEnumerator(code); + CodeChunkEnumerator codeEnumerator = new CodeChunkEnumerator(code); codeEnumerator.TryGetNextChunk(out byte[] value); value.Should().BeEquivalentTo(firstCodeChunk); @@ -118,7 +141,7 @@ public void SetCodeEdgeCases2() 0, 62, 63, 64, 65 }; - AccountHeader.CodeChunkEnumerator codeEnumerator = new AccountHeader.CodeChunkEnumerator(code); + CodeChunkEnumerator codeEnumerator = new CodeChunkEnumerator(code); codeEnumerator.TryGetNextChunk(out byte[] value); value.Should().BeEquivalentTo(firstCodeChunk); @@ -155,7 +178,7 @@ public void SetCodeEdgeCases3() 0, 62, 63, 64, 65 }; - AccountHeader.CodeChunkEnumerator codeEnumerator = new AccountHeader.CodeChunkEnumerator(code); + CodeChunkEnumerator codeEnumerator = new CodeChunkEnumerator(code); codeEnumerator.TryGetNextChunk(out byte[] value); value.Should().BeEquivalentTo(firstCodeChunk); diff --git a/src/Nethermind/Nethermind.Verkle.Test/HistoryTests.cs b/src/Nethermind/Nethermind.Verkle.Test/HistoryTests.cs new file mode 100644 index 00000000000..4450fcb1615 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Test/HistoryTests.cs @@ -0,0 +1,229 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using FluentAssertions; +using Nethermind.Db; +using Nethermind.Verkle.Tree; +using Nethermind.Verkle.Tree.VerkleDb; +using NUnit.Framework; + +namespace Nethermind.Verkle.Test; + +public class HistoryTests +{ + + [TearDown] + public void CleanTestData() + { + string dbPath = VerkleTestUtils.GetDbPathForTest(); + if (Directory.Exists(dbPath)) + { + Directory.Delete(dbPath, true); + } + } + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestInsertGetMultiBlockReverseState(DbMode dbMode) + { + VerkleTree tree = VerkleTestUtils.GetVerkleTreeForTest(dbMode); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._emptyArray); + tree.Flush(0); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._arrayAll0Last2); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._arrayAll0Last2); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._arrayAll0Last2); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._arrayAll0Last2); + tree.Flush(1); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._arrayAll0Last3); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._arrayAll0Last3); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._arrayAll0Last3); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._arrayAll0Last3); + tree.Flush(2); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + + tree.ReverseState(); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + + tree.ReverseState(); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + } + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestInsertGetBatchMultiBlockReverseState(DbMode dbMode) + { + VerkleTree tree = VerkleTestUtils.GetVerkleTreeForTest(dbMode); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._emptyArray); + tree.Flush(0); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._emptyArray); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._arrayAll0Last2); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._arrayAll0Last2); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._arrayAll0Last2); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._arrayAll0Last2); + tree.Flush(1); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._arrayAll0Last3); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._arrayAll0Last3); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._arrayAll0Last3); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._arrayAll0Last3); + tree.Flush(2); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last3); + + VerkleMemoryDb memory = tree.GetReverseMergedDiff(2, 1); + + tree.ApplyDiffLayer(memory, 2,1); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + } + + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestReverseDiffThenForwardDiff(DbMode dbMode) + { + VerkleTree tree = VerkleTestUtils.GetFilledVerkleTreeForTest(dbMode); + + VerkleMemoryDb memory = tree.GetReverseMergedDiff(3,1); + + tree.ApplyDiffLayer(memory, 3, 1); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last2); + + VerkleMemoryDb forwardMemory = tree.GetForwardMergedDiff(1, 3); + + tree.ApplyDiffLayer(forwardMemory, 1, 3); + + tree.Get(VerkleTestUtils._keyVersion).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last4); + tree.Get(VerkleTestUtils._keyBalance).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last4); + tree.Get(VerkleTestUtils._keyNonce).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last4); + tree.Get(VerkleTestUtils._keyCodeCommitment).Should().BeEquivalentTo(VerkleTestUtils._valueEmptyCodeHashValue); + tree.Get(VerkleTestUtils._keyCodeSize).Should().BeEquivalentTo(VerkleTestUtils._arrayAll0Last4); + + } + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestReverseStateOneBlock(DbMode dbMode) + { + VerkleTree tree = VerkleTestUtils.GetFilledVerkleTreeForTest(dbMode); + DateTime start = DateTime.Now; + tree.ReverseState(); + DateTime end = DateTime.Now; + Console.WriteLine($"ReverseState() 1 Block: {(end - start).TotalMilliseconds}"); + } + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestForwardStateOneBlock(DbMode dbMode) + { + VerkleTree tree = VerkleTestUtils.GetFilledVerkleTreeForTest(dbMode); + tree.ReverseState(); + VerkleMemoryDb forwardMemory = tree.GetForwardMergedDiff(2, 3); + DateTime start = DateTime.Now; + tree.ApplyDiffLayer(forwardMemory, 2, 3); + DateTime end = DateTime.Now; + Console.WriteLine($"ForwardState() 1 Block Insert: {(end - start).TotalMilliseconds}"); + } + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestBatchReverseDiffs(DbMode dbMode) + { + // VerkleTree tree = GetHugeVerkleTreeForTest(dbMode); + // for (int i = 2;i <= 1000;i++) { + // DateTime start = DateTime.Now; + // IVerkleDiffDb reverseDiff = tree.GetReverseMergedDiff(1, i); + // DateTime check1 = DateTime.Now; + // tree.ReverseState(reverseDiff, (i -1)); + // DateTime check2 = DateTime.Now; + // Console.WriteLine($"Batch Reverse Diff Fetch(1, {i}): {(check1 - start).TotalMilliseconds}"); + // Console.WriteLine($"Batch Reverse State(2, {i-1}): {(check2 - check1).TotalMilliseconds}"); + //} + } + + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void TestBatchForwardDiffs(DbMode dbMode) + { + // VerkleTree tree = GetHugeVerkleTreeForTest(dbMode); + // for (int i = 2;i <= 1000;i++) { + // DateTime start = DateTime.Now; + // IVerkleDiffDb forwardDiff = tree.GetForwardMergedDiff(1, i); + // DateTime check1 = DateTime.Now; + // tree.ForwardState(reverseDiff, (i -1)); + // DateTime check2 = DateTime.Now; + // Console.WriteLine($"Batch Forward Diff Fetch(1, {i}): {(check1 - start).TotalMilliseconds}"); + // Console.WriteLine($"Batch Forward State(2, {i-1}): {(check2 - check1).TotalMilliseconds}"); + //} + } + + +} diff --git a/src/Nethermind/Nethermind.Verkle.Test/InsertHugeTreeTests.cs b/src/Nethermind/Nethermind.Verkle.Test/InsertHugeTreeTests.cs index e42276cc634..2a3cad6f88a 100644 --- a/src/Nethermind/Nethermind.Verkle.Test/InsertHugeTreeTests.cs +++ b/src/Nethermind/Nethermind.Verkle.Test/InsertHugeTreeTests.cs @@ -4,6 +4,7 @@ using System.Net.Mime; using System.Reflection; using Nethermind.Db; +using Nethermind.Verkle.Tree; using NUnit.Framework; namespace Nethermind.Verkle.Test; @@ -85,45 +86,45 @@ public void CleanTestData() // // } - // [TestCase(DbMode.MemDb)] - // [TestCase(DbMode.PersistantDb)] - // public void InsertHugeTree(DbMode dbMode) - // { - // long block = 0; - // VerkleTree tree = GetVerkleTreeForTest(dbMode); - // byte[] key = new byte[32]; - // byte[] value = new byte[32]; - // DateTime start = DateTime.Now; - // for (int i = 0; i < numKeys; i++) - // { - // Random.NextBytes(key); - // Random.NextBytes(value); - // tree.Insert(key, value); - // } - // DateTime check1 = DateTime.Now; - // tree.Flush(block++); - // DateTime check2 = DateTime.Now; - // Console.WriteLine($"{block} Insert: {(check1 - start).TotalMilliseconds}"); - // Console.WriteLine($"{block} Flush: {(check2 - check1).TotalMilliseconds}"); - // for (int i = 100; i < numKeys; i += 100) - // { - // DateTime check5 = DateTime.Now; - // Random.NextBytes(key); - // Random.NextBytes(value); - // for (int j = 0; j < i; j += 1) - // { - // Random.NextBytes(key); - // Random.NextBytes(value); - // tree.Insert(key, value); - // } - // DateTime check3 = DateTime.Now; - // tree.Flush(block++); - // DateTime check4 = DateTime.Now; - // Console.WriteLine($"{block} Insert: {(check3 - check5).TotalMilliseconds}"); - // Console.WriteLine($"{block} Flush: {(check4 - check3).TotalMilliseconds}"); - // } - // DateTime check6 = DateTime.Now; - // Console.WriteLine($"Loop Time: {(check6 - check2).TotalMilliseconds}"); - // Console.WriteLine($"Total Time: {(check6 - start).TotalMilliseconds}"); - // } + [TestCase(DbMode.MemDb)] + [TestCase(DbMode.PersistantDb)] + public void InsertHugeTree(DbMode dbMode) + { + long block = 0; + VerkleTree tree = GetVerkleTreeForTest(dbMode); + byte[] key = new byte[32]; + byte[] value = new byte[32]; + DateTime start = DateTime.Now; + for (int i = 0; i < numKeys; i++) + { + Random.NextBytes(key); + Random.NextBytes(value); + tree.Insert(key, value); + } + DateTime check1 = DateTime.Now; + tree.Flush(block++); + DateTime check2 = DateTime.Now; + Console.WriteLine($"{block} Insert: {(check1 - start).TotalMilliseconds}"); + Console.WriteLine($"{block} Flush: {(check2 - check1).TotalMilliseconds}"); + for (int i = 100; i < numKeys; i += 100) + { + DateTime check5 = DateTime.Now; + Random.NextBytes(key); + Random.NextBytes(value); + for (int j = 0; j < i; j += 1) + { + Random.NextBytes(key); + Random.NextBytes(value); + tree.Insert(key, value); + } + DateTime check3 = DateTime.Now; + tree.Flush(block++); + DateTime check4 = DateTime.Now; + Console.WriteLine($"{block} Insert: {(check3 - check5).TotalMilliseconds}"); + Console.WriteLine($"{block} Flush: {(check4 - check3).TotalMilliseconds}"); + } + DateTime check6 = DateTime.Now; + Console.WriteLine($"Loop Time: {(check6 - check2).TotalMilliseconds}"); + Console.WriteLine($"Total Time: {(check6 - start).TotalMilliseconds}"); + } } diff --git a/src/Nethermind/Nethermind.Verkle.Test/Nethermind.Verkle.Test.csproj b/src/Nethermind/Nethermind.Verkle.Test/Nethermind.Verkle.Test.csproj index e4db1382a40..8b0b4c5c3d9 100644 --- a/src/Nethermind/Nethermind.Verkle.Test/Nethermind.Verkle.Test.csproj +++ b/src/Nethermind/Nethermind.Verkle.Test/Nethermind.Verkle.Test.csproj @@ -9,7 +9,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/src/Nethermind/Nethermind.Verkle.Test/VerkleDbTests.cs b/src/Nethermind/Nethermind.Verkle.Test/VerkleDbTests.cs index 9bf30b023c6..b55b736173a 100644 --- a/src/Nethermind/Nethermind.Verkle.Test/VerkleDbTests.cs +++ b/src/Nethermind/Nethermind.Verkle.Test/VerkleDbTests.cs @@ -1,5 +1,4 @@ using Nethermind.Core.Extensions; -using Nethermind.Verkle.VerkleStateDb; using NUnit.Framework; namespace Nethermind.Verkle.Test; @@ -25,15 +24,15 @@ public void ByteArrayEqualityTestsDictionary() Assert.IsTrue(table.TryGetValue(b, out byte[] _)); } - [Test] - public void TestDiffLayer() - { - DiffLayer forwardDiff = new DiffLayer(DiffType.Forward); - DiffLayer reverseDiff = new DiffLayer(DiffType.Reverse); - - MemoryStateDb currentState = new MemoryStateDb(); - MemoryStateDb changes = new MemoryStateDb(); - - - } + // [Test] + // public void TestDiffLayer() + // { + // DiffLayer forwardDiff = new DiffLayer(DiffType.Forward); + // DiffLayer reverseDiff = new DiffLayer(DiffType.Reverse); + // + // MemoryStateDb currentState = new MemoryStateDb(); + // MemoryStateDb changes = new MemoryStateDb(); + // + // + // } } diff --git a/src/Nethermind/Nethermind.Verkle.Test/VerkleProofTest.cs b/src/Nethermind/Nethermind.Verkle.Test/VerkleProofTest.cs new file mode 100644 index 00000000000..6dc33654c51 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Test/VerkleProofTest.cs @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using FluentAssertions; +using Nethermind.Core.Extensions; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Tree; +using Nethermind.Verkle.Tree.Proofs; +using NUnit.Framework; + +namespace Nethermind.Verkle.Test; + +public class VerkleProofTest +{ + [Test] + public void TestVerkleProof() + { + VerkleTree tree = VerkleTestUtils.GetVerkleTreeForTest(DbMode.MemDb); + + tree.Insert(VerkleTestUtils._keyVersion, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyBalance, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyNonce, VerkleTestUtils._emptyArray); + tree.Insert(VerkleTestUtils._keyCodeCommitment, VerkleTestUtils._valueEmptyCodeHashValue); + tree.Insert(VerkleTestUtils._keyCodeSize, VerkleTestUtils._emptyArray); + tree.Flush(0); + + VerkleProver prover = new VerkleProver(tree._stateDb); + prover.CreateVerkleProof(new List(new[] + {VerkleTestUtils._keyVersion, VerkleTestUtils._keyNonce, VerkleTestUtils._keyBalance, VerkleTestUtils._keyCodeCommitment}), out Banderwagon _); + + } + + [Test] + public void BasicProofTrue() + { + VerkleTree tree = VerkleTestUtils.GetVerkleTreeForTest(DbMode.MemDb); + + byte[][] keys = + { + new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + new byte[]{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + new byte[]{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + new byte[]{3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }; + + tree.Insert(keys[0], keys[0]); + tree.Insert(keys[1], keys[1]); + tree.Insert(keys[2], keys[2]); + tree.Insert(keys[3], keys[3]); + tree.Flush(0); + + VerkleProver prover = new VerkleProver(tree._stateDb); + VerkleProof proof = prover.CreateVerkleProof(new List(keys), out Banderwagon root); + + const string expectedProof = "00000000040000000a0a0a0a0800000056778fe0bcf12a14820d4c054d85cfcae4bdb7017107b6769cecd42629a3825e38f30e21c" + + "79747190371df99e88b886638be445d44f8f9b56ca7c062ea3299446c650ce85c8b5d3cb5ccef8be82858aa2fa9c2cad512086db5" + + "21bd2823e3fc38107802129c490edadbab32ec891ee6310e4f4f00e0056ce3bb0ffc6840a27577556a6fa8933ab25ddb0fb102fca" + + "932ac58a5f539f83b9bfb6e21ea742aa5ad7403f36f9c0821d7014e7a7b917c1d3b72acf724906a30a8fefb09889c3e4cfbc528a4" + + "0fd3331b653dea7be3fe55bc1a0451e0dbad672ec0236cac46e5b23d13d5562743b585beaf3dc1987c9bdf5701af9c4784a392549" + + "9bd6318b63ccec4b35f1bd427779680f60c2df48a9df458fa989fc0f8a7a38d54363b722138e4e4ac4351c5a0aa5cc5e53b697d8b" + + "57eaa43db3dc3987f9f1e71c31b5098721dad2910465fff50d7fb4d0145c41c53a395f99052a251fcb97ef31da582938a67756697" + + "024068f61bd61a10a2c7d8d2a522fa3834e1516f16bfc4ec7f1808069effeab095a5ff89d9bacad138316aa7c9001ce03830e443d" + + "a2aed1f66b5211ae7912bbe751bb05960d4f6bcdb3d266685d6e1b81c632e66f90df80b76cfe8e619bb29ed3322c2f9743d918f47" + + "062f4d077d5a658ab41c3d9c3add6def200e7f242d5ed840a7389ec6a7ab71f6ce813fb898a530af1a3c800f849bf56aae0c7a12a" + + "f1c0ee210863a29533a0c848de893cd1bc0256d8b3ddd3439ee55bc94eb77f71ac2d994b4fd1f08738f53183ac85b3c6e4ee1f8e9" + + "7e0154df668ec700131d4167b93d6180ed760ded7c1899f6f53116ea6c9b54ab809809ae05e821c2e4b0b3cccbf6d643f5aff2dd6" + + "ea235f2e53efccd6009f560e1c0eb01163e1415b2176a2679f8a3845884f3ffac354449be949b849325ec0d66af841825dbf6bd66" + + "8bb91a49c150be9b911a60e285c2ffa50f0380bcb86ed85bf7114c2c0d0aa8e7e6fb33351464a9de74b4219ebf351933831d1f5b5" + + "3467f856adfa7b478c428027dd408f61ff4eb9d94d0ee8c3e79e0265b0635af17db6aa7ca1b463b70e4c51fffb7f8403c94c9315a" + + "7b48d8a11ffd23510e0936842ae8368dedfb511a01dfc930c96d8ee26235b4acc8ace6a0d8fc3fb9142b69b2b989f97ce36ba4386" + + "8d93add3abe7a012"; + + Assert.That(proof.Encode().ToHexString().SequenceEqual(expectedProof), Is.True); + // (bool, UpdateHint?) verified = Verifier.VerifyVerkleProof(proof, new List(keys), new List(keys), root); + // Assert.That(verified.Item1, Is.True); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Test/VerkleTestUtils.cs b/src/Nethermind/Nethermind.Verkle.Test/VerkleTestUtils.cs new file mode 100644 index 00000000000..75374ddaf90 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Test/VerkleTestUtils.cs @@ -0,0 +1,152 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using FluentAssertions; +using Nethermind.Db; +using Nethermind.Verkle.Tree; +using NUnit.Framework; + +namespace Nethermind.Verkle.Test; + +public class VerkleTestUtils +{ + public static readonly byte[] _array1To32 = + { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + }; + public static readonly byte[] _array1To32Last128 = + { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 128, + }; + public static readonly byte[] _emptyArray = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + public static readonly byte[] _arrayAll1 = + { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + public static readonly byte[] _arrayAll0Last2 = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 + }; + + public static readonly byte[] _arrayAll0Last3 = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 + }; + + public static readonly byte[] _arrayAll0Last4 = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 + }; + + + public static readonly byte[] _keyVersion = + { + 121, 85, 7, 198, 131, 230, 143, 90, 165, 129, 173, 81, 186, 89, 19, 191, 13, 107, 197, 120, 243, 229, 224, 183, 72, 25, 6, 8, 210, 159, 31, 0, + }; + public static readonly byte[] _keyBalance = + { + 121, 85, 7, 198, 131, 230, 143, 90, 165, 129, 173, 81, 186, 89, 19, 191, 13, 107, 197, 120, 243, 229, 224, 183, 72, 25, 6, 8, 210, 159, 31, 1, + }; + public static readonly byte[] _keyNonce = + { + 121, 85, 7, 198, 131, 230, 143, 90, 165, 129, 173, 81, 186, 89, 19, 191, 13, 107, 197, 120, 243, 229, 224, 183, 72, 25, 6, 8, 210, 159, 31, 2, + }; + public static readonly byte[] _keyCodeCommitment = { + 121, 85, 7, 198, 131, 230, 143, 90, 165, 129, 173, 81, 186, 89, 19, 191, 13, 107, 197, 120, 243, 229, 224, 183, 72, 25, 6, 8, 210, 159, 31, 3, + }; + public static readonly byte[] _keyCodeSize = + { + 121, 85, 7, 198, 131, 230, 143, 90, 165, 129, 173, 81, 186, 89, 19, 191, 13, 107, 197, 120, 243, 229, 224, 183, 72, 25, 6, 8, 210, 159, 31, 4, + }; + public static readonly byte[] _valueEmptyCodeHashValue = + { + 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112, + }; + + public static string GetDbPathForTest() + { + string tempDir = Path.GetTempPath(); + string dbname = "VerkleTrie_TestID_" + TestContext.CurrentContext.Test.ID; + return Path.Combine(tempDir, dbname); + } + + public static VerkleTree GetVerkleTreeForTest(DbMode dbMode) + { + IDbProvider provider; + switch (dbMode) + { + case DbMode.MemDb: + provider = VerkleDbFactory.InitDatabase(dbMode, null); + return new VerkleTree(provider); + case DbMode.PersistantDb: + provider = VerkleDbFactory.InitDatabase(dbMode, GetDbPathForTest()); + return new VerkleTree(provider); + case DbMode.ReadOnlyDb: + default: + throw new ArgumentOutOfRangeException(nameof(dbMode), dbMode, null); + } + } + + public static VerkleTree GetFilledVerkleTreeForTest(DbMode dbMode) + { + VerkleTree tree = GetVerkleTreeForTest(dbMode); + + tree.Insert(_keyVersion, _emptyArray); + tree.Insert(_keyBalance, _emptyArray); + tree.Insert(_keyNonce, _emptyArray); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _emptyArray); + tree.Flush(0); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); + tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); + tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); + + tree.Insert(_keyVersion, _arrayAll0Last2); + tree.Insert(_keyBalance, _arrayAll0Last2); + tree.Insert(_keyNonce, _arrayAll0Last2); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _arrayAll0Last2); + tree.Flush(1); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last2); + tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); + tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last2); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); + + tree.Insert(_keyVersion, _arrayAll0Last3); + tree.Insert(_keyBalance, _arrayAll0Last3); + tree.Insert(_keyNonce, _arrayAll0Last3); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _arrayAll0Last3); + tree.Flush(2); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last3); + tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last3); + tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last3); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last3); + + tree.Insert(_keyVersion, _arrayAll0Last4); + tree.Insert(_keyBalance, _arrayAll0Last4); + tree.Insert(_keyNonce, _arrayAll0Last4); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _arrayAll0Last4); + tree.Flush(3); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last4); + tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last4); + tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last4); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last4); + + return tree; + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Test/VerkleTreeTests.cs b/src/Nethermind/Nethermind.Verkle.Test/VerkleTreeTests.cs index 5db0f57d16b..34bd2a472ed 100644 --- a/src/Nethermind/Nethermind.Verkle.Test/VerkleTreeTests.cs +++ b/src/Nethermind/Nethermind.Verkle.Test/VerkleTreeTests.cs @@ -1,7 +1,8 @@ +using System.Diagnostics.CodeAnalysis; using FluentAssertions; using Nethermind.Db; -using Nethermind.Field.Montgomery.FrEElement; -using Nethermind.Verkle.VerkleStateDb; +using Nethermind.Verkle.Fields.FrEElement; +using Nethermind.Verkle.Tree; using NUnit.Framework; namespace Nethermind.Verkle.Test; @@ -70,7 +71,7 @@ public class VerkleTreeTests private static string GetDbPathForTest() { string tempDir = Path.GetTempPath(); - string dbname = "VerkleTrie_TestID_" + TestContext.CurrentContext.Test.ID; + string dbname = $"VerkleTrie_TestID_{TestContext.CurrentContext.Test.ID}"; return Path.Combine(tempDir, dbname); } @@ -91,6 +92,65 @@ private static VerkleTree GetVerkleTreeForTest(DbMode dbMode) } } + private VerkleTree GetFilledVerkleTreeForTest(DbMode dbMode) + { + VerkleTree tree = GetVerkleTreeForTest(dbMode); + + tree.Insert(_keyVersion, _emptyArray); + tree.Insert(_keyBalance, _emptyArray); + tree.Insert(_keyNonce, _emptyArray); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _emptyArray); + tree.Flush(0); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); + tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); + tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); + + tree.Insert(_keyVersion, _arrayAll0Last2); + tree.Insert(_keyBalance, _arrayAll0Last2); + tree.Insert(_keyNonce, _arrayAll0Last2); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _arrayAll0Last2); + tree.Flush(1); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last2); + tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); + tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last2); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); + + tree.Insert(_keyVersion, _arrayAll0Last3); + tree.Insert(_keyBalance, _arrayAll0Last3); + tree.Insert(_keyNonce, _arrayAll0Last3); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _arrayAll0Last3); + tree.Flush(2); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last3); + tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last3); + tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last3); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last3); + + tree.Insert(_keyVersion, _arrayAll0Last4); + tree.Insert(_keyBalance, _arrayAll0Last4); + tree.Insert(_keyNonce, _arrayAll0Last4); + tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); + tree.Insert(_keyCodeSize, _arrayAll0Last4); + tree.Flush(3); + + tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last4); + tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last4); + tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last4); + tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); + tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last4); + + return tree; + } + [TearDown] public void CleanTestData() { @@ -104,35 +164,35 @@ public void CleanTestData() [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void InsertKey0Value0(DbMode dbMode) + public void TestInsertKey0Value0(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); byte[] key = _emptyArray; tree.Insert(key, key); - AssertRootNode(tree.RootHash, - "ff00a9f3f2d4f58fc23bceebf6b2310419ceac2c30445e2f374e571487715015"); + AssertRootHash(tree.RootHash, + "6B630905CE275E39F223E175242DF2C1E8395E6F46EC71DCE5557012C1334A5C"); tree.Get(key).Should().BeEquivalentTo(key); } [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void InsertKey1Value1(DbMode dbMode) + public void TestInsertKey1Value1(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); byte[] key = _array1To32; tree.Insert(key, key); - AssertRootNode(tree.RootHash, - "029b6c4c8af9001f0ac76472766c6579f41eec84a73898da06eb97ebdab80a09"); + AssertRootHash(tree.RootHash, + "6F5E7CFC3A158A64E5718B0D2F18F564171342380F5808F3D2A82F7E7F3C2778"); tree.Get(key).Should().BeEquivalentTo(key); } [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void InsertSameStemTwoLeaves(DbMode dbMode) + public void TestInsertSameStemTwoLeaves(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); byte[] keyA = _array1To32; @@ -140,11 +200,11 @@ public void InsertSameStemTwoLeaves(DbMode dbMode) byte[] keyB = _array1To32Last128; tree.Insert(keyA, keyA); - AssertRootNode(tree.RootHash, - "029b6c4c8af9001f0ac76472766c6579f41eec84a73898da06eb97ebdab80a09"); + AssertRootHash(tree.RootHash, + "6F5E7CFC3A158A64E5718B0D2F18F564171342380F5808F3D2A82F7E7F3C2778"); tree.Insert(keyB, keyB); - AssertRootNode(tree.RootHash, - "51e3b2b1b4e4fa85098c91c269af56b06a4474b69128dce99846f0549267fd09"); + AssertRootHash(tree.RootHash, + "14EE5E5C5B698E363055B41DD3334F8168C7FCA4F85C5E30AB39CF9CC2FEEF70"); tree.Get(keyA).Should().BeEquivalentTo(keyA); tree.Get(keyB).Should().BeEquivalentTo(keyB); @@ -152,18 +212,18 @@ public void InsertSameStemTwoLeaves(DbMode dbMode) [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void InsertKey1Val1Key2Val2(DbMode dbMode) + public void TestInsertKey1Val1Key2Val2(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); byte[] keyA = _emptyArray; byte[] keyB = _arrayAll1; tree.Insert(keyA, keyA); - AssertRootNode(tree.RootHash, - "ff00a9f3f2d4f58fc23bceebf6b2310419ceac2c30445e2f374e571487715015"); + AssertRootHash(tree.RootHash, + "6B630905CE275E39F223E175242DF2C1E8395E6F46EC71DCE5557012C1334A5C"); tree.Insert(keyB, keyB); - AssertRootNode(tree.RootHash, - "83ef6d10568d0ac4abbc5fdc17fe7172638803545fd2866aa1d9d204792a2c09"); + AssertRootHash(tree.RootHash, + "5E208CDBA664A7B8FBDC26A1C1185F153A5F721CBA389625C18157CEF7D4931C"); tree.Get(keyA).Should().BeEquivalentTo(keyA); tree.Get(keyB).Should().BeEquivalentTo(keyB); @@ -171,7 +231,7 @@ public void InsertKey1Val1Key2Val2(DbMode dbMode) [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void InsertLongestPath(DbMode dbMode) + public void TestInsertLongestPath(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); byte[] keyA = _emptyArray; @@ -179,11 +239,11 @@ public void InsertLongestPath(DbMode dbMode) keyB[30] = 1; tree.Insert(keyA, keyA); - AssertRootNode(tree.RootHash, - "ff00a9f3f2d4f58fc23bceebf6b2310419ceac2c30445e2f374e571487715015"); + AssertRootHash(tree.RootHash, + "6B630905CE275E39F223E175242DF2C1E8395E6F46EC71DCE5557012C1334A5C"); tree.Insert(keyB, keyB); - AssertRootNode(tree.RootHash, - "fe2e17833b90719eddcad493c352ccd491730643ecee39060c7c1fff5fcc621a"); + AssertRootHash(tree.RootHash, + "3258D722AEA34B5AE7CB24A9B0175EDF0533C651FA09592E823B5969C729FB88"); tree.Get(keyA).Should().BeEquivalentTo(keyA); tree.Get(keyB).Should().BeEquivalentTo(keyB); @@ -191,25 +251,25 @@ public void InsertLongestPath(DbMode dbMode) [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void InsertAndTraverseLongestPath(DbMode dbMode) + public void TestInsertAndTraverseLongestPath(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); byte[] keyA = _emptyArray; tree.Insert(keyA, keyA); - AssertRootNode(tree.RootHash, - "ff00a9f3f2d4f58fc23bceebf6b2310419ceac2c30445e2f374e571487715015"); + AssertRootHash(tree.RootHash, + "6B630905CE275E39F223E175242DF2C1E8395E6F46EC71DCE5557012C1334A5C"); byte[] keyB = (byte[])_emptyArray.Clone(); keyB[30] = 1; tree.Insert(keyB, keyB); - AssertRootNode(tree.RootHash, - "fe2e17833b90719eddcad493c352ccd491730643ecee39060c7c1fff5fcc621a"); + AssertRootHash(tree.RootHash, + "3258D722AEA34B5AE7CB24A9B0175EDF0533C651FA09592E823B5969C729FB88"); byte[] keyC = (byte[])_emptyArray.Clone(); keyC[29] = 1; tree.Insert(keyC, keyC); - AssertRootNode(tree.RootHash, - "74ff8821eca20188de49340124f249dac94404efdb3838bb6b4d298e483cc20e"); + AssertRootHash(tree.RootHash, + "5B82B26A1A7E00A1E997ABD51FE3075D05F54AA4CB1B3A70607E62064FADAA82"); tree.Get(keyA).Should().BeEquivalentTo(keyA); tree.Get(keyB).Should().BeEquivalentTo(keyB); @@ -232,13 +292,13 @@ public void TestSimpleUpdate(DbMode dbMode) byte[] key = _array1To32; byte[] value = _emptyArray; tree.Insert(key, value); - AssertRootNode(tree.RootHash, - "77a0747bd526d9d9af60bd5665d24d6cb421f5c8e726b1de62f914f3ff9a361c"); + AssertRootHash(tree.RootHash, + "140A25B322EAA1ADACD0EE1BB135ECA7B78FCF02B4B19E4A55B26B7A434F42AC"); tree.Get(key).Should().BeEquivalentTo(value); tree.Insert(key, key); - AssertRootNode(tree.RootHash, - "029b6c4c8af9001f0ac76472766c6579f41eec84a73898da06eb97ebdab80a09"); + AssertRootHash(tree.RootHash, + "6F5E7CFC3A158A64E5718B0D2F18F564171342380F5808F3D2A82F7E7F3C2778"); tree.Get(key).Should().BeEquivalentTo(key); } @@ -249,24 +309,24 @@ public void TestInsertGet(DbMode dbMode) VerkleTree tree = GetVerkleTreeForTest(dbMode); tree.Insert(_keyVersion, _emptyArray); - AssertRootNode(tree.RootHash, - "012cc5c81083b484e578390ca619725ff8597753a8da7f26676459e2ab543b08"); + AssertRootHash(tree.RootHash, + "476C50753A22B270DA9D409C0F9AB655AB2506CE4EF831481DD455F0EA730FEF"); tree.Insert(_keyBalance, _arrayAll0Last2); - AssertRootNode(tree.RootHash, - "1b3e9d60e1e510defdca6a382bbc6249c98870e341744a99906a230d9193350d"); + AssertRootHash(tree.RootHash, + "6D9E4F2D418DE2822CE9C2F4193C0E155E4CAC6CF4170E44098DC49D4B571B7B"); tree.Insert(_keyNonce, _emptyArray); - AssertRootNode(tree.RootHash, - "5bcb12efaf7f407743ea0258d2b1fc12b0856a423c3fe268c10d53b89a43771c"); + AssertRootHash(tree.RootHash, + "5C7AE53FE2AAE9852127140C1E2F5122BB3759A7975C0E7A1AEC7CAF7C711FDE"); tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - AssertRootNode(tree.RootHash, - "828983030205ddd526a2444f707f63f187d079872d33e5fba334f77fe8bb301c"); + AssertRootHash(tree.RootHash, + "3FD5FA25042DB0304792BFC007514DA5B777516FFBDAA5658AF36D355ABD9BD8"); tree.Insert(_keyCodeSize, _emptyArray); - AssertRootNode(tree.RootHash, - "1f470a52c36f350d24aba63cf5de6d676deff21fbd3f844150841197c1c6af19"); + AssertRootHash(tree.RootHash, + "006BD679A8204502DCBF9A002F0B828AECF5A29A3A5CE454E651E3A96CC02FE2"); tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); @@ -336,270 +396,150 @@ public void TestInsertGetMultiBlock(DbMode dbMode) tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); } - [TestCase(DbMode.MemDb)] + [TestCase(DbMode.MemDb)] [TestCase(DbMode.PersistantDb)] - public void TestInsertGetMultiBlockReverseState(DbMode dbMode) + public void TestBeverlyHillGenesis(DbMode dbMode) { VerkleTree tree = GetVerkleTreeForTest(dbMode); - - tree.Insert(_keyVersion, _emptyArray); - tree.Insert(_keyBalance, _emptyArray); - tree.Insert(_keyNonce, _emptyArray); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _emptyArray); - tree.Flush(0); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); - - tree.Insert(_keyVersion, _arrayAll0Last2); - tree.Insert(_keyBalance, _arrayAll0Last2); - tree.Insert(_keyNonce, _arrayAll0Last2); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last2); - tree.Flush(1); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); - - tree.Insert(_keyVersion, _arrayAll0Last3); - tree.Insert(_keyBalance, _arrayAll0Last3); - tree.Insert(_keyNonce, _arrayAll0Last3); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last3); - tree.Flush(2); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last3); - - tree.ReverseState(); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); - - tree.ReverseState(); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); - } - - [TestCase(DbMode.MemDb)] - [TestCase(DbMode.PersistantDb)] - public void TestInsertGetBatchMultiBlockReverseState(DbMode dbMode) - { - VerkleTree tree = GetVerkleTreeForTest(dbMode); - - tree.Insert(_keyVersion, _emptyArray); - tree.Insert(_keyBalance, _emptyArray); - tree.Insert(_keyNonce, _emptyArray); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _emptyArray); - tree.Flush(0); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); - - tree.Insert(_keyVersion, _arrayAll0Last2); - tree.Insert(_keyBalance, _arrayAll0Last2); - tree.Insert(_keyNonce, _arrayAll0Last2); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last2); - tree.Flush(1); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); - - tree.Insert(_keyVersion, _arrayAll0Last3); - tree.Insert(_keyBalance, _arrayAll0Last3); - tree.Insert(_keyNonce, _arrayAll0Last3); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last3); - tree.Flush(2); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last3); - - IVerkleDiffDb diff = tree.GetReverseMergedDiff(1, 2); - - tree.ReverseState(diff, 1); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); - } - - private VerkleTree GetFilledVerkleTreeForTest(DbMode dbMode) - { - VerkleTree tree = GetVerkleTreeForTest(dbMode); - - tree.Insert(_keyVersion, _emptyArray); - tree.Insert(_keyBalance, _emptyArray); - tree.Insert(_keyNonce, _emptyArray); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _emptyArray); - tree.Flush(0); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); - - tree.Insert(_keyVersion, _arrayAll0Last2); - tree.Insert(_keyBalance, _arrayAll0Last2); - tree.Insert(_keyNonce, _arrayAll0Last2); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last2); - tree.Flush(1); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last2); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last2); - - tree.Insert(_keyVersion, _arrayAll0Last3); - tree.Insert(_keyBalance, _arrayAll0Last3); - tree.Insert(_keyNonce, _arrayAll0Last3); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last3); - tree.Flush(2); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last3); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last3); - - tree.Insert(_keyVersion, _arrayAll0Last4); - tree.Insert(_keyBalance, _arrayAll0Last4); - tree.Insert(_keyNonce, _arrayAll0Last4); - tree.Insert(_keyCodeCommitment, _valueEmptyCodeHashValue); - tree.Insert(_keyCodeSize, _arrayAll0Last4); - tree.Flush(3); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last4); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last4); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last4); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last4); - - return tree; - } - - [TestCase(DbMode.MemDb)] - [TestCase(DbMode.PersistantDb)] - public void TestReverseDiffThenForwardDiff(DbMode dbMode) - { - VerkleTree tree = GetFilledVerkleTreeForTest(dbMode); - - IVerkleDiffDb diff = tree.GetReverseMergedDiff(1, 3); - - tree.ReverseState(diff, 2); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyBalance).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyNonce).Should().BeEquivalentTo(_emptyArray); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_emptyArray); - - IVerkleDiffDb forwardDiff = tree.GetForwardMergedDiff(1, 3); - - tree.ReverseState(forwardDiff, -2); - - tree.Get(_keyVersion).Should().BeEquivalentTo(_arrayAll0Last4); - tree.Get(_keyBalance).Should().BeEquivalentTo(_arrayAll0Last4); - tree.Get(_keyNonce).Should().BeEquivalentTo(_arrayAll0Last4); - tree.Get(_keyCodeCommitment).Should().BeEquivalentTo(_valueEmptyCodeHashValue); - tree.Get(_keyCodeSize).Should().BeEquivalentTo(_arrayAll0Last4); - - } - - [TestCase(DbMode.MemDb)] - [TestCase(DbMode.PersistantDb)] - public void TestReverseStateOneBlock(DbMode dbMode) - { - VerkleTree tree = GetFilledVerkleTreeForTest(dbMode); - DateTime start = DateTime.Now; - tree.ReverseState(); - DateTime end = DateTime.Now; - Console.WriteLine($"ReverseState() 1 Block: {(end - start).TotalMilliseconds}"); - } - - [TestCase(DbMode.MemDb)] - [TestCase(DbMode.PersistantDb)] - public void TestForwardStateOneBlock(DbMode dbMode) - { - VerkleTree tree = GetFilledVerkleTreeForTest(dbMode); - tree.ReverseState(); - IVerkleDiffDb forwardDiff = tree.GetForwardMergedDiff(2, 3); - DateTime start = DateTime.Now; - tree.ReverseState(forwardDiff, -1); - DateTime end = DateTime.Now; - Console.WriteLine($"ForwardState() 1 Block Insert: {(end - start).TotalMilliseconds}"); - } - - [TestCase(DbMode.MemDb)] - [TestCase(DbMode.PersistantDb)] - public void TestBatchReverseDiffs(DbMode dbMode) - { - // VerkleTree tree = GetHugeVerkleTreeForTest(dbMode); - // for (int i = 2;i <= 1000;i++) { - // DateTime start = DateTime.Now; - // IVerkleDiffDb reverseDiff = tree.GetReverseMergedDiff(1, i); - // DateTime check1 = DateTime.Now; - // tree.ReverseState(reverseDiff, (i -1)); - // DateTime check2 = DateTime.Now; - // Console.WriteLine($"Batch Reverse Diff Fetch(1, {i}): {(check1 - start).TotalMilliseconds}"); - // Console.WriteLine($"Batch Reverse State(2, {i-1}): {(check2 - check1).TotalMilliseconds}"); - //} + byte[][] keys = + { + new byte[] + { + 80, 91, 197, 250, 186, 158, 22, 244, 39, 111, 133, 220, 198, 184, 196, 37, 196, 170, 83, 13, 248, 137, 214, 145, 207, 141, 22, 250, 127, 178, 242, 98 + }, + new byte[] + { + 80, 91, 197, 250, 186, 158, 22, 244, 39, 111, 133, 220, 198, 184, 196, 37, 196, 170, 83, 13, 248, 137, 214, 145, 207, 141, 22, 250, 127, 178, 242, 0 + }, + new byte[] + { + 80, 91, 197, 250, 186, 158, 22, 244, 39, 111, 133, 220, 198, 184, 196, 37, 196, 170, 83, 13, 248, 137, 214, 145, 207, 141, 22, 250, 127, 178, 242, 1 + }, + new byte[] + { + 80, 91, 197, 250, 186, 158, 22, 244, 39, 111, 133, 220, 198, 184, 196, 37, 196, 170, 83, 13, 248, 137, 214, 145, 207, 141, 22, 250, 127, 178, 242, 2 + }, + new byte[] + { + 80, 91, 197, 250, 186, 158, 22, 244, 39, 111, 133, 220, 198, 184, 196, 37, 196, 170, 83, 13, 248, 137, 214, 145, 207, 141, 22, 250, 127, 178, 242, 3 + }, + new byte[] + { + 80, 28, 126, 51, 3, 54, 20, 30, 142, 44, 127, 93, 139, 146, 112, 200, 182, 35, 165, 99, 140, 74, 215, 203, 100, 29, 142, 136, 89, 75, 19, 0 + }, + new byte[] + { + 80, 28, 126, 51, 3, 54, 20, 30, 142, 44, 127, 93, 139, 146, 112, 200, 182, 35, 165, 99, 140, 74, 215, 203, 100, 29, 142, 136, 89, 75, 19, 1 + }, + new byte[] + { + 80, 28, 126, 51, 3, 54, 20, 30, 142, 44, 127, 93, 139, 146, 112, 200, 182, 35, 165, 99, 140, 74, 215, 203, 100, 29, 142, 136, 89, 75, 19, 2 + }, + new byte[] + { + 80, 28, 126, 51, 3, 54, 20, 30, 142, 44, 127, 93, 139, 146, 112, 200, 182, 35, 165, 99, 140, 74, 215, 203, 100, 29, 142, 136, 89, 75, 19, 3 + } + + }; + byte[][] values = + { + new byte[] + { + 245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169, 39, 89, 251, 75 + }, + new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + new byte[] + { + 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112 + }, + new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + new byte[] + { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + new byte[] + { + 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112 + }, + + }; + byte[][] expectedRootHash = + { + new byte[] + { + 65, 218, 34, 122, 247, 60, 5, 240, 251, 52, 246, 140, 37, 216, 19, 241, 119, 101, 100, 139, 61, 137, 58, 14, 46, 134, 177, 141, 32, 154, 1, 59 + }, + new byte[] + { + 69, 56, 80, 6, 24, 134, 42, 30, 244, 7, 143, 117, 127, 102, 1, 223, 77, 33, 172, 250, 47, 138, 224, 44, 49, 218, 223, 138, 225, 174, 75, 206 + }, + new byte[] + { + 1, 193, 213, 250, 133, 201, 192, 237, 111, 140, 199, 105, 38, 248, 215, 48, 91, 252, 209, 7, 111, 242, 47, 75, 91, 142, 31, 125, 12, 184, 18, 245 + }, + new byte[] + { + 81, 28, 164, 25, 6, 44, 54, 172, 110, 118, 89, 173, 112, 198, 226, 209, 24, 221, 92, 3, 221, 62, 85, 11, 85, 179, 58, 178, 78, 187, 238, 71 + }, + new byte[] + { + 57, 217, 114, 85, 250, 173, 204, 43, 147, 248, 170, 130, 74, 146, 15, 162, 181, 125, 23, 235, 3, 110, 20, 156, 89, 185, 169, 139, 69, 112, 37, 175 + }, + new byte[] + { + 3, 81, 31, 1, 31, 195, 243, 62, 60, 100, 13, 77, 215, 21, 9, 92, 237, 104, 172, 25, 234, 240, 207, 142, 94, 213, 237, 176, 195, 163, 39, 87 + }, + new byte[] + { + 83, 211, 141, 144, 197, 72, 206, 46, 100, 220, 68, 98, 90, 239, 120, 251, 113, 102, 18, 170, 98, 238, 138, 174, 249, 120, 142, 238, 79, 192, 75, 59 + }, + new byte[] + { + 91, 25, 255, 166, 55, 136, 143, 224, 38, 101, 85, 250, 65, 108, 59, 161, 105, 247, 140, 181, 185, 207, 120, 76, 92, 218, 72, 103, 18, 0, 214, 144 + }, + new byte[] + { + 5, 153, 156, 66, 226, 161, 228, 136, 209, 248, 42, 235, 222, 221, 118, 125, 87, 137, 13, 106, 11, 70, 26, 248, 3, 21, 218, 184, 201, 164, 194, 198 + } + + }; + + + for (int i = 0; i < keys.Length; i++) + { + tree.Insert(keys[i], values[i]); + AssertRootHash(tree.RootHash, expectedRootHash[i]); + } } - [TestCase(DbMode.MemDb)] - [TestCase(DbMode.PersistantDb)] - public void TestBatchForwardDiffs(DbMode dbMode) + [DoesNotReturn] + private static void AssertRootHash(byte[] realRootHash, string expectedRootHash) { - // VerkleTree tree = GetHugeVerkleTreeForTest(dbMode); - // for (int i = 2;i <= 1000;i++) { - // DateTime start = DateTime.Now; - // IVerkleDiffDb forwardDiff = tree.GetForwardMergedDiff(1, i); - // DateTime check1 = DateTime.Now; - // tree.ForwardState(reverseDiff, (i -1)); - // DateTime check2 = DateTime.Now; - // Console.WriteLine($"Batch Forward Diff Fetch(1, {i}): {(check1 - start).TotalMilliseconds}"); - // Console.WriteLine($"Batch Forward State(2, {i-1}): {(check2 - check1).TotalMilliseconds}"); - //} + Convert.ToHexString(realRootHash).Should() + .BeEquivalentTo(expectedRootHash); } - private static void AssertRootNode(byte[] realRootHash, string expectedRootHash) + [DoesNotReturn] + private static void AssertRootHash(IEnumerable realRootHash, IEnumerable expectedRootHash) { - Convert.ToHexString(realRootHash).Should() - .BeEquivalentTo(expectedRootHash); + realRootHash.Should().BeEquivalentTo(expectedRootHash); } } diff --git a/src/Nethermind/Nethermind.Verkle.Tree/AccountHeader.cs b/src/Nethermind/Nethermind.Verkle.Tree/AccountHeader.cs new file mode 100644 index 00000000000..ab627ec22b3 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/AccountHeader.cs @@ -0,0 +1,79 @@ +using Nethermind.Int256; +using Nethermind.Verkle.Utils; + +namespace Nethermind.Verkle.Tree; + +public readonly struct AccountHeader +{ + public const int Version = 0; + public const int Balance = 1; + public const int Nonce = 2; + public const int CodeHash = 3; + public const int CodeSize = 4; + + private const int MainStorageOffsetExponent = 31; + private static readonly UInt256 MainStorageOffsetBase = 256; + private static readonly UInt256 MainStorageOffset = MainStorageOffsetBase << MainStorageOffsetExponent; + + private static readonly UInt256 HeaderStorageOffset = 64; + private static readonly UInt256 CodeOffset = 128; + private static readonly UInt256 VerkleNodeWidth = 256; + + public static byte[] GetTreeKeyPrefix(ReadOnlySpan address20, UInt256 treeIndex) + { + return PedersenHash.Hash(ToAddress32(address20), treeIndex); + } + + public static Span ToAddress32(ReadOnlySpan address20) + { + Span destination = (Span) new byte[32]; + Span sl = destination[12..]; + address20.CopyTo(sl); + return destination; + } + + public static byte[] GetTreeKeyPrefixAccount(byte[] address) => GetTreeKeyPrefix(address, 0); + + public static byte[] GetTreeKey(byte[] address, UInt256 treeIndex, byte subIndexBytes) + { + byte[] treeKeyPrefix = GetTreeKeyPrefix(address, treeIndex); + treeKeyPrefix[31] = subIndexBytes; + return treeKeyPrefix; + } + + public static byte[] GetTreeKeyForVersion(byte[] address) => GetTreeKey(address, UInt256.Zero, Version); + public static byte[] GetTreeKeyForBalance(byte[] address) => GetTreeKey(address, UInt256.Zero, Balance); + public static byte[] GetTreeKeyForNonce(byte[] address) => GetTreeKey(address, UInt256.Zero, Nonce); + public static byte[] GetTreeKeyForCodeCommitment(byte[] address) => GetTreeKey(address, UInt256.Zero, CodeHash); + public static byte[] GetTreeKeyForCodeSize(byte[] address) => GetTreeKey(address, UInt256.Zero, CodeSize); + + + public static byte[] GetTreeKeyForCodeChunk(byte[] address, UInt256 chunk) + { + UInt256 chunkOffset = CodeOffset + chunk; + UInt256 treeIndex = chunkOffset / VerkleNodeWidth; + UInt256.Mod(chunkOffset, VerkleNodeWidth, out UInt256 subIndex); + return GetTreeKey(address, treeIndex, subIndex.ToBigEndian()[31]); + } + + public static byte[] GetTreeKeyForStorageSlot(byte[] address, UInt256 storageKey) + { + UInt256 pos; + + if (storageKey < CodeOffset - HeaderStorageOffset) pos = HeaderStorageOffset + storageKey; + else pos = MainStorageOffset + storageKey; + + UInt256 treeIndex = pos / VerkleNodeWidth; + + UInt256.Mod(pos, VerkleNodeWidth, out UInt256 subIndex); + return GetTreeKey(address, treeIndex, subIndex.ToBigEndian()[31]); + } + + public static void FillTreeAndSubIndexForChunk(UInt256 chunkId, ref Span subIndexBytes, out UInt256 treeIndex) + { + UInt256 chunkOffset = CodeOffset + chunkId; + treeIndex = chunkOffset / VerkleNodeWidth; + UInt256.Mod(chunkOffset, VerkleNodeWidth, out UInt256 subIndex); + subIndex.ToBigEndian(subIndexBytes); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/CodeChunkEnumerator.cs b/src/Nethermind/Nethermind.Verkle.Tree/CodeChunkEnumerator.cs new file mode 100644 index 00000000000..98d2d5796af --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/CodeChunkEnumerator.cs @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Verkle.Tree; + +public ref struct CodeChunkEnumerator +{ + const byte PushOffset = 95; + const byte Push1 = PushOffset + 1; + const byte Push32 = PushOffset + 32; + + private Span _code; + private byte _rollingOverPushLength = 0; + private readonly byte[] _bufferChunk = new byte[32]; + private readonly Span _bufferChunkCodePart; + + public CodeChunkEnumerator(Span code) + { + _code = code; + _bufferChunkCodePart = _bufferChunk.AsSpan().Slice(1); + } + + // Try get next chunk + public bool TryGetNextChunk(out byte[] chunk) + { + chunk = _bufferChunk; + + // we don't have chunks left + if (_code.IsEmpty) + { + return false; + } + + // we don't have full chunk + if (_code.Length < 31) + { + // need to have trailing zeroes + _bufferChunkCodePart.Fill(0); + + // set number of push bytes + _bufferChunk[0] = _rollingOverPushLength; + + // copy main bytes + _code.CopyTo(_bufferChunkCodePart); + + // we are done + _code = Span.Empty; + } + else + { + // fill up chunk to store + + // get current chunk of code + Span currentChunk = _code.Slice(0, 31); + + // copy main bytes + currentChunk.CopyTo(_bufferChunkCodePart); + + switch (_rollingOverPushLength) + { + case 32 or 31: // all bytes are roll over + + // set number of push bytes + _bufferChunk[0] = 31; + + // if 32, then we will roll over with 1 to even next chunk + _rollingOverPushLength -= 31; + break; + default: + // set number of push bytes + _bufferChunk[0] = _rollingOverPushLength; + _rollingOverPushLength = 0; + + // check if we have a push instruction in remaining code + // ignore the bytes we rolled over, they are not instructions + for (int i = _bufferChunk[0]; i < 31;) + { + byte instruction = currentChunk[i]; + i++; + if (instruction is >= Push1 and <= Push32) + { + // we calculate data to ignore in code + i += instruction - PushOffset; + + // check if we rolled over the chunk + _rollingOverPushLength = (byte)Math.Max(i - 31, 0); + } + } + break; + } + + // move to next chunk + _code = _code.Slice(31); + } + return true; + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/CompositeVerkleStateStore.cs b/src/Nethermind/Nethermind.Verkle.Tree/CompositeVerkleStateStore.cs new file mode 100644 index 00000000000..9abc80a68d8 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/CompositeVerkleStateStore.cs @@ -0,0 +1,105 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Trie.Pruning; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Tree.VerkleDb; + +namespace Nethermind.Verkle.Tree; + +public class CompositeVerkleStateStore: IVerkleStore +{ + + private readonly IVerkleStore _wrappedStore; + private VerkleMemoryDb _memDb; + + public CompositeVerkleStateStore(IVerkleStore verkleStore) + { + _wrappedStore = verkleStore ?? throw new ArgumentNullException(nameof(verkleStore)); + _memDb = new VerkleMemoryDb(); + } + + public event EventHandler? ReorgBoundaryReached; + + public byte[] RootHash + { + get => GetStateRoot(); + set => MoveToStateRoot(value); + } + public byte[]? GetLeaf(byte[] key) + { + return _memDb.GetLeaf(key, out var value) ? value : _wrappedStore.GetLeaf(key); + } + public SuffixTree? GetStem(byte[] key) + { + return _memDb.GetStem(key, out var value) ? value : _wrappedStore.GetStem(key); + } + public InternalNode? GetBranch(byte[] key) + { + return _memDb.GetBranch(key, out var value) ? value : _wrappedStore.GetBranch(key); + } + public void SetLeaf(byte[] leafKey, byte[] leafValue) + { + _memDb.SetLeaf(leafKey, leafValue); + } + public void SetStem(byte[] stemKey, SuffixTree suffixTree) + { + _memDb.SetStem(stemKey, suffixTree); + } + public void SetBranch(byte[] branchKey, InternalNode internalNodeValue) + { + _memDb.SetBranch(branchKey, internalNodeValue); + } + public void Flush(long blockNumber) + { + foreach (KeyValuePair entry in _memDb.LeafTable) + { + _wrappedStore.SetLeaf(entry.Key, entry.Value); + } + + foreach (KeyValuePair entry in _memDb.StemTable) + { + _wrappedStore.SetStem(entry.Key, entry.Value); + } + + foreach (KeyValuePair entry in _memDb.BranchTable) + { + _wrappedStore.SetBranch(entry.Key, entry.Value); + } + _wrappedStore.Flush(blockNumber); + _memDb = new VerkleMemoryDb(); + } + public void ReverseState() + { + _memDb = new VerkleMemoryDb(); + _wrappedStore.ReverseState(); + } + public void ApplyDiffLayer(BatchChangeSet changeSet) + { + _memDb = new VerkleMemoryDb(); + _wrappedStore.ApplyDiffLayer(changeSet); + } + public byte[] GetStateRoot() + { + return GetBranch(Array.Empty())?._internalCommitment.Point.ToBytes().ToArray() ?? throw new InvalidOperationException(); + } + public void MoveToStateRoot(byte[] stateRoot) + { + _memDb = new VerkleMemoryDb(); + _wrappedStore.MoveToStateRoot(stateRoot); + } + public ReadOnlyVerkleStateStore AsReadOnly(VerkleMemoryDb keyValueStore) + { + throw new NotImplementedException(); + } + public VerkleMemoryDb GetForwardMergedDiff(long fromBlock, long toBlock) + { + _memDb = new VerkleMemoryDb(); + return _wrappedStore.GetForwardMergedDiff(fromBlock, toBlock); + } + public VerkleMemoryDb GetReverseMergedDiff(long fromBlock, long toBlock) + { + _memDb = new VerkleMemoryDb(); + return _wrappedStore.GetReverseMergedDiff(fromBlock, toBlock); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/IVerkleTreeVisitor.cs b/src/Nethermind/Nethermind.Verkle.Tree/IVerkleTreeVisitor.cs new file mode 100644 index 00000000000..1035025ff59 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/IVerkleTreeVisitor.cs @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Trie; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree; + +public interface IVerkleTreeVisitor +{ + bool ShouldVisit(byte[] nextNode); + + void VisitTree(byte[] rootHash, TrieVisitContext trieVisitContext); + + void VisitMissingNode(byte[] nodeKey, TrieVisitContext trieVisitContext); + + void VisitBranchNode(BranchNode node, TrieVisitContext trieVisitContext); + + void VisitStemNode(StemNode node, TrieVisitContext trieVisitContext); + + void VisitLeafNode(byte[] nodeKey, TrieVisitContext trieVisitContext, byte[]? nodeValue); + +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Nethermind.Verkle.Tree.csproj b/src/Nethermind/Nethermind.Verkle.Tree/Nethermind.Verkle.Tree.csproj new file mode 100644 index 00000000000..c5b0f1971ac --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Nethermind.Verkle.Tree.csproj @@ -0,0 +1,19 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + diff --git a/src/Nethermind/Nethermind.Verkle/VerkleNodes/Nodes.cs b/src/Nethermind/Nethermind.Verkle.Tree/Nodes/InternalNodes.cs similarity index 55% rename from src/Nethermind/Nethermind.Verkle/VerkleNodes/Nodes.cs rename to src/Nethermind/Nethermind.Verkle.Tree/Nodes/InternalNodes.cs index 12339aa96bb..3a2621d66d2 100644 --- a/src/Nethermind/Nethermind.Verkle/VerkleNodes/Nodes.cs +++ b/src/Nethermind/Nethermind.Verkle.Tree/Nodes/InternalNodes.cs @@ -1,83 +1,12 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + using System.Diagnostics; -using Nethermind.Field.Montgomery.FrEElement; using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Fields.FrEElement; using Nethermind.Verkle.Utils; -namespace Nethermind.Verkle.VerkleNodes; - -public enum NodeType : byte -{ - BranchNode = 1, - StemNode = 2 -} - -public class SuffixTree -{ - public byte[] Stem { get; } - public Commitment C1 { get; } - public Commitment C2 { get; } - public Commitment ExtensionCommitment { get; } - public FrE InitCommitmentHash { get; } - - public SuffixTree(byte[] stem) - { - Stem = stem; - C1 = new Commitment(); - C2 = new Commitment(); - ExtensionCommitment = new Commitment(); - InitCommitmentHash = FrE.Zero; - Banderwagon stemCommitment = GetInitialCommitment(); - ExtensionCommitment.AddPoint(stemCommitment); - InitCommitmentHash = ExtensionCommitment.PointAsField.Dup(); - } - - internal SuffixTree(byte[] stem, byte[] c1, byte[] c2, byte[] extCommit) - { - Stem = stem; - C1 = new Commitment(new Banderwagon(c1)); - C2 = new Commitment(new Banderwagon(c2)); - ExtensionCommitment = new Commitment(new Banderwagon(extCommit)); - InitCommitmentHash = FrE.Zero; - } - - private Banderwagon GetInitialCommitment() => Committer.ScalarMul(FrE.One, 0) + - Committer.ScalarMul(FrE.FromBytesReduced(Stem.Reverse().ToArray()), 1); - - public FrE UpdateCommitment(LeafUpdateDelta deltaLeafCommitment) - { - FrE prevCommit = ExtensionCommitment.PointAsField.Dup(); - - FrE oldC1Value = C1.PointAsField.Dup(); - FrE oldC2Value = C2.PointAsField.Dup(); - if (deltaLeafCommitment.DeltaC1 is not null) C1.AddPoint(deltaLeafCommitment.DeltaC1); - if (deltaLeafCommitment.DeltaC2 is not null) C2.AddPoint(deltaLeafCommitment.DeltaC2); - - FrE deltaC1Commit = C1.PointAsField - oldC1Value; - FrE deltaC2Commit = C2.PointAsField - oldC2Value; - - Banderwagon deltaCommit = Committer.ScalarMul(deltaC1Commit, 2) - + Committer.ScalarMul(deltaC2Commit, 3); - - ExtensionCommitment.AddPoint(deltaCommit); - return ExtensionCommitment.PointAsField - prevCommit; - } - - public byte[] Encode() - { - int nodeLength = 31 + 32 + 32 + 32; - byte[] rlp = new byte[nodeLength]; - Buffer.BlockCopy(Stem, 0, rlp, 0, 31); - Buffer.BlockCopy(C1.Point.ToBytes(), 0, rlp, 31, 32); - Buffer.BlockCopy(C2.Point.ToBytes(), 0, rlp, 63, 32); - Buffer.BlockCopy(ExtensionCommitment.Point.ToBytes(), 0, rlp, 95, 32); - return rlp; - } - - public static SuffixTree Decode(byte[] rlp) - { - return new SuffixTree(rlp[..31], rlp[32..64], rlp[64..96], rlp[96..128]); - } -} +namespace Nethermind.Verkle.Tree.Nodes; public class StemNode : InternalNode { diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Nodes/Nodes.cs b/src/Nethermind/Nethermind.Verkle.Tree/Nodes/Nodes.cs new file mode 100644 index 00000000000..a1c59f0dffb --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Nodes/Nodes.cs @@ -0,0 +1,8 @@ + +namespace Nethermind.Verkle.Tree.Nodes; + +public enum NodeType : byte +{ + BranchNode = 1, + StemNode = 2 +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Nodes/SuffixTree.cs b/src/Nethermind/Nethermind.Verkle.Tree/Nodes/SuffixTree.cs new file mode 100644 index 00000000000..5889c343798 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Nodes/SuffixTree.cs @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Fields.FrEElement; +using Nethermind.Verkle.Utils; + +namespace Nethermind.Verkle.Tree.Nodes; + +public class SuffixTree +{ + public byte[] Stem { get; } + public Commitment C1 { get; } + public Commitment C2 { get; } + public Commitment ExtensionCommitment { get; } + public FrE InitCommitmentHash { get; } + + public SuffixTree(byte[] stem) + { + Stem = stem; + C1 = new Commitment(); + C2 = new Commitment(); + ExtensionCommitment = new Commitment(); + InitCommitmentHash = FrE.Zero; + Banderwagon stemCommitment = GetInitialCommitment(); + ExtensionCommitment.AddPoint(stemCommitment); + InitCommitmentHash = ExtensionCommitment.PointAsField.Dup(); + } + + internal SuffixTree(byte[] stem, byte[] c1, byte[] c2, byte[] extCommit) + { + Stem = stem; + C1 = new Commitment(new Banderwagon(c1)); + C2 = new Commitment(new Banderwagon(c2)); + ExtensionCommitment = new Commitment(new Banderwagon(extCommit)); + InitCommitmentHash = FrE.Zero; + } + + private Banderwagon GetInitialCommitment() => Committer.ScalarMul(FrE.One, 0) + + Committer.ScalarMul(FrE.FromBytesReduced(Stem.Reverse().ToArray()), 1); + + public FrE UpdateCommitment(LeafUpdateDelta deltaLeafCommitment) + { + FrE prevCommit = ExtensionCommitment.PointAsField.Dup(); + + FrE oldC1Value = C1.PointAsField.Dup(); + FrE oldC2Value = C2.PointAsField.Dup(); + if (deltaLeafCommitment.DeltaC1 is not null) C1.AddPoint(deltaLeafCommitment.DeltaC1); + if (deltaLeafCommitment.DeltaC2 is not null) C2.AddPoint(deltaLeafCommitment.DeltaC2); + + FrE deltaC1Commit = C1.PointAsField - oldC1Value; + FrE deltaC2Commit = C2.PointAsField - oldC2Value; + + Banderwagon deltaCommit = Committer.ScalarMul(deltaC1Commit, 2) + + Committer.ScalarMul(deltaC2Commit, 3); + + ExtensionCommitment.AddPoint(deltaCommit); + return ExtensionCommitment.PointAsField - prevCommit; + } + + public byte[] Encode() + { + int nodeLength = 31 + 32 + 32 + 32; + byte[] rlp = new byte[nodeLength]; + Buffer.BlockCopy(Stem, 0, rlp, 0, 31); + Buffer.BlockCopy(C1.Point.ToBytes(), 0, rlp, 31, 32); + Buffer.BlockCopy(C2.Point.ToBytes(), 0, rlp, 63, 32); + Buffer.BlockCopy(ExtensionCommitment.Point.ToBytes(), 0, rlp, 95, 32); + return rlp; + } + + public static SuffixTree Decode(byte[] rlp) + { + return new SuffixTree(rlp[..31], rlp[32..64], rlp[64..96], rlp[96..128]); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Proofs/SpecStructs.cs b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/SpecStructs.cs new file mode 100644 index 00000000000..254e3fabf17 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/SpecStructs.cs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Proofs; + +namespace Nethermind.Verkle.Tree.Proofs; + +public struct VProof +{ + public VerkleProofStruct _multiPoint; + public List _extStatus; + public List _cS; + public List _poaStems; + public List _keys; + public List _values; +} + +public struct ExecutionWitness +{ + public StateDiff StateDiff; + public VProof Proof; +} +public struct SuffixStateDiff +{ + public byte Suffix; + + // byte32 + public byte[]? CurrentValue; + + // byte32 + public byte[]? NewValue; +} + +public struct StemStateDiff +{ + // byte31 + public byte[] Stem; + + // max length = 256 + public List SuffixDiffs; +} + +public struct StateDiff +{ + // max length = 2**16 + public List Diff; +} + + +// public class VerkleProofGenVerify +// { +// public static +// } diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Proofs/Structures.cs b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/Structures.cs new file mode 100644 index 00000000000..6bf95669fd3 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/Structures.cs @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Text; +using FastEnumUtility; +using Nethermind.Core.Extensions; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Fields.FrEElement; +using Nethermind.Verkle.Proofs; + +namespace Nethermind.Verkle.Tree.Proofs; + +public struct VerkleProof +{ + public VerificationHint VerifyHint; + public Banderwagon[] CommsSorted; + public VerkleProofStruct Proof; + + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("\n####[Verkle Proof]####\n"); + stringBuilder.Append("\n###[Verify Hint]###\n"); + stringBuilder.Append(VerifyHint.ToString()); + stringBuilder.Append("\n###[Comms Sorted]###\n"); + foreach (Banderwagon comm in CommsSorted) + { + stringBuilder.AppendJoin(", ", comm.ToBytesLittleEndian().Reverse().ToArray()); + stringBuilder.Append('\n'); + } + stringBuilder.Append("\n###[Inner Proof]###\n"); + stringBuilder.Append(Proof.ToString()); + return stringBuilder.ToString(); + } + + public byte[] Encode() + { + List encoded = new List(); + encoded.AddRange(VerifyHint.Encode()); + + encoded.AddRange(CommsSorted.Length.ToByteArrayLittleEndian()); + foreach (Banderwagon comm in CommsSorted) + { + encoded.AddRange(comm.ToBytesLittleEndian().Reverse()); + } + + encoded.AddRange(Proof.Encode()); + + return encoded.ToArray(); + } +} + +public struct VerificationHint +{ + public byte[] Depths; + public ExtPresent[] ExtensionPresent; + public byte[][] DifferentStemNoProof; + + public override string ToString() + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("\n##[Depths]##\n"); + stringBuilder.AppendJoin(", ", Depths); + stringBuilder.Append("\n##[ExtensionPresent]##\n"); + stringBuilder.AppendJoin(", ", ExtensionPresent.Select(x => x.ToString())); + stringBuilder.Append("\n##[DifferentStemNoProof]##\n"); + foreach (byte[] stem in DifferentStemNoProof) + { + stringBuilder.AppendJoin(", ", stem); + } + return stringBuilder.ToString(); + } + + public byte[] Encode() + { + List encoded = new List(); + + encoded.AddRange(DifferentStemNoProof.Length.ToByteArrayLittleEndian()); + foreach (byte[] stem in DifferentStemNoProof) + { + encoded.AddRange(stem); + } + + encoded.AddRange(Depths.Length.ToByteArrayLittleEndian()); + + foreach ((byte depth, ExtPresent extPresent) in Depths.Zip(ExtensionPresent)) + { + byte extPresentByte = (byte)(extPresent.ToByte() | (depth << 3)); + encoded.Add(extPresentByte); + } + + return encoded.ToArray(); + } +} + +public struct UpdateHint +{ + public SortedDictionary DepthAndExtByStem; + public SortedDictionary, Banderwagon> CommByPath; + public SortedDictionary, byte[]> DifferentStemNoProof; +} + +public enum ExtPresent: byte +{ + None = 0, + DifferentStem = 1, + Present = 2 +} + +public struct SuffixPoly +{ + public FrE[] c1; + public FrE[] c2; +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Proofs/Verifier.cs b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/Verifier.cs new file mode 100644 index 00000000000..6b462550115 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/Verifier.cs @@ -0,0 +1,228 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Diagnostics; +using Nethermind.Core.Extensions; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Fields.FrEElement; +using Nethermind.Verkle.Polynomial; +using Nethermind.Verkle.Proofs; +using Nethermind.Verkle.Utils; + +namespace Nethermind.Verkle.Tree.Proofs; + +public class ListComparer: Comparer> +{ + public override int Compare(List? x, List? y) + { + if (x is null) + { + return y is null ? 0 : 1; + } + + if (y is null) + { + return -1; + } + return Bytes.Comparer.Compare(x.ToArray(), y.ToArray()); + } +} + +public class ListWithByteComparer: Comparer<(List, byte)> +{ + public override int Compare((List, byte) x, (List, byte) y) + { + ListComparer comp = new ListComparer(); + int val = comp.Compare(x.Item1, y.Item1); + return val == 0 ? x.Item2.CompareTo(y.Item2) : val; + } +} + + +public static class Verifier +{ + public static (bool, UpdateHint?) VerifyVerkleProof(VerkleProof proof, List keys, List values, Banderwagon root) + { + List commSortedByPath = new List { root }; + commSortedByPath.AddRange(proof.CommsSorted); + + SortedSet stems = new SortedSet(keys.Select(x => x[..31]), Bytes.Comparer); + SortedDictionary depthsAndExtByStem = new SortedDictionary(Bytes.Comparer); + SortedSet stemsWithExtension = new SortedSet(Bytes.Comparer); + SortedSet otherStemsUsed = new SortedSet(Bytes.Comparer); + SortedSet> allPaths = new SortedSet>(new ListComparer()); + SortedSet<(List, byte)> allPathsAndZs = new SortedSet<(List, byte)>(new ListWithByteComparer()); + SortedDictionary<(List, byte), FrE> leafValuesByPathAndZ = new SortedDictionary<(List, byte), FrE>(new ListWithByteComparer()); + SortedDictionary, byte[]> otherStemsByPrefix = new SortedDictionary, byte[]>(new ListComparer()); + + + foreach (((byte[] stem, byte depth) , ExtPresent extPresent) in stems.Zip(proof.VerifyHint.Depths).Zip(proof.VerifyHint.ExtensionPresent)) + { + depthsAndExtByStem.Add(stem, (extPresent, depth)); + switch (extPresent) + { + case ExtPresent.Present: + stemsWithExtension.Add(stem); + break; + case ExtPresent.None: + case ExtPresent.DifferentStem: + break; + default: + throw new ArgumentException($"impossible value for the enum {extPresent}"); + } + } + + foreach ((byte[] key, byte[]? value) in keys.Zip(values)) + { + byte[] stem = key[..31]; + (ExtPresent extPres, byte depth) = depthsAndExtByStem[stem]; + + for (int i = 0; i < depth; i++) + { + allPaths.Add(new List(stem[..i])); + allPathsAndZs.Add((new List(stem[..i]), stem[i])); + } + + switch (extPres) + { + case ExtPresent.DifferentStem: + + allPaths.Add(new List(stem[..depth])); + allPathsAndZs.Add((new List(stem[..depth]), 0)); + allPathsAndZs.Add((new List(stem[..depth]), 1)); + + leafValuesByPathAndZ.Add((new List(stem[..depth]), 0), FrE.One); + + // since the stem was different - value should not have been set + if (value != null) return (false, null); + + Debug.Assert(depth != stem.Length); + + byte[] otherStem; + + byte[][] found = stemsWithExtension.Where(x => x[..depth].SequenceEqual(stem[..depth])).ToArray(); + + switch (found.Length) + { + case 0: + found = proof.VerifyHint.DifferentStemNoProof.Where(x => x[..depth].SequenceEqual(stem[..depth])).ToArray(); + byte[] encounteredStem = found[^1]; + otherStem = encounteredStem; + otherStemsUsed.Add(encounteredStem); + + // Add extension node to proof in particular, we only want to open at (1, stem) + leafValuesByPathAndZ.Add((new List(stem[..depth]), 1), FrE.FromBytesReduced(encounteredStem.Reverse().ToArray())); + break; + case 1: + otherStem = found[0]; + break; + default: + throw new NotSupportedException($"found more than one instance of stem_with_extension at depth {depth}, see: {string.Join(" | ", found.Select(x => string.Join(", ", x)))}"); + } + + otherStemsByPrefix.Add(stem[..depth].ToList(), otherStem); + break; + case ExtPresent.Present: + allPaths.Add(new List(stem[..depth])); + allPathsAndZs.Add((new List(stem[..depth]), 0)); + allPathsAndZs.Add((new List(stem[..depth]), 1)); + + leafValuesByPathAndZ.Add((new List(stem[..depth]), 0), FrE.One); + if (extPres == ExtPresent.Present) + { + byte suffix = key[31]; + byte openingIndex = suffix < 128 ? (byte) 2 : (byte) 3; + + allPathsAndZs.Add((new List(stem[..depth]), openingIndex)); + leafValuesByPathAndZ.Add((new List(stem[..depth]), 1), FrE.FromBytesReduced(stem.Reverse().ToArray())); + + List suffixTreePath = new List(stem[..depth]); + suffixTreePath.Add(openingIndex); + + allPaths.Add(suffixTreePath); + byte valLowerIndex = (byte)(2 * (suffix % 128)); + byte valUpperIndex = (byte)(valLowerIndex + 1); + + allPathsAndZs.Add((suffixTreePath, valLowerIndex)); + allPathsAndZs.Add((suffixTreePath, valUpperIndex)); + + (FrE valLow, FrE valHigh) = VerkleUtils.BreakValueInLowHigh(value); + + leafValuesByPathAndZ.Add((suffixTreePath, valLowerIndex), valLow); + leafValuesByPathAndZ.Add((suffixTreePath, valUpperIndex), valHigh); + } + break; + case ExtPresent.None: + // If the extension was not present, then the value should be None + if (value != null) return (false, null); + + if (depth == 1) + { + leafValuesByPathAndZ.Add((new List(), stem[depth-1]), FrE.Zero); + } + else + { + leafValuesByPathAndZ.Add( + (stem[..depth].ToList(), stem[depth-1]), FrE.Zero + ); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + Debug.Assert(proof.VerifyHint.DifferentStemNoProof.SequenceEqual(otherStemsUsed)); + Debug.Assert(commSortedByPath.Count == allPaths.Count); + + SortedDictionary, Banderwagon> commByPath = new SortedDictionary, Banderwagon>(new ListComparer()); + foreach ((List path, Banderwagon comm) in allPaths.Zip(commSortedByPath)) + { + commByPath[path] = comm; + } + + SortedDictionary<(List, byte), Banderwagon> commByPathAndZ = new SortedDictionary<(List, byte), Banderwagon>(new ListWithByteComparer()); + foreach ((List path, byte z) in allPathsAndZs) + { + commByPathAndZ[(path, z)] = commByPath[path]; + } + + SortedDictionary<(List, byte), FrE> ysByPathAndZ = new SortedDictionary<(List, byte), FrE>(new ListWithByteComparer()); + foreach ((List path, byte z) in allPathsAndZs) + { + List childPath = new List(path.ToArray()) + { + z + }; + + if (!leafValuesByPathAndZ.TryGetValue((path, z), out FrE y)) + { + y = FrE.FromBytesReduced(commByPath[childPath].MapToField()); + } + ysByPathAndZ.Add((path, z), y); + } + + SortedDictionary<(List, byte), Banderwagon>.ValueCollection cs = commByPathAndZ.Values; + + IEnumerable zs = allPathsAndZs.Select(elem => FrE.SetElement(elem.Item2)); + SortedDictionary<(List, byte), FrE>.ValueCollection ys = ysByPathAndZ.Values; + + List queries = new List(cs.Count); + + foreach (((FrE y, FrE z) , Banderwagon comm) in ys.Zip(zs).Zip(cs)) + { + VerkleVerifierQuery query = new VerkleVerifierQuery(comm, z, y); + queries.Add(query); + } + + UpdateHint updateHint = new UpdateHint() + { + DepthAndExtByStem = depthsAndExtByStem, CommByPath = commByPath, DifferentStemNoProof = otherStemsByPrefix + }; + + Transcript proverTranscript = new Transcript("vt"); + MultiProof proofVerifier = new MultiProof(CRS.Instance, PreComputeWeights.Init()); + + return (proofVerifier.CheckMultiProof(proverTranscript, queries.ToArray(), proof.Proof), updateHint); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Proofs/VerkleProofCollector.cs b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/VerkleProofCollector.cs new file mode 100644 index 00000000000..f3765865d0a --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/VerkleProofCollector.cs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Crypto; +using Nethermind.Trie; + +namespace Nethermind.Verkle.Tree.Proofs; + +public class VerkleProofCollector: ITreeVisitor +{ + + public bool ShouldVisit(Keccak nextNode) + { + throw new NotImplementedException(); + } + public void VisitTree(Keccak rootHash, TrieVisitContext trieVisitContext) + { + throw new NotImplementedException(); + } + public void VisitMissingNode(Keccak nodeHash, TrieVisitContext trieVisitContext) + { + throw new NotImplementedException(); + } + public void VisitBranch(TrieNode node, TrieVisitContext trieVisitContext) + { + throw new NotImplementedException(); + } + public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) + { + throw new NotImplementedException(); + } + public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null) + { + throw new NotImplementedException(); + } + public void VisitCode(Keccak codeHash, TrieVisitContext trieVisitContext) + { + throw new NotImplementedException(); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Proofs/VerkleProver.cs b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/VerkleProver.cs new file mode 100644 index 00000000000..3650188f615 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Proofs/VerkleProver.cs @@ -0,0 +1,366 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Data; +using System.Diagnostics; +using Nethermind.Core.Extensions; +using Nethermind.Db; +using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Fields.FrEElement; +using Nethermind.Verkle.Polynomial; +using Nethermind.Verkle.Proofs; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Utils; + +namespace Nethermind.Verkle.Tree.Proofs; + +public class VerkleProver +{ + private readonly IVerkleStore _stateDb; + private readonly Dictionary _proofBranchPolynomialCache = new Dictionary(Bytes.EqualityComparer); + private readonly Dictionary _proofStemPolynomialCache = new Dictionary(Bytes.EqualityComparer); + + public VerkleProver(IDbProvider dbProvider) + { + VerkleStateStore stateDb = new VerkleStateStore(dbProvider); + _stateDb = new CompositeVerkleStateStore(stateDb); + } + + public VerkleProver(IVerkleStore stateStore) + { + _stateDb = new CompositeVerkleStateStore(stateStore); + } + + public VerkleProof CreateVerkleProof(List keys, out Banderwagon rootPoint) + { + _proofBranchPolynomialCache.Clear(); + _proofStemPolynomialCache.Clear(); + + HashSet commsSorted = new HashSet(); + SortedDictionary depthsByStem = new SortedDictionary(Bytes.Comparer); + SortedDictionary extPresentByStem = new SortedDictionary(Bytes.Comparer); + + List extPresent = new List(); + List extNone = new List(); + List extDifferent= new List(); + + // generate prover path for keys + Dictionary> neededOpenings = new Dictionary>(Bytes.EqualityComparer); + + foreach (byte[] key in keys) + { + Debug.Assert(key.Length == 32); + for (int i = 0; i < 32; i++) + { + byte[] currentPath = key[..i]; + InternalNode? node = _stateDb.GetBranch(currentPath); + if (node != null) + { + switch (node.NodeType) + { + case NodeType.BranchNode: + CreateBranchProofPolynomialIfNotExist(currentPath); + neededOpenings.TryAdd(currentPath, new SortedSet()); + neededOpenings[currentPath].Add(key[i]); + continue; + case NodeType.StemNode: + byte[] keyStem = key[..31]; + depthsByStem.TryAdd(keyStem, (byte)i); + CreateStemProofPolynomialIfNotExist(keyStem); + neededOpenings.TryAdd(keyStem, new SortedSet()); + if (keyStem.SequenceEqual(node.Stem)) + { + neededOpenings[keyStem].Add(key[31]); + extPresent.Add(key[..31]); + } + else + { + extDifferent.Add(key[..31]); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + else + { + extNone.Add(key[..31]); + } + // reaching here means end of the path for the leaf + break; + } + } + + List queries = new List(); + SortedSet stemWithNoProofSet = new SortedSet(); + + foreach (KeyValuePair> elem in neededOpenings) + { + int pathLength = elem.Key.Length; + + if (pathLength == 31) + { + queries.AddRange(AddStemCommitmentsOpenings(elem.Key, elem.Value, out bool stemWithNoProof)); + if (stemWithNoProof) stemWithNoProofSet.Add(elem.Key); + continue; + } + + queries.AddRange(AddBranchCommitmentsOpening(elem.Key, elem.Value)); + } + + VerkleProverQuery root = queries.First(); + + rootPoint = root._nodeCommitPoint; + foreach (VerkleProverQuery query in queries.Where(query => root._nodeCommitPoint != query._nodeCommitPoint)) + { + commsSorted.Add(query._nodeCommitPoint); + } + + MultiProof proofConstructor = new MultiProof(CRS.Instance, PreComputeWeights.Init()); + + + Transcript proverTranscript = new Transcript("vt"); + VerkleProofStruct proof = proofConstructor.MakeMultiProof(proverTranscript, queries); + + foreach (byte[] stem in extPresent) + { + extPresentByStem.TryAdd(stem, ExtPresent.Present); + } + + foreach (byte[] stem in extDifferent) + { + extPresentByStem.TryAdd(stem, ExtPresent.DifferentStem); + } + + foreach (byte[] stem in extNone) + { + extPresentByStem.TryAdd(stem, ExtPresent.None); + } + + return new VerkleProof + { + CommsSorted = commsSorted.ToArray(), + Proof = proof, + VerifyHint = new VerificationHint + { + Depths = depthsByStem.Values.ToArray(), DifferentStemNoProof = stemWithNoProofSet.ToArray(), ExtensionPresent = extPresentByStem.Values.ToArray() + } + }; + } + + private IEnumerable AddBranchCommitmentsOpening(byte[] branchPath, IEnumerable branchChild) + { + List queries = new List(); + if(!_proofBranchPolynomialCache.TryGetValue(branchPath, out FrE[] poly)) throw new EvaluateException(); + InternalNode? node = _stateDb.GetBranch(branchPath); + queries.AddRange(branchChild.Select(childIndex => new VerkleProverQuery(new LagrangeBasis(poly), node!._internalCommitment.Point, FrE.SetElement(childIndex), poly[childIndex]))); + return queries; + } + + private IEnumerable AddStemCommitmentsOpenings(byte[] stemPath, SortedSet stemChild, out bool stemWithNoProof) + { + stemWithNoProof = false; + List queries = new List(); + SuffixTree? suffix = _stateDb.GetStem(stemPath); + queries.AddRange(AddExtensionCommitmentOpenings(stemPath, stemChild, suffix)); + if (stemChild.Count == 0) + { + stemWithNoProof = true; + return queries; + } + + + _proofStemPolynomialCache.TryGetValue(stemPath, out SuffixPoly hashStruct); + + FrE[] c1Hashes = hashStruct.c1; + FrE[] c2Hashes = hashStruct.c2; + + foreach (byte valueIndex in stemChild) + { + int valueLowerIndex = 2 * (valueIndex % 128); + int valueUpperIndex = valueLowerIndex + 1; + + (FrE valueLow, FrE valueHigh) = VerkleUtils.BreakValueInLowHigh(_stateDb.GetLeaf(stemPath.Append(valueIndex).ToArray())); + + int offset = valueIndex < 128 ? 0 : 128; + + Banderwagon commitment; + FrE[] poly; + switch (offset) + { + case 0: + commitment = suffix.C1.Point; + poly = c1Hashes.ToArray(); + break; + case 128: + commitment = suffix.C2.Point; + poly = c2Hashes.ToArray(); + break; + default: + throw new Exception("unreachable"); + } + + VerkleProverQuery openAtValLow = new VerkleProverQuery(new LagrangeBasis(poly), commitment, FrE.SetElement(valueLowerIndex), valueLow); + VerkleProverQuery openAtValUpper = new VerkleProverQuery(new LagrangeBasis(poly), commitment, FrE.SetElement(valueUpperIndex), valueHigh); + + queries.Add(openAtValLow); + queries.Add(openAtValUpper); + } + + return queries; + } + + + + private IEnumerable OpenBranchCommitment(Dictionary> branchProof) + { + List queries = new List(); + foreach (KeyValuePair> proofData in branchProof) + { + if(!_proofBranchPolynomialCache.TryGetValue(proofData.Key, out FrE[] poly)) throw new EvaluateException(); + InternalNode? node = _stateDb.GetBranch(proofData.Key); + queries.AddRange(proofData.Value.Select(childIndex => new VerkleProverQuery(new LagrangeBasis(poly), node!._internalCommitment.Point, FrE.SetElement(childIndex), poly[childIndex]))); + } + return queries; + } + + private IEnumerable OpenStemCommitment(Dictionary> stemProof, out List stemWithNoProof) + { + stemWithNoProof = new List(); + List queries = new List(); + + foreach (KeyValuePair> proofData in stemProof) + { + SuffixTree? suffix = _stateDb.GetStem(proofData.Key); + queries.AddRange(AddExtensionCommitmentOpenings(proofData.Key, proofData.Value, suffix)); + if (proofData.Value.Count == 0) + { + stemWithNoProof.Add(proofData.Key); + continue; + } + + _proofStemPolynomialCache.TryGetValue(proofData.Key, out SuffixPoly hashStruct); + + FrE[] c1Hashes = hashStruct.c1; + FrE[] c2Hashes = hashStruct.c2; + + foreach (byte valueIndex in proofData.Value) + { + int valueLowerIndex = 2 * (valueIndex % 128); + int valueUpperIndex = valueLowerIndex + 1; + + (FrE valueLow, FrE valueHigh) = VerkleUtils.BreakValueInLowHigh(_stateDb.GetLeaf(proofData.Key.Append(valueIndex).ToArray())); + + int offset = valueIndex < 128 ? 0 : 128; + + Banderwagon commitment; + FrE[] poly; + switch (offset) + { + case 0: + commitment = suffix.C1.Point; + poly = c1Hashes.ToArray(); + break; + case 128: + commitment = suffix.C2.Point; + poly = c2Hashes.ToArray(); + break; + default: + throw new Exception("unreachable"); + } + + VerkleProverQuery openAtValLow = new VerkleProverQuery(new LagrangeBasis(poly), commitment, FrE.SetElement(valueLowerIndex), valueLow); + VerkleProverQuery openAtValUpper = new VerkleProverQuery(new LagrangeBasis(poly), commitment, FrE.SetElement(valueUpperIndex), valueHigh); + + queries.Add(openAtValLow); + queries.Add(openAtValUpper); + } + + } + + return queries; + } + + private IEnumerable AddExtensionCommitmentOpenings(byte[] stem, IEnumerable value, SuffixTree? suffix) + { + List queries = new List(); + FrE[] extPoly = new FrE[256]; + for (int i = 0; i < 256; i++) + { + extPoly[i] = FrE.Zero; + } + extPoly[0] = FrE.One; + extPoly[1] = FrE.FromBytesReduced(stem.Reverse().ToArray()); + extPoly[2] = suffix.C1.PointAsField; + extPoly[3] = suffix.C2.PointAsField; + + VerkleProverQuery openAtOne = new VerkleProverQuery(new LagrangeBasis(extPoly), suffix.ExtensionCommitment.Point, FrE.SetElement(0), FrE.One); + VerkleProverQuery openAtStem = new VerkleProverQuery(new LagrangeBasis(extPoly), suffix.ExtensionCommitment.Point, FrE.SetElement(1), FrE.FromBytesReduced(stem.Reverse().ToArray())); + queries.Add(openAtOne); + queries.Add(openAtStem); + + bool openC1 = false; + bool openC2 = false; + foreach (byte valueIndex in value) + { + if (valueIndex < 128) openC1 = true; + else openC2 = true; + } + + if (openC1) + { + VerkleProverQuery openAtC1 = new VerkleProverQuery(new LagrangeBasis(extPoly), suffix.ExtensionCommitment.Point, FrE.SetElement(2), suffix.C1.PointAsField); + queries.Add(openAtC1); + } + + if (openC2) + { + VerkleProverQuery openAtC2 = new VerkleProverQuery(new LagrangeBasis(extPoly), suffix.ExtensionCommitment.Point, FrE.SetElement(3), suffix.C2.PointAsField); + queries.Add(openAtC2); + } + + return queries; + } + + + + private void CreateBranchProofPolynomialIfNotExist(byte[] path) + { + if (_proofBranchPolynomialCache.ContainsKey(path)) return; + + FrE[] newPoly = new FrE[256]; + for (int i = 0; i < 256; i++) + { + InternalNode? node = _stateDb.GetBranch(path.Append((byte)i).ToArray()); + newPoly[i] = node == null ? FrE.Zero : node._internalCommitment.PointAsField; + } + _proofBranchPolynomialCache[path] = newPoly; + } + + private void CreateStemProofPolynomialIfNotExist(byte[] stem) + { + if (_proofStemPolynomialCache.ContainsKey(stem)) return; + + List c1Hashes = new List(256); + List c2Hashes = new List(256); + for (int i = 0; i < 128; i++) + { + (FrE valueLow, FrE valueHigh) = VerkleUtils.BreakValueInLowHigh(_stateDb.GetLeaf(stem.Append((byte)i).ToArray())); + c1Hashes.Add(valueLow); + c1Hashes.Add(valueHigh); + } + + for (int i = 128; i < 256; i++) + { + (FrE valueLow, FrE valueHigh) = VerkleUtils.BreakValueInLowHigh(_stateDb.GetLeaf(stem.Append((byte)i).ToArray())); + c2Hashes.Add(valueLow); + c2Hashes.Add(valueHigh); + } + _proofStemPolynomialCache[stem] = new SuffixPoly() + { + c1 = c1Hashes.ToArray(), + c2 = c2Hashes.ToArray() + }; + } + +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/ReadOnlyVerkleStateStore.cs b/src/Nethermind/Nethermind.Verkle.Tree/ReadOnlyVerkleStateStore.cs new file mode 100644 index 00000000000..76022118290 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/ReadOnlyVerkleStateStore.cs @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Crypto; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Tree.VerkleDb; + +namespace Nethermind.Verkle.Tree; + +public class ReadOnlyVerkleStateStore: IVerkleStore, ISyncTrieStore +{ + private VerkleStateStore _verkleStateStore; + private VerkleMemoryDb _keyValueStore; + + public ReadOnlyVerkleStateStore(VerkleStateStore verkleStateStore, VerkleMemoryDb keyValueStore) + { + _verkleStateStore = verkleStateStore; + _keyValueStore = keyValueStore; + } + + public byte[] RootHash + { + get => _verkleStateStore.RootHash; + set => throw new ArgumentException(); + } + public byte[]? GetLeaf(byte[] key) + { + if (_keyValueStore.GetLeaf(key, out byte[]? value)) return value; + return _verkleStateStore.GetLeaf(key); + } + public SuffixTree? GetStem(byte[] key) + { + if (_keyValueStore.GetStem(key, out var value)) return value; + return _verkleStateStore.GetStem(key); + } + public InternalNode? GetBranch(byte[] key) + { + if (_keyValueStore.GetBranch(key, out var value)) return value; + return _verkleStateStore.GetBranch(key); + } + public void SetLeaf(byte[] leafKey, byte[] leafValue) + { + _keyValueStore.SetLeaf(leafKey, leafValue); + } + public void SetStem(byte[] stemKey, SuffixTree suffixTree) + { + _keyValueStore.SetStem(stemKey, suffixTree); + } + public void SetBranch(byte[] branchKey, InternalNode internalNodeValue) + { + _keyValueStore.SetBranch(branchKey, internalNodeValue); + } + public void Flush(long blockNumber) { } + + public void ReverseState() { } + public void ApplyDiffLayer(BatchChangeSet changeSet) + { + } + public byte[] GetStateRoot() + { + return _verkleStateStore.GetStateRoot(); + } + public void MoveToStateRoot(byte[] stateRoot) + { + _verkleStateStore.MoveToStateRoot(stateRoot); + } + + public VerkleMemoryDb GetForwardMergedDiff(long fromBlock, long toBlock) + { + throw new NotImplementedException(); + } + public VerkleMemoryDb GetReverseMergedDiff(long fromBlock, long toBlock) + { + throw new NotImplementedException(); + } + public event EventHandler? ReorgBoundaryReached; + + public ReadOnlyVerkleStateStore AsReadOnly(VerkleMemoryDb keyValueStore) + { + return new ReadOnlyVerkleStateStore(_verkleStateStore, keyValueStore); + } + public bool IsFullySynced(Keccak stateRoot) + { + return _verkleStateStore.IsFullySynced(stateRoot); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Serializers/BranchStoreSerializer.cs b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/BranchStoreSerializer.cs new file mode 100644 index 00000000000..0a19444c809 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/BranchStoreSerializer.cs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Serialization.Rlp; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree.Serializers; + + +public class BranchStoreSerializer : IRlpStreamDecoder +{ + private static InternalNodeSerializer InternalNodeSerializer => InternalNodeSerializer.Instance; + + public static BranchStoreSerializer Instance => new BranchStoreSerializer(); + public int GetLength(BranchStore item, RlpBehaviors rlpBehaviors) + { + int length = Rlp.LengthOf(item.Count); + foreach (KeyValuePair pair in item) + { + length += Rlp.LengthOf(pair.Key); + length += pair.Value == null ? Rlp.EmptyArrayByte : InternalNodeSerializer.GetLength(pair.Value, RlpBehaviors.None); + } + return length; + } + + public BranchStore Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + BranchStore item = new BranchStore(); + int length = rlpStream.DecodeInt(); + for (int i = 0; i < length; i++) + { + byte[] key = rlpStream.DecodeByteArray(); + if (rlpStream.PeekNextItem().Length == 0) + { + item[key] = null; + rlpStream.SkipItem(); + } + else + { + item[key] = InternalNodeSerializer.Decode(rlpStream); + } + } + return item; + } + public void Encode(RlpStream stream, BranchStore item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + stream.Encode(item.Count); + foreach (KeyValuePair pair in item) + { + stream.Encode(pair.Key); + if (pair.Value is null) stream.EncodeEmptyByteArray(); + else InternalNodeSerializer.Encode(stream, pair.Value); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleNodes/NodeSerializers.cs b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/InternalNodeSerializer.cs similarity index 51% rename from src/Nethermind/Nethermind.Verkle/VerkleNodes/NodeSerializers.cs rename to src/Nethermind/Nethermind.Verkle.Tree/Serializers/InternalNodeSerializer.cs index 9b5ebab8b54..029ef9fbf30 100644 --- a/src/Nethermind/Nethermind.Verkle/VerkleNodes/NodeSerializers.cs +++ b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/InternalNodeSerializer.cs @@ -1,57 +1,12 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only using Nethermind.Serialization.Rlp; using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Tree.Nodes; using Nethermind.Verkle.Utils; -namespace Nethermind.Verkle.VerkleNodes; - -public class SuffixTreeSerializer : IRlpStreamDecoder, IRlpObjectDecoder -{ - public static SuffixTreeSerializer Instance => new SuffixTreeSerializer(); - public int GetLength(SuffixTree item, RlpBehaviors rlpBehaviors) - { - return 31 + 32 + 32 + 32; - } - - public int GetLength(SuffixTree item, RlpBehaviors rlpBehaviors, out int contentLength) - { - contentLength = GetLength(item, rlpBehaviors); - return Rlp.LengthOfSequence(contentLength); - } - - public SuffixTree Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - byte[] stem = rlpStream.Read(31).ToArray(); - byte[] c1 = rlpStream.Read(32).ToArray(); - byte[] c2 = rlpStream.Read(32).ToArray(); - byte[] extCommit = rlpStream.Read(32).ToArray(); - return new SuffixTree(stem, c1, c2, extCommit); - } - public void Encode(RlpStream stream, SuffixTree item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - stream.Write(item.Stem); - stream.Write(item.C1.Point.ToBytes()); - stream.Write(item.C2.Point.ToBytes()); - stream.Write(item.ExtensionCommitment.Point.ToBytes()); - } - public Rlp Encode(SuffixTree? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - int length = GetLength(item, rlpBehaviors); - RlpStream stream = new RlpStream(Rlp.LengthOfSequence(length)); - stream.StartSequence(length); - Encode(stream, item, rlpBehaviors); - return new Rlp(stream.Data); - } - - public SuffixTree Decode(byte[] data, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - RlpStream stream = data.AsRlpStream(); - stream.ReadSequenceLength(); - return Decode(stream, rlpBehaviors); - } -} +namespace Nethermind.Verkle.Tree.Serializers; public class InternalNodeSerializer : IRlpStreamDecoder, IRlpObjectDecoder { @@ -72,11 +27,11 @@ public InternalNode Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpB switch (nodeType) { case NodeType.BranchNode: - InternalNode node = new InternalNode(NodeType.BranchNode); + BranchNode node = new BranchNode(); node.UpdateCommitment(new Banderwagon(rlpStream.Read(32).ToArray())); return node; case NodeType.StemNode: - return new InternalNode(NodeType.StemNode, rlpStream.Read(31).ToArray(), new Commitment(new Banderwagon(rlpStream.Read(32).ToArray()))); + return new StemNode(rlpStream.Read(31).ToArray(), new Commitment(new Banderwagon(rlpStream.Read(32).ToArray()))); default: throw new ArgumentOutOfRangeException(); } diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Serializers/LeafStoreSerializer.cs b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/LeafStoreSerializer.cs new file mode 100644 index 00000000000..8ebb42fb5f2 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/LeafStoreSerializer.cs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Serialization.Rlp; + +namespace Nethermind.Verkle.Tree.Serializers; + + +public class LeafStoreSerializer : IRlpStreamDecoder +{ + public static LeafStoreSerializer Instance => new LeafStoreSerializer(); + public int GetLength(LeafStore item, RlpBehaviors rlpBehaviors) + { + int length = Rlp.LengthOf(item.Count); + foreach (KeyValuePair pair in item) + { + length += Rlp.LengthOf(pair.Key); + length += Rlp.LengthOf(pair.Value); + } + return length; + } + + public LeafStore Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + LeafStore item = new LeafStore(); + int length = rlpStream.DecodeInt(); + for (int i = 0; i < length; i++) + { + item[rlpStream.DecodeByteArray()] = rlpStream.DecodeByteArray(); + } + return item; + } + + public void Encode(RlpStream stream, LeafStore item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + stream.Encode(item.Count); + foreach (KeyValuePair pair in item) + { + stream.Encode(pair.Key.AsSpan()); + stream.Encode(pair.Value.AsSpan()); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Serializers/StemStoreSerializer.cs b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/StemStoreSerializer.cs new file mode 100644 index 00000000000..d57653a7624 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/StemStoreSerializer.cs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Serialization.Rlp; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree.Serializers; + + +public class StemStoreSerializer : IRlpStreamDecoder +{ + private static SuffixTreeSerializer SuffixTreeSerializer => SuffixTreeSerializer.Instance; + + public static StemStoreSerializer Instance => new StemStoreSerializer(); + + public int GetLength(StemStore item, RlpBehaviors rlpBehaviors) + { + int length = Rlp.LengthOf(item.Count); + foreach (KeyValuePair pair in item) + { + length += Rlp.LengthOf(pair.Key); + length += pair.Value == null ? Rlp.EmptyArrayByte : SuffixTreeSerializer.GetLength(pair.Value, RlpBehaviors.None); + } + return length; + } + + public StemStore Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + StemStore item = new StemStore(); + int length = rlpStream.DecodeInt(); + for (int i = 0; i < length; i++) + { + byte[] key = rlpStream.DecodeByteArray(); + if (rlpStream.PeekNextItem().Length == 0) + { + item[key] = null; + rlpStream.SkipItem(); + } + else + { + item[key] = SuffixTreeSerializer.Decode(rlpStream); + } + } + return item; + } + public void Encode(RlpStream stream, StemStore item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + stream.Encode(item.Count); + foreach (KeyValuePair pair in item) + { + stream.Encode(pair.Key); + if (pair.Value is null) stream.EncodeEmptyByteArray(); + else SuffixTreeSerializer.Encode(stream, pair.Value); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Serializers/SuffixTreeSerializer.cs b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/SuffixTreeSerializer.cs new file mode 100644 index 00000000000..c9947527898 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/SuffixTreeSerializer.cs @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Serialization.Rlp; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree.Serializers; + + +public class SuffixTreeSerializer : IRlpStreamDecoder, IRlpObjectDecoder +{ + public static SuffixTreeSerializer Instance => new SuffixTreeSerializer(); + public int GetLength(SuffixTree item, RlpBehaviors rlpBehaviors) + { + return 31 + 32 + 32 + 32; + } + + public int GetLength(SuffixTree item, RlpBehaviors rlpBehaviors, out int contentLength) + { + contentLength = GetLength(item, rlpBehaviors); + return Rlp.LengthOfSequence(contentLength); + } + + public SuffixTree Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + byte[] stem = rlpStream.Read(31).ToArray(); + byte[] c1 = rlpStream.Read(32).ToArray(); + byte[] c2 = rlpStream.Read(32).ToArray(); + byte[] extCommit = rlpStream.Read(32).ToArray(); + return new SuffixTree(stem, c1, c2, extCommit); + } + public void Encode(RlpStream stream, SuffixTree item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + stream.Write(item.Stem); + stream.Write(item.C1.Point.ToBytes()); + stream.Write(item.C2.Point.ToBytes()); + stream.Write(item.ExtensionCommitment.Point.ToBytes()); + } + public Rlp Encode(SuffixTree item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + int length = GetLength(item, rlpBehaviors); + RlpStream stream = new RlpStream(Rlp.LengthOfSequence(length)); + stream.StartSequence(length); + Encode(stream, item, rlpBehaviors); + return new Rlp(stream.Data); + } + + public SuffixTree Decode(byte[] data, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + RlpStream stream = data.AsRlpStream(); + stream.ReadSequenceLength(); + return Decode(stream, rlpBehaviors); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Serializers/VerkleMemoryDbSerializer.cs b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/VerkleMemoryDbSerializer.cs new file mode 100644 index 00000000000..f8d31de21d1 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Serializers/VerkleMemoryDbSerializer.cs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Serialization.Rlp; +using Nethermind.Verkle.Tree.VerkleDb; + +namespace Nethermind.Verkle.Tree.Serializers; + +public class VerkleMemoryDbSerializer: IRlpStreamDecoder +{ + public static VerkleMemoryDbSerializer Instance => new VerkleMemoryDbSerializer(); + + public int GetLength(VerkleMemoryDb item, RlpBehaviors rlpBehaviors) + { + int length = 0; + length += LeafStoreSerializer.Instance.GetLength(item.LeafTable, RlpBehaviors.None); + length += StemStoreSerializer.Instance.GetLength(item.StemTable, RlpBehaviors.None); + length += BranchStoreSerializer.Instance.GetLength(item.BranchTable, RlpBehaviors.None); + return length; + } + + public int GetLength(VerkleMemoryDb item, RlpBehaviors rlpBehaviors, out int contentLength) + { + contentLength = GetLength(item, rlpBehaviors); + return Rlp.LengthOfSequence(contentLength); + } + + public VerkleMemoryDb Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + return new VerkleMemoryDb( + LeafStoreSerializer.Instance.Decode(rlpStream), + StemStoreSerializer.Instance.Decode(rlpStream), + BranchStoreSerializer.Instance.Decode(rlpStream) + ); + } + public void Encode(RlpStream stream, VerkleMemoryDb item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + { + LeafStoreSerializer.Instance.Encode(stream, item.LeafTable); + StemStoreSerializer.Instance.Encode(stream, item.StemTable); + BranchStoreSerializer.Instance.Encode(stream, item.BranchTable); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/Usings.cs b/src/Nethermind/Nethermind.Verkle.Tree/Usings.cs new file mode 100644 index 00000000000..44f4c486587 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/Usings.cs @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +global using BranchStore = System.Collections.Concurrent.ConcurrentDictionary; +global using LeafStore = System.Collections.Concurrent.ConcurrentDictionary; +global using StemStore = System.Collections.Concurrent.ConcurrentDictionary; +global using VerkleUtils = Nethermind.Verkle.Utils.VerkleUtils; +global using NodeType = Nethermind.Verkle.Tree.Nodes.NodeType; + diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/ChangeSet.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/ChangeSet.cs new file mode 100644 index 00000000000..9c413ef451b --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/ChangeSet.cs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public class ChangeSet +{ + public long BlockNumber; + public VerkleMemoryDb DiffLayer; + + public ChangeSet(long blockNumber, VerkleMemoryDb diffLayer) + { + BlockNumber = blockNumber; + DiffLayer = diffLayer; + } +} + +public class BatchChangeSet +{ + public long FromBlockNumber; + public long ToBlockNumber; + public VerkleMemoryDb DiffLayer; + + public BatchChangeSet(long fromBlockNumber, long toBlockNumber, VerkleMemoryDb diffLayer) + { + FromBlockNumber = fromBlockNumber; + ToBlockNumber = toBlockNumber; + DiffLayer = diffLayer; + } +} + diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/DiffLayer.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/DiffLayer.cs new file mode 100644 index 00000000000..4028f000dc0 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/DiffLayer.cs @@ -0,0 +1,90 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Diagnostics; +using Nethermind.Db; +using Nethermind.Serialization.Rlp; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Tree.Serializers; + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public enum DiffType +{ + Forward, + Reverse +} + + +public class DiffLayer +{ + private readonly DiffType _diffType; + private IDb DiffDb { get; } + public DiffLayer(IDb diffDb, DiffType diffType) + { + DiffDb = diffDb; + _diffType = diffType; + } + public void InsertDiff(long blockNumber, VerkleMemoryDb memory) + { + RlpStream stream = new RlpStream(VerkleMemoryDbSerializer.Instance.GetLength(memory, RlpBehaviors.None)); + VerkleMemoryDbSerializer.Instance.Encode(stream, memory); + if (stream.Data != null) DiffDb.Set(blockNumber, stream.Data); + } + + public VerkleMemoryDb FetchDiff(long blockNumber) + { + byte[]? diff = DiffDb.Get(blockNumber); + if (diff is null) throw new ArgumentException(null, nameof(blockNumber)); + return VerkleMemoryDbSerializer.Instance.Decode(diff.AsRlpStream()); + } + + public VerkleMemoryDb MergeDiffs(long fromBlock, long toBlock) + { + VerkleMemoryDb mergedDiff = new VerkleMemoryDb(); + switch (_diffType) + { + case DiffType.Reverse: + Debug.Assert(fromBlock > toBlock); + for (long i = toBlock + 1; i <= fromBlock; i++) + { + VerkleMemoryDb reverseDiff = FetchDiff(i); + foreach (KeyValuePair item in reverseDiff.LeafTable) + { + mergedDiff.LeafTable.TryAdd(item.Key, item.Value); + } + foreach (KeyValuePair item in reverseDiff.BranchTable) + { + mergedDiff.BranchTable.TryAdd(item.Key, item.Value); + } + foreach (KeyValuePair item in reverseDiff.StemTable) + { + mergedDiff.StemTable.TryAdd(item.Key, item.Value); + } + } + break; + case DiffType.Forward: + Debug.Assert(fromBlock < toBlock); + for (long i = toBlock; i >= fromBlock; i--) + { + VerkleMemoryDb forwardDiff = FetchDiff(i); + foreach (KeyValuePair item in forwardDiff.LeafTable) + { + mergedDiff.LeafTable.TryAdd(item.Key, item.Value); + } + foreach (KeyValuePair item in forwardDiff.BranchTable) + { + mergedDiff.BranchTable.TryAdd(item.Key, item.Value); + } + foreach (KeyValuePair item in forwardDiff.StemTable) + { + mergedDiff.StemTable.TryAdd(item.Key, item.Value); + } + } + break; + default: + throw new NotSupportedException(); + } + return mergedDiff; + } +} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/IVerkleDb.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleDb.cs similarity index 60% rename from src/Nethermind/Nethermind.Verkle/VerkleStateDb/IVerkleDb.cs rename to src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleDb.cs index 8592ccf93b4..cc6d4f1eddf 100644 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/IVerkleDb.cs +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleDb.cs @@ -1,18 +1,20 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only -using Nethermind.Verkle.VerkleNodes; +using Nethermind.Verkle.Tree.Nodes; -namespace Nethermind.Verkle.VerkleStateDb; +namespace Nethermind.Verkle.Tree.VerkleDb; public interface IVerkleDb { bool GetLeaf(byte[] key, out byte[]? value); bool GetStem(byte[] key, out SuffixTree? value); bool GetBranch(byte[] key, out InternalNode? value); + void SetLeaf(byte[] leafKey, byte[] leafValue); void SetStem(byte[] stemKey, SuffixTree suffixTree); void SetBranch(byte[] branchKey, InternalNode internalNodeValue); + void RemoveLeaf(byte[] leafKey); void RemoveStem(byte[] stemKey); void RemoveBranch(byte[] branchKey); @@ -21,11 +23,3 @@ public interface IVerkleDb void BatchStemInsert(IEnumerable> suffixLeaf); void BatchBranchInsert(IEnumerable> branchLeaf); } - -public interface IVerkleDiffDb : IVerkleDb -{ - byte[] Encode(); - IEnumerable> LeafNodes { get; } - IEnumerable> StemNodes { get; } - IEnumerable> BranchNodes { get; } -} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleKeyValueDb.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleKeyValueDb.cs new file mode 100644 index 00000000000..86111fdf705 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleKeyValueDb.cs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Db; + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public interface IVerkleKeyValueDb +{ + public IDb LeafDb { get; } + public IDb StemDb { get; } + public IDb BranchDb { get; } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleMemDb.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleMemDb.cs new file mode 100644 index 00000000000..476d0146a97 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/IVerkleMemDb.cs @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Collections.Concurrent; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public interface IVerkleMemDb +{ + public ConcurrentDictionary LeafTable { get; } + public ConcurrentDictionary StemTable { get; } + public ConcurrentDictionary BranchTable { get; } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleHistoryStore.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleHistoryStore.cs new file mode 100644 index 00000000000..de838130614 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleHistoryStore.cs @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Db; + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public class VerkleHistoryStore +{ + private DiffLayer ForwardDiff { get; } + private DiffLayer ReverseDiff { get; } + + public VerkleHistoryStore(IDbProvider dbProvider) + { + ForwardDiff = new DiffLayer(dbProvider.ForwardDiff, DiffType.Forward); + ReverseDiff = new DiffLayer(dbProvider.ReverseDiff, DiffType.Reverse); + } + + public void InsertDiff(long blockNumber, VerkleMemoryDb postState, VerkleMemoryDb preState) + { + ForwardDiff.InsertDiff(blockNumber, postState); + ReverseDiff.InsertDiff(blockNumber, preState); + } + + public BatchChangeSet GetBatchDiff(long fromBlock, long toBlock) + { + VerkleMemoryDb diff = (fromBlock > toBlock) switch + { + true => ReverseDiff.MergeDiffs(fromBlock, toBlock), + false => ForwardDiff.MergeDiffs(fromBlock, toBlock) + }; + + return new BatchChangeSet(fromBlock, toBlock, diff); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleKeyValueDb.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleKeyValueDb.cs new file mode 100644 index 00000000000..810af375f7d --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleKeyValueDb.cs @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Db; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Tree.Serializers; + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public class VerkleKeyValueDb: IVerkleDb, IVerkleKeyValueDb, IKeyValueStore +{ + private readonly IDbProvider _dbProvider; + + public IDb LeafDb => _dbProvider.LeafDb; + public IDb StemDb => _dbProvider.StemDb; + public IDb BranchDb => _dbProvider.BranchDb; + + public VerkleKeyValueDb(IDbProvider dbProvider) + { + _dbProvider = dbProvider; + } + + public byte[]? GetLeaf(byte[] key) => LeafDb.Get(key); + public SuffixTree? GetStem(byte[] key) + { + byte[]? value = StemDb[key]; + return value is null ? null : SuffixTreeSerializer.Instance.Decode(value); + } + + public InternalNode? GetBranch(byte[] key) + { + byte[]? value = BranchDb[key]; + return value is null ? null : InternalNodeSerializer.Instance.Decode(value); + } + + public bool GetLeaf(byte[] key, out byte[]? value) + { + value = GetLeaf(key); + return value is not null; + } + public bool GetStem(byte[] key, out SuffixTree? value) + { + value = GetStem(key); + return value is not null; + } + public bool GetBranch(byte[] key, out InternalNode? value) + { + value = GetBranch(key); + return value is not null; + } + + public void SetLeaf(byte[] leafKey, byte[] leafValue) => _setLeaf(leafKey, leafValue, LeafDb); + public void SetStem(byte[] stemKey, SuffixTree suffixTree) => _setStem(stemKey, suffixTree, StemDb); + public void SetBranch(byte[] branchKey, InternalNode internalNodeValue) => _setBranch(branchKey, internalNodeValue, BranchDb); + + public void RemoveLeaf(byte[] leafKey) + { + LeafDb.Remove(leafKey); + } + public void RemoveStem(byte[] stemKey) + { + StemDb.Remove(stemKey); + } + public void RemoveBranch(byte[] branchKey) + { + BranchDb.Remove(branchKey); + } + + + public void BatchLeafInsert(IEnumerable> keyLeaf) + { + using IBatch batch = LeafDb.StartBatch(); + foreach ((byte[] key, byte[]? value) in keyLeaf) + { + _setLeaf(key, value, batch); + } + } + public void BatchStemInsert(IEnumerable> suffixLeaf) + { + using IBatch batch = StemDb.StartBatch(); + foreach ((byte[] key, SuffixTree? value) in suffixLeaf) + { + _setStem(key, value, batch); + } + } + public void BatchBranchInsert(IEnumerable> branchLeaf) + { + using IBatch batch = BranchDb.StartBatch(); + foreach ((byte[] key, InternalNode? value) in branchLeaf) + { + _setBranch(key, value, batch); + } + } + + public byte[]? this[byte[] key] + { + get + { + return key.Length switch + { + 32 => LeafDb[key], + 31 => StemDb[key], + _ => BranchDb[key] + }; + } + set + { + switch (key.Length) + { + case 32: + LeafDb[key] = value; + break; + case 31: + StemDb[key] = value; + break; + default: + BranchDb[key] = value; + break; + } + } + } + + private static void _setLeaf(byte[] leafKey, byte[]? leafValue, IKeyValueStore db) => db[leafKey] = leafValue; + private static void _setStem(byte[] stemKey, SuffixTree? suffixTree, IKeyValueStore db) + { + if (suffixTree != null) db[stemKey] = SuffixTreeSerializer.Instance.Encode(suffixTree).Bytes; + } + private static void _setBranch(byte[] branchKey, InternalNode? internalNodeValue, IKeyValueStore db) + { + if (internalNodeValue != null) db[branchKey] = InternalNodeSerializer.Instance.Encode(internalNodeValue).Bytes; + } + + +} diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleMemoryDb.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleMemoryDb.cs new file mode 100644 index 00000000000..e3ca0b7e1ec --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleDb/VerkleMemoryDb.cs @@ -0,0 +1,64 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core.Extensions; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree.VerkleDb; + +public class VerkleMemoryDb: IVerkleDb, IVerkleMemDb +{ + public LeafStore LeafTable { get; } + public StemStore StemTable { get; } + public BranchStore BranchTable { get; } + + public VerkleMemoryDb() + { + LeafTable = new LeafStore(Bytes.EqualityComparer); + StemTable = new StemStore(Bytes.EqualityComparer); + BranchTable = new BranchStore(Bytes.EqualityComparer); + } + + public VerkleMemoryDb(LeafStore leafTable, StemStore stemTable, BranchStore branchTable) + { + LeafTable = leafTable; + StemTable = stemTable; + BranchTable = branchTable; + } + + public bool GetLeaf(byte[] key, out byte[]? value) => LeafTable.TryGetValue(key, out value); + public bool GetStem(byte[] key, out SuffixTree? value) => StemTable.TryGetValue(key, out value); + public bool GetBranch(byte[] key, out InternalNode? value) => BranchTable.TryGetValue(key, out value); + + public void SetLeaf(byte[] leafKey, byte[] leafValue) => LeafTable[leafKey] = leafValue; + public void SetStem(byte[] stemKey, SuffixTree suffixTree) => StemTable[stemKey] = suffixTree; + public void SetBranch(byte[] branchKey, InternalNode internalNodeValue) => BranchTable[branchKey] = internalNodeValue; + + public void RemoveLeaf(byte[] leafKey) => LeafTable.Remove(leafKey, out _); + public void RemoveStem(byte[] stemKey) => StemTable.Remove(stemKey, out _); + public void RemoveBranch(byte[] branchKey) => BranchTable.Remove(branchKey, out _); + + public void BatchLeafInsert(IEnumerable> keyLeaf) + { + foreach ((byte[] key, byte[]? value) in keyLeaf) + { + SetLeaf(key, value); + } + } + public void BatchStemInsert(IEnumerable> suffixLeaf) + { + foreach ((byte[] key, SuffixTree? value) in suffixLeaf) + { + SetStem(key, value); + } + } + public void BatchBranchInsert(IEnumerable> branchLeaf) + { + foreach ((byte[] key, InternalNode? value) in branchLeaf) + { + SetBranch(key, value); + } + } + + +} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateStore.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleStateStore.cs similarity index 57% rename from src/Nethermind/Nethermind.Verkle/VerkleStateStore.cs rename to src/Nethermind/Nethermind.Verkle.Tree/VerkleStateStore.cs index 5c6adf21d1c..cc5bc053c04 100644 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateStore.cs +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleStateStore.cs @@ -1,101 +1,116 @@ using System.Diagnostics; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; using Nethermind.Db; -using Nethermind.Verkle.VerkleNodes; -using Nethermind.Verkle.VerkleStateDb; +using Nethermind.Trie; +using Nethermind.Trie.Pruning; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Tree.VerkleDb; -namespace Nethermind.Verkle; +namespace Nethermind.Verkle.Tree; -public class VerkleStateStore : IVerkleStore +public class VerkleStateStore : IVerkleStore, ISyncTrieStore { + public byte[] RootHash + { + get => GetStateRoot(); + set => MoveToStateRoot(value); + } // the blockNumber for with the fullState exists. private long FullStateBlock { get; set; } // The underlying key value database // We try to avoid fetching from this, and we only store at the end of a batch insert - private IVerkleDb Storage { get; } + private VerkleKeyValueDb Storage { get; } // This stores the key-value pairs that we need to insert into the storage. This is generally // used to batch insert changes for each block. This is also used to generate the forwardDiff. // This is flushed after every batch insert and cleared. - private IVerkleDiffDb Batch { get; } + private VerkleMemoryDb Batch { get; set; } - // This should store the top 3 layers of the trie, since these are the most accessed in - // the trie on average, thus speeding up some operations. But right now every things is - // stored in the cache - bad design. - // TODO: modify the cache to only store the top 3 layers - private IVerkleDiffDb Cache { get; } + private VerkleHistoryStore History { get; } - // These database stores the forwardDiff and reverseDiff for each block. Diffs are generated when - // the Flush(long blockNumber) method is called. - // TODO: add capability to update the diffs instead of overwriting if Flush(long blockNumber) is called multiple times for the same block number - private DiffLayer ForwardDiff { get; } - private DiffLayer ReverseDiff { get; } + private IDb StateRootToBlocks { get; } public VerkleStateStore(IDbProvider dbProvider) { - Storage = new DiskDb(dbProvider); - Batch = new MemoryStateDb(); - Cache = new MemoryStateDb(); - ForwardDiff = new DiffLayer(DiffType.Forward); - ReverseDiff = new DiffLayer(DiffType.Reverse); + Storage = new VerkleKeyValueDb(dbProvider); + Batch = new VerkleMemoryDb(); + History = new VerkleHistoryStore(dbProvider); + StateRootToBlocks = dbProvider.StateRootToBlocks; FullStateBlock = 0; + InitRootHash(); + } + + public ReadOnlyVerkleStateStore AsReadOnly(VerkleMemoryDb keyValueStore) + { + return new ReadOnlyVerkleStateStore(this, keyValueStore); } // This generates and returns a batchForwardDiff, that can be used to move the full state from fromBlock to toBlock. // for this fromBlock < toBlock - move forward in time - public IVerkleDiffDb GetForwardMergedDiff(long fromBlock, long toBlock) + public VerkleMemoryDb GetForwardMergedDiff(long fromBlock, long toBlock) { - return ForwardDiff.MergeDiffs(fromBlock, toBlock); + return History.GetBatchDiff(fromBlock, toBlock).DiffLayer; } // This generates and returns a batchForwardDiff, that can be used to move the full state from fromBlock to toBlock. // for this fromBlock > toBlock - move back in time - public IVerkleDiffDb GetReverseMergedDiff(long fromBlock, long toBlock) + public VerkleMemoryDb GetReverseMergedDiff(long fromBlock, long toBlock) { - return ReverseDiff.MergeDiffs(fromBlock, toBlock); + return History.GetBatchDiff(fromBlock, toBlock).DiffLayer; } + public event EventHandler? ReorgBoundaryReached; - public void InitRootHash() + private void InitRootHash() { + if(Batch.GetBranch(Array.Empty(), out InternalNode? _)) return; Batch.SetBranch(Array.Empty(), new BranchNode()); } public byte[]? GetLeaf(byte[] key) { - if (Cache.GetLeaf(key, out byte[]? value)) return value; - if (Batch.GetLeaf(key, out value)) return value; +#if DEBUG + if (key.Length != 32) throw new ArgumentException("key must be 32 bytes", nameof(key)); +#endif + if (Batch.GetLeaf(key, out byte[]? value)) return value; return Storage.GetLeaf(key, out value) ? value : null; } - public SuffixTree? GetStem(byte[] key) + public SuffixTree? GetStem(byte[] stemKey) { - if (Cache.GetStem(key, out SuffixTree? value)) return value; - if (Batch.GetStem(key, out value)) return value; - return Storage.GetStem(key, out value) ? value : null; +#if DEBUG + if (stemKey.Length != 31) throw new ArgumentException("stem must be 31 bytes", nameof(stemKey)); +#endif + if (Batch.GetStem(stemKey, out SuffixTree? value)) return value; + return Storage.GetStem(stemKey, out value) ? value : null; } public InternalNode? GetBranch(byte[] key) { - if (Cache.GetBranch(key, out InternalNode? value)) return value; - if (Batch.GetBranch(key, out value)) return value; + if (Batch.GetBranch(key, out InternalNode? value)) return value; return Storage.GetBranch(key, out value) ? value : null; } public void SetLeaf(byte[] leafKey, byte[] leafValue) { - Cache.SetLeaf(leafKey, leafValue); +#if DEBUG + if (leafKey.Length != 32) throw new ArgumentException("key must be 32 bytes", nameof(leafKey)); + if (leafValue.Length != 32) throw new ArgumentException("value must be 32 bytes", nameof(leafValue)); +#endif Batch.SetLeaf(leafKey, leafValue); } public void SetStem(byte[] stemKey, SuffixTree suffixTree) { - Cache.SetStem(stemKey, suffixTree); +#if DEBUG + if (stemKey.Length != 31) throw new ArgumentException("stem must be 32 bytes", nameof(stemKey)); +#endif Batch.SetStem(stemKey, suffixTree); } public void SetBranch(byte[] branchKey, InternalNode internalNodeValue) { - Cache.SetBranch(branchKey, internalNodeValue); Batch.SetBranch(branchKey, internalNodeValue); } @@ -107,9 +122,9 @@ public void Flush(long blockNumber) { // we should not have any null values in the Batch db - because deletion of values from verkle tree is not allowed // nullable values are allowed in MemoryStateDb only for reverse diffs. - MemoryStateDb reverseDiff = new MemoryStateDb(); + VerkleMemoryDb reverseDiff = new VerkleMemoryDb(); - foreach (KeyValuePair entry in Batch.LeafNodes) + foreach (KeyValuePair entry in Batch.LeafTable) { Debug.Assert(entry.Value is not null, "nullable value only for reverse diff"); if (Storage.GetLeaf(entry.Key, out byte[]? node)) reverseDiff.LeafTable[entry.Key] = node; @@ -118,7 +133,7 @@ public void Flush(long blockNumber) Storage.SetLeaf(entry.Key, entry.Value); } - foreach (KeyValuePair entry in Batch.StemNodes) + foreach (KeyValuePair entry in Batch.StemTable) { Debug.Assert(entry.Value is not null, "nullable value only for reverse diff"); if (Storage.GetStem(entry.Key, out SuffixTree? node)) reverseDiff.StemTable[entry.Key] = node; @@ -127,7 +142,7 @@ public void Flush(long blockNumber) Storage.SetStem(entry.Key, entry.Value); } - foreach (KeyValuePair entry in Batch.BranchNodes) + foreach (KeyValuePair entry in Batch.BranchTable) { Debug.Assert(entry.Value is not null, "nullable value only for reverse diff"); if (Storage.GetBranch(entry.Key, out InternalNode? node)) reverseDiff.BranchTable[entry.Key] = node; @@ -136,28 +151,27 @@ public void Flush(long blockNumber) Storage.SetBranch(entry.Key, entry.Value); } - ForwardDiff.InsertDiff(blockNumber, Batch); - ReverseDiff.InsertDiff(blockNumber, reverseDiff); + History.InsertDiff(blockNumber, Batch, reverseDiff); FullStateBlock = blockNumber; + StateRootToBlocks.Set(GetBranch(Array.Empty())?._internalCommitment.PointAsField.ToBytes().ToArray() ?? throw new InvalidOperationException(), blockNumber.ToBigEndianByteArrayWithoutLeadingZeros()); + + Batch = new VerkleMemoryDb(); } // now the full state back in time by one block. public void ReverseState() { - byte[] reverseDiffByte = ReverseDiff.FetchDiff(FullStateBlock); - MemoryStateDb reverseDiff = MemoryStateDb.Decode(reverseDiffByte); + VerkleMemoryDb reverseDiff = History.GetBatchDiff(FullStateBlock, FullStateBlock - 1).DiffLayer; foreach (KeyValuePair entry in reverseDiff.LeafTable) { reverseDiff.GetLeaf(entry.Key, out byte[]? node); if (node is null) { - Cache.RemoveLeaf(entry.Key); Storage.RemoveLeaf(entry.Key); } else { - Cache.SetLeaf(entry.Key, node); Storage.SetLeaf(entry.Key, node); } } @@ -167,12 +181,10 @@ public void ReverseState() reverseDiff.GetStem(entry.Key, out SuffixTree? node); if (node is null) { - Cache.RemoveStem(entry.Key); Storage.RemoveStem(entry.Key); } else { - Cache.SetStem(entry.Key, node); Storage.SetStem(entry.Key, node); } } @@ -182,12 +194,10 @@ public void ReverseState() reverseDiff.GetBranch(entry.Key, out InternalNode? node); if (node is null) { - Cache.RemoveBranch(entry.Key); Storage.RemoveBranch(entry.Key); } else { - Cache.SetBranch(entry.Key, node); Storage.SetBranch(entry.Key, node); } } @@ -195,21 +205,21 @@ public void ReverseState() } // use the batch diff to move the full state back in time to access historical state. - public void ReverseState(IVerkleDiffDb reverseBatch, long numBlocks) + public void ApplyDiffLayer(BatchChangeSet changeSet) { - MemoryStateDb reverseDiff = (MemoryStateDb)reverseBatch; + if (changeSet.FromBlockNumber != FullStateBlock) throw new ArgumentException($"Cannot apply diff FullStateBlock:{FullStateBlock}!=fromBlock:{changeSet.FromBlockNumber}", nameof(changeSet.FromBlockNumber)); + + VerkleMemoryDb reverseDiff = changeSet.DiffLayer; foreach (KeyValuePair entry in reverseDiff.LeafTable) { reverseDiff.GetLeaf(entry.Key, out byte[]? node); if (node is null) { - Cache.RemoveLeaf(entry.Key); Storage.RemoveLeaf(entry.Key); } else { - Cache.SetLeaf(entry.Key, node); Storage.SetLeaf(entry.Key, node); } } @@ -219,12 +229,10 @@ public void ReverseState(IVerkleDiffDb reverseBatch, long numBlocks) reverseDiff.GetStem(entry.Key, out SuffixTree? node); if (node is null) { - Cache.RemoveStem(entry.Key); Storage.RemoveStem(entry.Key); } else { - Cache.SetStem(entry.Key, node); Storage.SetStem(entry.Key, node); } } @@ -234,22 +242,54 @@ public void ReverseState(IVerkleDiffDb reverseBatch, long numBlocks) reverseDiff.GetBranch(entry.Key, out InternalNode? node); if (node is null) { - Cache.RemoveBranch(entry.Key); Storage.RemoveBranch(entry.Key); } else { - Cache.SetBranch(entry.Key, node); Storage.SetBranch(entry.Key, node); } } - FullStateBlock -= numBlocks; + FullStateBlock = changeSet.ToBlockNumber; + } + public bool IsFullySynced(Keccak stateRoot) + { + return false; + } + + public byte[] GetStateRoot() + { + return GetBranch(Array.Empty())?._internalCommitment.Point.ToBytes().ToArray() ?? throw new InvalidOperationException(); + } + + public InternalNode? GetRootNode() + { + return GetBranch(Array.Empty()); + } + + public void MoveToStateRoot(byte[] stateRoot) + { + byte[] currentRoot = GetBranch(Array.Empty())?._internalCommitment.PointAsField.ToBytes().ToArray() ?? throw new InvalidOperationException(); + + if (currentRoot.SequenceEqual(stateRoot)) return; + if (Keccak.EmptyTreeHash.Equals(stateRoot)) return; + + byte[]? fromBlockBytes = StateRootToBlocks[currentRoot]; + byte[]? toBlockBytes = StateRootToBlocks[stateRoot]; + if (fromBlockBytes is null) return; + if (toBlockBytes is null) return; + + long fromBlock = fromBlockBytes.ToLongFromBigEndianByteArrayWithoutLeadingZeros(); + long toBlock = toBlockBytes.ToLongFromBigEndianByteArrayWithoutLeadingZeros(); + + ApplyDiffLayer(History.GetBatchDiff(fromBlock, toBlock)); + + Debug.Assert(GetStateRoot().Equals(stateRoot)); } } -public interface IVerkleStore +public interface IVerkleStore: IStoreWithReorgBoundary { - void InitRootHash(); + public byte[] RootHash { get; set; } byte[]? GetLeaf(byte[] key); SuffixTree? GetStem(byte[] key); InternalNode? GetBranch(byte[] key); @@ -258,9 +298,15 @@ public interface IVerkleStore void SetBranch(byte[] branchKey, InternalNode internalNodeValue); void Flush(long blockNumber); void ReverseState(); - void ReverseState(IVerkleDiffDb reverseBatch, long numBlocks); + void ApplyDiffLayer(BatchChangeSet changeSet); + + byte[] GetStateRoot(); + void MoveToStateRoot(byte[] stateRoot); + + public ReadOnlyVerkleStateStore AsReadOnly(VerkleMemoryDb keyValueStore); + + public VerkleMemoryDb GetForwardMergedDiff(long fromBlock, long toBlock); - public IVerkleDiffDb GetForwardMergedDiff(long fromBlock, long toBlock); + public VerkleMemoryDb GetReverseMergedDiff(long fromBlock, long toBlock); - public IVerkleDiffDb GetReverseMergedDiff(long fromBlock, long toBlock); } diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleTree.Visitor.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleTree.Visitor.cs new file mode 100644 index 00000000000..275c2b432fe --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleTree.Visitor.cs @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only +using Nethermind.Core.Crypto; +using Nethermind.Trie; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree; + +public partial class VerkleTree +{ + public void Accept(ITreeVisitor visitor, Keccak rootHash, VisitingOptions? visitingOptions = null) + { + if (visitor is null) throw new ArgumentNullException(nameof(visitor)); + if (rootHash is null) throw new ArgumentNullException(nameof(rootHash)); + visitingOptions ??= VisitingOptions.Default; + + using TrieVisitContext trieVisitContext = new TrieVisitContext + { + // hacky but other solutions are not much better, something nicer would require a bit of thinking + // we introduced a notion of an account on the visit context level which should have no knowledge of account really + // but we know that we have multiple optimizations and assumptions on trees + ExpectAccounts = visitingOptions.ExpectAccounts, + MaxDegreeOfParallelism = visitingOptions.MaxDegreeOfParallelism, + KeepTrackOfAbsolutePath = true + }; + + if (!rootHash.Equals(Keccak.EmptyTreeHash)) + { + _stateDb.MoveToStateRoot(rootHash.Bytes); + } + else + { + return; + } + + if (visitor is RootCheckVisitor) + { + if (!rootHash.Bytes.SequenceEqual(_stateDb.GetStateRoot())) visitor.VisitMissingNode(Keccak.Zero, trieVisitContext); + } + else + { + throw new Exception(); + } + + } + + public void Accept(IVerkleTreeVisitor visitor, Keccak rootHash, VisitingOptions? visitingOptions = null) + { + if (visitor is null) throw new ArgumentNullException(nameof(visitor)); + if (rootHash is null) throw new ArgumentNullException(nameof(rootHash)); + visitingOptions ??= VisitingOptions.Default; + + using TrieVisitContext trieVisitContext = new TrieVisitContext + { + // hacky but other solutions are not much better, something nicer would require a bit of thinking + // we introduced a notion of an account on the visit context level which should have no knowledge of account really + // but we know that we have multiple optimizations and assumptions on trees + ExpectAccounts = visitingOptions.ExpectAccounts, + MaxDegreeOfParallelism = visitingOptions.MaxDegreeOfParallelism, + KeepTrackOfAbsolutePath = true + }; + + if (!rootHash.Equals(Keccak.EmptyTreeHash)) + { + _stateDb.MoveToStateRoot(rootHash.Bytes); + } + else + { + return; + } + + visitor.VisitTree(rootHash.Bytes, trieVisitContext); + + RecurseNodes(visitor, _stateDb.GetBranch(Array.Empty()), trieVisitContext); + + } + + private void RecurseNodes(IVerkleTreeVisitor visitor, InternalNode node, TrieVisitContext trieVisitContext) + { + switch (node.NodeType) + { + case Nodes.NodeType.BranchNode: + { + visitor.VisitBranchNode((BranchNode)node, trieVisitContext); + trieVisitContext.Level++; + for (int i = 0; i < 256; i++) + { + trieVisitContext.AbsolutePathIndex.Add((byte)i); + InternalNode? childNode = _stateDb.GetBranch(trieVisitContext.AbsolutePathIndex.ToArray()); + if (childNode is not null && visitor.ShouldVisit(trieVisitContext.AbsolutePathIndex.ToArray())) + { + RecurseNodes(visitor, childNode!, trieVisitContext); + } + trieVisitContext.AbsolutePathIndex.RemoveAt(trieVisitContext.AbsolutePathIndex.Count - 1); + } + trieVisitContext.Level--; + break; + } + case Nodes.NodeType.StemNode: + { + visitor.VisitStemNode((StemNode)node, trieVisitContext); + byte[] stemKey = node.Stem; + Span childKey = stackalloc byte[32]; + stemKey.CopyTo(childKey); + trieVisitContext.Level++; + for (int i = 0; i < 256; i++) + { + childKey[31] = (byte)i; + byte[]? childNode = _stateDb.GetLeaf(childKey.ToArray()); + if (childNode is not null && visitor.ShouldVisit(childKey.ToArray())) + { + visitor.VisitLeafNode(childKey.ToArray(), trieVisitContext, childNode); + } + } + trieVisitContext.Level--; + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleTree.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleTree.cs similarity index 62% rename from src/Nethermind/Nethermind.Verkle/VerkleTree.cs rename to src/Nethermind/Nethermind.Verkle.Tree/VerkleTree.cs index e9514768869..21ecaa592fc 100644 --- a/src/Nethermind/Nethermind.Verkle/VerkleTree.cs +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleTree.cs @@ -1,26 +1,42 @@ +using System.Diagnostics; using System.Runtime.CompilerServices; using Nethermind.Db; -using Nethermind.Field.Montgomery.FrEElement; using Nethermind.Verkle.Curve; +using Nethermind.Verkle.Fields.FrEElement; +using Nethermind.Verkle.Tree.Nodes; +using Nethermind.Verkle.Tree.VerkleDb; using Nethermind.Verkle.Utils; -using Nethermind.Verkle.VerkleNodes; -using Nethermind.Verkle.VerkleStateDb; +using Nethermind.Core.Extensions; -namespace Nethermind.Verkle; +namespace Nethermind.Verkle.Tree; -public class VerkleTree +public partial class VerkleTree { - private readonly IVerkleStore _stateDb; - public byte[] RootHash => _stateDb.GetBranch(Array.Empty())?._internalCommitment.PointAsField.ToBytes().ToArray() ?? throw new InvalidOperationException(); + public readonly IVerkleStore _stateDb; + + public byte[] RootHash + { + get => _stateDb.GetStateRoot(); + set => _stateDb.MoveToStateRoot(value); + } public VerkleTree(IDbProvider dbProvider) { - _stateDb = new VerkleStateStore(dbProvider); - _stateDb.InitRootHash(); + VerkleStateStore stateDb = new VerkleStateStore(dbProvider); + _stateDb = new CompositeVerkleStateStore(stateDb); + } + + protected VerkleTree(IVerkleStore stateStore) + { + _stateDb = new CompositeVerkleStateStore(stateStore); } private static Banderwagon GetLeafDelta(byte[]? oldValue, byte[] newValue, byte index) { +#if DEBUG + if (oldValue is not null && oldValue.Length != 32) throw new ArgumentException("oldValue must be null or 32 bytes", nameof(oldValue)); + if (newValue.Length != 32) throw new ArgumentException("newValue must be 32 bytes", nameof(newValue)); +#endif (FrE newValLow, FrE newValHigh) = VerkleUtils.BreakValueInLowHigh(newValue); (FrE oldValLow, FrE oldValHigh) = VerkleUtils.BreakValueInLowHigh(oldValue); @@ -36,6 +52,10 @@ private static Banderwagon GetLeafDelta(byte[]? oldValue, byte[] newValue, byte public void Insert(Span key, byte[] value) { if (value is null) throw new ArgumentNullException(nameof(value)); +#if DEBUG + if (key.Length != 32) throw new ArgumentException("key must be 32 bytes", nameof(key)); + if (value.Length != 32) throw new ArgumentException("value must be 32 bytes", nameof(value)); +#endif LeafUpdateDelta leafDelta = UpdateLeaf(key, value); UpdateTreeCommitments(key[..31], leafDelta); } @@ -44,6 +64,18 @@ public void Insert(Span key, byte[] value) public void InsertStemBatch(Span stem, Dictionary leafIndexValueMap) { +#if DEBUG + if (stem.Length != 31) throw new ArgumentException("stem must be 31 bytes", nameof(stem)); + Span key = new byte[32]; + foreach (KeyValuePair keyVal in leafIndexValueMap) + { + stem.CopyTo(key); + key[31] = keyVal.Key; + Console.WriteLine("KA: " + EnumerableExtensions.ToString(key.ToArray())); + Console.WriteLine("V: " + EnumerableExtensions.ToString(keyVal.Value)); + } +#endif + LeafUpdateDelta leafDelta = UpdateLeaf(stem, leafIndexValueMap); UpdateTreeCommitments(stem, leafDelta); } @@ -60,14 +92,15 @@ private void UpdateRootNode(Banderwagon rootDelta) { InternalNode root = _stateDb.GetBranch(Array.Empty()) ?? throw new ArgumentException(); root._internalCommitment.AddPoint(rootDelta); + _stateDb.SetBranch(Array.Empty(), root); } private Banderwagon TraverseBranch(TraverseContext traverseContext) { - byte pathIndex = traverseContext.Stem[traverseContext.CurrentIndex]; + byte childIndex = traverseContext.Stem[traverseContext.CurrentIndex]; byte[] absolutePath = traverseContext.Stem[..(traverseContext.CurrentIndex + 1)].ToArray(); - InternalNode? child = GetBranchChild(absolutePath); + InternalNode? child = GetBranchNode(absolutePath); if (child is null) { // 1. create new suffix node @@ -78,51 +111,43 @@ private Banderwagon TraverseBranch(TraverseContext traverseContext) // 1. Add internal.stem node // 2. return delta from ExtensionCommitment - Banderwagon point = Committer.ScalarMul(deltaHash, pathIndex); _stateDb.SetBranch(absolutePath, new StemNode(traverseContext.Stem.ToArray(), suffixCommitment!)); - return point; + return Committer.ScalarMul(deltaHash, childIndex); } - Banderwagon parentDeltaHash; - Banderwagon deltaPoint; if (child.IsBranchNode) { traverseContext.CurrentIndex += 1; - parentDeltaHash = TraverseBranch(traverseContext); + Banderwagon branchDeltaHash = TraverseBranch(traverseContext); traverseContext.CurrentIndex -= 1; - FrE deltaHash = child.UpdateCommitment(parentDeltaHash); + FrE deltaHash = child.UpdateCommitment(branchDeltaHash); _stateDb.SetBranch(absolutePath, child); - deltaPoint = Committer.ScalarMul(deltaHash, pathIndex); + return Committer.ScalarMul(deltaHash, childIndex); } - else + + traverseContext.CurrentIndex += 1; + (Banderwagon stemDeltaHash, bool changeStemToBranch) = TraverseStem(child, traverseContext); + traverseContext.CurrentIndex -= 1; + if (changeStemToBranch) { - traverseContext.CurrentIndex += 1; - (parentDeltaHash, bool changeStemToBranch) = TraverseStem((StemNode)child, traverseContext); - traverseContext.CurrentIndex -= 1; - if (changeStemToBranch) - { - BranchNode newChild = new BranchNode(); - newChild._internalCommitment.AddPoint(child._internalCommitment.Point); - // since this is a new child, this would be just the parentDeltaHash.PointToField - // now since there was a node before and that value is deleted - we need to subtract - // that from the delta as well - FrE deltaHash = newChild.UpdateCommitment(parentDeltaHash); - _stateDb.SetBranch(absolutePath, newChild); - deltaPoint = Committer.ScalarMul(deltaHash, pathIndex); - } - else - { - // in case of stem, no need to update the child commitment - because this commitment is the suffix commitment - // pass on the update to upper level - _stateDb.SetBranch(absolutePath, child); - deltaPoint = parentDeltaHash; - } + BranchNode newChild = new BranchNode(); + newChild._internalCommitment.AddPoint(child._internalCommitment.Point); + // since this is a new child, this would be just the parentDeltaHash.PointToField + // now since there was a node before and that value is deleted - we need to subtract + // that from the delta as well + FrE deltaHash = newChild.UpdateCommitment(stemDeltaHash); + _stateDb.SetBranch(absolutePath, newChild); + return Committer.ScalarMul(deltaHash, childIndex); } - return deltaPoint; + // in case of stem, no need to update the child commitment - because this commitment is the suffix commitment + // pass on the update to upper level + return stemDeltaHash; } - private (Banderwagon, bool) TraverseStem(StemNode node, TraverseContext traverseContext) + private (Banderwagon, bool) TraverseStem(InternalNode node, TraverseContext traverseContext) { + Debug.Assert(node.IsStem); + (List sharedPath, byte? pathDiffIndexOld, byte? pathDiffIndexNew) = VerkleUtils.GetPathDifference(node.Stem, traverseContext.Stem.ToArray()); @@ -167,10 +192,8 @@ private Banderwagon TraverseBranch(TraverseContext traverseContext) return (internalCommitment - oldSuffixNode.ExtensionCommitment.Point, true); } - SuffixTree oldValue = _stateDb.GetStem(traverseContext.Stem.ToArray()) ?? throw new ArgumentException(); - FrE deltaFr = oldValue.UpdateCommitment(traverseContext.LeafUpdateDelta); - _stateDb.SetStem(traverseContext.Stem.ToArray(), oldValue); - + (FrE deltaFr, Commitment updatedSuffixCommitment) = UpdateSuffixNode(traverseContext.Stem.ToArray(), traverseContext.LeafUpdateDelta); + _stateDb.SetBranch(traverseContext.Stem[..traverseContext.CurrentIndex].ToArray(), new StemNode(node.Stem, updatedSuffixCommitment) ); return (Committer.ScalarMul(deltaFr, traverseContext.Stem[traverseContext.CurrentIndex - 1]), false); } @@ -187,19 +210,16 @@ private Banderwagon FillSpaceWithInternalBranchNodes(byte[] path, int length, Ba return deltaPoint; } - private InternalNode? GetBranchChild(byte[] pathWithIndex) - { - return _stateDb.GetBranch(pathWithIndex); - } + private InternalNode? GetBranchNode(byte[] pathWithIndex) => _stateDb.GetBranch(pathWithIndex); - private (FrE, Commitment?) UpdateSuffixNode(byte[] stemKey, LeafUpdateDelta leafUpdateDelta, bool insertNew = false) + private (FrE, Commitment) UpdateSuffixNode(byte[] stemKey, LeafUpdateDelta leafUpdateDelta, bool insertNew = false) { - SuffixTree oldNode = insertNew ? new SuffixTree(stemKey) : _stateDb.GetStem(stemKey) ?? throw new ArgumentException(); + SuffixTree suffixNode = insertNew? new SuffixTree(stemKey): _stateDb.GetStem(stemKey)?? throw new ArgumentException(); - FrE deltaFr = oldNode.UpdateCommitment(leafUpdateDelta); - _stateDb.SetStem(stemKey, oldNode); + FrE deltaFr = suffixNode.UpdateCommitment(leafUpdateDelta); + _stateDb.SetStem(stemKey, suffixNode); // add the init commitment, because while calculating diff, we subtract the initCommitment in new nodes. - return insertNew ? (deltaFr + oldNode.InitCommitmentHash, oldNode.ExtensionCommitment.Dup()) : (deltaFr, null); + return insertNew ? (deltaFr + suffixNode.InitCommitmentHash, suffixNode.ExtensionCommitment.Dup()) : (deltaFr, suffixNode.ExtensionCommitment.Dup()); } private LeafUpdateDelta UpdateLeaf(Span key, byte[] value) @@ -210,13 +230,13 @@ private LeafUpdateDelta UpdateLeaf(Span key, byte[] value) } private LeafUpdateDelta UpdateLeaf(Span stem, Dictionary indexValuePairs) { - byte[] key = new byte[32]; + Span key = new byte[32]; stem.CopyTo(key); LeafUpdateDelta leafDelta = new LeafUpdateDelta(); foreach ((byte index, byte[] value) in indexValuePairs) { key[31] = index; - leafDelta.UpdateDelta(_updateLeaf(key, value), key[31]); + leafDelta.UpdateDelta(_updateLeaf(key.ToArray(), value), key[31]); } return leafDelta; } @@ -230,12 +250,12 @@ private Banderwagon _updateLeaf(byte[] key, byte[] value) return leafDeltaCommitment; } - public IVerkleDiffDb GetForwardMergedDiff(long fromBlock, long toBlock) + public VerkleMemoryDb GetForwardMergedDiff(long fromBlock, long toBlock) { return _stateDb.GetForwardMergedDiff(fromBlock, toBlock); } - public IVerkleDiffDb GetReverseMergedDiff(long fromBlock, long toBlock) + public VerkleMemoryDb GetReverseMergedDiff(long fromBlock, long toBlock) { return _stateDb.GetReverseMergedDiff(fromBlock, toBlock); } @@ -249,9 +269,9 @@ public void ReverseState() _stateDb.ReverseState(); } - public void ReverseState(IVerkleDiffDb reverseBatch, long numBlocks) + public void ApplyDiffLayer(VerkleMemoryDb reverseBatch, long fromBlock, long toBlock) { - _stateDb.ReverseState(reverseBatch, numBlocks); + _stateDb.ApplyDiffLayer(new BatchChangeSet(fromBlock, toBlock, reverseBatch)); } private ref struct TraverseContext @@ -267,4 +287,20 @@ public TraverseContext(Span stem, LeafUpdateDelta delta) LeafUpdateDelta = delta; } } + + public void GenerateVerkleProof(List keys) + { + foreach (byte[] key in keys) + { + + } + } + + public void FindKeyPath(byte[] key) + { + for (int i = 0; i < key.Length; i++) + { + + } + } } diff --git a/src/Nethermind/Nethermind.Verkle.Tree/VerkleTreeDumper.cs b/src/Nethermind/Nethermind.Verkle.Tree/VerkleTreeDumper.cs new file mode 100644 index 00000000000..8b790ffec89 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Tree/VerkleTreeDumper.cs @@ -0,0 +1,63 @@ +// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using System.Text; +using Nethermind.Core.Crypto; +using Nethermind.Core.Extensions; +using Nethermind.Trie; +using Nethermind.Verkle.Tree.Nodes; + +namespace Nethermind.Verkle.Tree; + +public class VerkleTreeDumper: IVerkleTreeVisitor +{ + + private readonly StringBuilder _builder = new StringBuilder(); + + public void Reset() + { + _builder.Clear(); + } + + public bool ShouldVisit(byte[] nextNode) + { + return true; + } + public void VisitTree(byte[] rootHash, TrieVisitContext trieVisitContext) + { + if (rootHash.SequenceEqual(Keccak.Zero.Bytes)) + { + _builder.AppendLine("EMPTY TREE"); + } + else + { + _builder.AppendLine("STATE TREE"); + } + } + + private string GetPrefix(TrieVisitContext context) => string.Concat($"{GetIndent(context.Level)}", context.IsStorage ? "STORAGE " : string.Empty, $"{GetChildIndex(context)}"); + private string GetIndent(int level) => new('+', level * 2); + private string GetChildIndex(TrieVisitContext context) => context.BranchChildIndex is null ? string.Empty : $"{context.BranchChildIndex:x2} "; + + public void VisitMissingNode(byte[] nodeKey, TrieVisitContext trieVisitContext) + { + _builder.AppendLine($"{GetIndent(trieVisitContext.Level)}{GetChildIndex(trieVisitContext)}MISSING {nodeKey}"); + } + public void VisitBranchNode(BranchNode node, TrieVisitContext trieVisitContext) + { + _builder.AppendLine($"{GetPrefix(trieVisitContext)}BRANCH | -> Key: {trieVisitContext.AbsolutePathIndex.ToArray().ToHexString()}"); + } + public void VisitStemNode(StemNode node, TrieVisitContext trieVisitContext) + { + _builder.AppendLine($"{GetPrefix(trieVisitContext)}STEM | -> Key: {trieVisitContext.AbsolutePathIndex.ToArray().ToHexString()}"); + } + public void VisitLeafNode(byte[] nodeKey, TrieVisitContext trieVisitContext, byte[]? nodeValue) + { + _builder.AppendLine($"{GetPrefix(trieVisitContext)}LEAF | -> Key: {nodeKey.ToHexString()} Value: {nodeValue.ToHexString()}"); + } + + public override string ToString() + { + return _builder.ToString(); + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Utils/Committer.cs b/src/Nethermind/Nethermind.Verkle.Utils/Committer.cs new file mode 100644 index 00000000000..029334bbf98 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Utils/Committer.cs @@ -0,0 +1,71 @@ +using System.Diagnostics; +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Curve; + +namespace Nethermind.Verkle.Utils +{ + public struct Committer + { + private static readonly CRS Constants = CRS.Instance; + + public static Banderwagon Commit(FrE[] value) + { + Banderwagon elem = Banderwagon.Identity(); + for (int i = 0; i < value.Length; i++) + { + elem += value[i] * Constants.BasisG[i]; + } + + return elem; + } + + public static Banderwagon ScalarMul(FrE value, int index) + { + return Constants.BasisG[index] * value; + } + } + + public class Commitment + { + private FrE? _pointAsField; + + public Commitment(Banderwagon point) + { + Point = point; + } + + public Commitment() + { + Point = Banderwagon.Identity(); + } + public Banderwagon Point { get; private set; } + public FrE PointAsField + { + get + { + if (_pointAsField is null) SetCommitmentToField(); + Debug.Assert(_pointAsField is not null, nameof(_pointAsField) + " != null"); + return _pointAsField.Value; + } + private set => _pointAsField = value; + } + + public Commitment Dup() + { + return new Commitment(Point.Dup()); + } + + private void SetCommitmentToField() + { + byte[] mapToBytes = Point.MapToField(); + PointAsField = FrE.FromBytesReduced(mapToBytes); + } + + public void AddPoint(Banderwagon point) + { + Point += point; + _pointAsField = null; + SetCommitmentToField(); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Utils/IVerkleTree.cs b/src/Nethermind/Nethermind.Verkle.Utils/IVerkleTree.cs new file mode 100644 index 00000000000..5864b5ac8be --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Utils/IVerkleTree.cs @@ -0,0 +1,36 @@ +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Verkle.Proofs; + +namespace Nethermind.Verkle.Utils +{ + using Fr = FrE; + + public interface IVerkleTree + { + bool Insert(byte[] key, byte[] value); + byte[] Get(byte[] key); + Fr RootHash(); + VerkleProof CreateVerkleProof(byte[][] keys); + } + + public struct VerkleProof + { + public VerificationHint VerifyHint; + public Fr[] CommsSorted; + public VerkleProofStruct Proof; + } + + public struct VerificationHint + { + public byte[] Depths; + public ExtPresent[] ExtensionPresent; + public byte[] DifferentStemNoProof; + } + + public enum ExtPresent + { + None, + DifferentStem, + Present + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Utils/Nethermind.Verkle.Utils.csproj b/src/Nethermind/Nethermind.Verkle.Utils/Nethermind.Verkle.Utils.csproj new file mode 100644 index 00000000000..e4df7f984ef --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Utils/Nethermind.Verkle.Utils.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Nethermind/Nethermind.Verkle.Utils/PedersenHash.cs b/src/Nethermind/Nethermind.Verkle.Utils/PedersenHash.cs new file mode 100644 index 00000000000..31cbce30fd5 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Utils/PedersenHash.cs @@ -0,0 +1,46 @@ +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Int256; +using Nethermind.Verkle.Curve; + +namespace Nethermind.Verkle.Utils +{ + public static class PedersenHash + { + + public static byte[] Hash(UInt256[] inputElements) + { + int inputLength = inputElements.Length; + FrE[] pedersenVec = new FrE[1 + 2 * inputLength]; + pedersenVec[0] = FrE.SetElement((ulong)(2 + 256 * inputLength * 32)); + + for (int i = 0; i < inputElements.Length; i++) + { + pedersenVec[2 * i + 1] = FrE.SetElement(inputElements[i].u0, inputElements[i].u1); + pedersenVec[2 * i + 2] = FrE.SetElement(inputElements[i].u2, inputElements[i].u3); + } + CRS crs = CRS.Instance; + + Banderwagon res = Banderwagon.Identity(); + for (int i = 0; i < pedersenVec.Length; i++) + { + res += crs.BasisG[i] * pedersenVec[i]; + } + + return res.ToBytesLittleEndian(); + } + public static byte[] Hash(ReadOnlySpan address32, UInt256 treeIndex) + { + UInt256 addressUInt256 = new UInt256(address32); + + CRS crs = CRS.Instance; + + Banderwagon res = crs.BasisG[0] * FrE.SetElement(2 + 256 * 64) + + crs.BasisG[1] * FrE.SetElement(addressUInt256.u0, addressUInt256.u1) + + crs.BasisG[2] * FrE.SetElement(addressUInt256.u2, addressUInt256.u3) + + crs.BasisG[3] * FrE.SetElement(treeIndex.u0, treeIndex.u1) + + crs.BasisG[4] * FrE.SetElement(treeIndex.u2, treeIndex.u3); + + return res.ToBytesLittleEndian(); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle.Utils/VerkleUtils.cs b/src/Nethermind/Nethermind.Verkle.Utils/VerkleUtils.cs new file mode 100644 index 00000000000..9c4351b2ba7 --- /dev/null +++ b/src/Nethermind/Nethermind.Verkle.Utils/VerkleUtils.cs @@ -0,0 +1,71 @@ +using Nethermind.Field.Montgomery.FrEElement; +using Nethermind.Int256; +using Nethermind.Verkle.Curve; + +namespace Nethermind.Verkle.Utils +{ + public struct LeafUpdateDelta + { + public Banderwagon? DeltaC1 { get; private set; } + public Banderwagon? DeltaC2 { get; private set; } + + public LeafUpdateDelta() + { + DeltaC1 = null; + DeltaC2 = null; + } + + public void UpdateDelta(Banderwagon deltaLeafCommitment, byte index) + { + if (index < 128) + { + if (DeltaC1 is null) DeltaC1 = deltaLeafCommitment; + else DeltaC1 += deltaLeafCommitment; + } + else + { + if (DeltaC2 is null) DeltaC2 = deltaLeafCommitment; + else DeltaC2 += deltaLeafCommitment; + } + } + } + + public static class VerkleUtils + { + private static FrE ValueExistsMarker + { + get + { + new UInt256(2).Exp(128, out UInt256 res); + return FrE.SetElement(res.u0, res.u1, res.u2, res.u3); + } + } + public static Span ToAddress32(ReadOnlySpan address20) + { + Span address32 = new byte[32]; + Span x = address32[12..]; + address20.CopyTo(x); + return address32; + } + + public static (FrE, FrE) BreakValueInLowHigh(byte[]? value) + { + if (value is null) return (FrE.Zero, FrE.Zero); + if (value.Length != 32) throw new ArgumentException(); + FrE lowFr = FrE.FromBytes(value[..16].Reverse().ToArray()) + ValueExistsMarker; + FrE highFr = FrE.FromBytes(value[16..].Reverse().ToArray()); + return (lowFr, highFr); + } + + public static (List, byte?, byte?) GetPathDifference(IEnumerable existingNodeKey, IEnumerable newNodeKey) + { + List samePathIndices = new List(); + foreach ((byte first, byte second) in existingNodeKey.Zip(newNodeKey)) + { + if (first != second) return (samePathIndices, first, second); + samePathIndices.Add(first); + } + return (samePathIndices, null, null); + } + } +} diff --git a/src/Nethermind/Nethermind.Verkle/AccountHeader.cs b/src/Nethermind/Nethermind.Verkle/AccountHeader.cs deleted file mode 100644 index bad9d658217..00000000000 --- a/src/Nethermind/Nethermind.Verkle/AccountHeader.cs +++ /dev/null @@ -1,166 +0,0 @@ -using Nethermind.Int256; -using Nethermind.Verkle.Utils; - -namespace Nethermind.Verkle; - -public readonly struct AccountHeader -{ - public const int Version = 0; - public const int Balance = 1; - public const int Nonce = 2; - public const int CodeHash = 3; - public const int CodeSize = 4; - - private const int MainStorageOffsetExponent = 31; - private static readonly UInt256 MainStorageOffsetBase = 256; - private static readonly UInt256 MainStorageOffset = MainStorageOffsetBase << MainStorageOffsetExponent; - - private static readonly UInt256 HeaderStorageOffset = 64; - private static readonly UInt256 CodeOffset = 128; - private static readonly UInt256 VerkleNodeWidth = 256; - - public static byte[] GetTreeKeyPrefix(byte[] address20, UInt256 treeIndex) - { - byte[]? address32 = VerkleUtils.ToAddress32(address20); - return PedersenHash.Hash(address32, treeIndex); - } - - public static byte[] GetTreeKeyPrefixAccount(byte[] address) => GetTreeKeyPrefix(address, 0); - - public static byte[] GetTreeKey(byte[] address, UInt256 treeIndex, byte subIndexBytes) - { - byte[] treeKeyPrefix = GetTreeKeyPrefix(address, treeIndex); - treeKeyPrefix[31] = subIndexBytes; - return treeKeyPrefix; - } - - public static byte[] GetTreeKeyForVersion(byte[] address) => GetTreeKey(address, UInt256.Zero, Version); - public static byte[] GetTreeKeyForBalance(byte[] address) => GetTreeKey(address, UInt256.Zero, Balance); - public static byte[] GetTreeKeyForNonce(byte[] address) => GetTreeKey(address, UInt256.Zero, Nonce); - public static byte[] GetTreeKeyForCodeCommitment(byte[] address) => GetTreeKey(address, UInt256.Zero, CodeHash); - public static byte[] GetTreeKeyForCodeSize(byte[] address) => GetTreeKey(address, UInt256.Zero, CodeSize); - - - public static byte[] GetTreeKeyForCodeChunk(byte[] address, UInt256 chunk) - { - UInt256 chunkOffset = CodeOffset + chunk; - UInt256 treeIndex = chunkOffset / VerkleNodeWidth; - UInt256.Mod(chunkOffset, VerkleNodeWidth, out UInt256 subIndex); - return GetTreeKey(address, treeIndex, subIndex.ToBigEndian()[31]); - } - - public static byte[] GetTreeKeyForStorageSlot(byte[] address, UInt256 storageKey) - { - UInt256 pos; - - if (storageKey < CodeOffset - HeaderStorageOffset) pos = HeaderStorageOffset + storageKey; - else pos = MainStorageOffset + storageKey; - - UInt256 treeIndex = pos / VerkleNodeWidth; - - UInt256.Mod(pos, VerkleNodeWidth, out UInt256 subIndex); - return GetTreeKey(address, treeIndex, subIndex.ToBigEndian()[31]); - } - - - public static void FillTreeAndSubIndexForChunk(UInt256 chunkId, ref Span subIndexBytes, out UInt256 treeIndex) - { - UInt256 chunkOffset = CodeOffset + chunkId; - treeIndex = chunkOffset / VerkleNodeWidth; - UInt256.Mod(chunkOffset, VerkleNodeWidth, out UInt256 subIndex); - subIndex.ToBigEndian(subIndexBytes); - } - - public ref struct CodeChunkEnumerator - { - const byte PushOffset = 95; - const byte Push1 = PushOffset + 1; - const byte Push32 = PushOffset + 32; - - private Span _code; - private byte _rollingOverPushLength = 0; - private readonly byte[] _bufferChunk = new byte[32]; - private readonly Span _bufferChunkCodePart; - - public CodeChunkEnumerator(Span code) - { - _code = code; - _bufferChunkCodePart = _bufferChunk.AsSpan().Slice(1); - } - - // Try get next chunk - public bool TryGetNextChunk(out byte[] chunk) - { - chunk = _bufferChunk; - - // we don't have chunks left - if (_code.IsEmpty) - { - return false; - } - - // we don't have full chunk - if (_code.Length < 31) - { - // need to have trailing zeroes - _bufferChunkCodePart.Fill(0); - - // set number of push bytes - _bufferChunk[0] = _rollingOverPushLength; - - // copy main bytes - _code.CopyTo(_bufferChunkCodePart); - - // we are done - _code = Span.Empty; - } - else - { - // fill up chunk to store - - // get current chunk of code - Span currentChunk = _code.Slice(0, 31); - - // copy main bytes - currentChunk.CopyTo(_bufferChunkCodePart); - - switch (_rollingOverPushLength) - { - case 32 or 31: // all bytes are roll over - - // set number of push bytes - _bufferChunk[0] = 31; - - // if 32, then we will roll over with 1 to even next chunk - _rollingOverPushLength -= 31; - break; - default: - // set number of push bytes - _bufferChunk[0] = _rollingOverPushLength; - _rollingOverPushLength = 0; - - // check if we have a push instruction in remaining code - // ignore the bytes we rolled over, they are not instructions - for (int i = _bufferChunk[0]; i < 31;) - { - byte instruction = currentChunk[i]; - i++; - if (instruction is >= Push1 and <= Push32) - { - // we calculate data to ignore in code - i += instruction - PushOffset; - - // check if we rolled over the chunk - _rollingOverPushLength = (byte)Math.Max(i - 31, 0); - } - } - break; - } - - // move to next chunk - _code = _code.Slice(31); - } - return true; - } - } -} diff --git a/src/Nethermind/Nethermind.Verkle/Nethermind.Verkle.csproj b/src/Nethermind/Nethermind.Verkle/Nethermind.Verkle.csproj deleted file mode 100644 index dfc79e3af51..00000000000 --- a/src/Nethermind/Nethermind.Verkle/Nethermind.Verkle.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - net7.0 - enable - enable - - - - - - - - - - - - - - - - - - diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/DiskDb.cs b/src/Nethermind/Nethermind.Verkle/VerkleStateDb/DiskDb.cs deleted file mode 100644 index a9aa84eb9bf..00000000000 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/DiskDb.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. - -using Nethermind.Core; -using Nethermind.Db; -using Nethermind.Verkle.VerkleNodes; - -namespace Nethermind.Verkle.VerkleStateDb; - -public class DiskDb : IVerkleDb -{ - private readonly IDbProvider _dbProvider; - - public IDb LeafDb => _dbProvider.LeafDb; - public IDb StemDb => _dbProvider.StemDb; - public IDb BranchDb => _dbProvider.BranchDb; - public DiskDb(IDbProvider dbProvider) - { - _dbProvider = dbProvider; - } - public byte[]? GetLeaf(byte[] key) => LeafDb[key]; - - public SuffixTree? GetStem(byte[] key) - { - return StemDb[key] is null ? null : SuffixTreeSerializer.Instance.Decode(StemDb[key]); - } - - public InternalNode? GetBranch(byte[] key) - { - return BranchDb[key] is null ? null : InternalNodeSerializer.Instance.Decode(BranchDb[key]); - } - - public void SetLeaf(byte[] leafKey, byte[]? leafValue, IKeyValueStore db) => db[leafKey] = leafValue; - - public void SetStem(byte[] stemKey, SuffixTree? suffixTree, IKeyValueStore db) => db[stemKey] = SuffixTreeSerializer.Instance.Encode(suffixTree).Bytes; - - public void SetBranch(byte[] branchKey, InternalNode? internalNodeValue, IKeyValueStore db) => db[branchKey] = InternalNodeSerializer.Instance.Encode(internalNodeValue).Bytes; - - public bool GetLeaf(byte[] key, out byte[]? value) - { - value = GetLeaf(key); - return value is not null; - } - public bool GetStem(byte[] key, out SuffixTree? value) - { - value = GetStem(key); - return value is not null; - } - public bool GetBranch(byte[] key, out InternalNode? value) - { - value = GetBranch(key); - return value is not null; - } - public void SetLeaf(byte[] leafKey, byte[] leafValue) => SetLeaf(leafKey, leafValue, LeafDb); - public void SetStem(byte[] stemKey, SuffixTree suffixTree) => SetStem(stemKey, suffixTree, StemDb); - public void SetBranch(byte[] branchKey, InternalNode internalNodeValue) => SetBranch(branchKey, internalNodeValue, BranchDb); - public void RemoveLeaf(byte[] leafKey) - { - LeafDb.Remove(leafKey); - } - public void RemoveStem(byte[] stemKey) - { - StemDb.Remove(stemKey); - } - public void RemoveBranch(byte[] branchKey) - { - BranchDb.Remove(branchKey); - } - - public void BatchLeafInsert(IEnumerable> keyLeaf) - { - using IBatch batch = LeafDb.StartBatch(); - foreach ((byte[] key, byte[]? value) in keyLeaf) - { - SetLeaf(key, value, batch); - } - } - public void BatchStemInsert(IEnumerable> suffixLeaf) - { - using IBatch batch = StemDb.StartBatch(); - foreach ((byte[] key, SuffixTree? value) in suffixLeaf) - { - SetStem(key, value, batch); - } - } - public void BatchBranchInsert(IEnumerable> branchLeaf) - { - using IBatch batch = BranchDb.StartBatch(); - foreach ((byte[] key, InternalNode? value) in branchLeaf) - { - SetBranch(key, value, batch); - } - } -} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/History.cs b/src/Nethermind/Nethermind.Verkle/VerkleStateDb/History.cs deleted file mode 100644 index 3c6645b1b31..00000000000 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/History.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. - -namespace Nethermind.Verkle.VerkleStateDb; - -public enum DiffType -{ - Forward, - Reverse -} - -public class DiffLayer : IDiffLayer -{ - private DiffType _diffType; - private Dictionary Diff { get; } - public DiffLayer(DiffType diffType) - { - Diff = new Dictionary(); - _diffType = diffType; - } - public void InsertDiff(long blockNumber, IVerkleDiffDb diff) - { - Diff[blockNumber] = diff.Encode(); - } - public byte[] FetchDiff(long blockNumber) => Diff[blockNumber]; - public IVerkleDiffDb MergeDiffs(long fromBlock, long toBlock) - { - MemoryStateDb mergedDiff = new MemoryStateDb(); - switch (_diffType) - { - case DiffType.Reverse: - for (long i = fromBlock; i <= toBlock; i++) - { - byte[] currDiffBytes = FetchDiff(i); - MemoryStateDb reverseDiff = MemoryStateDb.Decode(currDiffBytes); - Parallel.ForEach(reverseDiff.LeafTable, item => mergedDiff.LeafTable.TryAdd(item.Key, item.Value)); - Parallel.ForEach(reverseDiff.BranchTable, item => mergedDiff.BranchTable.TryAdd(item.Key, item.Value)); - Parallel.ForEach(reverseDiff.StemTable, item => mergedDiff.StemTable.TryAdd(item.Key, item.Value)); - } - break; - case DiffType.Forward: - for (long i = toBlock; i >= fromBlock; i--) - { - byte[] currDiffBytes = FetchDiff(i); - MemoryStateDb reverseDiff = MemoryStateDb.Decode(currDiffBytes); - Parallel.ForEach(reverseDiff.LeafTable, item => mergedDiff.LeafTable.TryAdd(item.Key, item.Value)); - Parallel.ForEach(reverseDiff.BranchTable, item => mergedDiff.BranchTable.TryAdd(item.Key, item.Value)); - Parallel.ForEach(reverseDiff.StemTable, item => mergedDiff.StemTable.TryAdd(item.Key, item.Value)); - } - break; - default: - throw new ArgumentOutOfRangeException(); - } - return mergedDiff; - - } -} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/IDiffLayer.cs b/src/Nethermind/Nethermind.Verkle/VerkleStateDb/IDiffLayer.cs deleted file mode 100644 index 1601e5e3a30..00000000000 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/IDiffLayer.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. - -namespace Nethermind.Verkle.VerkleStateDb; - -public interface IDiffLayer -{ - public void InsertDiff(long blockNumber, IVerkleDiffDb diff); - - public byte[] FetchDiff(long blockNumber); - - public IVerkleDiffDb MergeDiffs(long fromBlock, long toBlock); -} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/MemoryDb.cs b/src/Nethermind/Nethermind.Verkle/VerkleStateDb/MemoryDb.cs deleted file mode 100644 index c3da45ae39c..00000000000 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/MemoryDb.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. - -using Nethermind.Core.Extensions; -using Nethermind.Serialization.Rlp; -using Nethermind.Verkle.VerkleNodes; - -namespace Nethermind.Verkle.VerkleStateDb; -using BranchStore = Dictionary; -using LeafStore = Dictionary; -using SuffixStore = Dictionary; - -public class MemoryStateDb : IVerkleDiffDb -{ - public Dictionary LeafTable { get; } - public Dictionary StemTable { get; } - public Dictionary BranchTable { get; } - - public MemoryStateDb() - { - LeafTable = new Dictionary(Bytes.EqualityComparer); - StemTable = new Dictionary(Bytes.EqualityComparer); - BranchTable = new Dictionary(Bytes.EqualityComparer); - } - - public MemoryStateDb(LeafStore leafTable, SuffixStore stemTable, BranchStore branchTable) - { - LeafTable = leafTable; - StemTable = stemTable; - BranchTable = branchTable; - } - - public byte[] Encode() - { - int contentLength = MemoryStateDbSerializer.Instance.GetLength(this, RlpBehaviors.None); - RlpStream stream = new RlpStream(Rlp.LengthOfSequence(contentLength)); - stream.StartSequence(contentLength); - MemoryStateDbSerializer.Instance.Encode(stream, this); - return stream.Data ?? throw new ArgumentException(); - } - - public static MemoryStateDb Decode(byte[] data) - { - RlpStream stream = data.AsRlpStream(); - stream.ReadSequenceLength(); - return MemoryStateDbSerializer.Instance.Decode(stream); - } - - public IEnumerable> LeafNodes => LeafTable.AsEnumerable(); - public IEnumerable> StemNodes => StemTable.AsEnumerable(); - public IEnumerable> BranchNodes => BranchTable.AsEnumerable(); - public bool GetLeaf(byte[] key, out byte[]? value) => LeafTable.TryGetValue(key, out value); - public bool GetStem(byte[] key, out SuffixTree? value) => StemTable.TryGetValue(key, out value); - public bool GetBranch(byte[] key, out InternalNode? value) => BranchTable.TryGetValue(key, out value); - public void SetLeaf(byte[] leafKey, byte[]? leafValue) => LeafTable[leafKey] = leafValue; - public void SetStem(byte[] stemKey, SuffixTree? suffixTree) => StemTable[stemKey] = suffixTree; - public void SetBranch(byte[] branchKey, InternalNode? internalNodeValue) => BranchTable[branchKey] = internalNodeValue; - public void RemoveLeaf(byte[] leafKey) - { - LeafTable.Remove(leafKey); - } - public void RemoveStem(byte[] stemKey) - { - StemTable.Remove(stemKey); - } - public void RemoveBranch(byte[] branchKey) - { - BranchTable.Remove(branchKey); - } - - public void BatchLeafInsert(IEnumerable> keyLeaf) - { - foreach ((byte[] key, byte[]? value) in keyLeaf) - { - SetLeaf(key, value); - } - } - public void BatchStemInsert(IEnumerable> suffixLeaf) - { - foreach ((byte[] key, SuffixTree? value) in suffixLeaf) - { - SetStem(key, value); - } - } - public void BatchBranchInsert(IEnumerable> branchLeaf) - { - foreach ((byte[] key, InternalNode? value) in branchLeaf) - { - SetBranch(key, value); - } - } -} - - - -public class MemoryStateDbSerializer : IRlpStreamDecoder -{ - public static MemoryStateDbSerializer Instance => new MemoryStateDbSerializer(); - - public int GetLength(MemoryStateDb item, RlpBehaviors rlpBehaviors) - { - int length = 0; - length += Rlp.LengthOfSequence(LeafStoreSerializer.Instance.GetLength(item.LeafTable, RlpBehaviors.None)); - length += Rlp.LengthOfSequence(SuffixStoreSerializer.Instance.GetLength(item.StemTable, RlpBehaviors.None)); - length += Rlp.LengthOfSequence(BranchStoreSerializer.Instance.GetLength(item.BranchTable, RlpBehaviors.None)); - return length; - } - - public int GetLength(MemoryStateDb item, RlpBehaviors rlpBehaviors, out int contentLength) - { - contentLength = GetLength(item, rlpBehaviors); - return Rlp.LengthOfSequence(contentLength); - } - - public MemoryStateDb Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - return new MemoryStateDb( - LeafStoreSerializer.Instance.Decode(rlpStream), - SuffixStoreSerializer.Instance.Decode(rlpStream), - BranchStoreSerializer.Instance.Decode(rlpStream) - ); - } - public void Encode(RlpStream stream, MemoryStateDb item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - LeafStoreSerializer.Instance.Encode(stream, item.LeafTable); - SuffixStoreSerializer.Instance.Encode(stream, item.StemTable); - BranchStoreSerializer.Instance.Encode(stream, item.BranchTable); - } -} diff --git a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/MemoryStores.cs b/src/Nethermind/Nethermind.Verkle/VerkleStateDb/MemoryStores.cs deleted file mode 100644 index 7c59a59f2d2..00000000000 --- a/src/Nethermind/Nethermind.Verkle/VerkleStateDb/MemoryStores.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2022 Demerzel Solutions Limited -// Licensed under Apache-2.0. For full terms, see LICENSE in the project root. - -using Nethermind.Serialization.Rlp; -using Nethermind.Verkle.VerkleNodes; - -namespace Nethermind.Verkle.VerkleStateDb; -using BranchStore = Dictionary; -using LeafStore = Dictionary; -using SuffixStore = Dictionary; - - -public class LeafStoreSerializer : IRlpStreamDecoder -{ - public static LeafStoreSerializer Instance => new LeafStoreSerializer(); - public int GetLength(LeafStore item, RlpBehaviors rlpBehaviors) - { - int length = Rlp.LengthOf(item.Count); - foreach (KeyValuePair pair in item) - { - length += Rlp.LengthOf(pair.Key); - length += Rlp.LengthOf(pair.Value); - } - return length; - } - - public LeafStore Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - LeafStore item = new LeafStore(); - int length = rlpStream.DecodeInt(); - for (int i = 0; i < length; i++) - { - item[rlpStream.DecodeByteArray()] = rlpStream.DecodeByteArray(); - } - return item; - } - - public void Encode(RlpStream stream, LeafStore item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - stream.Encode(item.Count); - foreach (KeyValuePair pair in item) - { - stream.Encode(pair.Key); - stream.Encode(pair.Value); - } - } -} - -public class SuffixStoreSerializer : IRlpStreamDecoder> -{ - private static SuffixTreeSerializer SuffixTreeSerializer => SuffixTreeSerializer.Instance; - - public static SuffixStoreSerializer Instance => new SuffixStoreSerializer(); - - public int GetLength(SuffixStore item, RlpBehaviors rlpBehaviors) - { - int length = Rlp.LengthOf(item.Count); - foreach (KeyValuePair pair in item) - { - length += Rlp.LengthOf(pair.Key); - length += pair.Value == null ? Rlp.EmptyArrayByte : SuffixTreeSerializer.GetLength(pair.Value, RlpBehaviors.None); - } - return length; - } - - public SuffixStore Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - SuffixStore item = new SuffixStore(); - int length = rlpStream.DecodeInt(); - for (int i = 0; i < length; i++) - { - byte[] key = rlpStream.DecodeByteArray(); - if (rlpStream.PeekNextItem().Length == 0) - { - item[key] = null; - rlpStream.SkipItem(); - } - else - { - item[key] = SuffixTreeSerializer.Decode(rlpStream); - } - } - return item; - } - public void Encode(RlpStream stream, SuffixStore item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - stream.Encode(item.Count); - foreach (KeyValuePair pair in item) - { - stream.Encode(pair.Key); - if (pair.Value is null) stream.EncodeEmptyByteArray(); - else SuffixTreeSerializer.Encode(stream, pair.Value); - } - } -} - - -public class BranchStoreSerializer : IRlpStreamDecoder -{ - private static InternalNodeSerializer InternalNodeSerializer => InternalNodeSerializer.Instance; - - public static BranchStoreSerializer Instance => new BranchStoreSerializer(); - public int GetLength(BranchStore item, RlpBehaviors rlpBehaviors) - { - int length = Rlp.LengthOf(item.Count); - foreach (KeyValuePair pair in item) - { - length += Rlp.LengthOf(pair.Key); - length += pair.Value == null ? Rlp.EmptyArrayByte : InternalNodeSerializer.GetLength(pair.Value, RlpBehaviors.None); - } - return length; - } - - public BranchStore Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - BranchStore item = new BranchStore(); - int length = rlpStream.DecodeInt(); - for (int i = 0; i < length; i++) - { - byte[] key = rlpStream.DecodeByteArray(); - if (rlpStream.PeekNextItem().Length == 0) - { - item[key] = null; - rlpStream.SkipItem(); - } - else - { - item[key] = InternalNodeSerializer.Decode(rlpStream); - } - } - return item; - } - public void Encode(RlpStream stream, BranchStore item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - stream.Encode(item.Count); - foreach (KeyValuePair pair in item) - { - stream.Encode(pair.Key); - if (pair.Value is null) stream.EncodeEmptyByteArray(); - else InternalNodeSerializer.Encode(stream, pair.Value); - } - } -} diff --git a/src/Nethermind/Nethermind.sln b/src/Nethermind/Nethermind.sln index cdce31d6196..40acfbfdcd0 100644 --- a/src/Nethermind/Nethermind.sln +++ b/src/Nethermind/Nethermind.sln @@ -231,7 +231,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UPnP", "UPnP", "{2EDE2554-5 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nethermind.UPnP.Plugin", "Nethermind.UPnP.Plugin\Nethermind.UPnP.Plugin.csproj", "{48E50409-26FE-4FD8-AF6E-2A0E79F794CE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Verkle", "Nethermind.Verkle\Nethermind.Verkle.csproj", "{EC7B137C-3265-467C-86C2-76C82B55D41C}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Verkle.Tree", "Nethermind.Verkle.Tree\Nethermind.Verkle.Tree.csproj", "{EC7B137C-3265-467C-86C2-76C82B55D41C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nethermind.Verkle.Test", "Nethermind.Verkle.Test\Nethermind.Verkle.Test.csproj", "{0CF32B00-73D8-462E-96F0-7460BC132A88}" EndProject