diff --git a/src/Nethermind/Chains/beverly-hills.json b/src/Nethermind/Chains/beverly-hills.json
new file mode 100644
index 00000000000..f5e45ac53b2
--- /dev/null
+++ b/src/Nethermind/Chains/beverly-hills.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://906aaa403764b718fb6d23a80ad890eddfe6d33922eba7b9bc45e160e1079becd8f5f478f36607c7082d0e1015d43aec73ca35423e97ec69e5f55f0cfcd4f29f@188.166.72.218:3030",
+ "enode://99561977db2c6c24d6af793fb7c81ed16eccf37548c34590f4f973bbebe6b7ad297c8fbb1f7c7e12224a7e3f29ed5bd4c5a0d0a0d937a54eabee65173127ab50@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/kaustinen.json b/src/Nethermind/Chains/kaustinen.json
new file mode 100644
index 00000000000..7bfae6fd459
--- /dev/null
+++ b/src/Nethermind/Chains/kaustinen.json
@@ -0,0 +1,103 @@
+{
+ "name": "Kaustinen",
+ "dataDir": "kaustinen",
+ "engine": {
+ "Ethash": {
+ }
+ },
+ "params": {
+ "gasLimitBoundDivisor": "0x0400",
+ "accountStartNonce": "0x0",
+ "networkID" : "0x10F2C",
+ "eip140Transition": "0x0",
+ "eip145Transition": "0x0",
+ "eip150Transition": "0x0",
+ "eip150Hash": "0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0",
+ "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": "1679652600",
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "gasLimit": "0x2fefd8"
+ },
+ "nodes": [
+ "enode://4b669a76a6bb82d6074bc0296a792375fe257091885911051fb3b3f5fcaec051892d9c4baf937f6e28f0cf975d47cf2303f96e43b46e4963361fe6baecc86e6a@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/Directory.Packages.props b/src/Nethermind/Directory.Packages.props
index 74d9c5dc1a6..54eec518024 100644
--- a/src/Nethermind/Directory.Packages.props
+++ b/src/Nethermind/Directory.Packages.props
@@ -47,6 +47,7 @@
+
@@ -80,4 +81,4 @@
-
\ No newline at end of file
+
diff --git a/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationTracer.cs b/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationTracer.cs
index 927ac980204..33fa9b64bff 100644
--- a/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationTracer.cs
+++ b/src/Nethermind/Nethermind.AccountAbstraction/Executor/UserOperationTracer.cs
@@ -64,6 +64,7 @@ public UserOperationTxTracer(
public byte[] Output { get; private set; }
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => true;
public bool IsTracingOpLevelStorage => true;
public bool IsTracingMemory => false;
@@ -185,6 +186,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
}
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotImplementedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
}
diff --git a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs
index 10612330c41..45f16df8bde 100644
--- a/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs
+++ b/src/Nethermind/Nethermind.Api/IApiWithBlockchain.cs
@@ -22,6 +22,7 @@
using Nethermind.State;
using Nethermind.Trie.Pruning;
using Nethermind.TxPool;
+using Nethermind.Verkle.Tree;
namespace Nethermind.Api
{
@@ -43,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; }
///
diff --git a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs
index 9854452bfac..49ee5de548c 100644
--- a/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs
+++ b/src/Nethermind/Nethermind.Api/IApiWithNetwork.cs
@@ -18,6 +18,7 @@
using Nethermind.Sockets;
using Nethermind.Synchronization.Blocks;
using Nethermind.Synchronization.SnapSync;
+using Nethermind.Synchronization.VerkleSync;
namespace Nethermind.Api
{
@@ -52,5 +53,6 @@ public interface IApiWithNetwork : IApiWithBlockchain
IWebSocketsManager WebSocketsManager { get; set; }
ISubscriptionFactory? SubscriptionFactory { get; set; }
ISnapProvider? SnapProvider { get; set; }
+ IVerkleSyncProvider? VerkleProvider { get; set; }
}
}
diff --git a/src/Nethermind/Nethermind.Api/NethermindApi.cs b/src/Nethermind/Nethermind.Api/NethermindApi.cs
index fe323844e39..5a10aff2ca6 100644
--- a/src/Nethermind/Nethermind.Api/NethermindApi.cs
+++ b/src/Nethermind/Nethermind.Api/NethermindApi.cs
@@ -55,6 +55,9 @@
using Nethermind.Sockets;
using Nethermind.Synchronization.SnapSync;
using Nethermind.Synchronization.Blocks;
+using Nethermind.Synchronization.VerkleSync;
+using Nethermind.Verkle;
+using Nethermind.Verkle.Tree;
namespace Nethermind.Api
{
@@ -77,13 +80,15 @@ public IBlockchainBridge CreateBlockchainBridge()
ReadOnlyBlockTree readOnlyTree = BlockTree!.AsReadOnly();
LazyInitializer.EnsureInitialized(ref _readOnlyDbProvider, () => new ReadOnlyDbProvider(DbProvider, false));
- // TODO: reuse the same trie cache here
- ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = new(
- _readOnlyDbProvider,
- ReadOnlyTrieStore,
- readOnlyTree,
- SpecProvider,
- LogManager);
+ ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv = SpecProvider!.GenesisSpec.IsVerkleTreeEipEnabled switch
+ {
+ true =>
+ // TODO: reuse the same trie cache here
+ new ReadOnlyTxProcessingEnv(_readOnlyDbProvider, ReadOnlyVerkleTrieStore, readOnlyTree, SpecProvider, LogManager),
+ false =>
+ // TODO: reuse the same trie cache here
+ new ReadOnlyTxProcessingEnv(_readOnlyDbProvider, ReadOnlyTrieStore, readOnlyTree, SpecProvider, LogManager)
+ };
IMiningConfig miningConfig = ConfigProvider.GetConfig();
IBlocksConfig blocksConfig = ConfigProvider.GetConfig();
@@ -134,6 +139,9 @@ 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; }
public IKeyStore? KeyStore { get; set; }
@@ -231,6 +239,7 @@ public ISealEngine SealEngine
public IList Publishers { get; } = new List(); // this should be called publishers
public CompositePruningTrigger PruningTrigger { get; } = new();
public ISnapProvider? SnapProvider { get; set; }
+ public IVerkleSyncProvider? VerkleProvider { get; set; }
public IProcessExitSource? ProcessExit { get; set; }
}
}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs
index c8de8362917..d768668623b 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/DevBlockproducerTests.cs
@@ -12,17 +12,22 @@
using Nethermind.Consensus.Validators;
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
using Nethermind.Core.Test.Builders;
using Nethermind.Db;
using Nethermind.Db.Blooms;
using Nethermind.Evm;
using Nethermind.Evm.TransactionProcessing;
+using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Specs;
+using Nethermind.Specs.Forks;
using Nethermind.State;
using Nethermind.State.Repositories;
using Nethermind.Trie.Pruning;
+using Nethermind.Verkle.Tree;
using NUnit.Framework;
namespace Nethermind.Blockchain.Test.Producers
@@ -112,5 +117,261 @@ public void Test()
autoResetEvent.WaitOne(1000).Should().BeTrue("1");
blockTree.Head.Number.Should().Be(1);
}
+
+ [Test, Timeout(Timeout.MaxTestTime)]
+ 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.InternalNodes, 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,
+ SimpleConsoleLogManager.Instance);
+ VerkleStateTree stateTree = new (dbProvider, SimpleConsoleLogManager.Instance);
+ VerkleStateReader stateReader = new(stateTree, dbProvider.GetDb(DbNames.Code), SimpleConsoleLogManager.Instance);
+ VerkleWorldState worldState = new (stateTree, dbProvider.RegisteredDbs[DbNames.Code], SimpleConsoleLogManager.Instance);
+ BlockhashProvider blockHashProvider = new(blockTree, SimpleConsoleLogManager.Instance);
+ VirtualMachine virtualMachine = new(
+ blockHashProvider,
+ specProvider,
+ SimpleConsoleLogManager.Instance);
+ TransactionProcessor txProcessor = new(
+ specProvider,
+ worldState,
+ virtualMachine,
+ SimpleConsoleLogManager.Instance);
+ BlockProcessor blockProcessor = new(
+ specProvider,
+ Always.Valid,
+ NoBlockRewards.Instance,
+ new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, worldState),
+ worldState,
+ NullReceiptStorage.Instance,
+ NullWitnessCollector.Instance,
+ SimpleConsoleLogManager.Instance);
+ BlockchainProcessor blockchainProcessor = new(
+ blockTree,
+ blockProcessor,
+ NullRecoveryStep.Instance,
+ stateReader,
+ SimpleConsoleLogManager.Instance,
+ BlockchainProcessor.Options.Default);
+ BuildBlocksWhenRequested trigger = new();
+ ManualTimestamper timestamper = new ManualTimestamper();
+ DevBlockProducer devBlockProducer = new(
+ EmptyTxSource.Instance,
+ blockchainProcessor,
+ worldState,
+ blockTree,
+ trigger,
+ timestamper,
+ specProvider,
+ new BlocksConfig(),
+ SimpleConsoleLogManager.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.WithStateRoot(Keccak.Zero).TestObject);
+
+ autoResetEvent.WaitOne(1000).Should().BeTrue("genesis");
+
+ trigger.BuildBlock();
+ autoResetEvent.WaitOne(1000).Should().BeTrue("1");
+ blockTree.Head.Number.Should().Be(1);
+ }
+
+ [Test, Timeout(Timeout.MaxTestTime)]
+ public void TestVerkleBlocksWithExecutionWitness()
+ {
+ ISpecProvider specProvider = new TestSpecProvider(Prague.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.InternalNodes, 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,
+ SimpleConsoleLogManager.Instance);
+ VerkleStateTree stateTree = new (dbProvider, SimpleConsoleLogManager.Instance);
+ VerkleStateReader stateReader = new(stateTree, dbProvider.GetDb(DbNames.Code), SimpleConsoleLogManager.Instance);
+ VerkleWorldState worldState = new (stateTree, dbProvider.RegisteredDbs[DbNames.Code], SimpleConsoleLogManager.Instance);
+
+ worldState.CreateAccount(TestItem.AddressA, 1000.Ether());
+ worldState.CreateAccount(TestItem.AddressB, 1000.Ether());
+ worldState.CreateAccount(TestItem.AddressC, 1000.Ether());
+
+ byte[] code = Bytes.FromHexString("0xabcd");
+ worldState.InsertCode(TestItem.AddressA, code, specProvider.GenesisSpec);
+
+ worldState.Set(new StorageCell(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef"));
+
+ worldState.Commit(specProvider.GenesisSpec);
+ worldState.CommitTree(0);
+
+ BlockhashProvider blockHashProvider = new(blockTree, SimpleConsoleLogManager.Instance);
+ VirtualMachine virtualMachine = new(
+ blockHashProvider,
+ specProvider,
+ SimpleConsoleLogManager.Instance);
+ TransactionProcessor txProcessor = new(
+ specProvider,
+ worldState,
+ virtualMachine,
+ SimpleConsoleLogManager.Instance);
+ BlockProcessor blockProcessor = new(
+ specProvider,
+ Always.Valid,
+ NoBlockRewards.Instance,
+ new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, worldState),
+ worldState,
+ NullReceiptStorage.Instance,
+ NullWitnessCollector.Instance,
+ SimpleConsoleLogManager.Instance);
+ BlockchainProcessor blockchainProcessor = new(
+ blockTree,
+ blockProcessor,
+ NullRecoveryStep.Instance,
+ stateReader,
+ SimpleConsoleLogManager.Instance,
+ BlockchainProcessor.Options.Default);
+ BuildBlocksWhenRequested trigger = new();
+ ManualTimestamper timestamper = new ManualTimestamper();
+ DevBlockProducer devBlockProducer = new(
+ EmptyTxSource.Instance,
+ blockchainProcessor,
+ worldState,
+ blockTree,
+ trigger,
+ timestamper,
+ specProvider,
+ new BlocksConfig(),
+ SimpleConsoleLogManager.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.WithStateRoot(worldState.StateRoot).TestObject);
+
+ autoResetEvent.WaitOne(1000).Should().BeTrue("genesis");
+
+ trigger.BuildBlock();
+ autoResetEvent.WaitOne(1000).Should().BeTrue("1");
+ blockTree.Head.Number.Should().Be(1);
+ }
+
+ [Test, Timeout(Timeout.MaxTestTime)]
+ public void TestVerkleBlocksWithExecutionWitnessAndStatelessValidation()
+ {
+ ISpecProvider specProvider = new TestSpecProvider(Prague.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.InternalNodes, 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,
+ SimpleConsoleLogManager.Instance);
+ VerkleStateTree stateTree = new (dbProvider, SimpleConsoleLogManager.Instance);
+ VerkleStateReader stateReader = new(stateTree, dbProvider.GetDb(DbNames.Code), SimpleConsoleLogManager.Instance);
+ VerkleWorldState worldState = new (stateTree, dbProvider.RegisteredDbs[DbNames.Code], SimpleConsoleLogManager.Instance);
+ BlockhashProvider blockHashProvider = new(blockTree, SimpleConsoleLogManager.Instance);
+ VirtualMachine virtualMachine = new(
+ blockHashProvider,
+ specProvider,
+ SimpleConsoleLogManager.Instance);
+ TransactionProcessor txProcessor = new(
+ specProvider,
+ worldState,
+ virtualMachine,
+ SimpleConsoleLogManager.Instance);
+ BlockProcessor blockProcessor = new(
+ specProvider,
+ Always.Valid,
+ NoBlockRewards.Instance,
+ new BlockProcessor.BlockValidationTransactionsExecutor(txProcessor, worldState),
+ worldState,
+ NullReceiptStorage.Instance,
+ NullWitnessCollector.Instance,
+ SimpleConsoleLogManager.Instance);
+ BlockchainProcessor blockchainProcessor = new(
+ blockTree,
+ blockProcessor,
+ NullRecoveryStep.Instance,
+ stateReader,
+ SimpleConsoleLogManager.Instance,
+ BlockchainProcessor.Options.Default);
+ BuildBlocksWhenRequested trigger = new();
+ ManualTimestamper timestamper = new ManualTimestamper();
+ DevBlockProducer devBlockProducer = new(
+ EmptyTxSource.Instance,
+ blockchainProcessor,
+ worldState,
+ blockTree,
+ trigger,
+ timestamper,
+ specProvider,
+ new BlocksConfig(),
+ SimpleConsoleLogManager.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.WithStateRoot(Keccak.Zero).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/Producers/VerkleBlockProducerTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/Producers/VerkleBlockProducerTests.cs
new file mode 100644
index 00000000000..a5958f47842
--- /dev/null
+++ b/src/Nethermind/Nethermind.Blockchain.Test/Producers/VerkleBlockProducerTests.cs
@@ -0,0 +1,19 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Threading.Tasks;
+using Nethermind.Core.Test.Blockchain;
+using NUnit.Framework;
+
+namespace Nethermind.Blockchain.Test.Producers;
+
+public class VerkleBlockProducerTests
+{
+ [Test]
+ public async Task TestBlockProductionWithWitness()
+ {
+ TestVerkleBlockchain chain = await TestVerkleBlockchain.Create();
+ await chain.BuildSomeBlocksWithDeployment(5);
+ await chain.BuildSomeBlocks(100);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs b/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs
index 65c6d055cca..a9ef7a85c7c 100644
--- a/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs
+++ b/src/Nethermind/Nethermind.Blockchain.Test/TransactionsExecutorTests.cs
@@ -326,7 +326,7 @@ void SetAccountStates(IEnumerable missingAddresses)
SetAccountStates(testCase.MissingAddresses);
- BlockReceiptsTracer receiptsTracer = new();
+ BlockReceiptsTracer receiptsTracer = new(true, false);
receiptsTracer.StartNewBlockTrace(blockToProduce);
txExecutor.ProcessTransactions(blockToProduce, ProcessingOptions.ProducingBlock, receiptsTracer, spec);
diff --git a/src/Nethermind/Nethermind.Blockchain/BlockTreeMethodOptions.cs b/src/Nethermind/Nethermind.Blockchain/BlockTreeMethodOptions.cs
index 2eaab2ba9be..7e1b288a20f 100644
--- a/src/Nethermind/Nethermind.Blockchain/BlockTreeMethodOptions.cs
+++ b/src/Nethermind/Nethermind.Blockchain/BlockTreeMethodOptions.cs
@@ -69,6 +69,11 @@ public enum BlockTreeSuggestOptions
/// Force not to set as main block
///
ForceDontSetAsMain = 8,
+
+ ///
+ /// If block should be processed in a stateless manner
+ ///
+ ShouldProcessStateless = 16,
}
public static class BlockTreeSuggestOptionsExtensions
diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs
index 0a763dd2f73..042235c462f 100644
--- a/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/ISyncConfig.cs
@@ -103,5 +103,11 @@ public interface ISyncConfig : IConfig
[ConfigItem(Description = "[EXPERIMENTAL] Optimize db for write during sync. Significantly reduce total writes written and some sync time if you are not network limited.", DefaultValue = "Default")]
public ITunableDb.TuneType TuneDbMode { get; set; }
+
+ [ConfigItem(Description = "[EXPERIMENTAL] Enables Verkle Sync protocol.", DefaultValue = "false")]
+ public bool VerkleSync { get; set; }
+
+ [ConfigItem(Description = "Number of account range partition to create. Increase verkle sync request concurrency. Value must be between 1 to 256 (inclusive).", DefaultValue = "8")]
+ int VerkleSyncAccountRangePartitionCount { get; set; }
}
}
diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/IVerkleSyncPeer.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/IVerkleSyncPeer.cs
new file mode 100644
index 00000000000..58d6f3781bd
--- /dev/null
+++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/IVerkleSyncPeer.cs
@@ -0,0 +1,15 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Verkle.Tree.Sync;
+
+namespace Nethermind.Blockchain.Synchronization;
+
+public interface IVerkleSyncPeer
+{
+ Task GetSubTreeRange(SubTreeRange range, CancellationToken token);
+ Task GetLeafNodes(GetLeafNodesRequest request, CancellationToken token);
+ Task GetLeafNodes(LeafToRefreshRequest request, CancellationToken token);
+}
diff --git a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs
index d99576e4861..62dcbe1b4dc 100644
--- a/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs
+++ b/src/Nethermind/Nethermind.Blockchain/Synchronization/SyncConfig.cs
@@ -61,6 +61,9 @@ public string? PivotHash
public bool NonValidatorNode { get; set; } = false;
public ITunableDb.TuneType TuneDbMode { get; set; } = ITunableDb.TuneType.Default;
+ public bool VerkleSync { get; set; } = false;
+ public int VerkleSyncAccountRangePartitionCount { get; set; } = 8;
+
public override string ToString()
{
return
diff --git a/src/Nethermind/Nethermind.Blockchain/TrieStoreBoundaryWatcher.cs b/src/Nethermind/Nethermind.Blockchain/TrieStoreBoundaryWatcher.cs
index 8aebd45a381..1a687e5de8a 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;
@@ -27,7 +27,7 @@ public TrieStoreBoundaryWatcher(ITrieStore trieStore, IBlockTree blockTree, ILog
private void OnReorgBoundaryReached(object? sender, ReorgBoundaryReached e)
{
- if (_logger.IsDebug) _logger.Debug($"Saving reorg boundary {e.BlockNumber}");
+ _logger.Info($"Saving reorg boundary {e.BlockNumber}");
_blockTree.BestPersistedState = e.BlockNumber;
}
diff --git a/src/Nethermind/Nethermind.Config/BlocksConfig.cs b/src/Nethermind/Nethermind.Config/BlocksConfig.cs
index 1462905a388..fa6fa8aa490 100644
--- a/src/Nethermind/Nethermind.Config/BlocksConfig.cs
+++ b/src/Nethermind/Nethermind.Config/BlocksConfig.cs
@@ -21,6 +21,7 @@ public class BlocksConfig : IBlocksConfig
public bool RandomizedBlocks { get; set; }
public ulong SecondsPerSlot { get; set; } = 12;
+ public bool StatelessProcessing { get; set; } = false;
public string ExtraData
diff --git a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs
index 554c0286121..c7acd5c4267 100644
--- a/src/Nethermind/Nethermind.Config/IBlocksConfig.cs
+++ b/src/Nethermind/Nethermind.Config/IBlocksConfig.cs
@@ -35,6 +35,9 @@ public interface IBlocksConfig : IConfig
[ConfigItem(Description = "Seconds per slot.", DefaultValue = "12")]
ulong SecondsPerSlot { get; set; }
+ [ConfigItem(Description = "Should process block stateless if possible.", DefaultValue = "false")]
+ bool StatelessProcessing { get; set; }
+
byte[] GetExtraDataBytes();
}
}
diff --git a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs
index 52dc575fab0..52c1d90705f 100644
--- a/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus.AuRa/AuRaBlockProcessor.cs
@@ -25,7 +25,6 @@ namespace Nethermind.Consensus.AuRa
{
public class AuRaBlockProcessor : BlockProcessor
{
- private readonly ISpecProvider _specProvider;
private readonly IBlockTree _blockTree;
private readonly AuRaContractGasLimitOverride? _gasLimitOverride;
private readonly ContractRewriter? _contractRewriter;
@@ -57,7 +56,6 @@ public AuRaBlockProcessor(
logManager,
withdrawalProcessor)
{
- _specProvider = specProvider;
_blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
_logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
_txFilter = txFilter ?? NullTxFilter.Instance;
diff --git a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs
index 4db8a7d0aa6..8c44e529e3f 100644
--- a/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs
+++ b/src/Nethermind/Nethermind.Consensus.Ethash/NethDevPlugin.cs
@@ -66,12 +66,9 @@ public Task InitBlockProducer(IBlockProductionTrigger? blockProd
if (logger.IsInfo) logger.Info("Starting Neth Dev block producer & sealer");
- ReadOnlyTxProcessingEnv producerEnv = new(
- readOnlyDbProvider,
- getFromApi.ReadOnlyTrieStore,
- readOnlyBlockTree,
- getFromApi.SpecProvider,
- getFromApi.LogManager);
+ ReadOnlyTxProcessingEnv producerEnv = _nethermindApi.SpecProvider!.GenesisSpec.IsVerkleTreeEipEnabled
+ ? new ReadOnlyTxProcessingEnv(readOnlyDbProvider, getFromApi.ReadOnlyVerkleTrieStore, readOnlyBlockTree, getFromApi.SpecProvider, getFromApi.LogManager)
+ : new ReadOnlyTxProcessingEnv(readOnlyDbProvider, getFromApi.ReadOnlyTrieStore, readOnlyBlockTree, getFromApi.SpecProvider, getFromApi.LogManager);
BlockProcessor producerProcessor = new(
getFromApi!.SpecProvider,
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs
index e9d9643a978..d5f295ba49c 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockExtensions.cs
@@ -12,8 +12,8 @@ internal static class BlockExtensions
{
public static Block CreateCopy(this Block block, BlockHeader header) =>
block is BlockToProduce blockToProduce
- ? new BlockToProduce(header, blockToProduce.Transactions, blockToProduce.Uncles, blockToProduce.Withdrawals)
- : new Block(header, block.Transactions, block.Uncles, block.Withdrawals);
+ ? new BlockToProduce(header, blockToProduce.Transactions, blockToProduce.Uncles, blockToProduce.Withdrawals, blockToProduce.ExecutionWitness)
+ : new Block(header, block.Transactions, block.Uncles, block.Withdrawals, block.ExecutionWitness);
public static IEnumerable GetTransactions(this Block block) =>
block is BlockToProduce blockToProduce
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs
index 05b11f9d7b7..abca0c79bc8 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockProductionTransactionsExecutor.cs
@@ -23,6 +23,7 @@ public class BlockProductionTransactionsExecutor : IBlockProductionTransactionsE
private readonly IWorldState _stateProvider;
private readonly BlockProductionTransactionPicker _blockProductionTransactionPicker;
private readonly ILogger _logger;
+ private readonly ILogManager _logManager;
public BlockProductionTransactionsExecutor(
ReadOnlyTxProcessingEnv readOnlyTxProcessingEnv,
@@ -46,6 +47,20 @@ public BlockProductionTransactionsExecutor(
_stateProvider = stateProvider;
_blockProductionTransactionPicker = new BlockProductionTransactionPicker(specProvider);
_logger = logManager.GetClassLogger();
+ _logManager = logManager;
+ }
+
+ private BlockProductionTransactionsExecutor(
+ ITransactionProcessorAdapter transactionProcessor,
+ IWorldState stateProvider,
+ BlockProductionTransactionPicker blockProductionTransactionPicker,
+ ILogManager logManager)
+ {
+ _transactionProcessor = transactionProcessor;
+ _stateProvider = stateProvider;
+ _blockProductionTransactionPicker = blockProductionTransactionPicker;
+ _logger = logManager.GetClassLogger();
+ _logManager = logManager;
}
protected EventHandler? _transactionProcessed;
@@ -55,6 +70,12 @@ event EventHandler? IBlockProcessor.IBlockTransactionsExec
remove => _transactionProcessed -= value;
}
+ public IBlockProcessor.IBlockTransactionsExecutor WithNewStateProvider(IWorldState worldState)
+ {
+ return new BlockProductionTransactionsExecutor(_transactionProcessor, worldState,
+ _blockProductionTransactionPicker, _logManager);
+ }
+
event EventHandler? IBlockProductionTransactionsExecutor.AddingTransaction
{
add => _blockProductionTransactionPicker.AddingTransaction += value;
@@ -64,7 +85,8 @@ event EventHandler? IBlockProductionTransactionsExecutor.Addi
public virtual TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec)
{
IEnumerable transactions = GetTransactions(block);
-
+ var logg = SimpleConsoleLogger.Instance;
+ logg.Info($"---------------------full this is old-----------------{_stateProvider.StateRoot}");
int i = 0;
LinkedHashSet transactionsInBlock = new(ByHashTxComparer.Instance);
foreach (Transaction currentTx in transactions)
@@ -74,6 +96,7 @@ public virtual TxReceipt[] ProcessTransactions(Block block, ProcessingOptions pr
}
_stateProvider.Commit(spec, receiptsTracer);
+ logg.Info($"---------------------full this is new-----------------{_stateProvider.StateRoot}");
SetTransactions(block, transactionsInBlock);
return receiptsTracer.TxReceipts.ToArray();
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockStatelessValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockStatelessValidationTransactionsExecutor.cs
new file mode 100644
index 00000000000..678f9097ae8
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockStatelessValidationTransactionsExecutor.cs
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Linq;
+using Nethermind.Core;
+using Nethermind.Core.Specs;
+using Nethermind.Crypto;
+using Nethermind.Evm.Tracing;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.Logging;
+using Nethermind.State;
+
+namespace Nethermind.Consensus.Processing;
+
+public partial class BlockProcessor
+{
+ public class BlockStatelessValidationTransactionsExecutor : IBlockProcessor.IBlockTransactionsExecutor
+ {
+ private ITransactionProcessorAdapter _transactionProcessor;
+ private IWorldState? _stateProvider;
+
+ public BlockStatelessValidationTransactionsExecutor(ITransactionProcessor transactionProcessor)
+ : this(new ExecuteTransactionProcessorAdapter(transactionProcessor))
+ {
+ }
+
+ public BlockStatelessValidationTransactionsExecutor(ITransactionProcessorAdapter transactionProcessor)
+ {
+ _transactionProcessor = transactionProcessor;
+ _stateProvider = null;
+ }
+
+ public BlockStatelessValidationTransactionsExecutor(ITransactionProcessor transactionProcessor, IWorldState worldState)
+ : this(new ExecuteTransactionProcessorAdapter(transactionProcessor), worldState)
+ {
+ }
+
+ public BlockStatelessValidationTransactionsExecutor(ITransactionProcessorAdapter transactionProcessor, IWorldState worldState)
+ {
+ _transactionProcessor = transactionProcessor;
+ _stateProvider = worldState;
+ }
+
+ public event EventHandler? TransactionProcessed;
+
+ public IBlockProcessor.IBlockTransactionsExecutor WithNewStateProvider(IWorldState worldState)
+ {
+ _transactionProcessor = _transactionProcessor.WithNewStateProvider(worldState);
+ return new BlockStatelessValidationTransactionsExecutor(_transactionProcessor, worldState);
+ }
+
+ public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec)
+ {
+ // var ecdsa = new EthereumEcdsa(69420, LimboLogs.Instance);
+ if (!block.IsGenesis)
+ {
+ var logg = SimpleConsoleLogger.Instance;
+ logg.Info($"---------------------this is old-----------------{_stateProvider.StateRoot}");
+ for (int i = 0; i < block.Transactions.Length; i++)
+ {
+ Transaction currentTx = block.Transactions[i];
+ // currentTx.SenderAddress = ecdsa.RecoverAddress(currentTx);
+ ProcessTransaction(block, currentTx, i, receiptsTracer, _stateProvider, processingOptions);
+ }
+ _stateProvider.Commit(spec);
+ _stateProvider.RecalculateStateRoot();
+ logg.Info($"---------------------this is new-----------------{_stateProvider.StateRoot}");
+ }
+ return receiptsTracer.TxReceipts.ToArray();
+ }
+
+ private void ProcessTransaction(Block block, Transaction currentTx, int index, BlockReceiptsTracer receiptsTracer, IWorldState worldState, ProcessingOptions processingOptions)
+ {
+ _transactionProcessor.ProcessTransaction(block, currentTx, receiptsTracer, processingOptions, worldState);
+ TransactionProcessed?.Invoke(this, new TxProcessedEventArgs(index, currentTx, receiptsTracer.TxReceipts[index]));
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
index 4489c88109d..631187a755f 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.BlockValidationTransactionsExecutor.cs
@@ -30,6 +30,10 @@ public BlockValidationTransactionsExecutor(ITransactionProcessorAdapter transact
}
public event EventHandler? TransactionProcessed;
+ public IBlockProcessor.IBlockTransactionsExecutor WithNewStateProvider(IWorldState worldState)
+ {
+ return new BlockValidationTransactionsExecutor(_transactionProcessor, worldState);
+ }
public TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec)
{
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
index dfdecd8f4d0..160dceecb80 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockProcessor.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Numerics;
using Nethermind.Blockchain;
using Nethermind.Blockchain.Receipts;
@@ -11,27 +12,37 @@
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core;
using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
+using Nethermind.Core.Verkle;
using Nethermind.Crypto;
using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
+using Nethermind.Serialization.Json;
using Nethermind.Specs.Forks;
using Nethermind.State;
+using Nethermind.Verkle.Curve;
namespace Nethermind.Consensus.Processing;
public partial class BlockProcessor : IBlockProcessor
{
private readonly ILogger _logger;
- private readonly ISpecProvider _specProvider;
+ protected readonly ISpecProvider _specProvider;
protected readonly IWorldState _stateProvider;
private readonly IReceiptStorage _receiptStorage;
private readonly IWitnessCollector _witnessCollector;
- private readonly IWithdrawalProcessor _withdrawalProcessor;
+ protected readonly IWithdrawalProcessor _withdrawalProcessor;
private readonly IBlockValidator _blockValidator;
private readonly IRewardCalculator _rewardCalculator;
- private readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor;
+ protected readonly IBlockProcessor.IBlockTransactionsExecutor _blockTransactionsExecutor;
+
+ // TODO: will be removed in future
+ public IBlockProcessor.IBlockTransactionsExecutor StatelessBlockTransactionsExecutor;
+ public bool ShouldVerifyIncomingWitness { get; set; } = false;
+ public bool ShouldDoStatelessStuff { get; set; } = false;
+ public bool ShouldGenerateWitness { get; set; } = false;
private const int MaxUncommittedBlocks = 64;
@@ -39,7 +50,7 @@ public partial class BlockProcessor : IBlockProcessor
/// We use a single receipt tracer for all blocks. Internally receipt tracer forwards most of the calls
/// to any block-specific tracers.
///
- private readonly BlockReceiptsTracer _receiptsTracer;
+ protected readonly BlockReceiptsTracer _receiptsTracer;
public BlockProcessor(
ISpecProvider? specProvider,
@@ -63,7 +74,7 @@ public BlockProcessor(
_blockTransactionsExecutor = blockTransactionsExecutor ?? throw new ArgumentNullException(nameof(blockTransactionsExecutor));
- _receiptsTracer = new BlockReceiptsTracer();
+ _receiptsTracer = new BlockReceiptsTracer(true, true);
}
public event EventHandler BlockProcessed;
@@ -144,7 +155,7 @@ the previous head state.*/
public event EventHandler? BlocksProcessing;
// TODO: move to branch processor
- private void InitBranch(Keccak branchStateRoot, bool incrementReorgMetric = true)
+ protected virtual void InitBranch(Keccak branchStateRoot, bool incrementReorgMetric = true)
{
/* Please note that we do not reset the state if branch state root is null.
That said, I do not remember in what cases we receive null here.*/
@@ -188,6 +199,7 @@ private void RestoreBranch(Keccak branchingPointStateRoot)
{
if (_logger.IsTrace) _logger.Trace($"Processing block {suggestedBlock.ToString(Block.Format.Short)} ({options})");
+ // here we assume (and its a good assumption) that DAO is before stateless execution starts
ApplyDaoTransition(suggestedBlock);
Block block = PrepareBlockForProcessing(suggestedBlock);
TxReceipt[] receipts = ProcessBlock(block, blockTracer, options);
@@ -211,6 +223,29 @@ private void ValidateProcessedBlock(Block suggestedBlock, ProcessingOptions opti
}
}
+ // TODO: remove
+ private (IBlockProcessor.IBlockTransactionsExecutor, IWorldState) GetOrCreateExecutorAndState(Block block, ExecutionWitness witness)
+ {
+ IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor;
+ IWorldState worldState;
+ if (block.IsGenesis)
+ {
+ blockTransactionsExecutor = StatelessBlockTransactionsExecutor;
+ worldState = _stateProvider;
+
+ }
+ else
+ {
+ block.Header.MaybeParent!.TryGetTarget(out BlockHeader maybeParent);
+ Banderwagon stateRoot = Banderwagon.FromBytes(maybeParent!.StateRoot!.Bytes)!.Value;
+ worldState = new VerkleWorldState(witness, stateRoot, LimboLogs.Instance);
+ blockTransactionsExecutor = StatelessBlockTransactionsExecutor.WithNewStateProvider(worldState);
+ }
+
+ return (blockTransactionsExecutor, worldState);
+ }
+ // TODO: remove
+
// TODO: block processor pipeline
protected virtual TxReceipt[] ProcessBlock(
Block block,
@@ -219,6 +254,24 @@ protected virtual TxReceipt[] ProcessBlock(
{
IReleaseSpec spec = _specProvider.GetSpec(block.Header);
+ if (ShouldVerifyIncomingWitness)
+ {
+ if (!block.IsGenesis)
+ {
+ block.Header.MaybeParent!.TryGetTarget(out BlockHeader maybeParent);
+ Banderwagon stateRoot = Banderwagon.FromBytes(maybeParent!.StateRoot!.Bytes)!.Value;
+ try
+ {
+ VerkleWorldState? incomingWorldState = new (block.ExecutionWitness, stateRoot, LimboLogs.Instance);
+ _logger.Info($"Incoming Witness - VerkleWorldState StateRoot:{incomingWorldState.StateRoot}");
+ }
+ catch (Exception e)
+ {
+ _logger.Error("Verkle proof verification failed for incoming witness.", e);
+ }
+ }
+ }
+
_receiptsTracer.SetOtherTracer(blockTracer);
_receiptsTracer.StartNewBlockTrace(block);
TxReceipt[] receipts = _blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec);
@@ -228,12 +281,48 @@ protected virtual TxReceipt[] ProcessBlock(
_withdrawalProcessor.ProcessWithdrawals(block, spec);
_receiptsTracer.EndBlockTrace();
+ ExecutionWitness? witness = null;
+ if (ShouldGenerateWitness)
+ {
+ byte[][] witnessKeys = _receiptsTracer.WitnessKeys.ToArray();
+ VerkleWorldState? verkleWorldState = _stateProvider as VerkleWorldState;
+ witness = witnessKeys.Length == 0 ? null : verkleWorldState?.GenerateExecutionWitness(witnessKeys, out _);
+ // IJsonSerializer ser = new EthereumJsonSerializer();
+ // _logger.Info($"BLOCK PROCESSOR WITNESS: {spec.IsVerkleTreeEipEnabled} {!block.IsGenesis} {options} {ser.Serialize(witness)}");
+ if (options.ContainsFlag(ProcessingOptions.ProducingBlock) && spec.IsVerkleTreeEipEnabled &&
+ !block.IsGenesis) block.Body.ExecutionWitness = witness;
+ }
+
_stateProvider.Commit(spec);
_stateProvider.RecalculateStateRoot();
block.Header.StateRoot = _stateProvider.StateRoot;
block.Header.Hash = block.Header.CalculateHash();
+ if (ShouldGenerateWitness && ShouldDoStatelessStuff)
+ {
+ try
+ {
+ (IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor, IWorldState worldState) =
+ GetOrCreateExecutorAndState(block, witness!);
+ _receiptsTracer.StartNewBlockTrace(block);
+ TxReceipt[] receiptsSl = blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec);
+
+ block.Header.ReceiptsRoot = receipts.GetReceiptsRoot(spec, block.ReceiptsRoot);
+ ApplyMinerRewards(block, blockTracer, spec);
+ _withdrawalProcessor.ProcessWithdrawals(block, spec);
+ _receiptsTracer.EndBlockTrace();
+
+ worldState.Commit(spec);
+ worldState.RecalculateStateRoot();
+ }
+ catch (Exception e)
+ {
+ _logger.Error($"Failed while doing stateless stuff", e);
+ return receipts;
+ }
+ }
+
return receipts;
}
@@ -274,12 +363,17 @@ private Block PrepareBlockForProcessing(Block suggestedBlock)
WithdrawalsRoot = bh.WithdrawalsRoot,
IsPostMerge = bh.IsPostMerge,
};
+ if (bh.MaybeParent is not null)
+ {
+ bh.MaybeParent.TryGetTarget(out BlockHeader maybeParent);
+ headerForProcessing.MaybeParent = new WeakReference(maybeParent);
+ }
return suggestedBlock.CreateCopy(headerForProcessing);
}
// TODO: block processor pipeline
- private void ApplyMinerRewards(Block block, IBlockTracer tracer, IReleaseSpec spec)
+ protected void ApplyMinerRewards(Block block, IBlockTracer tracer, IReleaseSpec spec)
{
if (_logger.IsTrace) _logger.Trace("Applying miner rewards:");
BlockReward[] rewards = _rewardCalculator.CalculateRewards(block);
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs
index 0e4ac8037d9..78cb729d4cb 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/BlockchainProcessor.cs
@@ -31,6 +31,8 @@ public class BlockchainProcessor : IBlockchainProcessor, IBlockProcessingQueue
public ITracerBag Tracers => _compositeBlockTracer;
private readonly IBlockProcessor _blockProcessor;
+ private readonly IBlockProcessor? _statelessBlockProcessor;
+ private bool _canProcessStatelessBlocks = false;
private readonly IBlockPreprocessorStep _recoveryStep;
private readonly IStateReader _stateReader;
private readonly Options _options;
@@ -88,6 +90,40 @@ public BlockchainProcessor(
_stats = new ProcessingStats(_logger);
}
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public BlockchainProcessor(
+ IBlockTree? blockTree,
+ IBlockProcessor? blockProcessor,
+ IBlockProcessor? statelessBlockProcessor,
+ IBlockPreprocessorStep? recoveryStep,
+ IStateReader stateReader,
+ ILogManager? logManager,
+ Options options)
+ {
+ _logger = logManager?.GetClassLogger() ?? throw new ArgumentNullException(nameof(logManager));
+ _blockTree = blockTree ?? throw new ArgumentNullException(nameof(blockTree));
+ _blockProcessor = blockProcessor ?? throw new ArgumentNullException(nameof(blockProcessor));
+ _statelessBlockProcessor = statelessBlockProcessor ?? throw new ArgumentNullException(nameof(statelessBlockProcessor));
+ _canProcessStatelessBlocks = true;
+ _recoveryStep = recoveryStep ?? throw new ArgumentNullException(nameof(recoveryStep));
+ _stateReader = stateReader ?? throw new ArgumentNullException(nameof(stateReader));
+ _options = options;
+
+ _blockTree.NewBestSuggestedBlock += OnNewBestBlock;
+ _blockTree.NewHeadBlock += OnNewHeadBlock;
+
+ _stats = new ProcessingStats(_logger);
+ }
+
private void OnNewHeadBlock(object? sender, BlockEventArgs e)
{
_lastProcessedBlock = DateTime.UtcNow;
@@ -109,7 +145,7 @@ private void OnNewBestBlock(object sender, BlockEventArgs blockEventArgs)
public void Enqueue(Block block, ProcessingOptions processingOptions)
{
- if (_logger.IsTrace) _logger.Trace($"Enqueuing a new block {block.ToString(Block.Format.Short)} for processing.");
+ if (_logger.IsTrace) _logger.Trace($"Enqueuing a new block {block.ToString(Block.Format.Full)} for processing.");
int currentRecoveryQueueSize = Interlocked.Add(ref _currentRecoveryQueueSize, block.Transactions.Length);
Keccak? blockHash = block.Hash!;
@@ -270,7 +306,7 @@ private void RunProcessingLoop()
Block block = blockRef.Block;
- if (_logger.IsTrace) _logger.Trace($"Processing block {block.ToString(Block.Format.Short)}).");
+ if (_logger.IsTrace) _logger.Trace($"Processing block in processor {block.ToString(Block.Format.Full)}).");
_stats.Start();
Block processedBlock = Process(block, blockRef.ProcessingOptions, _compositeBlockTracer.GetTracer());
@@ -329,7 +365,8 @@ private void FireProcessingQueueEmpty()
bool shouldProcess =
suggestedBlock.IsGenesis
|| _blockTree.IsBetterThanHead(suggestedBlock.Header)
- || options.ContainsFlag(ProcessingOptions.ForceProcessing);
+ || options.ContainsFlag(ProcessingOptions.ForceProcessing)
+ || options.ContainsFlag(ProcessingOptions.StatelessProcessing);
if (!shouldProcess)
{
@@ -458,7 +495,7 @@ void DeleteInvalidBlocks(Keccak invalidBlockHash)
TraceFailingBranch(
processingBranch,
options,
- new BlockReceiptsTracer(),
+ new BlockReceiptsTracer(true, false),
DumpOptions.Receipts);
TraceFailingBranch(
@@ -522,7 +559,14 @@ private void PrepareBlocksToProcess(Block suggestedBlock, ProcessingOptions opti
if (!_stateReader.HasStateForBlock(parentOfFirstBlock))
{
- throw new InvalidOperationException("Attempted to process a blockchain without having starting state");
+ bool canThisBlockBeProcessedStateless = _canProcessStatelessBlocks &&
+ (blocksToProcess[0].ExecutionWitness is not null);
+ // here we assume that if a block has execution witness - then all the following block will
+ // also have execution witness
+ if (!canThisBlockBeProcessedStateless)
+ {
+ throw new InvalidOperationException("Attempted to process a blockchain without having starting state");
+ }
}
}
}
@@ -564,6 +608,7 @@ private ProcessingBranch PrepareProcessingBranch(Block suggestedBlock, Processin
branchingPoint = _blockTree.FindParentHeader(toBeProcessed.Header,
BlockTreeLookupOptions.TotalDifficultyNotNeeded);
+ toBeProcessed.Header.MaybeParent = new WeakReference(branchingPoint);
if (branchingPoint is null)
{
// genesis block
@@ -595,6 +640,7 @@ private ProcessingBranch PrepareProcessingBranch(Block suggestedBlock, Processin
break;
}
+ // TODO: check if we have a separate condition that we need to account for in Stateless Processing
if (isFastSyncTransition)
{
// If we hit this condition, it means that something is wrong in MultiSyncModeSelector.
@@ -657,6 +703,10 @@ private ProcessingBranch PrepareProcessingBranch(Block suggestedBlock, Processin
private bool RunSimpleChecksAheadOfProcessing(Block suggestedBlock, ProcessingOptions options)
{
/* a bit hacky way to get the invalid branch out of the processing loop */
+ // if (suggestedBlock.ExecutionWitness is not null)
+ // {
+ // _logger.Info($"RunSimpleChecksAheadOfProcessing: ExecutionWitness Present {suggestedBlock.ToString(Block.Format.Short)}");
+ // }
if (suggestedBlock.Number != 0 &&
!_blockTree.IsKnownBlock(suggestedBlock.Number - 1, suggestedBlock.ParentHash))
{
@@ -671,6 +721,7 @@ private bool RunSimpleChecksAheadOfProcessing(Block suggestedBlock, ProcessingOp
if (_logger.IsDebug)
_logger.Debug(
$"Skipping processing block {suggestedBlock.ToString(Block.Format.FullHashAndNumber)} without total difficulty");
+ // suggestedBlock.Header.TotalDifficulty = 1;
throw new InvalidOperationException(
"Block without total difficulty calculated was suggested for processing");
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs
index 277fc7c295b..68bf1496b2f 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/IBlockProcessor.cs
@@ -7,6 +7,7 @@
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
using Nethermind.Evm.Tracing;
+using Nethermind.State;
namespace Nethermind.Consensus.Processing
{
@@ -47,6 +48,7 @@ public interface IBlockTransactionsExecutor
{
TxReceipt[] ProcessTransactions(Block block, ProcessingOptions processingOptions, BlockReceiptsTracer receiptsTracer, IReleaseSpec spec);
event EventHandler TransactionProcessed;
+ IBlockTransactionsExecutor WithNewStateProvider(IWorldState worldState);
}
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs
index 555e1c9e1dd..3e7939580b8 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ProcessingOptions.cs
@@ -51,7 +51,10 @@ public enum ProcessingOptions
///
MarkAsProcessed = 128,
- All = 255,
+ ///
+ /// Process block using execution witnesses
+ ///
+ StatelessProcessing = 256,
///
/// Combination of switches for block producers when they preprocess block for state root calculation.
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs
index f99c5f01b12..eae77fabaf9 100644
--- a/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs
+++ b/src/Nethermind/Nethermind.Consensus/Processing/ReadOnlyTxProcessingEnv.cs
@@ -12,6 +12,7 @@
using Nethermind.Logging;
using Nethermind.State;
using Nethermind.Trie.Pruning;
+using Nethermind.Verkle.Tree;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
@@ -37,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,
@@ -59,6 +70,28 @@ public ReadOnlyTxProcessingEnv(
TransactionProcessor = new TransactionProcessor(specProvider, StateProvider, Machine, logManager);
}
+ public ReadOnlyTxProcessingEnv(
+ IReadOnlyDbProvider? readOnlyDbProvider,
+ ReadOnlyVerkleStateStore? readOnlyTrieStore,
+ IReadOnlyBlockTree? readOnlyBlockTree,
+ ISpecProvider? specProvider,
+ ILogManager? logManager)
+ {
+ if (specProvider is null) throw new ArgumentNullException(nameof(specProvider));
+
+ DbProvider = readOnlyDbProvider ?? throw new ArgumentNullException(nameof(readOnlyDbProvider));
+ ReadOnlyDb codeDb = readOnlyDbProvider.CodeDb.AsReadOnly(true);
+
+ StateReader = new VerkleStateReader(new VerkleStateTree(readOnlyTrieStore, logManager), codeDb, logManager);
+ StateProvider = new VerkleWorldState(new VerkleStateTree(readOnlyTrieStore, logManager), codeDb, logManager);
+
+ BlockTree = readOnlyBlockTree ?? throw new ArgumentNullException(nameof(readOnlyBlockTree));
+ BlockhashProvider = new BlockhashProvider(BlockTree, logManager);
+
+ Machine = new VirtualMachine(BlockhashProvider, specProvider, logManager);
+ TransactionProcessor = new TransactionProcessor(specProvider, StateProvider, Machine, logManager);
+ }
+
public IReadOnlyTransactionProcessor Build(Keccak stateRoot) => new ReadOnlyTransactionProcessor(TransactionProcessor, StateProvider, stateRoot);
}
}
diff --git a/src/Nethermind/Nethermind.Consensus/Processing/StatelessBlockProcessor.cs b/src/Nethermind/Nethermind.Consensus/Processing/StatelessBlockProcessor.cs
new file mode 100644
index 00000000000..3ec78a2eedb
--- /dev/null
+++ b/src/Nethermind/Nethermind.Consensus/Processing/StatelessBlockProcessor.cs
@@ -0,0 +1,117 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Linq;
+using Nethermind.Blockchain.Receipts;
+using Nethermind.Consensus.Rewards;
+using Nethermind.Consensus.Validators;
+using Nethermind.Consensus.Withdrawals;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Specs;
+using Nethermind.Crypto;
+using Nethermind.Evm.Tracing;
+using Nethermind.Logging;
+using Nethermind.State;
+using Nethermind.Verkle.Curve;
+
+namespace Nethermind.Consensus.Processing;
+
+public class StatelessBlockProcessor: BlockProcessor
+{
+ private readonly ILogger _logger;
+ private readonly ILogManager _logManager;
+
+ public StatelessBlockProcessor(
+ ISpecProvider? specProvider,
+ IBlockValidator? blockValidator,
+ IRewardCalculator? rewardCalculator,
+ IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor,
+ IWorldState? stateProvider,
+ IReceiptStorage? receiptStorage,
+ IWitnessCollector? witnessCollector,
+ ILogManager? logManager,
+ IWithdrawalProcessor? withdrawalProcessor = null)
+ : base(
+ specProvider,
+ blockValidator,
+ rewardCalculator,
+ blockTransactionsExecutor,
+ stateProvider,
+ receiptStorage,
+ witnessCollector,
+ logManager,
+ withdrawalProcessor)
+ {
+ _logManager = logManager ?? throw new ArgumentNullException(nameof(logManager));;
+ _logger = _logManager.GetClassLogger();
+ }
+
+ protected override void InitBranch(Keccak branchStateRoot, bool incrementReorgMetric = true)
+ {
+
+ }
+
+ private (IBlockProcessor.IBlockTransactionsExecutor, IWorldState) GetOrCreateExecutorAndState(Block block)
+ {
+ IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor;
+ IWorldState worldState;
+ if (!block.IsGenesis)
+ {
+ block.Header.MaybeParent!.TryGetTarget(out BlockHeader maybeParent);
+ Banderwagon stateRoot = Banderwagon.FromBytes(maybeParent!.StateRoot!.Bytes)!.Value;
+ worldState = new VerkleWorldState(block.ExecutionWitness!, stateRoot, _logManager);
+ blockTransactionsExecutor = _blockTransactionsExecutor.WithNewStateProvider(worldState);
+ }
+ else
+ {
+ blockTransactionsExecutor = _blockTransactionsExecutor;
+ worldState = _stateProvider;
+ }
+
+ return (blockTransactionsExecutor, worldState);
+ }
+
+ protected override TxReceipt[] ProcessBlock(
+ Block block,
+ IBlockTracer blockTracer,
+ ProcessingOptions options)
+ {
+ (IBlockProcessor.IBlockTransactionsExecutor? blockTransactionsExecutor, IWorldState worldState) =
+ GetOrCreateExecutorAndState(block);
+
+ IReleaseSpec spec = _specProvider.GetSpec(block.Header);
+
+ _receiptsTracer.SetOtherTracer(blockTracer);
+ _receiptsTracer.StartNewBlockTrace(block);
+ TxReceipt[] receipts = blockTransactionsExecutor.ProcessTransactions(block, options, _receiptsTracer, spec);
+
+ block.Header.ReceiptsRoot = receipts.GetReceiptsRoot(spec, block.ReceiptsRoot);
+ ApplyMinerRewards(block, blockTracer, spec);
+ _withdrawalProcessor.ProcessWithdrawals(block, spec);
+ _receiptsTracer.EndBlockTrace();
+
+ // if we are producing blocks - then calculate and add the witness to the block
+ // but we need to remember that the witness needs to be generate for the parent block state (for pre state)
+ // byte[][]? usedKeysCac = _receiptsTracer.WitnessKeys.ToArray();
+ // _logger.Info($"UsedKeys {usedKeysCac.Length}");
+ // foreach (var key in usedKeysCac)
+ // {
+ // _logger.Info($"{key.ToHexString()}");
+ // }
+ if (options.ContainsFlag(ProcessingOptions.ProducingBlock) && spec.IsVerkleTreeEipEnabled && !block.IsGenesis)
+ {
+ throw new InvalidOperationException($"{nameof(StatelessBlockProcessor)} cannot produce new block.");
+ }
+
+ worldState.Commit(spec);
+ worldState.RecalculateStateRoot();
+
+ block.Header.StateRoot = worldState.StateRoot;
+ block.Header.Hash = block.Header.CalculateHash();
+
+ return receipts;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
index f3f54fb7849..d87736f2d5f 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerBase.cs
@@ -178,9 +178,11 @@ public bool IsProducingBlocks(ulong? maxProducingInterval)
{
if (TrySetState(parent.StateRoot))
{
+ // prepare the block - set deterministic fields and get the transactions we want to include in the block
Block block = PrepareBlock(parent, payloadAttributes);
if (PreparedBlockCanBeMined(block))
{
+ // execute the transactions and then get the stateRoot, txRoot, receipts, witnesses, etc.
Block? processedBlock = ProcessPreparedBlock(block, blockTracer);
if (processedBlock is null)
{
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockProducerEnvFactory.cs
index 3d88b53ba6a..a71ab59e5d0 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;
@@ -12,10 +13,13 @@
using Nethermind.Consensus.Withdrawals;
using Nethermind.Core.Specs;
using Nethermind.Db;
+using Nethermind.Evm.TransactionProcessing;
using Nethermind.Logging;
using Nethermind.State;
using Nethermind.Trie.Pruning;
using Nethermind.TxPool;
+using Nethermind.Verkle;
+using Nethermind.Verkle.Tree;
namespace Nethermind.Consensus.Producers
{
@@ -24,6 +28,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 +38,7 @@ public class BlockProducerEnvFactory : IBlockProducerEnvFactory
protected readonly ITransactionComparerProvider _transactionComparerProvider;
protected readonly IBlocksConfig _blocksConfig;
protected readonly ILogManager _logManager;
+ protected readonly StateType _stateType;
public IBlockTransactionsExecutorFactory TransactionsExecutorFactory { get; set; }
@@ -62,6 +68,38 @@ public BlockProducerEnvFactory(
_transactionComparerProvider = transactionComparerProvider;
_blocksConfig = blocksConfig;
_logManager = logManager;
+ _stateType = StateType.Merkle;
+
+ 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;
+ _stateType = StateType.Verkle;
TransactionsExecutorFactory = new BlockProducerTransactionsExecutorFactory(specProvider, logManager);
}
@@ -106,8 +144,15 @@ public virtual BlockProducerEnv Create(ITxSource? additionalTxSource = null)
};
}
- protected virtual ReadOnlyTxProcessingEnv CreateReadonlyTxProcessingEnv(ReadOnlyDbProvider readOnlyDbProvider, ReadOnlyBlockTree readOnlyBlockTree) =>
- new(readOnlyDbProvider, _readOnlyTrieStore, readOnlyBlockTree, _specProvider, _logManager);
+ protected virtual ReadOnlyTxProcessingEnv CreateReadonlyTxProcessingEnv(ReadOnlyDbProvider readOnlyDbProvider, ReadOnlyBlockTree readOnlyBlockTree)
+ {
+ return _stateType switch
+ {
+ StateType.Merkle => new ReadOnlyTxProcessingEnv(readOnlyDbProvider, _readOnlyTrieStore, readOnlyBlockTree, _specProvider, _logManager),
+ StateType.Verkle => new ReadOnlyTxProcessingEnv(readOnlyDbProvider, _readOnlyVerkleTrieStore, readOnlyBlockTree, _specProvider, _logManager),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ }
protected virtual ITxSource CreateTxSourceForProducer(
ITxSource? additionalTxSource,
diff --git a/src/Nethermind/Nethermind.Consensus/Producers/BlockToProduce.cs b/src/Nethermind/Nethermind.Consensus/Producers/BlockToProduce.cs
index ab7bb2ffa9a..9c2c3252332 100644
--- a/src/Nethermind/Nethermind.Consensus/Producers/BlockToProduce.cs
+++ b/src/Nethermind/Nethermind.Consensus/Producers/BlockToProduce.cs
@@ -6,6 +6,7 @@
using System.Linq;
using System.Runtime.CompilerServices;
using Nethermind.Core;
+using Nethermind.Core.Verkle;
//TODO: Redo clique block producer
[assembly: InternalsVisibleTo("Nethermind.Consensus.Clique")]
@@ -34,8 +35,9 @@ public BlockToProduce(
BlockHeader blockHeader,
IEnumerable transactions,
IEnumerable uncles,
- IEnumerable? withdrawals = null)
- : base(blockHeader, Array.Empty(), uncles, withdrawals)
+ IEnumerable? withdrawals = null,
+ ExecutionWitness? execWitness = null)
+ : base(blockHeader, Array.Empty(), uncles, withdrawals, execWitness)
{
Transactions = transactions;
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Blockchain/TestVerkleBlockchain.cs b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestVerkleBlockchain.cs
new file mode 100644
index 00000000000..f408e7f2573
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/Blockchain/TestVerkleBlockchain.cs
@@ -0,0 +1,553 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Nethermind.Blockchain;
+using Nethermind.Blockchain.Find;
+using Nethermind.Blockchain.Receipts;
+using Nethermind.Config;
+using Nethermind.Consensus;
+using Nethermind.Consensus.Comparers;
+using Nethermind.Consensus.Processing;
+using Nethermind.Consensus.Producers;
+using Nethermind.Consensus.Rewards;
+using Nethermind.Consensus.Transactions;
+using Nethermind.Consensus.Validators;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Specs;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Crypto;
+using Nethermind.Db;
+using Nethermind.Db.Blooms;
+using Nethermind.Db.Rocks;
+using Nethermind.Evm;
+using Nethermind.Evm.TransactionProcessing;
+using Nethermind.Int256;
+using Nethermind.Logging;
+using Nethermind.Serialization.Json;
+using Nethermind.Specs;
+using Nethermind.Specs.Forks;
+using Nethermind.Specs.Test;
+using Nethermind.State;
+using Nethermind.State.Repositories;
+using Nethermind.TxPool;
+using Nethermind.Verkle.Tree;
+using Nethermind.Verkle.Tree.VerkleDb;
+using BlockTree = Nethermind.Blockchain.BlockTree;
+
+namespace Nethermind.Core.Test.Blockchain;
+
+public class TestVerkleBlockchain
+{
+ public const int DefaultTimeout = 400000;
+ public const int PrivateKeyPoolCount = 10000;
+
+ public PrivateKey[] RandomAddressWithBalance;
+
+ public Random random = new Random(0);
+
+ public VerkleStateReader StateReader { get; private set; } = null!;
+ public IEthereumEcdsa EthereumEcdsa { get; private set; } = null!;
+ public INonceManager NonceManager { get; private set; } = null!;
+ public TransactionProcessor TxProcessor { get; set; } = null!;
+ public IReceiptStorage ReceiptStorage { get; set; } = null!;
+ public ITxPool TxPool { get; set; } = null!;
+ public IDb CodeDb => DbProvider.CodeDb;
+ public IBlockProcessor BlockProcessor { get; set; } = null!;
+ public IBlockchainProcessor BlockchainProcessor { get; set; } = null!;
+
+ public IBlockPreprocessorStep BlockPreprocessorStep { get; set; } = null!;
+
+ public IBlockProcessingQueue BlockProcessingQueue { get; set; } = null!;
+ public IBlockTree BlockTree { get; set; } = null!;
+
+ public IBlockFinder BlockFinder
+ {
+ get => _blockFinder ?? BlockTree;
+ set => _blockFinder = value;
+ }
+
+ public ILogFinder LogFinder { get; private set; } = null!;
+ public IJsonSerializer JsonSerializer { get; set; } = null!;
+ public IWorldState State { get; set; } = null!;
+ public IReadOnlyStateProvider ReadOnlyState { get; private set; } = null!;
+ public IDb StateDb => DbProvider.StateDb;
+ public VerkleStateStore TrieStore { get; set; } = null!;
+ public IBlockProducer BlockProducer { get; private set; } = null!;
+ public IDbProvider DbProvider { get; set; } = null!;
+ public ISpecProvider SpecProvider { get; set; } = null!;
+
+ public ISealEngine SealEngine { get; set; } = null!;
+
+ public ITransactionComparerProvider TransactionComparerProvider { get; set; } = null!;
+
+ public IPoSSwitcher PoSSwitcher { get; set; } = null!;
+
+ public static async Task Create()
+ {
+ TestVerkleBlockchain chain = new ();
+ await chain.Build();
+ return chain;
+ }
+
+ public async Task BuildSomeBlocks(int numOfBlocks)
+ {
+ for (int i = 0; i < numOfBlocks; i++)
+ {
+ await AddBlock(GenerateRandomTxn(100));
+ }
+ }
+
+ public async Task BuildSomeBlocksWithDeployment(int numOfBlocks)
+ {
+ for (int i = 0; i < numOfBlocks; i++)
+ {
+ await AddBlock(GenerateRandomTxnWithCode(5));
+ }
+ }
+
+ public string SealEngineType { get; set; } = null!;
+
+
+ public SemaphoreSlim _resetEvent = null!;
+ private ManualResetEvent _suggestedBlockResetEvent = null!;
+ private AutoResetEvent _oneAtATime = new(true);
+ private IBlockFinder _blockFinder = null!;
+
+ public static readonly UInt256 InitialValue = 100000.Ether();
+ private TrieStoreBoundaryWatcher _trieStoreWatcher = null!;
+ public IHeaderValidator HeaderValidator { get; set; } = null!;
+
+ public IBlockValidator BlockValidator { get; set; } = null!;
+ public BuildBlocksWhenRequested BlockProductionTrigger { get; } = new();
+
+ public ReadOnlyVerkleStateStore ReadOnlyTrieStore { get; private set; } = null!;
+
+ public ManualTimestamper Timestamper { get; protected set; } = null!;
+
+ public ProducedBlockSuggester Suggester { get; protected set; } = null!;
+
+
+ public static TransactionBuilder BuildSimpleTransaction => Builders.Build.A.Transaction.SignedAndResolved(TestItem.PrivateKeyA).To(TestItem.AddressB);
+
+ public void GenerateRandomPrivateKeys(int numKeys)
+ {
+ RandomAddressWithBalance = new PrivateKey[numKeys];
+ for (int i = 0; i < numKeys; i++) RandomAddressWithBalance[i] = new PrivateKey(TestItem.GetRandomKeccak(random).Bytes);
+ }
+
+ public virtual async Task Build(ISpecProvider? specProvider = null, UInt256? initialValues = null)
+ {
+ GenerateRandomPrivateKeys(PrivateKeyPoolCount);
+
+ Timestamper = new ManualTimestamper(new DateTime(2020, 2, 15, 12, 50, 30, DateTimeKind.Utc));
+ JsonSerializer = new EthereumJsonSerializer();
+ SpecProvider = CreateSpecProvider(specProvider ?? new TestSpecProvider(Prague.Instance));
+ EthereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, LogManager);
+
+ DbProvider = CreateDbProvider();
+ TrieStore = new VerkleStateStore(DbProvider, LogManager);
+ byte[] code = Bytes.FromHexString("0xabcd");
+ State = new VerkleWorldState(TrieStore, DbProvider.CodeDb, LogManager);
+ State.CreateAccount(TestItem.AddressA, (initialValues ?? InitialValue));
+ State.CreateAccount(TestItem.AddressB, (initialValues ?? InitialValue));
+ State.CreateAccount(TestItem.AddressC, (initialValues ?? InitialValue));
+ State.CreateAccount(TestItem.AddressD, (initialValues ?? InitialValue));
+ State.CreateAccount(TestItem.AddressE, (initialValues ?? InitialValue));
+ State.CreateAccount(TestItem.AddressF, (initialValues ?? InitialValue));
+ State.InsertCode(TestItem.AddressA, code, SpecProvider.GenesisSpec);
+ State.Set(new StorageCell(TestItem.AddressA, UInt256.One), Bytes.FromHexString("0xabcdef"));
+ State.Commit(SpecProvider.GenesisSpec);
+ State.CommitTree(0);
+
+ ReadOnlyTrieStore = TrieStore.AsReadOnly(new VerkleMemoryDb());
+ StateReader = new VerkleStateReader(ReadOnlyTrieStore, CodeDb, LogManager);
+
+ IDb blockDb = new MemDb();
+ IDb headerDb = new MemDb();
+ IDb blockInfoDb = new MemDb();
+ BlockTree = new BlockTree(blockDb, headerDb, blockInfoDb, new ChainLevelInfoRepository(blockInfoDb), SpecProvider, NullBloomStorage.Instance, SimpleConsoleLogManager.Instance);
+ ReadOnlyState = new ChainHeadReadOnlyStateProvider(BlockTree, StateReader);
+ TransactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockTree);
+ TxPool = CreateTxPool();
+
+ IChainHeadInfoProvider chainHeadInfoProvider =
+ new ChainHeadInfoProvider(SpecProvider, BlockTree, StateReader);
+
+ NonceManager = new NonceManager(chainHeadInfoProvider.AccountStateProvider);
+
+ _trieStoreWatcher = new TrieStoreBoundaryWatcher(TrieStore, BlockTree, SimpleConsoleLogManager.Instance);
+
+ ReceiptStorage = new InMemoryReceiptStorage();
+ VirtualMachine virtualMachine = new(new BlockhashProvider(BlockTree, LogManager), SpecProvider, SimpleConsoleLogManager.Instance);
+ TxProcessor = new TransactionProcessor(SpecProvider, State, virtualMachine, SimpleConsoleLogManager.Instance);
+ BlockPreprocessorStep = new RecoverSignatures(EthereumEcdsa, TxPool, SpecProvider, LogManager);
+ HeaderValidator = new HeaderValidator(BlockTree, Always.Valid, SpecProvider, LogManager);
+
+ new ReceiptCanonicalityMonitor(BlockTree, ReceiptStorage, LogManager);
+
+ BlockValidator = new BlockValidator(
+ new TxValidator(SpecProvider.ChainId),
+ HeaderValidator,
+ Always.Valid,
+ SpecProvider,
+ LogManager);
+
+ PoSSwitcher = NoPoS.Instance;
+ ISealer sealer = new NethDevSealEngine(TestItem.AddressD);
+ SealEngine = new SealEngine(sealer, Always.Valid);
+
+ BloomStorage bloomStorage = new(new BloomConfig(), new MemDb(), new InMemoryDictionaryFileStoreFactory());
+ ReceiptsRecovery receiptsRecovery = new(new EthereumEcdsa(SpecProvider.ChainId, SimpleConsoleLogManager.Instance), SpecProvider);
+ LogFinder = new LogFinder(BlockTree, ReceiptStorage, ReceiptStorage, bloomStorage, SimpleConsoleLogManager.Instance, receiptsRecovery);
+ BlockProcessor = CreateBlockProcessor();
+
+ BlockchainProcessor chainProcessor = new(BlockTree, BlockProcessor, BlockPreprocessorStep, StateReader, SimpleConsoleLogManager.Instance, Consensus.Processing.BlockchainProcessor.Options.Default);
+ BlockchainProcessor = chainProcessor;
+ BlockProcessingQueue = chainProcessor;
+ chainProcessor.Start();
+
+ TxPoolTxSource txPoolTxSource = CreateTxPoolTxSource();
+ ITransactionComparerProvider transactionComparerProvider = new TransactionComparerProvider(SpecProvider, BlockFinder);
+ BlockProducer = CreateTestBlockProducer(txPoolTxSource, sealer, transactionComparerProvider);
+ await BlockProducer.Start();
+ Suggester = new ProducedBlockSuggester(BlockTree, BlockProducer);
+
+ _resetEvent = new SemaphoreSlim(0);
+ _suggestedBlockResetEvent = new ManualResetEvent(true);
+ BlockTree.NewHeadBlock += OnNewHeadBlock;
+ BlockProducer.BlockProduced += (s, e) =>
+ {
+ _suggestedBlockResetEvent.Set();
+ };
+
+ Block? genesis = GetGenesisBlock();
+ BlockTree.SuggestBlock(genesis);
+
+ await WaitAsync(_resetEvent, "Failed to process genesis in time.");
+ await AirdropToAddresses();
+ return this;
+ }
+
+
+ public Transaction[] GenerateRandomTxn(int numTxn)
+ {
+ Transaction[] txns = new Transaction[numTxn];
+
+ for (int i = 0; i < numTxn; i++)
+ {
+ int fromTx = random.Next(RandomAddressWithBalance.Length - 1);
+ int toTx = random.Next(RandomAddressWithBalance.Length - 1);
+ if (fromTx == toTx) toTx = fromTx + 1;
+ txns[i] = Builders.Build.A.Transaction.WithTo(RandomAddressWithBalance[fromTx].Address).WithValue(1.GWei())
+ .SignedAndResolved(RandomAddressWithBalance[toTx]).TestObject;
+ }
+
+ return txns;
+ }
+
+ public Transaction[] GenerateRandomTxnWithCode(int numTxn)
+ {
+ List txns = new();
+ int jump = RandomAddressWithBalance.Length / numTxn;
+ int key = 0;
+ while (key < RandomAddressWithBalance.Length)
+ {
+ byte[] code = new byte[TestItem.Random.Next(2000)];
+ PrivateKey caller = RandomAddressWithBalance[key];
+ UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, caller.Address);
+ txns.Add(Builders.Build.A.Transaction.WithTo(null).WithCode(code).WithNonce(nonce).WithGasLimit(200000)
+ .SignedAndResolved(caller).TestObject);
+ key += jump;
+ }
+ return txns.ToArray();
+ }
+
+ protected virtual async Task AirdropToAddresses()
+ {
+ int batch = 10;
+
+ List txToAdd = new();
+ for (int i = 0; i < batch; i++)
+ {
+ txToAdd.Add(Builders.Build.A.Transaction.WithTo(RandomAddressWithBalance[i].Address).WithGasLimit(100000).WithMaxFeePerGas(20.GWei())
+ .WithMaxPriorityFeePerGas(5.GWei())
+ .WithType(TxType.EIP1559).WithValue(1.Ether()).WithNonce((UInt256)i)
+ .SignedAndResolved(TestItem.PrivateKeyA).TestObject);
+ }
+ await AddBlock(txToAdd.ToArray());
+ txToAdd.Clear();
+ for (int i = batch; i < 2 * batch; i++)
+ {
+ txToAdd.Add(Builders.Build.A.Transaction.WithTo(RandomAddressWithBalance[i].Address).WithGasLimit(100000).WithMaxFeePerGas(30.GWei())
+ .WithMaxPriorityFeePerGas(5.GWei())
+ .WithType(TxType.EIP1559).WithValue(1.Ether()).WithNonce((UInt256)(i-batch))
+ .SignedAndResolved(TestItem.PrivateKeyB).TestObject);
+ }
+ await AddBlock(txToAdd.ToArray());
+ txToAdd.Clear();
+ for (int i = 2 * batch; i < 3 * batch; i++)
+ {
+ txToAdd.Add(Builders.Build.A.Transaction.WithTo(RandomAddressWithBalance[i].Address).WithGasLimit(100000).WithMaxFeePerGas(40.GWei())
+ .WithMaxPriorityFeePerGas(5.GWei())
+ .WithType(TxType.EIP1559).WithValue(1.Ether()).WithNonce((UInt256)(i-2 * batch))
+ .SignedAndResolved(TestItem.PrivateKeyC).TestObject);
+ }
+ await AddBlock(txToAdd.ToArray());
+ txToAdd.Clear();
+ for (int i = 3 * batch; i < 4 * batch; i++)
+ {
+ txToAdd.Add(Builders.Build.A.Transaction.WithTo(RandomAddressWithBalance[i].Address).WithGasLimit(100000).WithMaxFeePerGas(50.GWei())
+ .WithMaxPriorityFeePerGas(5.GWei())
+ .WithType(TxType.EIP1559).WithValue(1.Ether()).WithNonce((UInt256)(i-3 * batch))
+ .SignedAndResolved(TestItem.PrivateKeyD).TestObject);
+ }
+ await AddBlock(txToAdd.ToArray());
+ txToAdd.Clear();
+ for (int i = 4 * batch; i < RandomAddressWithBalance.Length; i++)
+ {
+ txToAdd.Add(Builders.Build.A.Transaction.WithTo(RandomAddressWithBalance[i].Address).WithGasLimit(100000).WithMaxFeePerGas(60.GWei())
+ .WithMaxPriorityFeePerGas(5.GWei())
+ .WithType(TxType.EIP1559).WithValue(1.Ether()).WithNonce((UInt256)(i-4 * batch))
+ .SignedAndResolved(TestItem.PrivateKeyE).TestObject);
+ }
+ }
+
+
+
+ private static ISpecProvider CreateSpecProvider(ISpecProvider specProvider)
+ {
+ return specProvider is TestSpecProvider { AllowTestChainOverride: false }
+ ? specProvider
+ : new OverridableSpecProvider(specProvider, s => new OverridableReleaseSpec(s) { IsEip3607Enabled = false });
+ }
+
+ private void OnNewHeadBlock(object? sender, BlockEventArgs e)
+ {
+ _resetEvent.Release(1);
+ }
+
+ protected virtual IDbProvider CreateDbProvider() => VerkleDbFactory.InitDatabase(DbMode.MemDb, null);
+
+ private async Task WaitAsync(SemaphoreSlim semaphore, string error, int timeout = DefaultTimeout)
+ {
+ if (!await semaphore.WaitAsync(timeout))
+ {
+ throw new InvalidOperationException(error);
+ }
+ }
+
+ private async Task WaitAsync(EventWaitHandle eventWaitHandle, string error, int timeout = DefaultTimeout)
+ {
+ if (!await eventWaitHandle.WaitOneAsync(timeout, CancellationToken.None))
+ {
+ throw new InvalidOperationException(error);
+ }
+ }
+
+ protected virtual IBlockProducer CreateTestBlockProducer(TxPoolTxSource txPoolTxSource, ISealer sealer, ITransactionComparerProvider transactionComparerProvider)
+ {
+ BlocksConfig blocksConfig = new();
+
+ BlockProducerEnvFactory blockProducerEnvFactory = new(
+ DbProvider,
+ BlockTree,
+ ReadOnlyTrieStore,
+ SpecProvider,
+ BlockValidator,
+ NoBlockRewards.Instance,
+ ReceiptStorage,
+ BlockPreprocessorStep,
+ TxPool,
+ transactionComparerProvider,
+ blocksConfig,
+ SimpleConsoleLogManager.Instance);
+
+ BlockProducerEnv env = blockProducerEnvFactory.Create(txPoolTxSource);
+ return new TestBlockProducer(
+ env.TxSource,
+ env.ChainProcessor,
+ env.ReadOnlyStateProvider,
+ sealer,
+ BlockTree,
+ BlockProductionTrigger,
+ Timestamper,
+ SpecProvider,
+ SimpleConsoleLogManager.Instance,
+ blocksConfig);
+ }
+
+ public virtual ILogManager LogManager { get; set; } = SimpleConsoleLogManager.Instance;
+
+ protected virtual TxPool.TxPool CreateTxPool() =>
+ new(
+ EthereumEcdsa,
+ new ChainHeadInfoProvider(new FixedForkActivationChainHeadSpecProvider(SpecProvider), BlockTree, ReadOnlyState),
+ new TxPoolConfig(),
+ new TxValidator(SpecProvider.ChainId),
+ LimboLogs.Instance,
+ TransactionComparerProvider.GetDefaultComparer());
+
+ protected virtual TxPoolTxSource CreateTxPoolTxSource()
+ {
+ BlocksConfig blocksConfig = new()
+ {
+ MinGasPrice = 0
+ };
+ ITxFilterPipeline txFilterPipeline = TxFilterPipelineBuilder.CreateStandardFilteringPipeline(SimpleConsoleLogManager.Instance,
+ SpecProvider, blocksConfig);
+ return new TxPoolTxSource(TxPool, SpecProvider, TransactionComparerProvider, LogManager, txFilterPipeline);
+ }
+
+ public BlockBuilder GenesisBlockBuilder { get; set; } = null!;
+
+ protected virtual Block GetGenesisBlock()
+ {
+ BlockBuilder genesisBlockBuilder = Builders.Build.A.Block.Genesis;
+ if (GenesisBlockBuilder is not null)
+ {
+ genesisBlockBuilder = GenesisBlockBuilder;
+ }
+
+ genesisBlockBuilder.WithStateRoot(State.StateRoot);
+ if (SealEngineType == Nethermind.Core.SealEngineType.AuRa)
+ {
+ genesisBlockBuilder.WithAura(0, new byte[65]);
+ }
+
+ return genesisBlockBuilder.TestObject;
+ }
+
+ protected virtual async Task AddBlocksOnStart()
+ {
+ await AddBlock(BuildSimpleTransaction.WithNonce(0).TestObject);
+ await AddBlock(BuildSimpleTransaction.WithNonce(1).TestObject, BuildSimpleTransaction.WithNonce(2).TestObject);
+ await AddBlock(BuildSimpleTransaction.WithNonce(3).TestObject, BuildSimpleTransaction.WithNonce(4).TestObject);
+ }
+
+ protected virtual IBlockProcessor CreateBlockProcessor() =>
+ new StatelessBlockProcessor(
+ SpecProvider,
+ BlockValidator,
+ NoBlockRewards.Instance,
+ new BlockProcessor.BlockStatelessValidationTransactionsExecutor(TxProcessor),
+ State,
+ ReceiptStorage,
+ NullWitnessCollector.Instance,
+ SimpleConsoleLogManager.Instance);
+
+ public async Task WaitForNewHead()
+ {
+ await WaitAsync(_resetEvent, "Failed to produce new head in time.");
+ _suggestedBlockResetEvent.Reset();
+ }
+
+ public async Task AddBlock(params Transaction[] transactions)
+ {
+ await AddBlockInternal(transactions);
+
+ await WaitAsync(_resetEvent, "Failed to produce new head in time.");
+ _suggestedBlockResetEvent.Reset();
+ _oneAtATime.Set();
+ }
+
+ public async Task AddBlock(bool shouldWaitForHead = true, params Transaction[] transactions)
+ {
+ await AddBlockInternal(transactions);
+
+ if (shouldWaitForHead)
+ {
+ await WaitAsync(_resetEvent, "Failed to produce new head in time.");
+ }
+ else
+ {
+ await WaitAsync(_suggestedBlockResetEvent, "Failed to produce new suggested block in time.");
+ }
+
+ _oneAtATime.Set();
+ }
+
+ private async Task AddBlockInternal(params Transaction[] transactions)
+ {
+ // we want it to be last event, so lets re-register
+ BlockTree.NewHeadBlock -= OnNewHeadBlock;
+ BlockTree.NewHeadBlock += OnNewHeadBlock;
+
+ await WaitAsync(_oneAtATime, "Multiple block produced at once.");
+ AcceptTxResult[] txResults = transactions.Select(t => TxPool.SubmitTx(t, TxHandlingOptions.None)).ToArray();
+ Timestamper.Add(TimeSpan.FromSeconds(1));
+ await BlockProductionTrigger.BuildBlock();
+ return txResults;
+ }
+
+ public void AddTransactions(params Transaction[] txs)
+ {
+ for (int i = 0; i < txs.Length; i++)
+ {
+ TxPool.SubmitTx(txs[i], TxHandlingOptions.None);
+ }
+ }
+
+ public virtual void Dispose()
+ {
+ BlockProducer?.StopAsync();
+ if (DbProvider != null)
+ {
+ CodeDb?.Dispose();
+ StateDb?.Dispose();
+ }
+
+ _trieStoreWatcher?.Dispose();
+ DbProvider?.Dispose();
+ }
+
+ ///
+ /// Creates a simple transfer transaction with value defined by
+ /// from a rich account to
+ ///
+ /// Address to add funds to
+ /// Value of ether to add to the account
+ ///
+ public async Task AddFunds(Address address, UInt256 ether) =>
+ await AddBlock(GetFundsTransaction(address, ether));
+
+ public async Task AddFunds(params (Address address, UInt256 ether)[] funds) =>
+ await AddBlock(funds.Select((f, i) => GetFundsTransaction(f.address, f.ether, (uint)i)).ToArray());
+
+ public async Task AddFundsAfterLondon(params (Address address, UInt256 ether)[] funds) =>
+ await AddBlock(funds.Select((f, i) => GetFunds1559Transaction(f.address, f.ether, (uint)i)).ToArray());
+
+
+
+ private Transaction GetFundsTransaction(Address address, UInt256 ether, uint index = 0)
+ {
+ UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, TestItem.AddressA);
+ Transaction tx = Builders.Build.A.Transaction
+ .SignedAndResolved(TestItem.PrivateKeyA)
+ .To(address)
+ .WithNonce(nonce + index)
+ .WithValue(ether)
+ .TestObject;
+ return tx;
+ }
+
+ private Transaction GetFunds1559Transaction(Address address, UInt256 ether, uint index = 0)
+ {
+ UInt256 nonce = StateReader.GetNonce(BlockTree.Head!.StateRoot!, TestItem.AddressA);
+ Transaction tx = Builders.Build.A.Transaction
+ .SignedAndResolved(TestItem.PrivateKeyA)
+ .To(address)
+ .WithNonce(nonce + index)
+ .WithMaxFeePerGas(20.GWei())
+ .WithMaxPriorityFeePerGas(5.GWei())
+ .WithType(TxType.EIP1559)
+ .WithValue(ether)
+ .WithChainId(MainnetSpecProvider.Instance.ChainId)
+ .TestObject;
+ return tx;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/AccountBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/AccountBuilder.cs
index 1b279572264..5cef48c7a4a 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/AccountBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/AccountBuilder.cs
@@ -1,8 +1,10 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using Microsoft.AspNetCore.Mvc.Controllers;
using Nethermind.Core.Crypto;
using Nethermind.Int256;
+using Nethermind.Serialization.Rlp;
namespace Nethermind.Core.Test.Builders
{
@@ -27,7 +29,7 @@ public AccountBuilder WithNonce(UInt256 nonce)
public AccountBuilder WithCode(byte[] code)
{
- TestObjectInternal = TestObjectInternal.WithChangedCodeHash(Keccak.Compute(code));
+ TestObjectInternal = TestObjectInternal.WithChangedCodeHash(Keccak.Compute(code), code);
return this;
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
index 5792e4a646b..ec4b6b4e24d 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
@@ -5,6 +5,7 @@
using System.Linq;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
+using Nethermind.Core.Verkle;
using Nethermind.Crypto;
using Nethermind.Int256;
using Nethermind.State.Proofs;
@@ -260,5 +261,12 @@ public BlockBuilder WithWithdrawals(params Withdrawal[]? withdrawals)
return this;
}
+
+ public BlockBuilder WithExecutionWitness(ExecutionWitness? witness)
+ {
+ TestObjectInternal = TestObjectInternal
+ .WithReplacedBody(TestObjectInternal.Body.WithChangedExecutionWitness(witness));
+ return this;
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.Tree.cs b/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.Tree.cs
index ba34d21ceb5..e0ff37c2609 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.Tree.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.Tree.cs
@@ -3,17 +3,23 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Net;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Crypto;
using Nethermind.Db;
+using Nethermind.Db.Rocks;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
using Nethermind.State;
using Nethermind.State.Snap;
using Nethermind.Trie.Pruning;
+using Nethermind.Verkle.Tree;
+using Nethermind.Verkle.Tree.Interfaces;
+using Nethermind.Verkle.Tree.Sync;
namespace Nethermind.Core.Test.Builders
{
@@ -23,12 +29,12 @@ public static class Tree
{
public static Keccak AccountAddress0 = new Keccak("0000000000000000000000000000000000000000000000000000000001101234");
- private static readonly Account _account0 = Build.An.Account.WithBalance(0).TestObject;
- private static readonly Account _account1 = Build.An.Account.WithBalance(1).TestObject;
- private static readonly Account _account2 = Build.An.Account.WithBalance(2).TestObject;
- private static readonly Account _account3 = Build.An.Account.WithBalance(3).TestObject;
- private static readonly Account _account4 = Build.An.Account.WithBalance(4).TestObject;
- private static readonly Account _account5 = Build.An.Account.WithBalance(5).TestObject;
+ public static readonly Account _account0 = Build.An.Account.WithBalance(0).TestObject;
+ public static readonly Account _account1 = Build.An.Account.WithBalance(1).TestObject;
+ public static readonly Account _account2 = Build.An.Account.WithBalance(2).TestObject;
+ public static readonly Account _account3 = Build.An.Account.WithBalance(3).TestObject;
+ public static readonly Account _account4 = Build.An.Account.WithBalance(4).TestObject;
+ public static readonly Account _account5 = Build.An.Account.WithBalance(5).TestObject;
public static PathWithAccount[] AccountsWithPaths = new PathWithAccount[]
{
@@ -61,6 +67,17 @@ public static StateTree GetStateTree(ITrieStore? store)
return stateTree;
}
+ public static VerkleStateTree GetVerkleStateTree(IVerkleTrieStore? store)
+ {
+ store ??= new VerkleStateStore(VerkleDbFactory.InitDatabase(DbMode.MemDb, null), LimboLogs.Instance);
+
+ var stateTree = new VerkleStateTree(store, LimboLogs.Instance);
+
+ // FillStateTreeWithTestAccounts(stateTree);
+
+ return stateTree;
+ }
+
public static void FillStateTreeWithTestAccounts(StateTree stateTree)
{
stateTree.Set(AccountsWithPaths[0].Path, AccountsWithPaths[0].Account);
@@ -72,6 +89,35 @@ public static void FillStateTreeWithTestAccounts(StateTree stateTree)
stateTree.Commit(0);
}
+ public static byte[] stem0 = new Keccak("0000000000000000000000000000000000000000000000000000000001101234").Bytes[1..];
+ public static byte[] stem1 = new Keccak("0000000000000000000000000000000000000000000000000000000001112345").Bytes[1..];
+ public static byte[] stem2 = new Keccak("0000000000000000000000000000000000000000000000000000000001113456").Bytes[1..];
+ public static byte[] stem3 = new Keccak("0000000000000000000000000000000000000000000000000000000001114567").Bytes[1..];
+ public static byte[] stem4 = new Keccak("0000000000000000000000000000000000000000000000000000000001123456").Bytes[1..];
+ public static byte[] stem5 = new Keccak("0000000000000000000000000000000000000000000000000000000001123457").Bytes[1..];
+
+ public static PathWithSubTree[] SubTreesWithPaths = new PathWithSubTree[]
+ {
+ new PathWithSubTree(stem0, _account0.ToVerkleDict()),
+ new PathWithSubTree(stem1, _account1.ToVerkleDict()),
+ new PathWithSubTree(stem2, _account2.ToVerkleDict()),
+ new PathWithSubTree(stem3, _account3.ToVerkleDict()),
+ new PathWithSubTree(stem4, _account4.ToVerkleDict()),
+ new PathWithSubTree(stem5, _account5.ToVerkleDict()),
+ };
+
+ public static void FillStateTreeWithTestAccounts(VerkleStateTree stateTree)
+ {
+ stateTree.InsertStemBatch(stem0, _account0.ToVerkleDict());
+ stateTree.InsertStemBatch(stem1, _account1.ToVerkleDict());
+ stateTree.InsertStemBatch(stem2, _account2.ToVerkleDict());
+ stateTree.InsertStemBatch(stem3, _account3.ToVerkleDict());
+ stateTree.InsertStemBatch(stem4, _account4.ToVerkleDict());
+ stateTree.InsertStemBatch(stem5, _account5.ToVerkleDict());
+ stateTree.Commit();
+ stateTree.CommitTree(0);
+ }
+
public static (StateTree stateTree, StorageTree storageTree) GetTrees(ITrieStore? store)
{
store ??= new TrieStore(new MemDb(), LimboLogs.Instance);
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.VerkleTree.cs b/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.VerkleTree.cs
new file mode 100644
index 00000000000..a762a4bd3aa
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/TestItem.VerkleTree.cs
@@ -0,0 +1,151 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Verkle;
+using Nethermind.Db;
+using Nethermind.Db.Rocks;
+using Nethermind.Int256;
+using Nethermind.Logging;
+using Nethermind.State;
+using Nethermind.Verkle.Tree;
+using Nethermind.Verkle.Tree.Interfaces;
+using Nethermind.Verkle.Tree.Sync;
+using Nethermind.Verkle.Tree.Utils;
+using NUnit.Framework;
+
+namespace Nethermind.Core.Test.Builders;
+
+public static partial class TestItem
+{
+ public static readonly Stem Stem0 = new Stem("00000000000000000000000000000000000000000000000000000001101234");
+ public static readonly Stem Stem1 = new Stem("00000000000000000000000000000000000000000000000000000001112345");
+ public static readonly Stem Stem2 = new Stem("00000000000000000000000000000000000000000000000000000001113456");
+ public static readonly Stem Stem3 = new Stem("00000000000000000000000000000000000000000000000000000001114567");
+ public static readonly Stem Stem4 = new Stem("00000000000000000000000000000000000000000000000000000001123456");
+ public static readonly Stem Stem5 = new Stem("00000000000000000000000000000000000000000000000000000001123457");
+
+ public static readonly Account _account0 = Build.An.Account.WithBalance(0).TestObject;
+ public static readonly Account _account1 = Build.An.Account.WithBalance(1).TestObject;
+ public static readonly Account _account2 = Build.An.Account.WithBalance(2).TestObject;
+ public static readonly Account _account3 = Build.An.Account.WithBalance(3).TestObject;
+ public static readonly Account _account4 = Build.An.Account.WithBalance(4).TestObject;
+ public static readonly Account _account5 = Build.An.Account.WithBalance(5).TestObject;
+
+ public static PathWithSubTree[] SubTreesWithPaths = new PathWithSubTree[]
+ {
+ new PathWithSubTree(Stem0, _account0.ToVerkleDict()),
+ new PathWithSubTree(Stem1, _account1.ToVerkleDict()),
+ new PathWithSubTree(Stem2, _account2.ToVerkleDict()),
+ new PathWithSubTree(Stem3, _account3.ToVerkleDict()),
+ new PathWithSubTree(Stem4, _account4.ToVerkleDict()),
+ new PathWithSubTree(Stem5, _account5.ToVerkleDict()),
+ };
+
+ private static string GetDbPathForTest()
+ {
+ string tempDir = Path.GetTempPath();
+ string dbname = "VerkleTrie_TestID_" + TestContext.CurrentContext.Test.ID;
+ return Path.Combine(tempDir, dbname);
+ }
+
+ public static IVerkleTrieStore GetVerkleStore(DbMode dbMode, int history = 128)
+ {
+ IDbProvider provider;
+ switch (dbMode)
+ {
+ case DbMode.MemDb:
+ provider = VerkleDbFactory.InitDatabase(dbMode, null);
+ break;
+ case DbMode.PersistantDb:
+ provider = VerkleDbFactory.InitDatabase(dbMode, GetDbPathForTest());
+ break;
+ case DbMode.ReadOnlyDb:
+ default:
+ throw new ArgumentOutOfRangeException(nameof(dbMode), dbMode, null);
+ }
+
+ return new VerkleStateStore(provider, LimboLogs.Instance,maxNumberOfBlocksInCache: history);
+ }
+
+ public static VerkleStateTree GetVerkleStateTree(IVerkleTrieStore? store)
+ {
+ store ??= GetVerkleStore(DbMode.MemDb);
+ VerkleStateTree stateTree = new VerkleStateTree(store, LimboLogs.Instance);
+ FillStateTreeWithTestAccounts(stateTree);
+ return stateTree;
+ }
+
+ public static void FillStateTreeWithTestAccounts(VerkleStateTree stateTree)
+ {
+ stateTree.InsertStemBatch(Stem0, _account0.ToVerkleDict());
+ stateTree.InsertStemBatch(Stem1, _account1.ToVerkleDict());
+ stateTree.InsertStemBatch(Stem2, _account2.ToVerkleDict());
+ stateTree.InsertStemBatch(Stem3, _account3.ToVerkleDict());
+ stateTree.InsertStemBatch(Stem4, _account4.ToVerkleDict());
+ stateTree.InsertStemBatch(Stem5, _account5.ToVerkleDict());
+ stateTree.Commit();
+ stateTree.CommitTree(0);
+ }
+
+ public static void InsertBigVerkleTree(VerkleTree tree, int numBlocks, long leafPerBlock, long pathPoolCount, out SortedDictionary leafs)
+ {
+ Pedersen[] pathPool = new Pedersen[pathPoolCount];
+ leafs = new();
+
+ for (int i = 0; i < pathPoolCount; i++)
+ {
+ byte[] key = new byte[32];
+ ((UInt256)i).ToBigEndian(key);
+ Pedersen keccak = new Pedersen(key);
+ pathPool[i] = keccak;
+ }
+
+
+ for (int leafIndex = 0; leafIndex < 10000; leafIndex++)
+ {
+ byte[] value = new byte[32];
+ Random.NextBytes(value);
+ Pedersen path = pathPool[Random.Next(pathPool.Length - 1)];
+ tree.Insert(path, value);
+ leafs[path] = value;
+ }
+
+ tree.Commit();
+ tree.CommitTree(0);
+
+ for (int blockNumber = 1; blockNumber <= numBlocks; blockNumber++)
+ {
+ for (int accountIndex = 0; accountIndex < leafPerBlock; accountIndex++)
+ {
+ byte[] leafValue = new byte[32];
+
+
+
+ Random.NextBytes(leafValue);
+ Pedersen path = pathPool[Random.Next(pathPool.Length - 1)];
+
+ if (leafs.ContainsKey(path))
+ {
+ if (!(Random.NextSingle() > 0.5)) continue;
+ Console.WriteLine($"blockNumber:{blockNumber} uKey:{path} uValue:{leafValue.ToHexString()}");
+ tree.Insert(path, leafValue);
+ leafs[path] = leafValue;
+ Console.WriteLine("new values");
+ }
+ else
+ {
+ Console.WriteLine($"blockNumber:{blockNumber} nKey:{path} nValue:{leafValue.ToHexString()}");
+ tree.Insert(path, leafValue);
+ leafs[path] = leafValue;
+ }
+ }
+
+ tree.Commit();
+ tree.CommitTree(blockNumber);
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs
index ed2e3f3fb23..eca3e8eb5dd 100644
--- a/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Encoding/BlockDecoderTests.cs
@@ -2,14 +2,22 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Collections.Generic;
using System.IO;
+using FluentAssertions;
+using MathNet.Numerics.Random;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Core.Test.Builders;
+using Nethermind.Core.Verkle;
using Nethermind.Crypto;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Serialization.Rlp;
+using Nethermind.Serialization.Rlp.Verkle;
+using Nethermind.Verkle.Curve;
+using Nethermind.Verkle.Fields.FrEElement;
+using Nethermind.Verkle.Proofs;
using NUnit.Framework;
namespace Nethermind.Core.Test.Encoding;
@@ -56,6 +64,14 @@ public BlockDecoderTests()
.WithUncles(uncles)
.WithWithdrawals(8)
.WithMixHash(Keccak.EmptyTreeHash)
+ .TestObject,
+ Build.A.Block
+ .WithNumber(1)
+ .WithTransactions(transactions)
+ .WithUncles(uncles)
+ .WithWithdrawals(8)
+ .WithMixHash(Keccak.EmptyTreeHash)
+ .WithExecutionWitness(GenRandomWitness())
.TestObject
};
}
@@ -111,4 +127,81 @@ public void Get_length_null()
BlockDecoder decoder = new();
Assert.That(decoder.GetLength(null, RlpBehaviors.None), Is.EqualTo(1));
}
+
+ [Test]
+ public void TestWitnessRlp()
+ {
+ ExecutionWitnessDecoder decoder = new();
+ ExecutionWitness item = GenRandomWitness();
+ RlpStream stream = new (decoder.GetLength(item, RlpBehaviors.None));
+ decoder.Encode(stream, item);
+ string dataPrev = stream.Data.ToHexString();
+
+ ExecutionWitness exec = decoder.Decode(new RlpStream(stream.Data));
+ RlpStream stream2 = new (decoder.GetLength(exec, RlpBehaviors.None));
+ decoder.Encode(stream2, exec);
+ string dataNew = stream2.Data.ToHexString();
+
+ dataPrev.Should().BeEquivalentTo(dataNew);
+ }
+
+ private static ExecutionWitness GenRandomWitness()
+ {
+ var rand = new Random();
+ const int suffixDiffLength = 20;
+ const int stemLength = 20;
+ List suffixDiffs = new();
+ for (int i = 0; i < suffixDiffLength; i++)
+ {
+ var d = new SuffixStateDiff()
+ {
+ Suffix = (byte)i, CurrentValue = rand.NextBytes(32), NewValue = rand.NextBytes(32)
+ };
+ suffixDiffs.Add(d);
+ }
+
+ List stateDiff = new List();
+ for (int i = 0; i < stemLength; i++)
+ {
+ stateDiff.Add(new StemStateDiff()
+ {
+ SuffixDiffs = new List(suffixDiffs.ToArray()),
+ Stem = rand.NextBytes(31)
+ });
+ }
+
+ List otherStems = new();
+ for (int i = 0; i < 5; i++)
+ {
+ otherStems.Add(new Stem(rand.NextBytes(31)));
+ }
+
+ byte[] depthExt = rand.NextBytes(5);
+
+ List comm = new();
+ for (int i = 0; i < 100; i++)
+ {
+ Banderwagon? point;
+ while (true)
+ {
+ point = Banderwagon.FromBytes(rand.NextBytes(32), subgroupCheck: true);
+ if (point.HasValue) break;
+ }
+ comm.Add(point.Value);
+ }
+
+ Banderwagon? pointd;
+ while (true)
+ {
+ pointd = Banderwagon.FromBytes(rand.NextBytes(32), subgroupCheck: true);
+ if (pointd.HasValue) break;
+ }
+ Banderwagon dd = pointd.Value;
+
+ IpaProofStruct proof = new IpaProofStruct(comm.ToArray()[..8], FrE.One, comm.ToArray()[..8]);
+
+ var outerProof = new WitnessVerkleProof(otherStems.ToArray(), depthExt, comm.ToArray(), dd, proof);
+
+ return new ExecutionWitness(stateDiff, outerProof);
+ }
}
diff --git a/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj b/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj
index 1dac9a82022..e59a8d12b68 100644
--- a/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj
+++ b/src/Nethermind/Nethermind.Core.Test/Nethermind.Core.Test.csproj
@@ -24,6 +24,7 @@
+
diff --git a/src/Nethermind/Nethermind.Core/Account.cs b/src/Nethermind/Nethermind.Core/Account.cs
index 8ed5f59f536..937487ba44a 100644
--- a/src/Nethermind/Nethermind.Core/Account.cs
+++ b/src/Nethermind/Nethermind.Core/Account.cs
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
+using System.Collections.Generic;
+using System.Linq;
using Nethermind.Core.Crypto;
using Nethermind.Int256;
@@ -35,6 +37,30 @@ public Account(UInt256 balance)
CodeHash = Keccak.OfAnEmptyString;
StorageRoot = Keccak.EmptyTreeHash;
IsTotallyEmpty = Balance.IsZero;
+ CodeSize = 0;
+ Version = UInt256.Zero;
+ }
+
+ public Account(UInt256 balance, UInt256 nonce, Keccak codeHash, UInt256 codeSize, UInt256 version)
+ {
+ Balance = balance;
+ Nonce = nonce;
+ CodeHash = codeHash;
+ StorageRoot = Keccak.EmptyTreeHash;
+ IsTotallyEmpty = Balance.IsZero && Nonce == _accountStartNonce && CodeHash == Keccak.OfAnEmptyString && StorageRoot == Keccak.EmptyTreeHash;
+ CodeSize = codeSize;
+ Version = version;
+ }
+
+ public Account(UInt256 balance, UInt256 nonce, Keccak codeHash)
+ {
+ Balance = balance;
+ Nonce = nonce;
+ CodeHash = codeHash;
+ StorageRoot = Keccak.EmptyTreeHash;
+ IsTotallyEmpty = Balance.IsZero && Nonce == _accountStartNonce && CodeHash == Keccak.OfAnEmptyString && StorageRoot == Keccak.EmptyTreeHash;
+ CodeSize = 0;
+ Version = UInt256.Zero;
}
private Account()
@@ -44,6 +70,8 @@ private Account()
CodeHash = Keccak.OfAnEmptyString;
StorageRoot = Keccak.EmptyTreeHash;
IsTotallyEmpty = true;
+ CodeSize = 0;
+ Version = UInt256.Zero;
}
public Account(in UInt256 nonce, in UInt256 balance, Keccak storageRoot, Keccak codeHash)
@@ -53,6 +81,8 @@ public Account(in UInt256 nonce, in UInt256 balance, Keccak storageRoot, Keccak
StorageRoot = storageRoot;
CodeHash = codeHash;
IsTotallyEmpty = Balance.IsZero && Nonce == _accountStartNonce && CodeHash == Keccak.OfAnEmptyString && StorageRoot == Keccak.EmptyTreeHash;
+ CodeSize = 0;
+ Version = UInt256.Zero;
}
private Account(in UInt256 nonce, in UInt256 balance, Keccak storageRoot, Keccak codeHash, bool isTotallyEmpty)
@@ -62,6 +92,8 @@ private Account(in UInt256 nonce, in UInt256 balance, Keccak storageRoot, Keccak
StorageRoot = storageRoot;
CodeHash = codeHash;
IsTotallyEmpty = isTotallyEmpty;
+ CodeSize = 0;
+ Version = UInt256.Zero;
}
public bool HasCode => !CodeHash.Equals(Keccak.OfAnEmptyString);
@@ -70,8 +102,13 @@ private Account(in UInt256 nonce, in UInt256 balance, Keccak storageRoot, Keccak
public UInt256 Nonce { get; }
public UInt256 Balance { get; }
+ public UInt256 CodeSize { get; set; }
+ public UInt256 Version { get; }
public Keccak StorageRoot { get; }
public Keccak CodeHash { get; }
+
+ // TODO: change codeHash when this set
+ public byte[]? Code { get; set; }
public bool IsTotallyEmpty { get; }
public bool IsEmpty => IsTotallyEmpty || (Balance.IsZero && Nonce == _accountStartNonce && CodeHash == Keccak.OfAnEmptyString);
public bool IsContract => CodeHash != Keccak.OfAnEmptyString;
@@ -91,9 +128,14 @@ 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)
{
- return new(Nonce, Balance, StorageRoot, newCodeHash, IsTotallyEmpty && newCodeHash == Keccak.OfAnEmptyString);
+ // TODO: does the code and codeHash match?
+ return new(Nonce, Balance, StorageRoot, newCodeHash, IsTotallyEmpty && newCodeHash == Keccak.OfAnEmptyString)
+ {
+ Code = code,
+ CodeSize = new UInt256((ulong)(code?.Length ?? 0))
+ };
}
}
}
diff --git a/src/Nethermind/Nethermind.Core/Block.cs b/src/Nethermind/Nethermind.Core/Block.cs
index fe2d08fdb8e..306e20ecf39 100644
--- a/src/Nethermind/Nethermind.Core/Block.cs
+++ b/src/Nethermind/Nethermind.Core/Block.cs
@@ -7,6 +7,8 @@
using System.Linq;
using System.Text;
using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Verkle;
using Nethermind.Int256;
namespace Nethermind.Core;
@@ -24,10 +26,11 @@ public Block(
BlockHeader header,
IEnumerable transactions,
IEnumerable uncles,
- IEnumerable? withdrawals = null)
+ IEnumerable? withdrawals = null,
+ ExecutionWitness? execWitness = null)
{
Header = header ?? throw new ArgumentNullException(nameof(header));
- Body = new(transactions.ToArray(), uncles.ToArray(), withdrawals?.ToArray());
+ Body = new(transactions.ToArray(), uncles.ToArray(), withdrawals?.ToArray(), execWitness);
}
public Block(BlockHeader header) : this(
@@ -57,6 +60,7 @@ public Transaction[] Transactions
public BlockHeader[] Uncles => Body.Uncles; // do not add setter here
public Withdrawal[]? Withdrawals => Body.Withdrawals;
+ public ExecutionWitness? ExecutionWitness => Body.ExecutionWitness;
public Keccak? Hash => Header.Hash; // do not add setter here
@@ -147,6 +151,25 @@ private string ToFullString()
builder.Append(w.ToString(" "));
}
+ if (ExecutionWitness is not null)
+ {
+ builder.AppendLine($" ExecutionWitness");
+ builder.AppendLine($" StateDiff: {ExecutionWitness.StateDiff.Count}");
+ builder.AppendLine($" WitnessVerkleProof: {ExecutionWitness.VerkleProof!.D}");
+ builder.AppendLine($" D: {ExecutionWitness.VerkleProof.D.ToBytes().ToHexString()}");
+ builder.AppendLine(
+ $" IpaProof: {ExecutionWitness.VerkleProof.IpaProof.Encode().ToHexString()}");
+ builder.AppendLine(
+ $" ExtensionPresent: {ExecutionWitness.VerkleProof.DepthExtensionPresent.ToHexString()}");
+
+ if(ExecutionWitness.VerkleProof.OtherStems is not null)
+ builder.AppendLine(
+ $" OtherStems: {string.Join(", ", ExecutionWitness.VerkleProof.OtherStems.Select(x => x.ToString()))}");
+
+ builder.AppendLine(
+ $" ExtensionPresent: {string.Join(", ", ExecutionWitness.VerkleProof.CommitmentsByPath.Select(x => x.ToBytes().ToHexString()))}");
+ }
+
return builder.ToString();
}
diff --git a/src/Nethermind/Nethermind.Core/BlockBody.cs b/src/Nethermind/Nethermind.Core/BlockBody.cs
index 76658c6ab8a..8b30ec5175d 100644
--- a/src/Nethermind/Nethermind.Core/BlockBody.cs
+++ b/src/Nethermind/Nethermind.Core/BlockBody.cs
@@ -2,16 +2,18 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using Nethermind.Core.Verkle;
namespace Nethermind.Core
{
public class BlockBody
{
- public BlockBody(Transaction[]? transactions, BlockHeader[]? uncles, Withdrawal[]? withdrawals = null)
+ public BlockBody(Transaction[]? transactions, BlockHeader[]? uncles, Withdrawal[]? withdrawals = null, ExecutionWitness? execWitness = null)
{
Transactions = transactions ?? Array.Empty();
Uncles = uncles ?? Array.Empty();
Withdrawals = withdrawals;
+ ExecutionWitness = execWitness;
}
public BlockBody() : this(null, null, null) { }
@@ -21,6 +23,7 @@ public BlockBody() : this(null, null, null) { }
public BlockBody WithChangedUncles(BlockHeader[] uncles) => new(Transactions, uncles, Withdrawals);
public BlockBody WithChangedWithdrawals(Withdrawal[]? withdrawals) => new(Transactions, Uncles, withdrawals);
+ public BlockBody WithChangedExecutionWitness(ExecutionWitness? witness) => new(Transactions, Uncles, Withdrawals, witness);
public static BlockBody WithOneTransactionOnly(Transaction tx) => new(new[] { tx }, null, null);
@@ -30,6 +33,8 @@ public BlockBody() : this(null, null, null) { }
public Withdrawal[]? Withdrawals { get; }
+ public ExecutionWitness? ExecutionWitness { get; set; }
+
public bool IsEmpty => Transactions.Length == 0 && Uncles.Length == 0 && (Withdrawals?.Length ?? 0) == 0;
}
}
diff --git a/src/Nethermind/Nethermind.Core/BlockHeader.cs b/src/Nethermind/Nethermind.Core/BlockHeader.cs
index 5c0bbcfd529..87ccaac14a3 100644
--- a/src/Nethermind/Nethermind.Core/BlockHeader.cs
+++ b/src/Nethermind/Nethermind.Core/BlockHeader.cs
@@ -3,10 +3,12 @@
using System;
using System.Diagnostics;
+using System.Linq;
using System.Text;
using Nethermind.Core.Attributes;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
+using Nethermind.Core.Verkle;
using Nethermind.Int256;
namespace Nethermind.Core;
@@ -66,10 +68,9 @@ public BlockHeader(
public UInt256 BaseFeePerGas { get; set; }
public Keccak? WithdrawalsRoot { get; set; }
public UInt256? ExcessDataGas { get; set; }
-
public bool HasBody => (TxRoot is not null && TxRoot != Keccak.EmptyTreeHash)
- || (UnclesHash is not null && UnclesHash != Keccak.OfAnEmptySequenceRlp)
- || (WithdrawalsRoot is not null && WithdrawalsRoot != Keccak.EmptyTreeHash);
+ || (UnclesHash is not null && UnclesHash != Keccak.OfAnEmptySequenceRlp)
+ || (WithdrawalsRoot is not null && WithdrawalsRoot != Keccak.EmptyTreeHash);
public bool HasTransactions => (TxRoot is not null && TxRoot != Keccak.EmptyTreeHash);
diff --git a/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs b/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs
index b215e408639..22e99efc3a9 100644
--- a/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs
+++ b/src/Nethermind/Nethermind.Core/Collections/JournalSet.cs
@@ -14,12 +14,24 @@ 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 int TakeSnapshot() => Position;
private int Position => Count - 1;
+ public JournalSet(IEqualityComparer comparer)
+ {
+ _items = new List();
+ _set = new HashSet(comparer);
+ }
+
+ public JournalSet()
+ {
+ _items = new List();
+ _set = new HashSet();
+ }
+
public void Restore(int snapshot)
{
if (snapshot >= Count)
diff --git a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
index 718024991ec..a16109dd7eb 100644
--- a/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
+++ b/src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
@@ -114,6 +114,67 @@ public int Compare(Span x, Span y)
return y.Length > x.Length ? 1 : 0;
}
+
+ public static int CompareDiffLength(Span x, Span y)
+ {
+ if (Unsafe.AreSame(ref MemoryMarshal.GetReference(x), ref MemoryMarshal.GetReference(y)) &&
+ x.Length == y.Length)
+ {
+ return 0;
+ }
+
+ if (x.Length == 0)
+ {
+ return y.Length == 0 ? 0 : -1;
+ }
+
+ for (int i = 0; i < x.Length; i++)
+ {
+ if (y.Length <= i)
+ {
+ return 1;
+ }
+
+ int result = x[i].CompareTo(y[i]);
+ if (result != 0)
+ {
+ return result;
+ }
+ }
+
+ return y.Length > x.Length ? -1 : 0;
+ }
+
+ public int CompareGreaterThan(Span x, Span y)
+ {
+ if (x.Length == 0)
+ {
+ return y.Length == 0 ? 0 : 1;
+ }
+
+ Span ulongX = MemoryMarshal.Cast(x);
+ Span ulongY = MemoryMarshal.Cast(y);
+
+ for (int i = 0; i < ulongX.Length; i++)
+ {
+ if (ulongX[i] > ulongY[i])
+ return 1;
+
+ if (ulongX[i] < ulongY[i])
+ return -1;
+ }
+
+ for (int i = ulongX.Length * Unsafe.SizeOf(); i < x.Length; i++)
+ {
+ if (x[i] > y[i])
+ return 1;
+
+ if (x[i] < y[i])
+ return -1;
+ }
+
+ return y.Length > x.Length ? 1 : 0;
+ }
}
public static readonly byte[] Zero32 = new byte[32];
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..16db18af475 100644
--- a/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs
+++ b/src/Nethermind/Nethermind.Core/Extensions/IntExtensions.cs
@@ -46,5 +46,12 @@ public static byte[] ToBigEndianByteArray(this int value)
return bytes;
}
+
+ public static byte[] ToByteArrayLittleEndian(this int value)
+ {
+ byte[] bytes = new byte[sizeof(int)];
+ BinaryPrimitives.WriteInt32LittleEndian(bytes, value);
+ return bytes;
+ }
}
}
diff --git a/src/Nethermind/Nethermind.Core/IVerkleWitness.cs b/src/Nethermind/Nethermind.Core/IVerkleWitness.cs
new file mode 100644
index 00000000000..bfdcdd0c74c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/IVerkleWitness.cs
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+
+using Nethermind.Int256;
+
+namespace Nethermind.Core;
+
+public interface IVerkleWitness : IJournal
+{
+ public byte[][] GetAccessedKeys();
+ public long AccessForCodeOpCodes(Address caller);
+ public long AccessValueTransfer(Address caller, Address callee);
+
+ public long AccessForContractCreationInit(Address contractAddress, bool isValueTransfer);
+
+ public long AccessContractCreated(Address contractAddress);
+
+ public long AccessBalance(Address address);
+
+ public long AccessCodeHash(Address address);
+
+ public long AccessStorage(Address address, UInt256 key, bool isWrite);
+
+ public long AccessCodeChunk(Address address, byte chunkId, bool isWrite);
+
+ public long AccessCompleteAccount(Address address, bool isWrite = false);
+
+ public long AccessForTransaction(Address originAddress, Address destinationAddress, bool isValueTransfer);
+ public long AccessForProofOfAbsence(Address address);
+}
diff --git a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj
index 5a7b9a74981..5dae6aef221 100644
--- a/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj
+++ b/src/Nethermind/Nethermind.Core/Nethermind.Core.csproj
@@ -8,6 +8,10 @@
true
+
+
+
+
diff --git a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
index 3f1ad4dd96c..f9c6ee6d655 100644
--- a/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
+++ b/src/Nethermind/Nethermind.Core/Specs/IReleaseSpec.cs
@@ -262,6 +262,11 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec
///
bool IsEip4844Enabled { get; }
+ ///
+ /// State - Verkle Trees
+ ///
+ bool IsVerkleTreeEipEnabled { get; }
+
///
/// Should transactions be validated against chainId.
///
@@ -271,8 +276,9 @@ public interface IReleaseSpec : IEip1559Spec, IReceiptSpec
public ulong WithdrawalTimestamp { get; }
public ulong Eip4844TransitionTimestamp { get; }
+ public ulong VerkleTreeTransitionTimeStamp { get; }
- // STATE related
+ // STATE related
public bool ClearEmptyAccountWhenTouched => IsEip158Enabled;
// VM
diff --git a/src/Nethermind/Nethermind.Core/Verkle/AccountHeader.cs b/src/Nethermind/Nethermind.Core/Verkle/AccountHeader.cs
new file mode 100644
index 00000000000..73339edada0
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/AccountHeader.cs
@@ -0,0 +1,71 @@
+using System;
+using Nethermind.Core.Caching;
+using Nethermind.Int256;
+using Nethermind.Verkle.Tree.Utils;
+
+namespace Nethermind.Core.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 const int MainStorageOffsetBase = 256;
+ private const int HeaderStorageOffset = 64;
+ private const int CodeOffset = 128;
+ private const int VerkleNodeWidth = 256;
+
+ private static readonly UInt256 MainStorageOffset = (UInt256)MainStorageOffsetBase << MainStorageOffsetExponent;
+
+ private static readonly LruCache<(byte[], UInt256), Pedersen> _keyCache = new(1000000, 10000, "Verkle Key Cache");
+
+ private static Pedersen GetTreeKeyPrefix(ReadOnlySpan address20, UInt256 treeIndex)
+ {
+ if (_keyCache.TryGet((address20.ToArray(), treeIndex), out Pedersen value)) return value;
+ value = Pedersen.Compute(address20, treeIndex);
+ _keyCache.Set((address20.ToArray(), treeIndex), value);
+ return value;
+ }
+
+ public static Pedersen GetTreeKeyPrefixAccount(byte[] address) => GetTreeKeyPrefix(address, 0);
+
+ public static Pedersen GetTreeKey(byte[] address, UInt256 treeIndex, byte subIndexBytes)
+ {
+ Pedersen treeKeyPrefix = GetTreeKeyPrefix(address, treeIndex);
+ treeKeyPrefix.SuffixByte = subIndexBytes;
+ return treeKeyPrefix;
+ }
+
+ public static Pedersen 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 Pedersen 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.Core/Verkle/CodeChunkEnumerator.cs b/src/Nethermind/Nethermind.Core/Verkle/CodeChunkEnumerator.cs
new file mode 100644
index 00000000000..7f9d2af887a
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/CodeChunkEnumerator.cs
@@ -0,0 +1,99 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+
+namespace Nethermind.Core.Verkle;
+
+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.Core/Verkle/Committer.cs b/src/Nethermind/Nethermind.Core/Verkle/Committer.cs
new file mode 100644
index 00000000000..92041b32712
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/Committer.cs
@@ -0,0 +1,75 @@
+using System.Diagnostics;
+using Nethermind.Verkle.Curve;
+using Nethermind.Verkle.Fields.FrEElement;
+
+namespace Nethermind.Core.Verkle
+{
+ public struct Committer
+ {
+ private static readonly CRS Constants = CRS.Instance;
+
+ public static Banderwagon Commit(FrE[] value)
+ {
+ return Banderwagon.MultiScalarMul(Constants.BasisG, value);
+ }
+
+ public static Banderwagon ScalarMul(FrE value, int index)
+ {
+ return Constants.BasisG[index] * value;
+ }
+ }
+
+ public class Commitment
+ {
+ private FrE? _pointAsField;
+
+ public byte[] ToBytes() => Point.ToBytes();
+
+ 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);
+ }
+
+ private void SetCommitmentToField()
+ {
+ PointAsField = Point.MapToScalarField();
+ }
+
+ public void AddPoint(Banderwagon point)
+ {
+ Point += point;
+ _pointAsField = null;
+ SetCommitmentToField();
+ }
+
+ public FrE UpdateCommitmentGetDelta(Banderwagon point)
+ {
+ FrE prevPointAsField = PointAsField;
+ Point += point;
+ _pointAsField = null;
+ SetCommitmentToField();
+ return PointAsField - prevPointAsField;
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/ExecutionWitness.cs b/src/Nethermind/Nethermind.Core/Verkle/ExecutionWitness.cs
new file mode 100644
index 00000000000..9b3f68acb87
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/ExecutionWitness.cs
@@ -0,0 +1,87 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Collections.Generic;
+using System.Linq;
+using FastEnumUtility;
+using Nethermind.Verkle.Curve;
+using Nethermind.Verkle.Proofs;
+
+namespace Nethermind.Core.Verkle;
+
+
+public class ExecutionWitness
+{
+ public List StateDiff { get; set; } = new(0);
+ public WitnessVerkleProof? VerkleProof { get; set; } = null;
+
+ public ExecutionWitness() { }
+
+ public ExecutionWitness(List stateDiff, WitnessVerkleProof proof)
+ {
+ StateDiff = stateDiff;
+ VerkleProof = proof;
+ }
+}
+
+public class WitnessVerkleProof
+{
+ public Stem[]? OtherStems { get; set; }
+ public byte[] DepthExtensionPresent { get; set; }
+ public Banderwagon[] CommitmentsByPath { get; set; }
+ public Banderwagon D { get; set; }
+ public IpaProofStruct IpaProof { get; set; }
+
+ public WitnessVerkleProof(
+ Stem[] otherStems,
+ byte[] depthExtensionPresent,
+ Banderwagon[] commitmentsByPath,
+ Banderwagon d,
+ IpaProofStruct ipaProof)
+ {
+ OtherStems = otherStems;
+ DepthExtensionPresent = depthExtensionPresent;
+ CommitmentsByPath = commitmentsByPath;
+ D = d;
+ IpaProof = ipaProof;
+ }
+
+ public static implicit operator WitnessVerkleProof(VerkleProof proof)
+ {
+ Stem[] otherStems = proof.VerifyHint.DifferentStemNoProof.Select(x => new Stem(x)).ToArray();
+
+ byte[] depthExtensionPresent = new byte[proof.VerifyHint.ExtensionPresent.Length];
+ for (int i = 0; i < depthExtensionPresent.Length; i++)
+ {
+ depthExtensionPresent[i] = (byte)(proof.VerifyHint.Depths[i] << 3);
+ depthExtensionPresent[i] =
+ (byte)(depthExtensionPresent[i] | (proof.VerifyHint.ExtensionPresent[i].ToByte()));
+ }
+
+ return new WitnessVerkleProof(otherStems,
+ depthExtensionPresent,
+ proof.CommsSorted,
+ proof.Proof.D,
+ proof.Proof.IpaProof
+ );
+ }
+}
+
+
+public struct StateDiff
+{
+ public List SuffixDiffs { get; set; }
+}
+
+public struct StemStateDiff
+{
+ public Stem Stem { get; set; }
+ public List SuffixDiffs { get; set; }
+}
+
+public struct SuffixStateDiff
+{
+ public byte Suffix { get; set; }
+ public byte[]? CurrentValue { get; set; }
+ public byte[]? NewValue { get; set; }
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/Leaf.cs b/src/Nethermind/Nethermind.Core/Verkle/Leaf.cs
new file mode 100644
index 00000000000..3e45f9abf2d
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/Leaf.cs
@@ -0,0 +1,127 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using Nethermind.Core.Extensions;
+
+namespace Nethermind.Core.Verkle;
+
+[DebuggerStepThrough]
+[DebuggerDisplay("{ToString()}")]
+public readonly struct Leaf : IEquatable, IComparable
+{
+ private readonly Vector256 Bytes;
+
+ public const int MemorySize = 32;
+
+ public Span BytesAsSpan => MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref Unsafe.AsRef(in Bytes), 1));
+
+ public ReadOnlySpan Span => MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in Bytes), 1));
+
+ ///
+ /// 0x0000000000000000000000000000000000000000000000000000000000000000
+ ///
+ public static Leaf Zero { get; } = default;
+
+ ///
+ /// 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ ///
+ public static Leaf MaxValue { get; } = new("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+ public Leaf(byte[]? bytes)
+ {
+ if (bytes is null || bytes.Length == 0)
+ {
+ Bytes = default;
+ return;
+ }
+
+ Debug.Assert(bytes.Length == MemorySize);
+ Bytes = Unsafe.As>(ref MemoryMarshal.GetArrayDataReference(bytes));
+ }
+
+ public Leaf(string? hex)
+ {
+ if (hex is null || hex.Length == 0)
+ {
+ Bytes = default;
+ return;
+ }
+
+ byte[] bytes = Nethermind.Core.Extensions.Bytes.FromHexString(hex);
+ Debug.Assert(bytes.Length == MemorySize);
+ Bytes = Unsafe.As>(ref MemoryMarshal.GetArrayDataReference(bytes));
+ }
+
+ public Leaf(Span bytes)
+ : this((ReadOnlySpan)bytes) { }
+
+ public Leaf(ReadOnlySpan bytes)
+ {
+ if (bytes.Length == 0)
+ {
+ Bytes = default;
+ return;
+ }
+
+ Debug.Assert(bytes.Length == Leaf.MemorySize);
+ Bytes = Unsafe.As>(ref MemoryMarshal.GetReference(bytes));
+ }
+
+ public override bool Equals(object? obj) => obj is Leaf leaf && Equals(leaf);
+
+ public bool Equals(Leaf other) => Bytes.Equals(other.Bytes);
+
+ public bool Equals(Pedersen? other) => BytesAsSpan.SequenceEqual(other?.Bytes);
+
+ public override int GetHashCode()
+ {
+ long v0 = Unsafe.As, long>(ref Unsafe.AsRef(in Bytes));
+ long v1 = Unsafe.Add(ref Unsafe.As, long>(ref Unsafe.AsRef(in Bytes)), 1);
+ long v2 = Unsafe.Add(ref Unsafe.As, long>(ref Unsafe.AsRef(in Bytes)), 2);
+ long v3 = Unsafe.Add(ref Unsafe.As, long>(ref Unsafe.AsRef(in Bytes)), 3);
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+
+ public int CompareTo(Leaf other)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(BytesAsSpan, other.BytesAsSpan);
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+
+ public string ToShortString(bool withZeroX = true)
+ {
+ string hash = BytesAsSpan.ToHexString(withZeroX);
+ return $"{hash[..(withZeroX ? 8 : 6)]}...{hash[^6..]}";
+ }
+
+ public string ToString(bool withZeroX)
+ {
+ return BytesAsSpan.ToHexString(withZeroX);
+ }
+
+ public static bool operator ==(Leaf left, Leaf right) => left.Equals(right);
+
+ public static bool operator !=(Leaf left, Leaf right) => !(left == right);
+ public static bool operator >(Leaf left, Leaf right) => left.CompareTo(right) > 0;
+ public static bool operator <(Leaf left, Leaf right) => left.CompareTo(right) < 0;
+ public static bool operator >=(Leaf left, Leaf right) => left.CompareTo(right) >= 0;
+ public static bool operator <=(Leaf left, Leaf right) => left.CompareTo(right) <= 0;
+
+ public Pedersen ToPedersen()
+ {
+ return new Pedersen(BytesAsSpan.ToArray());
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/LeafIterator.cs b/src/Nethermind/Nethermind.Core/Verkle/LeafIterator.cs
new file mode 100644
index 00000000000..a673a260da7
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/LeafIterator.cs
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using LeafEnumerator = System.Collections.Generic.IEnumerator>;
+
+namespace Nethermind.Verkle.Tree.Utils;
+
+public class LeafIterator
+{
+ public LeafIterator(LeafEnumerator enumerator, int priority)
+ {
+ Enumerator = enumerator;
+ Priority = priority;
+ }
+ public readonly LeafEnumerator Enumerator;
+ public readonly int Priority;
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/LeafKey.cs b/src/Nethermind/Nethermind.Core/Verkle/LeafKey.cs
new file mode 100644
index 00000000000..81b201c80fb
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/LeafKey.cs
@@ -0,0 +1,56 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Nethermind.Core.Verkle;
+
+public readonly struct LeafKey: IEquatable, IComparable
+{
+ public byte[] Bytes { get; }
+
+ private LeafKey(byte[] bytes)
+ {
+ Bytes = bytes;
+ }
+
+ public int CompareTo(LeafKey other)
+ {
+ return Core.Extensions.Bytes.Comparer.Compare(Bytes, other.Bytes);
+ }
+
+ public bool Equals(LeafKey other)
+ {
+ if (ReferenceEquals(Bytes, other.Bytes))
+ {
+ return true;
+ }
+
+ if (Bytes is null) return other.Bytes is null;
+
+ return other.Bytes is not null && Core.Extensions.Bytes.AreEqual(Bytes, other.Bytes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is LeafKey key && Equals(key);
+ }
+
+ public override int GetHashCode()
+ {
+ if (Bytes is null) return 0;
+
+ long v0 = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(Bytes));
+ long v1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long)));
+ long v2 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 2));
+ long v3 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 3));
+
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/Pedersen.cs b/src/Nethermind/Nethermind.Core/Verkle/Pedersen.cs
new file mode 100644
index 00000000000..83cdc19a674
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/Pedersen.cs
@@ -0,0 +1,474 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using Nethermind.Core;
+using Nethermind.Core.Extensions;
+using Nethermind.Int256;
+
+namespace Nethermind.Core.Verkle;
+
+[DebuggerStepThrough]
+[DebuggerDisplay("{ToString()}")]
+public readonly struct ValuePedersen : IEquatable, IComparable, IEquatable
+{
+ private readonly Vector256 Bytes;
+
+ public const int MemorySize = 32;
+
+ public Span BytesAsSpan => MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref Unsafe.AsRef(in Bytes), 1));
+
+ public ReadOnlySpan Span => MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in Bytes), 1));
+
+ ///
+ /// 0x0000000000000000000000000000000000000000000000000000000000000000
+ ///
+ public static ValuePedersen Zero { get; } = default;
+
+ ///
+ /// 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ ///
+ public static ValuePedersen MaxValue { get; } = new("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+ public static implicit operator ValuePedersen(Pedersen? keccak)
+ {
+ return new ValuePedersen(keccak?.Bytes);
+ }
+
+ public ValuePedersen(byte[]? bytes)
+ {
+ if (bytes is null || bytes.Length == 0)
+ {
+ Bytes = default;
+ return;
+ }
+
+ Debug.Assert(bytes.Length == MemorySize);
+ Bytes = Unsafe.As>(ref MemoryMarshal.GetArrayDataReference(bytes));
+ }
+
+ public ValuePedersen(string? hex)
+ {
+ if (hex is null || hex.Length == 0)
+ {
+ Bytes = default;
+ return;
+ }
+
+ byte[] bytes = Nethermind.Core.Extensions.Bytes.FromHexString(hex);
+ Debug.Assert(bytes.Length == MemorySize);
+ Bytes = Unsafe.As>(ref MemoryMarshal.GetArrayDataReference(bytes));
+ }
+
+ public ValuePedersen(Span bytes)
+ : this((ReadOnlySpan)bytes) { }
+
+ public ValuePedersen(ReadOnlySpan bytes)
+ {
+ if (bytes.Length == 0)
+ {
+ Bytes = default;
+ return;
+ }
+
+ Debug.Assert(bytes.Length == ValuePedersen.MemorySize);
+ Bytes = Unsafe.As>(ref MemoryMarshal.GetReference(bytes));
+ }
+
+ public override bool Equals(object? obj) => obj is ValuePedersen keccak && Equals(keccak);
+
+ public bool Equals(ValuePedersen other) => Bytes.Equals(other.Bytes);
+
+ public bool Equals(Pedersen? other) => BytesAsSpan.SequenceEqual(other?.Bytes);
+
+ public override int GetHashCode()
+ {
+ long v0 = Unsafe.As, long>(ref Unsafe.AsRef(in Bytes));
+ long v1 = Unsafe.Add(ref Unsafe.As, long>(ref Unsafe.AsRef(in Bytes)), 1);
+ long v2 = Unsafe.Add(ref Unsafe.As, long>(ref Unsafe.AsRef(in Bytes)), 2);
+ long v3 = Unsafe.Add(ref Unsafe.As, long>(ref Unsafe.AsRef(in Bytes)), 3);
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+
+ public int CompareTo(ValuePedersen other)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(BytesAsSpan, other.BytesAsSpan);
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+
+ public string ToShortString(bool withZeroX = true)
+ {
+ string hash = BytesAsSpan.ToHexString(withZeroX);
+ return $"{hash[..(withZeroX ? 8 : 6)]}...{hash[^6..]}";
+ }
+
+ public string ToString(bool withZeroX)
+ {
+ return BytesAsSpan.ToHexString(withZeroX);
+ }
+
+ public static bool operator ==(ValuePedersen left, ValuePedersen right) => left.Equals(right);
+
+ public static bool operator !=(ValuePedersen left, ValuePedersen right) => !(left == right);
+ public static bool operator >(ValuePedersen left, ValuePedersen right) => left.CompareTo(right) > 0;
+ public static bool operator <(ValuePedersen left, ValuePedersen right) => left.CompareTo(right) < 0;
+ public static bool operator >=(ValuePedersen left, ValuePedersen right) => left.CompareTo(right) >= 0;
+ public static bool operator <=(ValuePedersen left, ValuePedersen right) => left.CompareTo(right) <= 0;
+
+ public Pedersen ToPedersen()
+ {
+ return new Pedersen(BytesAsSpan.ToArray());
+ }
+}
+
+///
+/// Used as dictionary key with implicit conversion to de-virtualize comparisons
+///
+[DebuggerStepThrough]
+public readonly struct PedersenKey : IEquatable, IComparable
+{
+ public byte[] Bytes { get; }
+
+ private PedersenKey(byte[] bytes)
+ {
+ Bytes = bytes;
+ }
+
+ public static implicit operator PedersenKey(Pedersen k) => new(k.Bytes);
+
+ public int CompareTo(PedersenKey other)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(Bytes, other.Bytes);
+ }
+
+ public bool Equals(PedersenKey other)
+ {
+ if (ReferenceEquals(Bytes, other.Bytes))
+ {
+ return true;
+ }
+
+ if (Bytes is null)
+ {
+ return other.Bytes is null;
+ }
+
+ if (other.Bytes is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(Bytes, other.Bytes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is PedersenKey key && Equals(key);
+ }
+
+ public override int GetHashCode()
+ {
+ if (Bytes is null) return 0;
+
+ long v0 = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(Bytes));
+ long v1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long)));
+ long v2 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 2));
+ long v3 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 3));
+
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+}
+
+[DebuggerStepThrough]
+public class Pedersen : IEquatable, IComparable
+{
+ public const int Size = 32;
+
+ public const int MemorySize =
+ MemorySizes.SmallObjectOverhead +
+ MemorySizes.RefSize +
+ MemorySizes.ArrayOverhead +
+ Size -
+ MemorySizes.SmallObjectFreeDataSize;
+
+ ///
+ /// 0x0000000000000000000000000000000000000000000000000000000000000000
+ ///
+ public static Pedersen Zero { get; } = new(new byte[Size]);
+
+ ///
+ /// 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ ///
+ public static Pedersen MaxValue { get; } = new("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+ public byte[] Bytes { get; }
+ public ReadOnlySpan BytesAsSpan => Bytes;
+ public ReadOnlySpan StemAsSpan => new(Bytes, 0, 31);
+
+ public ReadOnlySpan NodeKeyAsSpan(int i) => new(Bytes, 0, i);
+
+ public byte SuffixByte
+ {
+ get => Bytes[31];
+ set => Bytes[31] = value;
+ }
+
+ public Pedersen(string hexString)
+ : this(Nethermind.Core.Extensions.Bytes.FromHexString(hexString)) { }
+
+ public Pedersen(byte[] bytes)
+ {
+ if (bytes.Length != Size)
+ {
+ throw new ArgumentException($"{nameof(Pedersen)} must be {Size} bytes and was {bytes.Length} bytes", nameof(bytes));
+ }
+
+ Bytes = bytes.AsSpan().ToArray();
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+
+ public string ToShortString(bool withZeroX = true)
+ {
+ string hash = Bytes.ToHexString(withZeroX);
+ return $"{hash[..(withZeroX ? 8 : 6)]}...{hash[^6..]}";
+ }
+
+ public string ToString(bool withZeroX)
+ {
+ return Bytes.ToHexString(withZeroX);
+ }
+
+ public static implicit operator Pedersen(byte[] bytes)
+ {
+ return new Pedersen(bytes);
+ }
+
+ [DebuggerStepThrough]
+ public static Pedersen Compute(ReadOnlySpan address20, UInt256 treeIndex)
+ {
+ return new Pedersen(PedersenHash.ComputeHashBytes(address20, treeIndex));
+ }
+
+ [DebuggerStepThrough]
+ public static Pedersen Compute(byte[] address20, UInt256 treeIndex)
+ {
+ return new Pedersen(PedersenHash.ComputeHashBytes(address20, treeIndex));
+ }
+
+ public bool Equals(Pedersen? other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(other.Bytes, Bytes);
+ }
+
+ public int CompareTo(Pedersen? other)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(Bytes, other?.Bytes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj?.GetType() == typeof(Pedersen) && Equals((Pedersen)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ long v0 = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(Bytes));
+ long v1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long)));
+ long v2 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 2));
+ long v3 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 3));
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+
+ public static bool operator ==(Pedersen? a, Pedersen? b)
+ {
+ if (a is null)
+ {
+ return b is null;
+ }
+
+ if (b is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(a.Bytes, b.Bytes);
+ }
+
+ public static bool operator !=(Pedersen? a, Pedersen? b)
+ {
+ return !(a == b);
+ }
+
+ public static bool operator >(Pedersen? k1, Pedersen? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) > 0;
+ }
+
+ public static bool operator <(Pedersen? k1, Pedersen? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) < 0;
+ }
+
+ public static bool operator >=(Pedersen? k1, Pedersen? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) >= 0;
+ }
+
+ public static bool operator <=(Pedersen? k1, Pedersen? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) <= 0;
+ }
+
+ public PedersenStructRef ToStructRef() => new(Bytes);
+}
+
+public ref struct PedersenStructRef
+{
+ public const int Size = 32;
+
+ public int MemorySize => MemorySizes.ArrayOverhead + Size;
+
+ public Span Bytes { get; }
+
+ public PedersenStructRef(Span bytes)
+ {
+ if (bytes.Length != Size)
+ {
+ throw new ArgumentException($"{nameof(Pedersen)} must be {Size} bytes and was {bytes.Length} bytes", nameof(bytes));
+ }
+
+ Bytes = bytes;
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+
+ public string ToShortString(bool withZeroX = true)
+ {
+ string hash = Bytes.ToHexString(withZeroX);
+ return $"{hash[..(withZeroX ? 8 : 6)]}...{hash[^6..]}";
+ }
+
+ public string ToString(bool withZeroX)
+ {
+ return Bytes.ToHexString(withZeroX);
+ }
+
+ [DebuggerStepThrough]
+ public static PedersenStructRef Compute(byte[] address20, UInt256 treeIndex)
+ {
+ var result = new PedersenStructRef();
+ PedersenHash.ComputeHashBytesToSpan(address20, treeIndex, result.Bytes);
+ return result;
+ }
+
+ [DebuggerStepThrough]
+ public static PedersenStructRef Compute(ReadOnlySpan address20, UInt256 treeIndex)
+ {
+ var result = new PedersenStructRef();
+ PedersenHash.ComputeHashBytesToSpan(address20, treeIndex, result.Bytes);
+ return result;
+ }
+
+ private static PedersenStructRef InternalCompute(ReadOnlySpan address20, UInt256 treeIndex)
+ {
+ var result = new PedersenStructRef();
+ PedersenHash.ComputeHashBytesToSpan(address20, treeIndex, result.Bytes);
+ return result;
+ }
+
+ public bool Equals(Pedersen? other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(other.Bytes, Bytes);
+ }
+
+ public bool Equals(PedersenStructRef other) => Nethermind.Core.Extensions.Bytes.AreEqual(other.Bytes, Bytes);
+
+ public override bool Equals(object? obj)
+ {
+ return obj?.GetType() == typeof(Pedersen) && Equals((Pedersen)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return MemoryMarshal.Read(Bytes);
+ }
+
+ public static bool operator ==(PedersenStructRef a, Pedersen? b)
+ {
+ if (b is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(a.Bytes, b.Bytes);
+ }
+
+ public static bool operator ==(Pedersen? a, PedersenStructRef b)
+ {
+ if (a is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(a.Bytes, b.Bytes);
+ }
+
+ public static bool operator ==(PedersenStructRef a, PedersenStructRef b)
+ {
+ return Nethermind.Core.Extensions.Bytes.AreEqual(a.Bytes, b.Bytes);
+ }
+
+ public static bool operator !=(PedersenStructRef a, Pedersen b)
+ {
+ return !(a == b);
+ }
+
+ public static bool operator !=(Pedersen a, PedersenStructRef b)
+ {
+ return !(a == b);
+ }
+
+ public static bool operator !=(PedersenStructRef a, PedersenStructRef b)
+ {
+ return !(a == b);
+ }
+
+ public Pedersen ToKeccak() => new(Bytes.ToArray());
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/PedersenHash.cs b/src/Nethermind/Nethermind.Core/Verkle/PedersenHash.cs
new file mode 100644
index 00000000000..22284459901
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/PedersenHash.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Buffers.Binary;
+using System.Runtime.CompilerServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+using Nethermind.Int256;
+using Nethermind.Verkle.Curve;
+using Nethermind.Verkle.Fields.FrEElement;
+
+namespace Nethermind.Core.Verkle;
+
+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 void ComputeHashBytesToSpan(ReadOnlySpan address20, UInt256 treeIndex, Span output)
+ {
+ Hash(address20, treeIndex).CopyTo(output);
+ }
+
+ public static byte[] ComputeHashBytes(ReadOnlySpan address20, UInt256 treeIndex) =>
+ Hash(address20, treeIndex);
+
+ public static byte[] Hash(ReadOnlySpan address20, UInt256 treeIndex)
+ {
+ ulong u0, u1, u2, u3;
+ if (address20.Length == 32)
+ {
+ UInt256 temp = new UInt256(address20);
+ u0 = temp.u0;
+ u1 = temp.u1;
+ u2 = temp.u2;
+ u3 = temp.u3;
+ }
+ else
+ {
+ u0 = 0;
+ Span u1Bytes = new byte[8];
+ address20[..4].CopyTo(u1Bytes[4..]);
+ u1 = BinaryPrimitives.ReadUInt64LittleEndian(u1Bytes);
+ u2 = BinaryPrimitives.ReadUInt64LittleEndian(address20.Slice(4, 8));
+ u3 = BinaryPrimitives.ReadUInt64LittleEndian(address20.Slice(12, 8));
+ }
+
+
+ CRS crs = CRS.Instance;
+
+ Banderwagon res = crs.BasisG[0] * FrE.SetElement(2 + 256 * 64)
+ + crs.BasisG[1] * FrE.SetElement(u0, u1)
+ + crs.BasisG[2] * FrE.SetElement(u2, 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.Core/Verkle/Stem.cs b/src/Nethermind/Nethermind.Core/Verkle/Stem.cs
new file mode 100644
index 00000000000..d8f0395c7fb
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/Stem.cs
@@ -0,0 +1,215 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Nethermind.Core.Extensions;
+
+namespace Nethermind.Core.Verkle;
+
+public unsafe struct ValueStem
+{
+ internal const int Size = 31;
+ public fixed byte Bytes[Size];
+
+ public Span BytesAsSpan => MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref this, 1));
+}
+
+///
+/// Used as dictionary key with implicit conversion to de-virtualize comparisons
+///
+[DebuggerStepThrough]
+public readonly struct StemKey : IEquatable, IComparable
+{
+ public const int Size = 31;
+ public byte[] Bytes { get; }
+
+ private StemKey(byte[] bytes)
+ {
+ if (bytes.Length != Size)
+ {
+ throw new ArgumentException($"{nameof(Stem)} must be {Size} bytes and was {bytes.Length} bytes", nameof(bytes));
+ }
+ Bytes = bytes;
+ }
+
+ public static implicit operator StemKey(Stem k) => new(k.Bytes);
+
+ public int CompareTo(StemKey other)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(Bytes, other.Bytes);
+ }
+
+ public bool Equals(StemKey other)
+ {
+ if (ReferenceEquals(Bytes, other.Bytes))
+ {
+ return true;
+ }
+
+ if (Bytes is null)
+ {
+ return other.Bytes is null;
+ }
+
+ if (other.Bytes is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(Bytes, other.Bytes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj is StemKey key && Equals(key);
+ }
+
+ public override int GetHashCode()
+ {
+ if (Bytes is null) return 0;
+
+ long v0 = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(Bytes));
+ long v1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long)));
+ long v2 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 2));
+ long v3 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 3 - 1));
+ v3 <<= 1; // because one bit extra from previous long
+
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+}
+
+[DebuggerStepThrough]
+public class Stem : IEquatable, IComparable
+{
+ public const int Size = 31;
+
+ ///
+ /// 0x0000000000000000000000000000000000000000000000000000000000000000
+ ///
+ public static Stem Zero { get; } = new(new byte[Size]);
+
+ ///
+ /// 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ ///
+ public static Stem MaxValue { get; } = new("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+ public byte[] Bytes { get; }
+ public ReadOnlySpan BytesAsSpan => Bytes;
+
+ public Stem(string hexString)
+ : this(Core.Extensions.Bytes.FromHexString(hexString)) { }
+
+ public Stem(byte[] bytes)
+ {
+ if (bytes.Length != Size)
+ {
+ throw new ArgumentException($"{nameof(Stem)} must be {Size} bytes and was {bytes.Length} bytes", nameof(bytes));
+ }
+
+ Bytes = bytes;
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+
+ public string ToShortString(bool withZeroX = true)
+ {
+ string hash = Bytes.ToHexString(withZeroX);
+ return $"{hash[..(withZeroX ? 8 : 6)]}...{hash[^6..]}";
+ }
+
+ public string ToString(bool withZeroX)
+ {
+ return Bytes.ToHexString(withZeroX);
+ }
+
+ public static implicit operator Stem(byte[] bytes)
+ {
+ return new Stem(bytes);
+ }
+
+ public bool Equals(Stem? other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(other.Bytes, Bytes);
+ }
+
+ public int CompareTo(Stem? other)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(Bytes, other?.Bytes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj?.GetType() == typeof(Stem) && Equals((Stem)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ long v0 = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(Bytes));
+ long v1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long)));
+ long v2 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 2));
+ long v3 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 3 - 1));
+ v3 <<= 1; // because one bit extra from previous long
+
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+
+ public static bool operator ==(Stem? a, Stem? b)
+ {
+ if (a is null)
+ {
+ return b is null;
+ }
+
+ if (b is null)
+ {
+ return false;
+ }
+
+ return Nethermind.Core.Extensions.Bytes.AreEqual(a.Bytes, b.Bytes);
+ }
+
+ public static bool operator !=(Stem? a, Stem? b)
+ {
+ return !(a == b);
+ }
+
+ public static bool operator >(Stem? k1, Stem? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) > 0;
+ }
+
+ public static bool operator <(Stem? k1, Stem? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) < 0;
+ }
+
+ public static bool operator >=(Stem? k1, Stem? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) >= 0;
+ }
+
+ public static bool operator <=(Stem? k1, Stem? k2)
+ {
+ return Nethermind.Core.Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) <= 0;
+ }
+
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/Structures.cs b/src/Nethermind/Nethermind.Core/Verkle/Structures.cs
new file mode 100644
index 00000000000..9c986dc4885
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/Structures.cs
@@ -0,0 +1,124 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using FastEnumUtility;
+using Nethermind.Core.Collections;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Verkle;
+using Nethermind.Verkle.Curve;
+using Nethermind.Verkle.Fields.FrEElement;
+using Nethermind.Verkle.Proofs;
+using Nethermind.Verkle.Tree.Utils;
+
+namespace Nethermind.Core.Verkle;
+
+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 static VerkleProof Decode(byte[] proof)
+ {
+ return new VerkleProof();
+ }
+}
+
+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 Dictionary DepthAndExtByStem { get; set; }
+ public Dictionary, Banderwagon> CommByPath { get; set; }
+ public SortedDictionary, Stem> DifferentStemNoProof { get; set; }
+}
+
+public enum ExtPresent : byte
+{
+ None = 0,
+ DifferentStem = 1,
+ Present = 2
+}
+
+public struct SuffixPoly
+{
+ public FrE[] C1 { get; set; }
+ public FrE[] C2 { get; set; }
+}
diff --git a/src/Nethermind/Nethermind.Core/Verkle/VerkleCommitment.cs b/src/Nethermind/Nethermind.Core/Verkle/VerkleCommitment.cs
new file mode 100644
index 00000000000..b215d395786
--- /dev/null
+++ b/src/Nethermind/Nethermind.Core/Verkle/VerkleCommitment.cs
@@ -0,0 +1,136 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Nethermind.Core.Extensions;
+
+namespace Nethermind.Core.Verkle;
+
+public class VerkleCommitment: IEquatable, IComparable
+{
+ public const int Size = 32;
+
+ public const int MemorySize =
+ MemorySizes.SmallObjectOverhead +
+ MemorySizes.RefSize +
+ MemorySizes.ArrayOverhead +
+ Size -
+ MemorySizes.SmallObjectFreeDataSize;
+
+ ///
+ /// 0x0000000000000000000000000000000000000000000000000000000000000000
+ ///
+ public static VerkleCommitment Zero { get; } = new(new byte[Size]);
+ public static VerkleCommitment EmptyTreeHash = Zero;
+
+ ///
+ /// 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ ///
+ public static VerkleCommitment MaxValue { get; } = new("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+
+ public byte[] Bytes { get; }
+
+ public VerkleCommitment(string hexString)
+ : this(Extensions.Bytes.FromHexString(hexString)) { }
+
+ public VerkleCommitment(byte[] bytes)
+ {
+ if (bytes.Length != Size)
+ {
+ throw new ArgumentException($"{nameof(VerkleCommitment)} must be {Size} bytes and was {bytes.Length} bytes", nameof(bytes));
+ }
+
+ Bytes = bytes;
+ }
+
+ public override string ToString()
+ {
+ return ToString(true);
+ }
+
+ public string ToShortString(bool withZeroX = true)
+ {
+ string hash = Bytes.ToHexString(withZeroX);
+ return $"{hash[..(withZeroX ? 8 : 6)]}...{hash[^6..]}";
+ }
+
+ public string ToString(bool withZeroX)
+ {
+ return Bytes.ToHexString(withZeroX);
+ }
+
+ public bool Equals(VerkleCommitment? other)
+ {
+ if (other is null)
+ {
+ return false;
+ }
+
+ return Extensions.Bytes.AreEqual(other.Bytes, Bytes);
+ }
+
+ public int CompareTo(VerkleCommitment? other)
+ {
+ return Extensions.Bytes.Comparer.Compare(Bytes, other?.Bytes);
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return obj?.GetType() == typeof(VerkleCommitment) && Equals((VerkleCommitment)obj);
+ }
+
+ public override int GetHashCode()
+ {
+ long v0 = Unsafe.ReadUnaligned(ref MemoryMarshal.GetArrayDataReference(Bytes));
+ long v1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long)));
+ long v2 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 2));
+ long v3 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Bytes), sizeof(long) * 3));
+ v0 ^= v1;
+ v2 ^= v3;
+ v0 ^= v2;
+
+ return (int)v0 ^ (int)(v0 >> 32);
+ }
+
+ public static bool operator ==(VerkleCommitment? a, VerkleCommitment? b)
+ {
+ if (a is null)
+ {
+ return b is null;
+ }
+
+ if (b is null)
+ {
+ return false;
+ }
+
+ return Extensions.Bytes.AreEqual(a.Bytes, b.Bytes);
+ }
+
+ public static bool operator !=(VerkleCommitment? a, VerkleCommitment? b)
+ {
+ return !(a == b);
+ }
+
+ public static bool operator >(VerkleCommitment? k1, VerkleCommitment? k2)
+ {
+ return Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) > 0;
+ }
+
+ public static bool operator <(VerkleCommitment? k1, VerkleCommitment? k2)
+ {
+ return Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) < 0;
+ }
+
+ public static bool operator >=(VerkleCommitment? k1, VerkleCommitment? k2)
+ {
+ return Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) >= 0;
+ }
+
+ public static bool operator <=(VerkleCommitment? k1, VerkleCommitment? k2)
+ {
+ return Extensions.Bytes.Comparer.Compare(k1?.Bytes, k2?.Bytes) <= 0;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs b/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs
index 3bebbc3c727..4a26a7900c7 100644
--- a/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs
+++ b/src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs
@@ -119,6 +119,26 @@ public void Flush()
///
public void Clear() { throw new NotSupportedException(); }
+ public IEnumerable> GetIterator()
+ {
+ using Iterator iterator = _mainDb.CreateIterator(true, _columnFamily);
+ return _mainDb.GetAllCore(iterator);
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ using Iterator iterator = _mainDb.CreateIterator(true, _columnFamily);
+ iterator.Seek(start);
+ return _mainDb.GetAllCore(iterator);
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ using Iterator iterator = _mainDb.CreateIterator(true, _columnFamily);
+ iterator.Seek(start);
+ return _mainDb.GetAllCore(iterator);
+ }
+
private void UpdateWriteMetrics() => _mainDb.UpdateWriteMetrics();
private void UpdateReadMetrics() => _mainDb.UpdateReadMetrics();
diff --git a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
index 1d8dbd20691..913729a4c03 100644
--- a/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
+++ b/src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
@@ -578,6 +578,23 @@ protected internal Iterator CreateIterator(bool ordered = false, ColumnFamilyHan
}
}
+ private Iterator CreateIterator(byte[] start, byte[] end, bool ordered = false, ColumnFamilyHandle? ch = null)
+ {
+ ReadOptions readOptions = new();
+ readOptions.SetTailing(!ordered);
+ readOptions.SetIterateLowerBound(start);
+ readOptions.SetIterateUpperBound(end);
+ try
+ {
+ return _db.NewIterator(ch, readOptions);
+ }
+ catch (RocksDbSharpException e)
+ {
+ CreateMarkerIfCorrupt(e);
+ throw;
+ }
+ }
+
public IEnumerable GetAllValues(bool ordered = false)
{
if (_isDisposing)
@@ -626,6 +643,39 @@ internal IEnumerable GetAllValuesCore(Iterator iterator)
}
}
+ private IEnumerable> GetAllCoreBounded(Iterator iterator)
+ {
+ if (_isDisposing)
+ {
+ throw new ObjectDisposedException($"Attempted to read form a disposed database {Name}");
+ }
+
+ while (iterator.Valid())
+ {
+ yield return new KeyValuePair(iterator.Key(), iterator.Value());
+
+ try
+ {
+ iterator.Next();
+ }
+ catch (RocksDbSharpException e)
+ {
+ CreateMarkerIfCorrupt(e);
+ throw;
+ }
+ }
+
+ try
+ {
+ iterator.Dispose();
+ }
+ catch (RocksDbSharpException e)
+ {
+ CreateMarkerIfCorrupt(e);
+ throw;
+ }
+ }
+
public IEnumerable> GetAllCore(Iterator iterator)
{
if (_isDisposing)
@@ -796,6 +846,25 @@ public void Clear()
Delete();
}
+ public IEnumerable> GetIterator()
+ {
+ Iterator iterator = CreateIterator(true);
+ return GetAllCore(iterator);
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ Iterator iterator = CreateIterator(true);
+ iterator.Seek(start);
+ return GetAllCoreBounded(iterator);
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ Iterator iterator = CreateIterator(start, end, true);
+ return GetAllCoreBounded(iterator);
+ }
+
private void Delete()
{
try
diff --git a/src/Nethermind/Nethermind.Db.Rocks/VerkleDbFactory.cs b/src/Nethermind/Nethermind.Db.Rocks/VerkleDbFactory.cs
new file mode 100644
index 00000000000..4a1ec6401b6
--- /dev/null
+++ b/src/Nethermind/Nethermind.Db.Rocks/VerkleDbFactory.cs
@@ -0,0 +1,65 @@
+using System;
+using System.IO;
+using System.IO.Abstractions;
+using Nethermind.Config;
+using Nethermind.Core;
+using Nethermind.Db.Rocks.Config;
+using Nethermind.Logging;
+
+namespace Nethermind.Db.Rocks
+{
+ public enum DbMode
+ {
+ [ConfigItem(Description = "Diagnostics mode which uses an in-memory DB")]
+ MemDb,
+ [ConfigItem(Description = "Diagnostics mode which uses an Persistant DB")]
+ PersistantDb,
+ [ConfigItem(Description = "Diagnostics mode which uses a read-only DB")]
+ ReadOnlyDb
+ }
+
+ public class VerkleDbFactory
+ {
+ private static (IDbProvider DbProvider, RocksDbFactory RocksDbFactory, MemDbFactory MemDbFactory) InitDbApi(DbMode diagnosticMode, string baseDbPath, bool storeReceipts)
+ {
+ DbConfig dbConfig = new DbConfig();
+ DisposableStack disposeStack = new DisposableStack();
+ IDbProvider dbProvider;
+ RocksDbFactory rocksDbFactory;
+ MemDbFactory memDbFactory;
+ switch (diagnosticMode)
+ {
+ case DbMode.ReadOnlyDb:
+ DbProvider rocksDbProvider = new DbProvider(DbModeHint.Persisted);
+ dbProvider = new ReadOnlyDbProvider(rocksDbProvider, storeReceipts); // ToDo storeReceipts as createInMemoryWriteStore - bug?
+ disposeStack.Push(rocksDbProvider);
+ rocksDbFactory = new RocksDbFactory(dbConfig, NullLogManager.Instance, Path.Combine(baseDbPath, "debug"));
+ memDbFactory = new MemDbFactory();
+ break;
+ case DbMode.MemDb:
+ dbProvider = new DbProvider(DbModeHint.Mem);
+ rocksDbFactory = new RocksDbFactory(dbConfig, NullLogManager.Instance, Path.Combine(baseDbPath, "debug"));
+ memDbFactory = new MemDbFactory();
+ break;
+ case DbMode.PersistantDb:
+ dbProvider = new DbProvider(DbModeHint.Persisted);
+ rocksDbFactory = new RocksDbFactory(dbConfig, NullLogManager.Instance, baseDbPath);
+ memDbFactory = new MemDbFactory();
+ break;
+ default:
+ throw new ArgumentException();
+
+ }
+
+ return (dbProvider, rocksDbFactory, memDbFactory);
+ }
+
+ public static IDbProvider InitDatabase(DbMode dbMode, string? dbPath)
+ {
+ (IDbProvider dbProvider, RocksDbFactory rocksDbFactory, MemDbFactory memDbFactory) = InitDbApi(dbMode, dbPath ?? "testDb", true);
+ StandardDbInitializer dbInitializer = new StandardDbInitializer(dbProvider, rocksDbFactory, memDbFactory, new FileSystem());
+ dbInitializer.InitStandardDbs(true);
+ return dbProvider;
+ }
+ }
+}
diff --git a/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs b/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs
index eb7e7cf258e..5a3107c449c 100644
--- a/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs
+++ b/src/Nethermind/Nethermind.Db.Rpc/RpcDb.cs
@@ -74,6 +74,20 @@ public bool KeyExists(ReadOnlySpan key)
public IDb Innermost => this; // record db is just a helper DB here
public void Flush() { }
public void Clear() { }
+ public IEnumerable> GetIterator()
+ {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ throw new NotImplementedException();
+ }
public IEnumerable> GetAll(bool ordered = false) => _recordDb.GetAll();
diff --git a/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs b/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs
index 96879227c90..5c5f3ef14d5 100644
--- a/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs
+++ b/src/Nethermind/Nethermind.Db.Test/DbOnTheRocksTests.cs
@@ -25,6 +25,8 @@ namespace Nethermind.Db.Test
[Parallelizable(ParallelScope.None)]
public class DbOnTheRocksTests
{
+ public static Random Random { get; } = new();
+
[Test]
public void Smoke_test()
{
@@ -70,6 +72,34 @@ public void Can_get_all_on_empty()
}
}
+ [Test]
+ public void RangeIteratorTest()
+ {
+ IDbConfig config = new DbConfig();
+ DbOnTheRocks db = new("testRangeIterator1", GetRocksDbSettings("testRangeIterator1", "TestRangeIterator1"),
+ config, LimboLogs.Instance);
+
+ byte[] key = new byte[32];
+ byte[] value = new byte[32];
+
+ Random.NextBytes(key);
+ Random.NextBytes(value);
+
+ for (int i = 0; i < 10000; i++)
+ {
+ Random.NextBytes(key);
+ Random.NextBytes(value);
+ db.Set(key, value.AsSpan().ToArray());
+ }
+
+ var xx = db.GetIterator();
+
+ foreach (KeyValuePair x in xx)
+ {
+ Console.WriteLine($"Key:{x.Key.ToHexString()} Value:{x.Value.ToHexString()}");
+ }
+ }
+
[Test]
public async Task Dispose_while_writing_does_not_cause_access_violation_exception()
{
diff --git a/src/Nethermind/Nethermind.Db/CompressingDb.cs b/src/Nethermind/Nethermind.Db/CompressingDb.cs
index 5ca39059933..fe13fa2d787 100644
--- a/src/Nethermind/Nethermind.Db/CompressingDb.cs
+++ b/src/Nethermind/Nethermind.Db/CompressingDb.cs
@@ -130,6 +130,20 @@ public IEnumerable GetAllValues(bool ordered = false) =>
public void Flush() => _wrapped.Flush();
public void Clear() => _wrapped.Clear();
+ public IEnumerable> GetIterator()
+ {
+ return _wrapped.GetIterator();
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ return _wrapped.GetIterator(start);
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ return _wrapped.GetIterator(start, end);
+ }
public long GetSize() => _wrapped.GetSize();
diff --git a/src/Nethermind/Nethermind.Db/DbNames.cs b/src/Nethermind/Nethermind.Db/DbNames.cs
index a0f4652b6eb..e374436abef 100644
--- a/src/Nethermind/Nethermind.Db/DbNames.cs
+++ b/src/Nethermind/Nethermind.Db/DbNames.cs
@@ -16,5 +16,11 @@ public static class DbNames
public const string Witness = "witness";
public const string CHT = "canonicalHashTrie";
public const string Metadata = "metadata";
+ public const string Leaf = "leaf";
+ public const string InternalNodes = "internalNodes";
+ public const string ForwardDiff = "forwardDiff";
+ public const string ReverseDiff = "reverseDiff";
+ public const string Preimages = "preimages";
+ public const string StateRootToBlock = "stateRoots";
}
}
diff --git a/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs b/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs
index f94f7b27dd4..475306b0497 100755
--- a/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs
+++ b/src/Nethermind/Nethermind.Db/FullPruning/FullPruningDb.cs
@@ -130,6 +130,21 @@ public void Clear()
cloningDb?.Clear();
}
+ public IEnumerable> GetIterator()
+ {
+ return _currentDb.GetIterator();
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ return _currentDb.GetIterator(start);
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ return _currentDb.GetIterator(start, end);
+ }
+
///
public bool CanStartPruning => _pruningContext is null; // we can start pruning only if no pruning is in progress
diff --git a/src/Nethermind/Nethermind.Db/IDb.cs b/src/Nethermind/Nethermind.Db/IDb.cs
index 9cff4079e90..34bd1b86fb3 100644
--- a/src/Nethermind/Nethermind.Db/IDb.cs
+++ b/src/Nethermind/Nethermind.Db/IDb.cs
@@ -25,5 +25,9 @@ public interface IDb : IKeyValueStoreWithBatching, IDisposable
void Clear();
public IReadOnlyDb CreateReadOnly(bool createInMemWriteStore) => new ReadOnlyDb(this, createInMemWriteStore);
+
+ public IEnumerable> GetIterator();
+ public IEnumerable> GetIterator(byte[] start);
+ public IEnumerable> GetIterator(byte[] start, byte[] end);
}
}
diff --git a/src/Nethermind/Nethermind.Db/IDbProvider.cs b/src/Nethermind/Nethermind.Db/IDbProvider.cs
index 5625941f1f5..e2d91387818 100644
--- a/src/Nethermind/Nethermind.Db/IDbProvider.cs
+++ b/src/Nethermind/Nethermind.Db/IDbProvider.cs
@@ -32,6 +32,13 @@ public interface IDbProvider : IDisposable
public IDb MetadataDb => GetDb(DbNames.Metadata);
+ public IDb LeafDb => GetDb(DbNames.Leaf);
+ public IDb InternalNodesDb => GetDb(DbNames.InternalNodes);
+
+ 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.Db/MemDb.cs b/src/Nethermind/Nethermind.Db/MemDb.cs
index 79c56952cd7..43665b6e009 100644
--- a/src/Nethermind/Nethermind.Db/MemDb.cs
+++ b/src/Nethermind/Nethermind.Db/MemDb.cs
@@ -19,23 +19,27 @@ public class MemDb : IFullDb, IDbWithSpan
public long ReadsCount { get; private set; }
public long WritesCount { get; private set; }
+ private readonly SortedSet? _sortedKeys;
private readonly SpanConcurrentDictionary _db;
- public MemDb(string name)
- : this(0, 0)
+ public MemDb(string name, bool sorted = false)
+ : this(0, 0, sorted)
{
Name = name;
}
- public MemDb() : this(0, 0)
+ public MemDb(bool sorted = false) : this(0, 0, sorted)
{
+ Name = "";
}
- public MemDb(int writeDelay, int readDelay)
+ public MemDb(int writeDelay, int readDelay, bool sorted = false)
{
+ Name = "";
_writeDelay = writeDelay;
_readDelay = readDelay;
_db = new SpanConcurrentDictionary(Bytes.SpanEqualityComparer);
+ if (sorted) _sortedKeys = new SortedSet(Bytes.Comparer);
}
public string Name { get; }
@@ -69,6 +73,7 @@ public KeyValuePair[] this[byte[][] keys]
public virtual void Remove(ReadOnlySpan key)
{
_db.TryRemove(key, out _);
+ _sortedKeys?.Remove(key.ToArray());
}
public bool KeyExists(ReadOnlySpan key)
@@ -85,11 +90,63 @@ public void Flush()
public void Clear()
{
_db.Clear();
+ _sortedKeys?.Clear();
}
- public IEnumerable> GetAll(bool ordered = false) => _db;
+ public virtual IEnumerable> GetIterator()
+ {
+ if (_sortedKeys is null) throw new ArgumentException($"cannot get ordered data");
+ using SortedSet.Enumerator keyEnumerator = _sortedKeys.GetEnumerator();
+ while (keyEnumerator.MoveNext())
+ yield return new KeyValuePair(keyEnumerator.Current, Get(keyEnumerator.Current));
+ }
+
+ public virtual IEnumerable> GetIterator(byte[] start)
+ {
+ if (_sortedKeys is null) throw new ArgumentException($"cannot get ordered data");
+ return GetIterator(start, _sortedKeys.Max);
+ }
+
+ public virtual IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ if (_sortedKeys is null) throw new ArgumentException($"cannot get ordered data");
+ using SortedSet.Enumerator keyEnumerator = _sortedKeys
+ .GetViewBetween(start, end)
+ .GetEnumerator();
+
+ while (keyEnumerator.MoveNext())
+ yield return new KeyValuePair(keyEnumerator.Current, Get(keyEnumerator.Current));
+ }
+
+ public IEnumerable> GetAll(bool ordered = false)
+ {
+ return ordered ? GetAllSortedIterator() : _db;
+ }
- public IEnumerable GetAllValues(bool ordered = false) => Values;
+ private IEnumerable> GetAllSortedIterator()
+ {
+ if (_sortedKeys is null) throw new ArgumentException($"cannot get ordered data");
+ using SortedSet.Enumerator iterator = _sortedKeys.GetEnumerator();
+ while (iterator.MoveNext())
+ {
+ yield return new KeyValuePair(iterator.Current, _db[iterator.Current!]);
+ }
+ }
+
+ private IEnumerable GetAllValuesSortedIterator()
+ {
+ if (_sortedKeys is null) throw new ArgumentException($"cannot get ordered data");
+ using SortedSet.Enumerator iterator = _sortedKeys.GetEnumerator();
+ while (iterator.MoveNext())
+ {
+ yield return _db[iterator.Current!];
+ }
+ }
+
+ public IEnumerable GetAllValues(bool ordered = false)
+ {
+ return ordered ? GetAllValuesSortedIterator() : Values;
+ }
public virtual IBatch StartBatch()
{
@@ -144,6 +201,7 @@ public virtual void Set(ReadOnlySpan key, byte[]? value, WriteFlags flags
WritesCount++;
_db[key] = value;
+ _sortedKeys?.Add(key.ToArray());
}
}
}
diff --git a/src/Nethermind/Nethermind.Db/MemDbFactory.cs b/src/Nethermind/Nethermind.Db/MemDbFactory.cs
index fa7510ef645..de017419a72 100644
--- a/src/Nethermind/Nethermind.Db/MemDbFactory.cs
+++ b/src/Nethermind/Nethermind.Db/MemDbFactory.cs
@@ -7,6 +7,6 @@ public class MemDbFactory : IMemDbFactory
{
public IColumnsDb CreateColumnsDb(string dbName) => new MemColumnsDb(dbName);
- public IDb CreateDb(string dbName) => new MemDb(dbName);
+ public IDb CreateDb(string dbName) => new MemDb(dbName, true);
}
}
diff --git a/src/Nethermind/Nethermind.Db/Metrics.cs b/src/Nethermind/Nethermind.Db/Metrics.cs
index 9952dd6f773..487c889e69a 100644
--- a/src/Nethermind/Nethermind.Db/Metrics.cs
+++ b/src/Nethermind/Nethermind.Db/Metrics.cs
@@ -118,6 +118,62 @@ public static class Metrics
[Description("Number of Metadata DB writes.")]
public static long MetadataDbWrites { get; set; }
+ [CounterMetric]
+ [Description("Number of Leaf DB reads.")]
+ public static long LeafDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Leaf DB writes.")]
+ public static long LeafDbWrites { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Stem DB reads.")]
+ public static long StemDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Stem DB writes.")]
+ public static long StemDbWrites { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Branch DB reads.")]
+ public static long BranchDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Branch DB writes.")]
+ public static long BranchDbWrites { get; set; }
+
+ [CounterMetric]
+ [Description("Number of ForwardDiff DB reads.")]
+ public static long ForwardDiffDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of ForwardDiff DB writes.")]
+ public static long ForwardDiffDbWrites { get; set; }
+
+ [CounterMetric]
+ [Description("Number of ReverseDiff DB reads.")]
+ public static long ReverseDiffDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of ReverseDiff DB writes.")]
+ public static long ReverseDiffDbWrites { get; set; }
+
+ [CounterMetric]
+ [Description("Number of StateRootToBlock DB reads.")]
+ public static long StateRootToBlockDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of StateRootToBlock DB writes.")]
+ public static long StateRootToBlockDbWrites { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Preimages DB reads.")]
+ public static long PreimagesDbReads { get; set; }
+
+ [CounterMetric]
+ [Description("Number of Preimages DB writes.")]
+ public static long PreimagesDbWrites { get; set; }
+
[GaugeMetric]
[Description("Indicator if StadeDb is being pruned.")]
public static int StateDbPruning { get; set; }
diff --git a/src/Nethermind/Nethermind.Db/NullDb.cs b/src/Nethermind/Nethermind.Db/NullDb.cs
index 4c39c9da25c..7caf75a290a 100644
--- a/src/Nethermind/Nethermind.Db/NullDb.cs
+++ b/src/Nethermind/Nethermind.Db/NullDb.cs
@@ -51,6 +51,20 @@ public bool KeyExists(ReadOnlySpan key)
public IDb Innermost => this;
public void Flush() { }
public void Clear() { }
+ public IEnumerable> GetIterator()
+ {
+ yield break;
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ yield break;
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ yield break;
+ }
public IEnumerable> GetAll(bool ordered = false) => Enumerable.Empty>();
diff --git a/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs b/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs
index fe54b92e6fa..73a0caec256 100644
--- a/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs
+++ b/src/Nethermind/Nethermind.Db/ReadOnlyDb.cs
@@ -90,6 +90,21 @@ public void Flush()
public void Clear() { throw new InvalidOperationException(); }
+ public IEnumerable> GetIterator()
+ {
+ return _wrappedDb.GetIterator();
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ return _wrappedDb.GetIterator(start);
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ return _wrappedDb.GetIterator(start, end);
+ }
+
public virtual void ClearTempChanges()
{
_memDb.Clear();
diff --git a/src/Nethermind/Nethermind.Db/SimpleFilePublicKeyDb.cs b/src/Nethermind/Nethermind.Db/SimpleFilePublicKeyDb.cs
index 4e607a4a745..4cc0841b3e9 100644
--- a/src/Nethermind/Nethermind.Db/SimpleFilePublicKeyDb.cs
+++ b/src/Nethermind/Nethermind.Db/SimpleFilePublicKeyDb.cs
@@ -98,6 +98,21 @@ public void Clear()
File.Delete(DbPath);
}
+ public IEnumerable> GetIterator()
+ {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable> GetIterator(byte[] start)
+ {
+ throw new NotImplementedException();
+ }
+
+ public IEnumerable> GetIterator(byte[] start, byte[] end)
+ {
+ throw new NotImplementedException();
+ }
+
public IEnumerable> GetAll(bool ordered = false) => _cache;
public IEnumerable GetAllValues(bool ordered = false) => _cache.Values;
diff --git a/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs b/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs
index 8f5f0d7f199..e32c6a7c585 100644
--- a/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs
+++ b/src/Nethermind/Nethermind.Db/StandardDbInitializer.cs
@@ -65,6 +65,13 @@ private void RegisterAll(bool useReceiptsDb)
RegisterCustomDb(DbNames.Receipts, () => new ReadOnlyColumnsDb(new MemColumnsDb(), false));
}
RegisterDb(BuildRocksDbSettings(DbNames.Metadata, () => Metrics.MetadataDbReads++, () => Metrics.MetadataDbWrites++));
+ // TODO: convert this to two column families
+ RegisterDb(BuildRocksDbSettings(DbNames.Leaf, () => Metrics.LeafDbReads++, () => Metrics.LeafDbWrites++));
+ RegisterDb(BuildRocksDbSettings(DbNames.InternalNodes, () => Metrics.BranchDbReads++, () => Metrics.BranchDbWrites++));
+ RegisterDb(BuildRocksDbSettings(DbNames.ForwardDiff, () => Metrics.ForwardDiffDbReads++, () => Metrics.ForwardDiffDbWrites++));
+ RegisterDb(BuildRocksDbSettings(DbNames.ReverseDiff, () => Metrics.ReverseDiffDbReads++, () => Metrics.ReverseDiffDbWrites++));
+ RegisterDb(BuildRocksDbSettings(DbNames.StateRootToBlock, () => Metrics.StateRootToBlockDbReads++, () => Metrics.StateRootToBlockDbWrites++));
+ RegisterDb(BuildRocksDbSettings(DbNames.Preimages, () => Metrics.PreimagesDbReads++, () => Metrics.PreimagesDbWrites++));
}
private RocksDbSettings BuildRocksDbSettings(string dbName, Action updateReadsMetrics, Action updateWriteMetrics, bool deleteOnStart = false)
diff --git a/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeDataAnalyzerHelperTests.cs b/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeDataAnalyzerHelperTests.cs
index 729e432b1cf..adec2f7d36f 100644
--- a/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeDataAnalyzerHelperTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/CodeAnalysis/CodeDataAnalyzerHelperTests.cs
@@ -20,7 +20,7 @@ public void Validate_CodeBitmap_With_Push10()
(byte)Instruction.JUMPDEST
};
- var bitmap = CodeDataAnalyzerHelper.CreateCodeBitmap(code);
+ var bitmap = CodeDataAnalyzerHelper.CreateCodeBitmap(new ByteCode(code));
bitmap[0].Should().Be(127);
bitmap[1].Should().Be(224);
}
@@ -35,7 +35,7 @@ public void Validate_CodeBitmap_With_Push30()
(byte)Instruction.JUMPDEST
};
- var bitmap = CodeDataAnalyzerHelper.CreateCodeBitmap(code);
+ var bitmap = CodeDataAnalyzerHelper.CreateCodeBitmap(new ByteCode(code));
bitmap[0].Should().Be(127);
bitmap[1].Should().Be(255);
bitmap[2].Should().Be(255);
diff --git a/src/Nethermind/Nethermind.Evm.Test/CodeTests.cs b/src/Nethermind/Nethermind.Evm.Test/CodeTests.cs
new file mode 100644
index 00000000000..6a5f97cb73d
--- /dev/null
+++ b/src/Nethermind/Nethermind.Evm.Test/CodeTests.cs
@@ -0,0 +1,69 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using FluentAssertions;
+using Nethermind.Core.Extensions;
+using Nethermind.Core.Test.Builders;
+using Nethermind.Db;
+using Nethermind.Evm.CodeAnalysis;
+using Nethermind.Int256;
+using Nethermind.Logging;
+using Nethermind.Specs;
+using Nethermind.Specs.Forks;
+using Nethermind.State;
+using NUnit.Framework;
+
+namespace Nethermind.Evm.Test;
+
+[TestFixture]
+public class CodeTests
+{
+ [Test]
+ public void ICodeTests()
+ {
+ TestSpecProvider specProvider = new (Prague.Instance);
+ VerkleStateTree tree = TestItem.Tree.GetVerkleStateTree(null);
+ MemDb codeDb = new ();
+ VerkleWorldState worldState = new (tree, codeDb, LimboLogs.Instance);
+
+ byte[] code = new byte[2000];
+ TestItem.Random.NextBytes(code);
+
+ worldState.CreateAccount(TestItem.AddressA, 200000);
+ worldState.CreateAccount(TestItem.AddressB, 200000);
+ worldState.Commit(specProvider.SpecToReturn);
+ worldState.InsertCode(TestItem.AddressA, code, specProvider.SpecToReturn, false);
+ worldState.Commit(specProvider.SpecToReturn);
+ worldState.CommitTree(0);
+
+ ByteCode byteCode = new (code);
+ VerkleCode verkleCode = new (worldState, TestItem.AddressA);
+
+ Assert.IsTrue(byteCode.Length == verkleCode.Length);
+
+ byte[] byteCodeBytes = byteCode.ToBytes();
+ byte[] verkleCodeBytes = verkleCode.ToBytes();
+ byteCodeBytes.Should().BeEquivalentTo(verkleCodeBytes);
+
+ for (int i = 0; i < code.Length; i++) AssetEqualSlice(byteCode, verkleCode, i, code.Length);
+ for (int i = 0; i < code.Length; i++) AssetEqualZeroPaddedSpan(byteCode, verkleCode, i, code.Length);
+ }
+
+ private void AssetEqualSlice(ByteCode byteCode, VerkleCode verkleCode, int start, int length)
+ {
+ Span byteCodeSlice = byteCode.Slice(start, Math.Min(length - start, length));
+ Span verkleCodeSlice = verkleCode.Slice(start, Math.Min(length - start, length));
+ byteCodeSlice.ToArray().Should().BeEquivalentTo(verkleCodeSlice.ToArray());
+ }
+
+ private void AssetEqualZeroPaddedSpan(ByteCode byteCode, VerkleCode verkleCode, int start, int length)
+ {
+ ZeroPaddedSpan byteCodeSlice = byteCode.SliceWithZeroPadding((UInt256)start, length);
+ ZeroPaddedSpan verkleCodeSlice = verkleCode.SliceWithZeroPadding((UInt256)start, length);
+ Assert.IsTrue(byteCodeSlice.Length == verkleCodeSlice.Length);
+ Assert.IsTrue(byteCodeSlice.PaddingLength == verkleCodeSlice.PaddingLength);
+ Assert.IsTrue(byteCodeSlice.PadDirection == verkleCodeSlice.PadDirection);
+ Assert.IsTrue(byteCodeSlice.Span.SequenceEqual(verkleCodeSlice.Span));
+ }
+}
diff --git a/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs b/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs
index 64bfc890bba..e5992dee8ba 100644
--- a/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/IntrinsicGasCalculatorTests.cs
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.IO;
using FluentAssertions;
using Nethermind.Core;
@@ -12,6 +11,7 @@
using Nethermind.Core.Test.Builders;
using Nethermind.Int256;
using Nethermind.Specs.Forks;
+using Nethermind.Verkle.Tree;
using NUnit.Framework;
namespace Nethermind.Evm.Test
@@ -19,6 +19,7 @@ namespace Nethermind.Evm.Test
[TestFixture]
public class IntrinsicGasCalculatorTests
{
+ private const long IntrinsicWitnessGasCode = 13300;
public static IEnumerable<(Transaction Tx, long cost, string Description)> TestCaseSource()
{
yield return (Build.A.Transaction.SignedAndResolved().TestObject, 21000, "empty");
@@ -46,6 +47,8 @@ public class IntrinsicGasCalculatorTests
public void Intrinsic_cost_is_calculated_properly((Transaction Tx, long Cost, string Description) testCase)
{
IntrinsicGasCalculator.Calculate(testCase.Tx, Berlin.Instance).Should().Be(testCase.Cost);
+ VerkleWitness witness = new VerkleWitness();
+ IntrinsicGasCalculator.Calculate(testCase.Tx, Prague.Instance, ref witness).Should().Be(testCase.Cost + IntrinsicWitnessGasCode);
}
[TestCaseSource(nameof(AccessTestCaseSource))]
@@ -75,7 +78,15 @@ void Test(IReleaseSpec spec, bool supportsAccessLists)
}
else
{
- IntrinsicGasCalculator.Calculate(tx, spec).Should().Be(21000 + testCase.Cost, spec.Name);
+ if (spec.IsVerkleTreeEipEnabled)
+ {
+ VerkleWitness witness = new VerkleWitness();
+ IntrinsicGasCalculator.Calculate(tx, spec, ref witness).Should().Be(21000 + IntrinsicWitnessGasCode + testCase.Cost, spec.Name);
+ }
+ else
+ {
+ IntrinsicGasCalculator.Calculate(tx, spec).Should().Be(21000 + testCase.Cost, spec.Name);
+ }
}
}
@@ -89,6 +100,7 @@ void Test(IReleaseSpec spec, bool supportsAccessLists)
Test(Istanbul.Instance, false);
Test(MuirGlacier.Instance, false);
Test(Berlin.Instance, true);
+ Test(Prague.Instance, true);
}
[TestCaseSource(nameof(DataTestCaseSource))]
@@ -98,9 +110,23 @@ public void Intrinsic_cost_of_data_is_calculated_properly((byte[] Data, int OldC
void Test(IReleaseSpec spec, bool isAfterRepricing)
{
- IntrinsicGasCalculator.Calculate(tx, spec).Should()
- .Be(21000 + (isAfterRepricing ? testCase.NewCost : testCase.OldCost), spec.Name,
- testCase.Data.ToHexString());
+ long expectedGas = 21000 + (isAfterRepricing ? testCase.NewCost : testCase.OldCost);
+ long actualGas;
+ switch (spec.IsVerkleTreeEipEnabled)
+ {
+ case true:
+ expectedGas += IntrinsicWitnessGasCode;
+ VerkleWitness witness = new VerkleWitness();
+ actualGas = IntrinsicGasCalculator.Calculate(tx, spec, ref witness);
+ break;
+ case false:
+ actualGas = IntrinsicGasCalculator.Calculate(tx, spec);
+ break;
+ }
+
+ actualGas.Should()
+ .Be(expectedGas, spec.Name, testCase.Data.ToHexString());
+
}
Test(Homestead.Instance, false);
@@ -113,6 +139,7 @@ void Test(IReleaseSpec spec, bool isAfterRepricing)
Test(Istanbul.Instance, true);
Test(MuirGlacier.Instance, true);
Test(Berlin.Instance, true);
+ Test(Prague.Instance, true);
}
}
}
diff --git a/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj b/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj
index ad6a02a3d0c..a848891235f 100644
--- a/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj
+++ b/src/Nethermind/Nethermind.Evm.Test/Nethermind.Evm.Test.csproj
@@ -25,6 +25,7 @@
+
diff --git a/src/Nethermind/Nethermind.Evm.Test/SModTests.cs b/src/Nethermind/Nethermind.Evm.Test/SModTests.cs
index 17b2f524b65..9a5d4887485 100644
--- a/src/Nethermind/Nethermind.Evm.Test/SModTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/SModTests.cs
@@ -2,12 +2,20 @@
// SPDX-License-Identifier: LGPL-3.0-only
using Nethermind.Int256;
+using Nethermind.State;
using NUnit.Framework;
namespace Nethermind.Evm.Test
{
+ [TestFixture(StateType.Merkle)]
+ [TestFixture(StateType.Verkle)]
public class SModTests : VirtualMachineTestsBase
{
+ public SModTests(StateType stateType): base(stateType)
+ {
+
+ }
+
[TestCase(1, 1, 0)]
[TestCase(1, 0, 0)]
[TestCase(1, -1, 0)]
diff --git a/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs b/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs
index f648b10f041..c59d51ca16a 100644
--- a/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/SimdTests.cs
@@ -6,19 +6,22 @@
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
using Nethermind.Specs;
+using Nethermind.State;
using NUnit.Framework;
namespace Nethermind.Evm.Test
{
- [TestFixture(true)]
- [TestFixture(false)]
+ [TestFixture(true, StateType.Merkle)]
+ [TestFixture(false, StateType.Merkle)]
+ [TestFixture(true, StateType.Verkle)]
+ [TestFixture(false, StateType.Verkle)]
[Parallelizable(ParallelScope.Self)]
public class SimdTests : VirtualMachineTestsBase
{
private readonly bool _simdDisabled;
protected override long BlockNumber => MainnetSpecProvider.ConstantinopleFixBlockNumber;
- public SimdTests(bool simdDisabled)
+ public SimdTests(bool simdDisabled, StateType stateType): base(stateType)
{
_simdDisabled = simdDisabled;
}
diff --git a/src/Nethermind/Nethermind.Evm.Test/SltTests.cs b/src/Nethermind/Nethermind.Evm.Test/SltTests.cs
index 3e62d281eda..e67c5d7225a 100644
--- a/src/Nethermind/Nethermind.Evm.Test/SltTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/SltTests.cs
@@ -2,12 +2,20 @@
// SPDX-License-Identifier: LGPL-3.0-only
using Nethermind.Int256;
+using Nethermind.State;
using NUnit.Framework;
namespace Nethermind.Evm.Test
{
+
+ [TestFixture(StateType.Merkle)]
+ [TestFixture(StateType.Verkle)]
public class SltTests : VirtualMachineTestsBase
{
+ public SltTests(StateType stateType): base(stateType)
+ {
+
+ }
[TestCase(1, 1, 0)]
[TestCase(1, 0, 0)]
[TestCase(1, -1, 0)]
diff --git a/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs b/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs
index d05e3ea7f0b..202a1e32ab5 100644
--- a/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/TestAllTracerWithOutput.cs
@@ -13,6 +13,7 @@ namespace Nethermind.Evm.Test
public class TestAllTracerWithOutput : ITxTracer
{
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => true;
public bool IsTracingActions => true;
public bool IsTracingOpLevelStorage => true;
public bool IsTracingMemory => true;
@@ -57,6 +58,10 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
{
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
}
diff --git a/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs b/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs
index 8cbada7d500..d96bbf170a6 100644
--- a/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/Tracing/BlockReceiptsTracerTests.cs
@@ -19,7 +19,7 @@ public void Sets_state_root_if_provided_on_success()
{
Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject;
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(NullBlockTracer.Instance);
tracer.StartNewBlockTrace(block);
tracer.StartNewTxTrace(block.Transactions[0]);
@@ -33,7 +33,7 @@ public void Sets_tx_type()
{
Block block = Build.A.Block.WithTransactions(Build.A.Transaction.WithChainId(TestBlockchainIds.ChainId).WithType(TxType.AccessList).TestObject).TestObject;
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(NullBlockTracer.Instance);
tracer.StartNewBlockTrace(block);
tracer.StartNewTxTrace(block.Transactions[0]);
@@ -47,7 +47,7 @@ public void Sets_state_root_if_provided_on_failure()
{
Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject;
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(NullBlockTracer.Instance);
tracer.StartNewBlockTrace(block);
tracer.StartNewTxTrace(block.Transactions[0]);
@@ -62,7 +62,7 @@ public void Invokes_other_tracer_mark_as_failed_if_other_block_tracer_is_tx_trac
Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject;
IBlockTracer otherTracer = Substitute.For();
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(otherTracer);
tracer.StartNewBlockTrace(block);
tracer.StartNewTxTrace(block.Transactions[0]);
@@ -77,7 +77,7 @@ public void Invokes_other_tracer_mark_as_success_if_other_block_tracer_is_tx_tra
Block block = Build.A.Block.WithTransactions(Build.A.Transaction.TestObject).TestObject;
IBlockTracer otherTracer = Substitute.For();
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(otherTracer);
tracer.StartNewBlockTrace(block);
tracer.StartNewTxTrace(block.Transactions[0]);
diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs
index 0ac0d44fa5d..db772fcb9e8 100644
--- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorFeeTests.cs
@@ -167,7 +167,7 @@ public void Should_stop_when_cancellation(bool withCancellation)
CancellationBlockTracer cancellationBlockTracer = new(feesTracer, token);
- BlockReceiptsTracer blockTracer = new();
+ BlockReceiptsTracer blockTracer = new(true, false);
blockTracer.SetOtherTracer(cancellationBlockTracer);
blockTracer.StartNewBlockTrace(block);
@@ -230,7 +230,7 @@ public void Check_fees_with_free_transaction()
private void ExecuteAndTrace(Block block, IBlockTracer otherTracer)
{
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(otherTracer);
tracer.StartNewBlockTrace(block);
diff --git a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs
index bfb4470881d..255b14a43fb 100644
--- a/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/TransactionProcessorTests.cs
@@ -668,7 +668,7 @@ private BlockReceiptsTracer BuildTracer(Block block, Transaction tx, bool stateD
}
IBlockTracer otherTracer = types != ParityTraceTypes.None ? new ParityLikeBlockTracer(tx.Hash, ParityTraceTypes.Trace | ParityTraceTypes.StateDiff) : (IBlockTracer)NullBlockTracer.Instance;
- BlockReceiptsTracer tracer = new();
+ BlockReceiptsTracer tracer = new(true, false);
tracer.SetOtherTracer(otherTracer);
return tracer;
}
diff --git a/src/Nethermind/Nethermind.Evm.Test/VerkleTreeTests.cs b/src/Nethermind/Nethermind.Evm.Test/VerkleTreeTests.cs
new file mode 100644
index 00000000000..5e518eea61c
--- /dev/null
+++ b/src/Nethermind/Nethermind.Evm.Test/VerkleTreeTests.cs
@@ -0,0 +1,79 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using Nethermind.Specs;
+using Nethermind.State;
+using NUnit.Framework;
+
+namespace Nethermind.Evm.Test;
+
+public class VerkleTreeTests: VirtualMachineTestsBase
+{
+ public VerkleTreeTests() : base(StateType.Verkle) { }
+
+ protected override long BlockNumber => MainnetSpecProvider.GrayGlacierBlockNumber;
+ protected override ulong Timestamp => MainnetSpecProvider.PragueBlockTimestamp;
+
+ [Test]
+ public void TestGasCostUpdateForPushOpCodes()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForContractCreationComplete()
+ {
+
+ }
+
+ [Test]
+ public void TestGasCostUpdateForContractCreationInit()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForBalanceOpCode()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForCodeOpCodes()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForStorageAccessAndUpdate()
+ {
+
+ }
+ [Test]
+ public void TestGasCostForProofOfAbsence()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForCodeChunksAccess()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForCodeCopy()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForPush1()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForPushX()
+ {
+
+ }
+ [Test]
+ public void TestGasCostUpdateForCreateOpCodes()
+ {
+
+ }
+
+}
diff --git a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
index d9b4ce524a2..2ed23c7cf8a 100644
--- a/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
+++ b/src/Nethermind/Nethermind.Evm.Test/VirtualMachineTestsBase.cs
@@ -11,6 +11,7 @@
using Nethermind.Core.Test.Builders;
using Nethermind.Crypto;
using Nethermind.Db;
+using Nethermind.Db.Rocks;
using Nethermind.Int256;
using Nethermind.Evm.Tracing;
using Nethermind.Evm.Tracing.GethStyle;
@@ -24,6 +25,9 @@ namespace Nethermind.Evm.Test
{
public class VirtualMachineTestsBase
{
+ public VirtualMachineTestsBase(StateType stateType = StateType.Merkle) { _stateType = stateType; }
+ public VirtualMachineTestsBase() { _stateType = StateType.Merkle; }
+
protected const string SampleHexData1 = "a01234";
protected const string SampleHexData2 = "b15678";
protected const string HexZero = "00";
@@ -32,6 +36,7 @@ public class VirtualMachineTestsBase
private IEthereumEcdsa _ethereumEcdsa;
protected ITransactionProcessor _processor;
private IDb _stateDb;
+ private readonly StateType _stateType;
protected VirtualMachine Machine { get; private set; }
protected IWorldState TestState { get; private set; }
@@ -59,10 +64,24 @@ public virtual void Setup()
{
ILogManager logManager = GetLogManager();
- IDb codeDb = new MemDb();
- _stateDb = new MemDb();
- ITrieStore trieStore = new TrieStore(_stateDb, logManager);
- TestState = new WorldState(trieStore, codeDb, logManager);
+ switch (_stateType)
+ {
+ case StateType.Merkle:
+ IDb codeDb = new MemDb();
+ _stateDb = new MemDb();
+ ITrieStore trieStore = new TrieStore(_stateDb, logManager);
+ TestState = new WorldState(trieStore, codeDb, logManager);
+ break;
+ case StateType.Verkle:
+ IDbProvider provider = VerkleDbFactory.InitDatabase(DbMode.MemDb, null);
+ _stateDb = provider.StateDb;
+ VerkleStateTree vTree = new VerkleStateTree(provider, LimboLogs.Instance);
+ TestState = new VerkleWorldState(vTree, new MemDb(), logManager);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
_ethereumEcdsa = new EthereumEcdsa(SpecProvider.ChainId, logManager);
IBlockhashProvider blockhashProvider = TestBlockhashProvider.Instance;
Machine = new VirtualMachine(blockhashProvider, SpecProvider, logManager);
diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeDataAnalyzer.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeDataAnalyzer.cs
index 129c04faec5..05e17ce3e31 100644
--- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeDataAnalyzer.cs
+++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeDataAnalyzer.cs
@@ -9,9 +9,9 @@ namespace Nethermind.Evm.CodeAnalysis
public class CodeDataAnalyzer : ICodeInfoAnalyzer
{
private byte[]? _codeBitmap;
- public byte[] MachineCode { get; set; }
+ public ICode MachineCode { get; set; }
- public CodeDataAnalyzer(byte[] code)
+ public CodeDataAnalyzer(ICode code)
{
MachineCode = code;
}
@@ -54,7 +54,7 @@ public static class CodeDataAnalyzerHelper
/// Collects data locations in code.
/// An unset bit means the byte is an opcode, a set bit means it's data.
///
- public static byte[] CreateCodeBitmap(byte[] code)
+ public static byte[] CreateCodeBitmap(ICode code)
{
// The bitmap is 4 bytes longer than necessary, in case the code
// ends with a PUSH32, the algorithm will push zeroes onto the
diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
index 3be8b18785b..708e93b1562 100644
--- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
+++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/CodeInfo.cs
@@ -3,12 +3,132 @@
using System;
using System.Collections;
+using System.Linq;
using System.Reflection.PortableExecutable;
using System.Threading;
+using DotNetty.Common.Utilities;
+using Nethermind.Core;
using Nethermind.Evm.Precompiles;
+using Nethermind.Int256;
+using Nethermind.Serialization.Rlp;
+using Nethermind.State;
namespace Nethermind.Evm.CodeAnalysis
{
+
+ public interface ICode
+ {
+ byte this[int index] { get; }
+ int Length { get; }
+
+ ZeroPaddedSpan SliceWithZeroPadding(in UInt256 startIndex, int length,
+ PadDirection padDirection = PadDirection.Right);
+
+ byte[] ToBytes();
+ Span Slice(int index, int length);
+ }
+ public readonly struct ByteCode: ICode
+ {
+
+ public ByteCode(byte[] code)
+ {
+ MachineCode = code;
+ }
+
+ public byte[] MachineCode { get; }
+
+ public byte this[int index]
+ {
+ get => MachineCode[index];
+ }
+
+ public int Length => MachineCode.Length;
+
+ public ZeroPaddedSpan SliceWithZeroPadding(in UInt256 startIndex, int length, PadDirection padDirection = PadDirection.Right) => MachineCode.SliceWithZeroPadding(startIndex, length, padDirection);
+
+ public byte[] ToBytes() => MachineCode.ToArray();
+
+ public Span Slice(int index, int length) => MachineCode.Slice(index, length);
+ }
+
+ public readonly struct VerkleCode: ICode
+ {
+ private IWorldState WorldState { get; }
+ private Address Owner { get; }
+ public VerkleCode(IWorldState worldState, Address codeOwner)
+ {
+ if (worldState.StateType != StateType.Verkle) throw new NotSupportedException("verkle state needed");
+ Owner = codeOwner;
+ WorldState = worldState;
+ Length = (int)worldState.GetAccount(codeOwner).CodeSize;
+ }
+
+ public byte this[int index]
+ {
+ get
+ {
+ int chunkId = index / 31;
+ int chunkLoc = index % 31;
+ return WorldState.GetCodeChunk(Owner, (UInt256)chunkId)[chunkLoc];
+ }
+ }
+
+ public int Length { get; init; }
+
+ public ZeroPaddedSpan SliceWithZeroPadding(in UInt256 startIndex, int length,
+ PadDirection padDirection = PadDirection.Right)
+ {
+ if (startIndex >= Length || startIndex > int.MaxValue)
+ {
+ return new ZeroPaddedSpan(default, length, PadDirection.Right);
+ }
+
+ Span toReturn = Slice((int)startIndex, length);
+ return new ZeroPaddedSpan(toReturn, length - toReturn.Length, padDirection);
+
+ }
+
+ public byte[] ToBytes() => Slice(0, Length).ToArray();
+
+ public Span Slice(int index, int length)
+ {
+ if (index >= Length)
+ return Array.Empty();
+
+ int endIndex = index + length - 1;
+ if (endIndex >= length)
+ {
+ endIndex = Length - 1;
+ }
+
+ int startChunkId = index / 31;
+ int startChunkLoc = (index % 31) + 1;
+
+ int endChunkId = endIndex / 31;
+ int endChunkLoc = (endIndex % 31) + 1;
+
+ byte[] codeSlice = new byte[(endIndex - index) + 1];
+ Span codeSliceSpan = codeSlice;
+ if (startChunkId == endChunkId)
+ {
+ WorldState.GetCodeChunk(Owner, (UInt256)startChunkId)[startChunkLoc..(endChunkLoc + 1)].CopyTo(codeSliceSpan);
+ }
+ else
+ {
+ WorldState.GetCodeChunk(Owner, (UInt256)startChunkId)[startChunkLoc..].CopyTo(codeSliceSpan);
+ codeSliceSpan = codeSliceSpan.Slice(32 - startChunkLoc);
+ for (int i = (startChunkId+1); i < endChunkId; i++)
+ {
+ WorldState.GetCodeChunk(Owner, (UInt256)i)[1..].CopyTo(codeSliceSpan);
+ codeSliceSpan = codeSliceSpan.Slice(31);
+ }
+ WorldState.GetCodeChunk(Owner, (UInt256)endChunkId)[1..(endChunkLoc + 1)].CopyTo(codeSliceSpan);
+ }
+ return codeSlice;
+ }
+ }
+
+
public class CodeInfo
{
private const int SampledCodeLength = 10_001;
@@ -16,13 +136,18 @@ public class CodeInfo
private const int NumberOfSamples = 100;
private static Random _rand = new();
- public byte[] MachineCode { get; set; }
+ public ICode MachineCode { get; set; }
public IPrecompile? Precompile { get; set; }
private ICodeInfoAnalyzer? _analyzer;
+ public CodeInfo(IWorldState worldState, Address codeOwner)
+ {
+ MachineCode = new VerkleCode(worldState, codeOwner);
+ }
+
public CodeInfo(byte[] code)
{
- MachineCode = code;
+ MachineCode = new ByteCode(code);
}
public bool IsPrecompile => Precompile is not null;
@@ -30,7 +155,7 @@ public CodeInfo(byte[] code)
public CodeInfo(IPrecompile precompile)
{
Precompile = precompile;
- MachineCode = Array.Empty();
+ MachineCode = new ByteCode(Array.Empty());
}
public bool ValidateJump(int destination, bool isSubroutine)
diff --git a/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpdestAnalyzer.cs b/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpdestAnalyzer.cs
index d3757b8f7b9..f29437fe6f8 100644
--- a/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpdestAnalyzer.cs
+++ b/src/Nethermind/Nethermind.Evm/CodeAnalysis/JumpdestAnalyzer.cs
@@ -9,12 +9,12 @@ namespace Nethermind.Evm.CodeAnalysis
{
public class JumpdestAnalyzer : ICodeInfoAnalyzer
{
- private byte[] MachineCode { get; set; }
+ private ICode MachineCode { get; set; }
private BitArray? _validJumpDestinations;
private BitArray? _validJumpSubDestinations;
- public JumpdestAnalyzer(byte[] code)
+ public JumpdestAnalyzer(ICode code)
{
MachineCode = code;
}
diff --git a/src/Nethermind/Nethermind.Evm/EvmState.cs b/src/Nethermind/Nethermind.Evm/EvmState.cs
index fd00178f4e8..d6ebde60a16 100644
--- a/src/Nethermind/Nethermind.Evm/EvmState.cs
+++ b/src/Nethermind/Nethermind.Evm/EvmState.cs
@@ -38,7 +38,7 @@ public StackPool(int maxCallStackDepth = VirtualMachine.MaxCallDepth * 2)
///
/// The word 'return' acts here once as a verb 'to return stack to the pool' and once as a part of the
- /// compound noun 'return stack' which is a stack of subroutine return values.
+ /// compound noun 'return stack' which is a stack of subroutine return values.
///
///
///
@@ -106,6 +106,11 @@ private int[] RentReturnStack()
// As we can add here from VM, we need it as ICollection
public ICollection Logs => _logs;
+ ///
+ /// Verkle Tree: to maintain a list of all accessed subtrees and leaves
+ ///
+ public IVerkleWitness? VerkleTreeWitness { get; }
+
private readonly JournalSet _accessedAddresses;
private readonly JournalSet _accessedStorageCells;
private readonly JournalCollection _logs;
@@ -114,6 +119,7 @@ private int[] RentReturnStack()
private readonly int _accessedStorageKeysSnapshot;
private readonly int _destroyListSnapshot;
private readonly int _logsSnapshot;
+ private readonly int _verkleWitnessSnapshot;
public int DataStackHead = 0;
@@ -179,6 +185,7 @@ internal EvmState(
_accessedStorageCells = stateForAccessLists._accessedStorageCells;
_destroyList = stateForAccessLists._destroyList;
_logs = stateForAccessLists._logs;
+ VerkleTreeWitness = stateForAccessLists.VerkleTreeWitness;
}
else
{
@@ -187,13 +194,14 @@ internal EvmState(
_accessedStorageCells = new JournalSet();
_destroyList = new JournalSet();
_logs = new JournalCollection();
+ VerkleTreeWitness = env.VerkleWitness;
}
_accessedAddressesSnapshot = _accessedAddresses.TakeSnapshot();
_accessedStorageKeysSnapshot = _accessedStorageCells.TakeSnapshot();
_destroyListSnapshot = _destroyList.TakeSnapshot();
_logsSnapshot = _logs.TakeSnapshot();
-
+ _verkleWitnessSnapshot = VerkleTreeWitness?.TakeSnapshot() ?? 0;
}
public Address From
@@ -295,6 +303,7 @@ private void Restore()
_destroyList.Restore(_destroyListSnapshot);
_accessedAddresses.Restore(_accessedAddressesSnapshot);
_accessedStorageCells.Restore(_accessedStorageKeysSnapshot);
+ VerkleTreeWitness?.Restore(_verkleWitnessSnapshot);
}
}
}
diff --git a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs
index afd332d5a39..3fe35afbb46 100644
--- a/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs
+++ b/src/Nethermind/Nethermind.Evm/ExecutionEnvironment.cs
@@ -20,7 +20,8 @@ public ExecutionEnvironment
TxExecutionContext txExecutionContext,
UInt256 transferValue,
UInt256 value,
- int callDepth = 0)
+ int callDepth = 0,
+ IVerkleWitness? verkleWitness = null)
{
CodeInfo = codeInfo;
ExecutingAccount = executingAccount;
@@ -31,6 +32,7 @@ public ExecutionEnvironment
TransferValue = transferValue;
Value = value;
CallDepth = callDepth;
+ VerkleWitness = verkleWitness;
}
///
@@ -38,6 +40,8 @@ public ExecutionEnvironment
///
public readonly CodeInfo CodeInfo;
+ public readonly IVerkleWitness? VerkleWitness;
+
///
/// Currently executing account (in DELEGATECALL this will be equal to caller).
///
diff --git a/src/Nethermind/Nethermind.Evm/GasCostOf.cs b/src/Nethermind/Nethermind.Evm/GasCostOf.cs
index 6875a781100..fe91b2f94a6 100644
--- a/src/Nethermind/Nethermind.Evm/GasCostOf.cs
+++ b/src/Nethermind/Nethermind.Evm/GasCostOf.cs
@@ -61,5 +61,11 @@ public static class GasCostOf
public const long AccessStorageListEntry = 1900; // eip-2930
public const long TLoad = WarmStateRead; // eip-1153
public const long TStore = WarmStateRead; // eip-1153
+
+ public const long WitnessChunkRead = 200; // verkle-trees
+ public const long WitnessChunkWrite = 500; // verkle-trees
+ public const long WitnessChunkFill = 6200; // verkle-trees
+ public const long WitnessBranchRead = 1900; // verkle-trees
+ public const long WitnessBranchWrite = 3000; // verkle-trees
}
}
diff --git a/src/Nethermind/Nethermind.Evm/GasUtils.cs b/src/Nethermind/Nethermind.Evm/GasUtils.cs
new file mode 100644
index 00000000000..350aba0ded6
--- /dev/null
+++ b/src/Nethermind/Nethermind.Evm/GasUtils.cs
@@ -0,0 +1,17 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System.Runtime.CompilerServices;
+
+namespace Nethermind.Evm;
+
+public static class GasUtils
+{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool UpdateGas(long gasCost, ref long gasAvailable)
+ {
+ if (gasAvailable < gasCost) return false;
+ gasAvailable -= gasCost;
+ return true;
+ }
+}
diff --git a/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs b/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs
index 248f0855796..94400f63078 100644
--- a/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs
+++ b/src/Nethermind/Nethermind.Evm/IntrinsicGasCalculator.cs
@@ -7,6 +7,7 @@
using Nethermind.Core.Eip2930;
using Nethermind.Core.Specs;
using Nethermind.Int256;
+using Nethermind.Verkle.Tree;
namespace Nethermind.Evm
{
@@ -21,6 +22,14 @@ public static long Calculate(Transaction transaction, IReleaseSpec releaseSpec)
return result;
}
+ public static long Calculate(Transaction transaction, IReleaseSpec releaseSpec, ref VerkleWitness witness)
+ {
+ long result = Calculate(transaction, releaseSpec);
+ if (releaseSpec.IsVerkleTreeEipEnabled)
+ result += witness.AccessForTransaction(transaction.SenderAddress!, transaction.To!, !transaction.Value.IsZero);
+ return result;
+ }
+
private static long CreateCost(Transaction transaction, IReleaseSpec releaseSpec)
{
long createCost = 0;
diff --git a/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj b/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj
index bf4f06ca167..6f60182aac1 100644
--- a/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj
+++ b/src/Nethermind/Nethermind.Evm/Nethermind.Evm.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs
index 9cdc92be7f6..991368a61cb 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/AccessTxTracer.cs
@@ -21,6 +21,7 @@ public class AccessTxTracer : ITxTracer
public bool IsTracingState => false;
public bool IsTracingStorage => false;
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -82,6 +83,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
throw new NotImplementedException();
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotImplementedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
throw new NotImplementedException();
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs
index 5d86ede3a7a..7193818625f 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/AlwaysCancelTxTracer.cs
@@ -29,6 +29,7 @@ public static AlwaysCancelTxTracer Instance
}
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => true;
public bool IsTracingActions => true;
public bool IsTracingOpLevelStorage => true;
public bool IsTracingMemory => true;
@@ -48,6 +49,9 @@ public static AlwaysCancelTxTracer Instance
public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool isPostMerge = false) => throw new OperationCanceledException(ErrorMessage);
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys) =>
+ throw new OperationCanceledException(ErrorMessage);
+
public void ReportOperationError(EvmExceptionType error) => throw new OperationCanceledException(ErrorMessage);
public void ReportOperationRemainingGas(long gas) => throw new OperationCanceledException(ErrorMessage);
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs
index 225e84ea564..05245909c13 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/BlockReceiptsTracer.cs
@@ -5,16 +5,20 @@
using System.Collections.Generic;
using System.Linq;
using Nethermind.Core;
+using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
+using Nethermind.Core.Extensions;
using Nethermind.Int256;
-using Nethermind.State;
namespace Nethermind.Evm.Tracing
{
public class BlockReceiptsTracer : IBlockTracer, ITxTracer, IJournal
{
private Block _block = null!;
- public bool IsTracingReceipt => true;
+ private readonly bool _isTracingReceipt;
+ private readonly bool _isTracingVerkleWitness;
+ public bool IsTracingReceipt => _isTracingReceipt | _currentTxTracer.IsTracingReceipt;
+ public bool IsTracingVerkleWitness => _isTracingVerkleWitness | _currentTxTracer.IsTracingVerkleWitness;
public bool IsTracingActions => _currentTxTracer.IsTracingActions;
public bool IsTracingOpLevelStorage => _currentTxTracer.IsTracingOpLevelStorage;
public bool IsTracingMemory => _currentTxTracer.IsTracingMemory;
@@ -31,9 +35,16 @@ public class BlockReceiptsTracer : IBlockTracer, ITxTracer, IJournal
private IBlockTracer _otherTracer = NullBlockTracer.Instance;
+ public BlockReceiptsTracer(bool traceReceipts, bool traceWitness)
+ {
+ _isTracingReceipt = traceReceipts;
+ _isTracingVerkleWitness = traceWitness;
+ }
+
public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak stateRoot = null)
{
- _txReceipts.Add(BuildReceipt(recipient, gasSpent, StatusCode.Success, logs, stateRoot));
+ if(_isTracingReceipt)
+ _txReceipts.Add(BuildReceipt(recipient, gasSpent, StatusCode.Success, logs, stateRoot));
// hacky way to support nested receipt tracers
if (_otherTracer is ITxTracer otherTxTracer)
@@ -49,7 +60,8 @@ public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEn
public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Keccak stateRoot = null)
{
- _txReceipts.Add(BuildFailedReceipt(recipient, gasSpent, error, stateRoot));
+ if(_isTracingReceipt)
+ _txReceipts.Add(BuildFailedReceipt(recipient, gasSpent, error, stateRoot));
// hacky way to support nested receipt tracers
if (_otherTracer is ITxTracer otherTxTracer)
@@ -97,6 +109,23 @@ private TxReceipt BuildReceipt(Address recipient, long spentGas, byte statusCode
public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool isPostMerge = false) =>
_currentTxTracer.StartOperation(depth, gas, opcode, pc, isPostMerge);
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ if(_isTracingVerkleWitness)
+ _witnessKeys.Add(verkleWitnessKeys);
+
+ // hacky way to support nested witness tracers
+ if (_otherTracer is ITxTracer otherTxTracer)
+ {
+ otherTxTracer.SetVerkleWitnessKeys(verkleWitnessKeys);
+ }
+
+ if (_currentTxTracer.IsTracingReceipt)
+ {
+ _currentTxTracer.SetVerkleWitnessKeys(verkleWitnessKeys);
+ }
+ }
+
public void ReportOperationError(EvmExceptionType error) =>
_currentTxTracer.ReportOperationError(error);
@@ -194,15 +223,24 @@ public void ReportFees(UInt256 fees, UInt256 burntFees)
private ITxTracer _currentTxTracer = NullTxTracer.Instance;
private int _currentIndex;
private readonly List _txReceipts = new();
+ private readonly List> _witnessKeys = new();
+ private SortedSet _aggregatedWitnessKeys = new(Bytes.Comparer);
private Transaction? _currentTx;
public IReadOnlyList TxReceipts => _txReceipts;
public TxReceipt LastReceipt => _txReceipts[^1];
+ public SortedSet WitnessKeys => _aggregatedWitnessKeys;
+ public IReadOnlyList LastWitness => _witnessKeys[^1];
public bool IsTracingRewards => _otherTracer.IsTracingRewards;
public int TakeSnapshot() => _txReceipts.Count;
public void Restore(int snapshot)
{
int numToRemove = _txReceipts.Count - snapshot;
+ for (int i = 0; i < numToRemove; i++)
+ {
+ _witnessKeys.RemoveAt(_witnessKeys.Count - 1);
+ }
+
for (int i = 0; i < numToRemove; i++)
{
_txReceipts.RemoveAt(_txReceipts.Count - 1);
@@ -224,6 +262,7 @@ public void StartNewBlockTrace(Block block)
_block = block;
_currentIndex = 0;
_txReceipts.Clear();
+ _witnessKeys.Clear();
_otherTracer.StartNewBlockTrace(block);
}
@@ -244,13 +283,22 @@ public void EndTxTrace()
public void EndBlockTrace()
{
_otherTracer.EndBlockTrace();
+ if (_witnessKeys.Count > 0)
+ {
+ _aggregatedWitnessKeys = new SortedSet(Bytes.Comparer);
+ foreach (IReadOnlyList? keys in _witnessKeys)
+ {
+ _aggregatedWitnessKeys.AddRange(keys);
+ }
+ }
+
if (_txReceipts.Count > 0)
{
Bloom blockBloom = new();
_block.Header.Bloom = blockBloom;
- for (var index = 0; index < _txReceipts.Count; index++)
+ for (int index = 0; index < _txReceipts.Count; index++)
{
- var receipt = _txReceipts[index];
+ TxReceipt? receipt = _txReceipts[index];
blockBloom.Accumulate(receipt.Bloom!);
}
}
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs
index 52d5627529c..dbbf125f135 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/CallOutputTracer.cs
@@ -13,6 +13,7 @@ namespace Nethermind.Evm.Tracing
public class CallOutputTracer : ITxTracer
{
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -54,6 +55,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
throw new NotSupportedException();
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotSupportedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
throw new NotSupportedException();
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs
index c77dee5bfb3..e86b8f08ec9 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/CancellationTxTracer.cs
@@ -17,6 +17,7 @@ public class CancellationTxTracer : ITxTracer
private readonly CancellationToken _token;
private readonly bool _isTracingReceipt;
private readonly bool _isTracingActions;
+ private readonly bool _isTracingVerkleWitness;
private readonly bool _isTracingOpLevelStorage;
private readonly bool _isTracingMemory;
private readonly bool _isTracingInstructions;
@@ -43,6 +44,12 @@ public bool IsTracingReceipt
init => _isTracingReceipt = value;
}
+ public bool IsTracingVerkleWitness
+ {
+ get => _isTracingVerkleWitness || _innerTracer.IsTracingVerkleWitness;
+ init => _isTracingVerkleWitness = value;
+ }
+
public bool IsTracingActions
{
get => _isTracingActions || _innerTracer.IsTracingActions;
@@ -196,6 +203,15 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
}
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ _token.ThrowIfCancellationRequested();
+ if (_innerTracer.IsTracingInstructions)
+ {
+ _innerTracer.SetVerkleWitnessKeys(verkleWitnessKeys);
+ }
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
_token.ThrowIfCancellationRequested();
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs
index 9d208fdc914..74978649d39 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/CompositeTxTracer.cs
@@ -20,11 +20,11 @@ public CompositeTxTracer(params ITxTracer[] txTracers) : this((IList)
public CompositeTxTracer(IList txTracers)
{
_txTracers = txTracers;
- for (int index = 0; index < txTracers.Count; index++)
+ foreach (ITxTracer? t in txTracers)
{
- ITxTracer t = txTracers[index];
IsTracingState |= t.IsTracingState;
IsTracingReceipt |= t.IsTracingReceipt;
+ IsTracingVerkleWitness |= t.IsTracingVerkleWitness;
IsTracingActions |= t.IsTracingActions;
IsTracingOpLevelStorage |= t.IsTracingOpLevelStorage;
IsTracingMemory |= t.IsTracingMemory;
@@ -42,6 +42,7 @@ public CompositeTxTracer(IList txTracers)
public bool IsTracingState { get; }
public bool IsTracingStorage { get; }
public bool IsTracingReceipt { get; }
+ public bool IsTracingVerkleWitness { get; }
public bool IsTracingActions { get; }
public bool IsTracingOpLevelStorage { get; }
public bool IsTracingMemory { get; }
@@ -161,6 +162,18 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
}
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ for (int index = 0; index < _txTracers.Count; index++)
+ {
+ ITxTracer innerTracer = _txTracers[index];
+ if (innerTracer.IsTracingInstructions)
+ {
+ innerTracer.SetVerkleWitnessKeys(verkleWitnessKeys);
+ }
+ }
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
for (int index = 0; index < _txTracers.Count; index++)
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs
index fd94fc3dc7f..026cddde772 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/EstimateGasTracer.cs
@@ -20,6 +20,7 @@ public EstimateGasTracer()
}
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => true;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -67,6 +68,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
throw new NotSupportedException();
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotSupportedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
throw new NotSupportedException();
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/FeesTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/FeesTracer.cs
index b261e5b5b90..4cc7b968075 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/FeesTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/FeesTracer.cs
@@ -13,6 +13,7 @@ public class FeesTracer : IBlockTracer, ITxTracer
{
public bool IsTracingRewards => false;
public bool IsTracingState => false;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -90,6 +91,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
throw new NotImplementedException();
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotImplementedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
throw new NotImplementedException();
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs b/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs
index 32e6aa347cc..72bfb6db3b2 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/GasEstimator.cs
@@ -102,6 +102,7 @@ public OutOfGasTracer()
OutOfGas = false;
}
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -137,6 +138,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
{
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
OutOfGas |= error == EvmExceptionType.OutOfGas;
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs
index 6d9b2454e01..f5c4f67ae6e 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/GethStyle/GethLikeTxTracer.cs
@@ -27,6 +27,7 @@ public GethLikeTxTracer(GethTraceOptions options)
bool IStateTracer.IsTracingState => false;
bool IStorageTracer.IsTracingStorage => false;
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
bool ITxTracer.IsTracingActions => false;
public bool IsTracingOpLevelStorage { get; }
public bool IsTracingMemory { get; }
@@ -85,6 +86,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
}
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotSupportedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
_traceEntry.Error = GetErrorDescription(error);
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
index 5d5b3ac06fb..1d025220b1a 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/ITxTracer.cs
@@ -24,6 +24,15 @@ public interface ITxTracer : IWorldStateTracer
///
bool IsTracingReceipt { get; }
+ ///
+ /// Defines whether SetVerkleWitnessKeys will be called
+ ///
+ ///
+ /// Controls
+ /// -
+ ///
+ bool IsTracingVerkleWitness { get; }
+
///
/// High level calls with information on the target account
///
@@ -160,6 +169,13 @@ public interface ITxTracer : IWorldStateTracer
/// Depends on
void StartOperation(int depth, long gas, Instruction opcode, int pc, bool isPostMerge = false);
+ ///
+ ///
+ ///
+ ///
+ /// Depends on
+ void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys);
+
///
///
///
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs
index 242d8dbe714..97d9acd4da5 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/NullTxTracer.cs
@@ -17,6 +17,7 @@ public class NullTxTracer : ITxTracer
private NullTxTracer() { }
public bool IsTracingReceipt => false;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -39,6 +40,9 @@ public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string
public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool isPostMerge = false)
=> throw new InvalidOperationException(ErrorMessage);
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys) =>
+ throw new InvalidOperationException(ErrorMessage);
+
public void ReportOperationError(EvmExceptionType error)
=> throw new InvalidOperationException(ErrorMessage);
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs
index b5300031b50..7b3a5558e88 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/ParityStyle/ParityLikeTxTracer.cs
@@ -65,6 +65,7 @@ public ParityLikeTxTracer(Block block, Transaction? tx, ParityTraceTypes parityT
}
public bool IsTracingReceipt { get; }
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions { get; }
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -273,6 +274,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
_currentVmTrace.Ops.Add(operationTrace);
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotSupportedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
if (error != EvmExceptionType.InvalidJumpDestination &&
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs
index 9d967083e87..e157b8e59fb 100644
--- a/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs
+++ b/src/Nethermind/Nethermind.Evm/Tracing/Proofs/ProofTxTracer.cs
@@ -29,6 +29,7 @@ public ProofTxTracer(bool treatSystemAccountDifferently)
public bool IsTracingBlockHash => true;
public bool IsTracingAccess => false;
public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
public bool IsTracingActions => false;
public bool IsTracingOpLevelStorage => false;
public bool IsTracingMemory => false;
@@ -149,6 +150,11 @@ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool
throw new NotSupportedException();
}
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ throw new NotImplementedException();
+ }
+
public void ReportOperationError(EvmExceptionType error)
{
throw new NotSupportedException();
diff --git a/src/Nethermind/Nethermind.Evm/Tracing/VerkleWitnessTracer.cs b/src/Nethermind/Nethermind.Evm/Tracing/VerkleWitnessTracer.cs
new file mode 100644
index 00000000000..5deeacea2b3
--- /dev/null
+++ b/src/Nethermind/Nethermind.Evm/Tracing/VerkleWitnessTracer.cs
@@ -0,0 +1,189 @@
+// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited
+// SPDX-License-Identifier: LGPL-3.0-only
+
+using System;
+using System.Collections.Generic;
+using Nethermind.Core;
+using Nethermind.Core.Crypto;
+using Nethermind.Int256;
+
+namespace Nethermind.Evm.Tracing;
+
+public class VerkleWitnessTracer: ITxTracer
+{
+ public bool IsTracingReceipt => true;
+ public bool IsTracingVerkleWitness => false;
+ public bool IsTracingActions => false;
+ public bool IsTracingOpLevelStorage => false;
+ public bool IsTracingMemory => false;
+ public bool IsTracingInstructions => false;
+ public bool IsTracingRefunds => false;
+ public bool IsTracingCode => false;
+ public bool IsTracingStack => false;
+ public bool IsTracingState => false;
+ public bool IsTracingStorage => false;
+ public bool IsTracingBlockHash => false;
+ public bool IsTracingAccess => false;
+ public bool IsTracingFees => false;
+ public IReadOnlyList VerkleWitnessKeys { get; set; }
+
+ public void MarkAsSuccess(Address recipient, long gasSpent, byte[] output, LogEntry[] logs, Keccak stateRoot = null)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void MarkAsFailed(Address recipient, long gasSpent, byte[] output, string error, Keccak stateRoot = null)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void StartOperation(int depth, long gas, Instruction opcode, int pc, bool isPostMerge = false)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void SetVerkleWitnessKeys(IReadOnlyList verkleWitnessKeys)
+ {
+ VerkleWitnessKeys = verkleWitnessKeys;
+ }
+
+ public void ReportOperationError(EvmExceptionType error)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void ReportOperationRemainingGas(long gas)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void SetOperationStack(List stackTrace)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void ReportStackPush(in ReadOnlySpan stackItem)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void SetOperationMemory(List memoryTrace)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void SetOperationMemorySize(ulong newSize)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void ReportMemoryChange(long offset, in ReadOnlySpan data)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void ReportStorageChange(in ReadOnlySpan