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

Commit 81e715a

Browse files
authored
MPT StorageDoesNotExist (#1699)
### Description A couple of `StorageDoesNotExist` issues to be addressed: 1. Witness generation fails for `getProof` proofs of length 0. 2. For `StorageDoesNotExist`, when the trie is empty, the key occupies `33 (33 = 161 - 128)` bytes, as in the example below: ``` [227 161 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] ``` Currently, the length for the RLP items is set `valueLen = 34`, so we don't have space for all 33 bytes. 3. It seems that some constraints of the `StorageDoesNotExist` proof were lost on the way - currently there are only constraints for the `wrong` leaf, but the constraints for the case when the node in branch is `nil` are missing. ### Type of change - [x] Bug fix (non-breaking change which fixes an issue) ### How Has This Been Tested? `TestStorageDoesNotExistOnlySProof` in `mpt-witness-generator/witness/gen_witness_from_infura_blockchain_test.go`.
1 parent 90eebff commit 81e715a

File tree

11 files changed

+1204
-178
lines changed

11 files changed

+1204
-178
lines changed

mpt-witness-generator/witness/branch.go

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ func prepareBranchWitness(rows [][]byte, branch []byte, branchStart int, branchR
6565
}
6666
}
6767

68-
func prepareBranchNode(branch1, branch2, extNode1, extNode2, extListRlpBytes []byte, extValues [][]byte, key, driftedInd,
69-
branchC16, branchC1 byte, isBranchSPlaceholder, isBranchCPlaceholder, isExtension bool) Node {
68+
func prepareBranchNode(branch1, branch2, extNode1, extNode2, extListRlpBytes []byte, extValues [][]byte, key, driftedInd byte,
69+
isBranchSPlaceholder, isBranchCPlaceholder, isExtension bool) Node {
7070
extensionNode := ExtensionNode{
7171
ListRlpBytes: extListRlpBytes,
7272
}
@@ -197,7 +197,7 @@ func addBranchAndPlaceholder(proof1, proof2,
197197
leafRow0, key, neighbourNode []byte,
198198
keyIndex, extensionNodeInd int,
199199
additionalBranch, isAccountProof, nonExistingAccountProof,
200-
isShorterProofLastLeaf bool, branchC16, branchC1 byte, toBeHashed *[][]byte) (bool, bool, int, byte, Node) {
200+
isShorterProofLastLeaf bool, toBeHashed *[][]byte) (bool, bool, int, Node) {
201201
len1 := len(proof1)
202202
len2 := len(proof2)
203203

@@ -211,32 +211,14 @@ func addBranchAndPlaceholder(proof1, proof2,
211211
}
212212

213213
isExtension := (len1 == len2+2) || (len2 == len1+2)
214-
if !isExtension {
215-
if branchC16 == 1 {
216-
branchC16 = 0
217-
branchC1 = 1
218-
} else {
219-
branchC16 = 1
220-
branchC1 = 0
221-
}
222-
} else {
214+
if isExtension {
223215
var numNibbles byte
224216
if len1 > len2 {
225217
numNibbles, extListRlpBytes, extValues = prepareExtensions(extNibblesS, extensionNodeInd, proof1[len1-3], proof1[len1-3])
226218
} else {
227219
numNibbles, extListRlpBytes, extValues = prepareExtensions(extNibblesC, extensionNodeInd, proof2[len2-3], proof2[len2-3])
228220
}
229221
numberOfNibbles = int(numNibbles)
230-
231-
if numberOfNibbles%2 == 0 {
232-
if branchC16 == 1 {
233-
branchC16 = 0
234-
branchC1 = 1
235-
} else {
236-
branchC16 = 1
237-
branchC1 = 0
238-
}
239-
}
240222
}
241223

242224
/*
@@ -290,8 +272,7 @@ func addBranchAndPlaceholder(proof1, proof2,
290272
driftedInd := getDriftedPosition(leafRow0, numberOfNibbles)
291273

292274
node = prepareBranchNode(proof1[len1-2], proof1[len1-2], extNode, extNode, extListRlpBytes, extValues,
293-
key[keyIndex+numberOfNibbles], driftedInd,
294-
branchC16, branchC1, false, true, isExtension)
275+
key[keyIndex+numberOfNibbles], driftedInd, false, true, isExtension)
295276

296277
// We now get the first nibble of the leaf that was turned into branch.
297278
// This first nibble presents the position of the leaf once it moved
@@ -303,9 +284,8 @@ func addBranchAndPlaceholder(proof1, proof2,
303284
driftedInd := getDriftedPosition(leafRow0, numberOfNibbles)
304285

305286
node = prepareBranchNode(proof2[len2-2], proof2[len2-2], extNode, extNode, extListRlpBytes, extValues,
306-
key[keyIndex+numberOfNibbles], driftedInd,
307-
branchC16, branchC1, true, false, isExtension)
287+
key[keyIndex+numberOfNibbles], driftedInd, true, false, isExtension)
308288
}
309289

310-
return isModifiedExtNode, isExtension, numberOfNibbles, branchC16, node
290+
return isModifiedExtNode, isExtension, numberOfNibbles, node
311291
}

mpt-witness-generator/witness/gen_witness_from_infura_blockchain_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,3 +2302,34 @@ func TestWrongAccount(t *testing.T) {
23022302

23032303
prepareWitness("WrongAccount", trieModifications, statedb)
23042304
}
2305+
2306+
func TestStorageDoesNotExistOnlySProof(t *testing.T) {
2307+
blockNum := 2000003
2308+
blockNumberParent := big.NewInt(int64(blockNum))
2309+
blockHeaderParent := oracle.PrefetchBlock(blockNumberParent, true, nil)
2310+
database := state.NewDatabase(blockHeaderParent)
2311+
statedb, _ := state.New(blockHeaderParent.Root, database, nil)
2312+
addr := common.HexToAddress("0xcaac46d9bd68bffb533320545a90cd92c6e98e58")
2313+
2314+
// Implicitly create account:
2315+
trieMod1 := TrieModification{
2316+
Type: BalanceChanged,
2317+
Balance: big.NewInt(98),
2318+
Address: addr,
2319+
}
2320+
2321+
key1 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")
2322+
// leave the same
2323+
val1 := common.Hash{}
2324+
2325+
trieMod2 := TrieModification{
2326+
Type: StorageDoesNotExist,
2327+
Key: key1,
2328+
Value: val1,
2329+
Address: addr,
2330+
}
2331+
2332+
trieModifications := []TrieModification{trieMod1, trieMod2}
2333+
2334+
prepareWitness("StorageDoesNotExistOnlySProof", trieModifications, statedb)
2335+
}

mpt-witness-generator/witness/leaf.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func prepareEmptyNonExistingStorageRow() []byte {
1414
return nonExistingStorageRow
1515
}
1616

17-
func prepareNonExistingStorageRow(leafC, keyNibbles []byte, noLeaf bool) ([]byte, []byte) {
17+
func prepareNonExistingStorageRow(leafC, keyNibbles []byte) ([]byte, []byte) {
1818
// nonExistingStorageRow is used only for proof that nothing is stored at a particular storage key
1919
nonExistingStorageRow := prepareEmptyNonExistingStorageRow()
2020

@@ -307,7 +307,7 @@ func prepareAccountLeafNode(addr common.Address, addrh []byte, leafS, leafC, nei
307307

308308
// prepareLeafAndPlaceholderNode prepares a leaf node and its placeholder counterpart
309309
// (used when one of the proofs does not have a leaf).
310-
func prepareLeafAndPlaceholderNode(addr common.Address, addrh []byte, proof1, proof2 [][]byte, storage_key common.Hash, key []byte, nonExistingAccountProof, isAccountProof, isSModExtension, isCModExtension bool) Node {
310+
func prepareLeafAndPlaceholderNode(addr common.Address, addrh []byte, proof1, proof2 [][]byte, storage_key common.Hash, key []byte, isAccountProof, isSModExtension, isCModExtension bool) Node {
311311
len1 := len(proof1)
312312
len2 := len(proof2)
313313

@@ -407,7 +407,10 @@ func prepareAccountLeafPlaceholderNode(addr common.Address, addrh, key []byte, k
407407
}
408408

409409
func prepareStorageLeafPlaceholderNode(storage_key common.Hash, key []byte, keyIndex int) Node {
410-
leaf := make([]byte, valueLen)
410+
// valueLen + 1 because the placeholder leaf in the empty trie occupies 35 bytes:
411+
// [227 161 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
412+
// 33 (33 = 161 - 128) bytes for path, as in the example above
413+
leaf := make([]byte, valueLen+1)
411414
setStorageLeafKeyRLP(&leaf, key, keyIndex)
412415
keyLen := getLeafKeyLen(keyIndex)
413416
leaf[0] = 192 + 1 + byte(keyLen) + 1
@@ -529,8 +532,7 @@ func prepareStorageLeafNode(leafS, leafC, neighbourNode []byte, storage_key comm
529532
var nonExistingStorageRow []byte
530533
var wrongRlpBytes []byte
531534
if nonExistingStorageProof {
532-
noLeaf := false
533-
wrongRlpBytes, nonExistingStorageRow = prepareNonExistingStorageRow(leafC, key, noLeaf)
535+
wrongRlpBytes, nonExistingStorageRow = prepareNonExistingStorageRow(leafC, key)
534536
} else {
535537
nonExistingStorageRow = prepareEmptyNonExistingStorageRow()
536538
}

mpt-witness-generator/witness/modified_extension_node.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func equipLeafWithModExtensionNode(statedb *state.StateDB, leafNode Node, addr c
1515
key, neighbourNode []byte,
1616
keyIndex, extensionNodeInd, numberOfNibbles int,
1717
additionalBranch, isAccountProof, nonExistingAccountProof,
18-
isShorterProofLastLeaf bool, branchC16, branchC1 byte, toBeHashed *[][]byte) Node {
18+
isShorterProofLastLeaf bool, toBeHashed *[][]byte) Node {
1919
len1 := len(proof1)
2020
len2 := len(proof2)
2121

mpt-witness-generator/witness/prepare_witness.go

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -369,11 +369,18 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
369369

370370
var nodes []Node
371371

372-
branchC16 := byte(0)
373-
branchC1 := byte(1)
374372
for i := 0; i < upTo; i++ {
375373
if !isBranch(proof1[i]) {
376-
if i != len1-1 { // extension node
374+
isNonExistingProof := (isAccountProof && nonExistingAccountProof) || (!isAccountProof && nonExistingStorageProof)
375+
areThereNibbles := len(extNibblesS) != 0 || len(extNibblesC) != 0
376+
// If i < upTo-1, it means it's not a leaf, so it's an extension node.
377+
// There is no any special relation between isNonExistingProof and isExtension,
378+
// except that in the non-existing proof the extension node can appear in `i == upTo-1`.
379+
// For non-existing proof, the last node in the proof could be an extension node (we have
380+
// nil in the underlying branch). For the non-existing proof with the wrong leaf
381+
// (non-existing proofs can be with a nil leaf or with a wrong leaf),
382+
// we don't need to worry because it appears in i = upTo-1).
383+
if (i != upTo-1) || (areThereNibbles && isNonExistingProof) { // extension node
377384
var numberOfNibbles byte
378385
isExtension = true
379386
numberOfNibbles, extListRlpBytes, extValues = prepareExtensions(extNibblesS, extensionNodeInd, proof1[i], proof2[i])
@@ -393,27 +400,6 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
393400

394401
nodes = append(nodes, node)
395402
} else {
396-
switchC16 := true // If not extension node, switchC16 = true.
397-
if isExtension {
398-
keyLen := getExtensionNodeKeyLen(proof1[i-1])
399-
if keyLen == 1 {
400-
switchC16 = false
401-
} else {
402-
if proof1[i-1][2] != 0 { // If even, switch16 = true.
403-
switchC16 = false
404-
}
405-
}
406-
}
407-
if switchC16 {
408-
if branchC16 == 1 {
409-
branchC16 = 0
410-
branchC1 = 1
411-
} else {
412-
branchC16 = 1
413-
branchC1 = 0
414-
}
415-
}
416-
417403
var extNode1 []byte = nil
418404
var extNode2 []byte = nil
419405
if isExtension {
@@ -422,7 +408,7 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
422408
}
423409

424410
bNode := prepareBranchNode(proof1[i], proof2[i], extNode1, extNode2, extListRlpBytes, extValues,
425-
key[keyIndex], key[keyIndex], branchC16, branchC1, false, false, isExtension)
411+
key[keyIndex], key[keyIndex], false, false, isExtension)
426412
nodes = append(nodes, bNode)
427413

428414
keyIndex += 1
@@ -438,10 +424,10 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
438424
leafRow0 = proof2[len2-1]
439425
}
440426

441-
isModifiedExtNode, _, numberOfNibbles, branchC16, bNode := addBranchAndPlaceholder(proof1, proof2, extNibblesS, extNibblesC,
427+
isModifiedExtNode, _, numberOfNibbles, bNode := addBranchAndPlaceholder(proof1, proof2, extNibblesS, extNibblesC,
442428
leafRow0, key, neighbourNode,
443429
keyIndex, extensionNodeInd, additionalBranch,
444-
isAccountProof, nonExistingAccountProof, isShorterProofLastLeaf, branchC16, branchC1, &toBeHashed)
430+
isAccountProof, nonExistingAccountProof, isShorterProofLastLeaf, &toBeHashed)
445431

446432
nodes = append(nodes, bNode)
447433

@@ -458,7 +444,7 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
458444
} else {
459445
isCModExtension = true
460446
}
461-
leafNode = prepareLeafAndPlaceholderNode(addr, addrh, proof1, proof2, storage_key, key, nonExistingAccountProof, isAccountProof, isSModExtension, isCModExtension)
447+
leafNode = prepareLeafAndPlaceholderNode(addr, addrh, proof1, proof2, storage_key, key, isAccountProof, isSModExtension, isCModExtension)
462448
}
463449
} else {
464450
// Add storage leaf after branch placeholder
@@ -472,7 +458,7 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
472458
} else {
473459
isCModExtension = true
474460
}
475-
leafNode = prepareLeafAndPlaceholderNode(addr, addrh, proof1, proof2, storage_key, key, nonExistingAccountProof, isAccountProof, isSModExtension, isCModExtension)
461+
leafNode = prepareLeafAndPlaceholderNode(addr, addrh, proof1, proof2, storage_key, key, isAccountProof, isSModExtension, isCModExtension)
476462
}
477463
}
478464

@@ -482,14 +468,14 @@ func convertProofToWitness(statedb *state.StateDB, addr common.Address, addrh []
482468
if isModifiedExtNode {
483469
leafNode = equipLeafWithModExtensionNode(statedb, leafNode, addr, proof1, proof2, extNibblesS, extNibblesC, key, neighbourNode,
484470
keyIndex, extensionNodeInd, numberOfNibbles, additionalBranch,
485-
isAccountProof, nonExistingAccountProof, isShorterProofLastLeaf, branchC16, branchC1, &toBeHashed)
471+
isAccountProof, nonExistingAccountProof, isShorterProofLastLeaf, &toBeHashed)
486472
}
487473
nodes = append(nodes, leafNode)
488474
} else {
489-
node := prepareLeafAndPlaceholderNode(addr, addrh, proof1, proof2, storage_key, key, nonExistingAccountProof, isAccountProof, false, false)
475+
node := prepareLeafAndPlaceholderNode(addr, addrh, proof1, proof2, storage_key, key, isAccountProof, false, false)
490476
nodes = append(nodes, node)
491477
}
492-
} else if isBranch(proof2[len(proof2)-1]) {
478+
} else if (len1 == 0 && len2 == 0) || isBranch(proof2[len(proof2)-1]) {
493479
// Account proof has drifted leaf as the last row, storage proof has non-existing-storage row
494480
// as the last row.
495481
// When non existing proof and only the branches are returned, we add a placeholder leaf.

0 commit comments

Comments
 (0)