Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.

Commit da454e2

Browse files
Modified extension gadget (#1685)
### Description This PR will replace old modified extension node PRs (there were multiple because the witness generator was in a separate repository at that time). Support for modified extension nodes. This happens when an extension node is replaced by another (shorter or longer) extension node. For example, we have an extension node at `n1 n2 n3 n4 n5 n6` with branch with two leaves at positions `n` and `m`. If we add a leaf at `n1 n2 n3 n4 n7` where `n5 != n7`, a new extension node is inserted at `n1 n2 n3 n4` with a new branch with an extension node at position `n5` (with only one nibble `n6`) and a leaf at position `n7`. In this case, the S proof contains the extension node at `n1 n2 n3 n4 n5 n6` and no underlying branch and leaf (the modification happens at `n1 n2 n3 n4 n7` and only an extension node is find there), thus we need to add a placeholder branch and a placeholder leaf. ### Type of change - [x] New feature (non-breaking change which adds functionality) --------- Co-authored-by: Chih Cheng Liang <[email protected]>
1 parent 734e430 commit da454e2

File tree

116 files changed

+6979
-1503
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+6979
-1503
lines changed

mpt-witness-generator/oracle/prefetch.go

+23-16
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ import (
66
"encoding/json"
77
"fmt"
88
"io"
9-
"io/ioutil"
109
"log"
1110
"math/big"
1211
"net/http"
1312
"os"
13+
"time"
1414

1515
"github.com/ethereum/go-ethereum/common"
1616
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -88,7 +88,7 @@ func toFilename(key string) string {
8888
}
8989

9090
func cacheRead(key string) []byte {
91-
dat, err := ioutil.ReadFile(toFilename(key))
91+
dat, err := os.ReadFile(toFilename(key))
9292
if err == nil {
9393
return dat
9494
}
@@ -101,19 +101,27 @@ func cacheExists(key string) bool {
101101
}
102102

103103
func cacheWrite(key string, value []byte) {
104-
ioutil.WriteFile(toFilename(key), value, 0644)
104+
os.WriteFile(toFilename(key), value, 0644)
105105
}
106106

107107
func getAPI(jsonData []byte) io.Reader {
108108
key := hexutil.Encode(crypto.Keccak256(jsonData))
109-
/* Note: switching between two testnets (to prepare tests with account in the first level)
110-
if cacheExists(key) {
111-
return bytes.NewReader(cacheRead(key))
109+
var (
110+
err error
111+
resp *http.Response
112+
retries int = 3
113+
)
114+
for retries > 0 {
115+
resp, err = http.Post(NodeUrl, "application/json", bytes.NewBuffer(jsonData))
116+
if err != nil {
117+
retries -= 1
118+
time.Sleep(1000)
119+
} else {
120+
break
121+
}
112122
}
113-
*/
114-
resp, _ := http.Post(NodeUrl, "application/json", bytes.NewBuffer(jsonData))
115123
defer resp.Body.Close()
116-
ret, _ := ioutil.ReadAll(resp.Body)
124+
ret, _ := io.ReadAll(resp.Body)
117125
cacheWrite(key, ret)
118126
return bytes.NewReader(ret)
119127
}
@@ -239,13 +247,8 @@ func PrefetchBlock(blockNumber *big.Int, startBlock bool, hasher types.TrieHashe
239247
r.Params[1] = true
240248
jsonData, _ := json.Marshal(r)
241249

242-
/*dat, _ := ioutil.ReadAll(getAPI(jsonData))
243-
fmt.Println(string(dat))*/
244-
245250
jr := jsonrespt{}
246251
check(json.NewDecoder(getAPI(jsonData)).Decode(&jr))
247-
//fmt.Println(jr.Result)
248-
// blockHeader := types.Header(jr.Result)
249252
blockHeader := jr.Result.ToHeader()
250253

251254
// put in the start block header
@@ -277,7 +280,7 @@ func PrefetchBlock(blockNumber *big.Int, startBlock bool, hasher types.TrieHashe
277280
saveinput = append(saveinput, inputs[i].Bytes()[:]...)
278281
}
279282
key := fmt.Sprintf("/tmp/eth/%d", blockNumber.Uint64()-1)
280-
ioutil.WriteFile(key, saveinput, 0644)
283+
os.WriteFile(key, saveinput, 0644)
281284

282285
// save the txs
283286
txs := make([]*types.Transaction, len(jr.Result.Transactions))
@@ -308,7 +311,11 @@ func getProofAccount(blockNumber *big.Int, addr common.Address, skey common.Hash
308311
json.NewDecoder(getAPI(jsonData)).Decode(&jr)
309312

310313
if storage {
311-
return jr.Result.StorageProof[0].Proof
314+
if len(jr.Result.StorageProof) != 0 {
315+
return jr.Result.StorageProof[0].Proof
316+
} else {
317+
return []string{}
318+
}
312319
} else {
313320
return jr.Result.AccountProof
314321
}

mpt-witness-generator/witness/branch.go

+8-17
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ func isBranch(proofEl []byte) bool {
2525
// S occupies the first 34 columns, C occupies the next 34 columns.
2626
// The branch children are positioned each in its own row.
2727
func prepareBranchWitness(rows [][]byte, branch []byte, branchStart int, branchRLPOffset int) {
28+
branchNodeRLPLen := 2 // we have two positions for RLP meta data
2829
rowInd := 1
2930
colInd := branchNodeRLPLen - 1
3031

@@ -65,7 +66,7 @@ func prepareBranchWitness(rows [][]byte, branch []byte, branchStart int, branchR
6566
}
6667

6768
func prepareBranchNode(branch1, branch2, extNode1, extNode2, extListRlpBytes []byte, extValues [][]byte, key, driftedInd,
68-
branchC16, branchC1 byte, isBranchSPlaceholder, isBranchCPlaceholder, isExtension, isSModExtension, isCModExtension bool) Node {
69+
branchC16, branchC1 byte, isBranchSPlaceholder, isBranchCPlaceholder, isExtension bool) Node {
6970
extensionNode := ExtensionNode{
7071
ListRlpBytes: extListRlpBytes,
7172
}
@@ -112,11 +113,10 @@ func prepareBranchNode(branch1, branch2, extNode1, extNode2, extListRlpBytes []b
112113
}
113114

114115
extensionBranch := ExtensionBranchNode{
115-
IsExtension: isExtension,
116-
IsModExtension: [2]bool{isSModExtension, isCModExtension},
117-
IsPlaceholder: [2]bool{isBranchSPlaceholder, isBranchCPlaceholder},
118-
Extension: extensionNode,
119-
Branch: branchNode,
116+
IsExtension: isExtension,
117+
IsPlaceholder: [2]bool{isBranchSPlaceholder, isBranchCPlaceholder},
118+
Extension: extensionNode,
119+
Branch: branchNode,
120120
}
121121

122122
values := make([][]byte, 17)
@@ -282,15 +282,6 @@ func addBranchAndPlaceholder(proof1, proof2,
282282

283283
// Note that isModifiedExtNode happens also when we have a branch instead of shortExtNode
284284
isModifiedExtNode := !isBranch(longExtNode) && !isShorterProofLastLeaf
285-
isSModifiedExtNode := false
286-
isCModifiedExtNode := false
287-
if isModifiedExtNode {
288-
if len1 < len2 {
289-
isSModifiedExtNode = true
290-
} else {
291-
isCModifiedExtNode = true
292-
}
293-
}
294285

295286
if len1 > len2 {
296287
// We now get the first nibble of the leaf that was turned into branch.
@@ -300,7 +291,7 @@ func addBranchAndPlaceholder(proof1, proof2,
300291

301292
node = prepareBranchNode(proof1[len1-2], proof1[len1-2], extNode, extNode, extListRlpBytes, extValues,
302293
key[keyIndex+numberOfNibbles], driftedInd,
303-
branchC16, branchC1, false, true, isExtension, isSModifiedExtNode, isCModifiedExtNode)
294+
branchC16, branchC1, false, true, isExtension)
304295

305296
// We now get the first nibble of the leaf that was turned into branch.
306297
// This first nibble presents the position of the leaf once it moved
@@ -313,7 +304,7 @@ func addBranchAndPlaceholder(proof1, proof2,
313304

314305
node = prepareBranchNode(proof2[len2-2], proof2[len2-2], extNode, extNode, extListRlpBytes, extValues,
315306
key[keyIndex+numberOfNibbles], driftedInd,
316-
branchC16, branchC1, true, false, isExtension, isSModifiedExtNode, isCModifiedExtNode)
307+
branchC16, branchC1, true, false, isExtension)
317308
}
318309

319310
return isModifiedExtNode, isExtension, numberOfNibbles, branchC16, node

mpt-witness-generator/witness/extension_node.go

-163
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,5 @@
11
package witness
22

3-
// setExtNodeSelectors sets in the branch init row the information about the extension node.
4-
func setExtNodeSelectors(row, proofEl []byte, numberOfNibbles int, branchC16 byte) {
5-
row[isExtensionPos] = 1
6-
if len(proofEl) > 56 { // 56 because there is 1 byte for length
7-
// isCExtLongerThan55 doesn't need to be set here
8-
row[isSExtLongerThan55Pos] = 1
9-
}
10-
11-
if len(proofEl) < 32 {
12-
// isExtNodeSNonHashed doesn't need to be set here
13-
row[isExtNodeSNonHashedPos] = 1
14-
}
15-
16-
if numberOfNibbles == 1 {
17-
if branchC16 == 1 {
18-
row[isExtShortC16Pos] = 1
19-
} else {
20-
row[isExtShortC1Pos] = 1
21-
}
22-
} else {
23-
if numberOfNibbles%2 == 0 {
24-
if branchC16 == 1 {
25-
row[isExtLongEvenC16Pos] = 1
26-
} else {
27-
row[isExtLongEvenC1Pos] = 1
28-
}
29-
} else {
30-
if branchC16 == 1 {
31-
row[isExtLongOddC16Pos] = 1
32-
} else {
33-
row[isExtLongOddC1Pos] = 1
34-
}
35-
}
36-
}
37-
}
38-
39-
func prepareEmptyExtensionRows(beforeModification, afterModification bool) [][]byte {
40-
ext_row1 := make([]byte, rowLen)
41-
ext_row2 := make([]byte, rowLen)
42-
if !beforeModification && !afterModification {
43-
ext_row1 = append(ext_row1, 16)
44-
ext_row2 = append(ext_row2, 17)
45-
} else if beforeModification {
46-
ext_row1 = append(ext_row1, 20)
47-
ext_row2 = append(ext_row2, 21)
48-
} else if afterModification {
49-
ext_row1 = append(ext_row1, 22)
50-
ext_row2 = append(ext_row2, 23)
51-
}
52-
53-
return [][]byte{ext_row1, ext_row2}
54-
}
55-
56-
// TODO: remove when Nodes are fully implemented
57-
func prepareExtensionRows(extNibbles [][]byte, extensionNodeInd int, proofEl1, proofEl2 []byte, beforeModification, afterModification bool) (byte, []byte, []byte) {
58-
var extensionRowS []byte
59-
var extensionRowC []byte
60-
61-
extRows := prepareEmptyExtensionRows(beforeModification, afterModification)
62-
extensionRowS = extRows[0]
63-
extensionRowC = extRows[1]
64-
prepareExtensionRow(extensionRowS, proofEl1, true)
65-
prepareExtensionRow(extensionRowC, proofEl2, false)
66-
67-
evenNumberOfNibbles := proofEl1[2] == 0
68-
keyLen := getExtensionNodeKeyLen(proofEl1)
69-
numberOfNibbles := getExtensionNumberOfNibbles(proofEl1)
70-
71-
// We need nibbles as witness to compute key RLC, so we set them
72-
// into extensionRowC s_advices (we can do this because both extension
73-
// nodes have the same key, so we can have this info only in one).
74-
// There can be more up to 64 nibbles, but there is only 32 bytes
75-
// in extensionRowC s_advices. So we store every second nibble (having
76-
// the whole byte and one nibble is enough to compute the other nibble).
77-
startNibblePos := 2 // we don't need any nibbles for case keyLen = 1
78-
if keyLen > 1 {
79-
if evenNumberOfNibbles {
80-
startNibblePos = 1
81-
} else {
82-
startNibblePos = 2
83-
}
84-
}
85-
ind := 0
86-
for j := startNibblePos; j < len(extNibbles[extensionNodeInd]); j += 2 {
87-
extensionRowC[branchNodeRLPLen+ind] =
88-
extNibbles[extensionNodeInd][j]
89-
ind++
90-
}
91-
92-
return numberOfNibbles, extensionRowS, extensionRowC
93-
}
94-
953
func prepareExtensions(extNibbles [][]byte, extensionNodeInd int, proofEl1, proofEl2 []byte) (byte, []byte, [][]byte) {
964
var values [][]byte
975
v1 := make([]byte, valueLen)
@@ -197,77 +105,6 @@ func getExtensionNodeNibbles(proofEl []byte) []byte {
197105
return nibbles
198106
}
199107

200-
// TODO: remove when Nodes are fully implemented
201-
func prepareExtensionRow(witnessRow, proofEl []byte, setKey bool) {
202-
// storageProof[i]:
203-
// [228,130,0,149,160,114,253,150,133,18,192,156,19,241,162,51,210,24,1,151,16,48,7,177,42,60,49,34,230,254,242,79,132,165,90,75,249]
204-
// Note that the first element (228 in this case) can go much higher - for example, if there
205-
// are 40 nibbles, this would take 20 bytes which would make the first element 248.
206-
207-
// If only one nibble in key:
208-
// [226,16,160,172,105,12...
209-
// Could also be non-hashed branch:
210-
// [223,16,221,198,132,32,0,0,0,1,198,132,32,0,0,0,1,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128]
211-
212-
// Extension node with non-hashed branch:
213-
// List contains up to 55 bytes (192 + 55)
214-
// [247,160,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,213,128,194,32,1,128,194,32,1,128,128,128,128,128,128,128,128,128,128,128,128,128]
215-
216-
// List contains more than 55 bytes
217-
// [248,58,159,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,217,128,196,130,32,0,1,128,196,130,32,0,1,128,128,128,128,128,128,128,128,128,128,128,128,128]
218-
219-
// Note that the extension node can be much shorter than the one above - in case when
220-
// there are less nibbles, so we cannot say that 226 appears as the first byte only
221-
// when there are hashed nodes in the branch and there is only one nibble.
222-
// Branch with two non-hashed nodes (that's the shortest possible branch):
223-
// [217,128,196,130,32,0,1,128,196,130,32,0,1,128,128,128,128,128,128,128,128,128,128,128,128,128]
224-
// Note: branch contains at least 26 bytes. 192 + 26 = 218
225-
226-
/*
227-
If proofEl[0] <= 247 (length at most 55, so proofEl[1] doesn't specify the length of the whole
228-
remaining stream, only of the next substream)
229-
If proofEl[1] <= 128:
230-
There is only 1 byte for nibbles (keyLen = 1) and this is proofEl[1].
231-
Else:
232-
Nibbles are stored in more than 1 byte, proofEl[1] specifies the length of bytes.
233-
Else:
234-
proofEl[1] contains the length of the remaining stream.
235-
proofEl[2] specifies the length of the bytes (for storing nibbles).
236-
Note that we can't have only one nibble in this case.
237-
*/
238-
239-
if setKey {
240-
witnessRow[0] = proofEl[0]
241-
witnessRow[1] = proofEl[1]
242-
}
243-
244-
lenKey, startKey := getExtensionLenStartKey(proofEl)
245-
if startKey == 3 {
246-
witnessRow[2] = proofEl[2]
247-
}
248-
249-
if setKey {
250-
for j := 0; j < lenKey; j++ {
251-
witnessRow[startKey+j] = proofEl[startKey+j]
252-
}
253-
}
254-
255-
encodedNodeLen := proofEl[startKey+lenKey]
256-
nodeLen := byte(0)
257-
start := branch2start
258-
if encodedNodeLen > 192 {
259-
// we have a list, that means a non-hashed node
260-
nodeLen = encodedNodeLen - 192
261-
} else if encodedNodeLen == 160 {
262-
// hashed-node
263-
nodeLen = encodedNodeLen - 128
264-
}
265-
witnessRow[start] = encodedNodeLen
266-
for j := 0; j < int(nodeLen); j++ {
267-
witnessRow[start+1+j] = proofEl[startKey+lenKey+1+j]
268-
}
269-
}
270-
271108
func prepareExtension(v1, v2, proofEl []byte, setKey bool) []byte {
272109
// storageProof[i]:
273110
// [228,130,0,149,160,114,253,150,133,18,192,156,19,241,162,51,210,24,1,151,16,48,7,177,42,60,49,34,230,254,242,79,132,165,90,75,249]

0 commit comments

Comments
 (0)