From e5fc51de4568626c461897bcaa9d58b35ee86973 Mon Sep 17 00:00:00 2001 From: KimiWu Date: Tue, 16 Apr 2024 15:27:22 +0800 Subject: [PATCH] test: complete tests and refine GenerateWitness --- geth-utils/gethutil/mpt/trie/stacktrie.go | 100 +++++----- .../witness/gen_witness_transactions_test.go | 186 +++++++++++++++++- .../gethutil/mpt/witness/prepare_witness.go | 156 +++------------ 3 files changed, 250 insertions(+), 192 deletions(-) diff --git a/geth-utils/gethutil/mpt/trie/stacktrie.go b/geth-utils/gethutil/mpt/trie/stacktrie.go index e87f3fc4bf..ee1c7f648d 100644 --- a/geth-utils/gethutil/mpt/trie/stacktrie.go +++ b/geth-utils/gethutil/mpt/trie/stacktrie.go @@ -69,7 +69,7 @@ type StackTrie struct { // NewStackTrie allocates and initializes an empty trie. func NewStackTrie(db ethdb.KeyValueWriter) *StackTrie { return &StackTrie{ - nodeType: emptyNode, + nodeType: EmptyNode, db: db, } } @@ -166,7 +166,7 @@ func (st *StackTrie) setDb(db ethdb.KeyValueWriter) { func newLeaf(ko int, key, val []byte, db ethdb.KeyValueWriter) *StackTrie { st := stackTrieFromPool(db) - st.nodeType = leafNode + st.nodeType = LeafNode st.keyOffset = ko st.key = append(st.key, key[ko:]...) st.val = val @@ -175,7 +175,7 @@ func newLeaf(ko int, key, val []byte, db ethdb.KeyValueWriter) *StackTrie { func newExt(ko int, key []byte, child *StackTrie, db ethdb.KeyValueWriter) *StackTrie { st := stackTrieFromPool(db) - st.nodeType = extNode + st.nodeType = ExtNode st.keyOffset = ko st.key = append(st.key, key[ko:]...) st.children[0] = child @@ -184,11 +184,11 @@ func newExt(ko int, key []byte, child *StackTrie, db ethdb.KeyValueWriter) *Stac // List all values that StackTrie#nodeType can hold const ( - emptyNode = iota - branchNode - extNode - leafNode - hashedNode + EmptyNode = iota + BranchNode + ExtNode + LeafNode + HashedNode ) // TryUpdate inserts a (key, value) pair into the stack trie @@ -214,7 +214,7 @@ func (st *StackTrie) Reset() { for i := range st.children { st.children[i] = nil } - st.nodeType = emptyNode + st.nodeType = EmptyNode st.keyOffset = 0 } @@ -233,12 +233,12 @@ func (st *StackTrie) getDiffIndex(key []byte) int { // https://github.dev/ethereum/go-ethereum/blob/00905f7dc406cfb67f64cd74113777044fb886d8/core/types/hashing.go#L105-L134 func (st *StackTrie) insert(key, value []byte) { switch st.nodeType { - case branchNode: /* Branch */ + case BranchNode: /* Branch */ idx := int(key[st.keyOffset]) // Unresolve elder siblings for i := idx - 1; i >= 0; i-- { if st.children[i] != nil { - if st.children[i].nodeType != hashedNode { + if st.children[i].nodeType != HashedNode { st.children[i].hash(true) } break @@ -252,7 +252,7 @@ func (st *StackTrie) insert(key, value []byte) { st.children[idx].insert(key, value) } - case extNode: /* Ext */ + case ExtNode: /* Ext */ // Compare both key chunks and see where they differ diffidx := st.getDiffIndex(key) // Check if chunks are identical. If so, recurse into @@ -287,13 +287,13 @@ func (st *StackTrie) insert(key, value []byte) { // a branch node. st.children[0] = nil p = st - st.nodeType = branchNode + st.nodeType = BranchNode } else { // the common prefix is at least one byte // long, insert a new intermediate branch // node. st.children[0] = stackTrieFromPool(st.db) - st.children[0].nodeType = branchNode + st.children[0].nodeType = BranchNode st.children[0].keyOffset = st.keyOffset + diffidx p = st.children[0] } @@ -307,7 +307,7 @@ func (st *StackTrie) insert(key, value []byte) { p.children[newIdx] = o st.key = st.key[:diffidx] - case leafNode: /* Leaf */ + case LeafNode: /* Leaf */ // Compare both key chunks and see where they differ diffidx := st.getDiffIndex(key) @@ -327,15 +327,15 @@ func (st *StackTrie) insert(key, value []byte) { var p *StackTrie if diffidx == 0 { // Convert current leaf into a branch - st.nodeType = branchNode + st.nodeType = BranchNode p = st st.children[0] = nil } else { // Convert current node into an ext, // and insert a child branch node. - st.nodeType = extNode + st.nodeType = ExtNode st.children[0] = NewStackTrie(st.db) - st.children[0].nodeType = branchNode + st.children[0].nodeType = BranchNode st.children[0].keyOffset = st.keyOffset + diffidx p = st.children[0] } @@ -355,11 +355,11 @@ func (st *StackTrie) insert(key, value []byte) { // over to the children. st.key = st.key[:diffidx] st.val = nil - case emptyNode: /* Empty */ - st.nodeType = leafNode + case EmptyNode: /* Empty */ + st.nodeType = LeafNode st.key = key[st.keyOffset:] st.val = value - case hashedNode: + case HashedNode: panic("trying to insert into hash") default: panic("invalid type") @@ -367,7 +367,7 @@ func (st *StackTrie) insert(key, value []byte) { } func (st *StackTrie) branchToHasher(doUpdate bool) *hasher { - if st.nodeType != branchNode { + if st.nodeType != BranchNode { panic("Converting branch to RLP: wrong node") } var nodes [17]Node @@ -401,7 +401,7 @@ func (st *StackTrie) branchToHasher(doUpdate bool) *hasher { } func (st *StackTrie) extNodeToHasher(doUpdate bool) *hasher { - if st.nodeType != extNode { + if st.nodeType != ExtNode { panic("Converting extension node to RLP: wrong node") } st.children[0].hash(doUpdate) @@ -433,22 +433,22 @@ func (st *StackTrie) extNodeToHasher(doUpdate bool) *hasher { return h } -// hash() hashes the node 'st' and converts it into 'hashedNode', if possible. +// hash() hashes the node 'st' and converts it into 'HashedNode', if possible. // Possible outcomes: // 1. The rlp-encoded value was >= 32 bytes: // - Then the 32-byte `hash` will be accessible in `st.val`. -// - And the 'st.type' will be 'hashedNode' +// - And the 'st.type' will be 'HashedNode' // // 2. The rlp-encoded value was < 32 bytes // - Then the <32 byte rlp-encoded value will be accessible in 'st.val'. -// - And the 'st.type' will be 'hashedNode' AGAIN +// - And the 'st.type' will be 'HashedNode' AGAIN // // This method will also: -// set 'st.type' to hashedNode +// set 'st.type' to HashedNode // clear 'st.key' func (st *StackTrie) hash(doUpdate bool) { /* Shortcut if node is already hashed */ - if st.nodeType == hashedNode { + if st.nodeType == HashedNode { return } // The 'hasher' is taken from a pool, but we don't actually @@ -457,11 +457,11 @@ func (st *StackTrie) hash(doUpdate bool) { var h *hasher switch st.nodeType { - case branchNode: + case BranchNode: h = st.branchToHasher(doUpdate) - case extNode: + case ExtNode: h = st.extNodeToHasher(doUpdate) - case leafNode: + case LeafNode: h = NewHasher(false) defer returnHasherToPool(h) h.tmp.Reset() @@ -478,17 +478,17 @@ func (st *StackTrie) hash(doUpdate bool) { if err := rlp.Encode(&h.tmp, n); err != nil { panic(err) } - case emptyNode: + case EmptyNode: st.val = emptyRoot.Bytes() st.key = st.key[:0] - st.nodeType = hashedNode + st.nodeType = HashedNode return default: panic("Invalid node type") } if doUpdate { st.key = st.key[:0] - st.nodeType = hashedNode + st.nodeType = HashedNode } if len(h.tmp) < 32 { st.val = common.CopyBytes(h.tmp) @@ -674,20 +674,20 @@ func printProof(ps [][]byte, t, idx []byte) { enable := byte(150) fmt.Print(" [") for i, p := range ps { - if t[i] == extNode { + if t[i] == ExtNode { fmt.Print("EXT - ") if idx[0] >= enable { fmt.Print(" (", p, ") - ") } - } else if t[i] == branchNode { + } else if t[i] == BranchNode { fmt.Print("BRANCH - ") // fmt.Print(" (", p, ") - ") - } else if t[i] == leafNode { + } else if t[i] == LeafNode { fmt.Print("LEAF - ") if idx[0] >= enable { fmt.Print(" (", p, ") - ") } - } else if t[i] == hashedNode { + } else if t[i] == HashedNode { fmt.Print("HASHED - ") // elems, _, _ := rlp.SplitList(p) // c, _ := rlp.CountValues(elems) @@ -774,8 +774,8 @@ func (st *StackTrie) UpdateAndGetProofs(db ethdb.KeyValueReader, list types.Deri func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [][]byte, []uint8, error) { k := KeybytesToHex(key) // fmt.Println(" k", k) - if st.nodeType == emptyNode { - return [][]byte{}, nil, []uint8{emptyNode}, nil + if st.nodeType == EmptyNode { + return [][]byte{}, nil, []uint8{EmptyNode}, nil } // Note that when root is a leaf, this leaf should be returned even if you ask for a different key (than the key of @@ -786,8 +786,8 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [] // (the one not just added) is the same as in the S proof. This wouldn't work if we would have a placeholder leaf // in the S proof (another reason is that the S proof with a placeholder leaf would be an empty trie and thus with // a root of an empty trie - which is not the case in S proof). - if st.nodeType == leafNode { - return [][]byte{st.val}, nil, []uint8{leafNode}, nil + if st.nodeType == LeafNode { + return [][]byte{st.val}, nil, []uint8{LeafNode}, nil } var nibbles [][]byte @@ -799,21 +799,21 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [] for i := 0; i < len(k); i++ { // fmt.Print(" ", k[i], "/", c.nodeType, " | ") proofType = append(proofType, c.nodeType) - if c.nodeType == extNode { + if c.nodeType == ExtNode { // fmt.Print(c.key, " ") i += len(c.key) - 1 nodes = append(nodes, c) c = c.children[0] - } else if c.nodeType == branchNode { + } else if c.nodeType == BranchNode { nodes = append(nodes, c) c = c.children[k[i]] if c == nil { break } - } else if c.nodeType == leafNode { + } else if c.nodeType == LeafNode { nodes = append(nodes, c) break - } else if c.nodeType == hashedNode { + } else if c.nodeType == HashedNode { c_rlp, error := db.Get(c.val) if error != nil { panic(error) @@ -840,7 +840,7 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [] } c.val = branchChild // if there are children, the node type should be branch - proofType[len(proofType)-1] = branchNode + proofType[len(proofType)-1] = BranchNode } } @@ -852,7 +852,7 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [] lNodes := len(nodes) for i := lNodes - 1; i >= 0; i-- { node := nodes[i] - if node.nodeType == leafNode { + if node.nodeType == LeafNode { nibbles = append(nibbles, []byte{}) rlp, error := db.Get(node.val) if error != nil { // TODO: avoid error when RLP @@ -860,7 +860,7 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [] } else { proof = append(proof, rlp) } - } else if node.nodeType == branchNode || node.nodeType == extNode { + } else if node.nodeType == BranchNode || node.nodeType == ExtNode { node.hash(false) raw_rlp, error := db.Get(node.val) @@ -868,7 +868,7 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, [] return nil, nil, nil, error } proof = append(proof, raw_rlp) - if node.nodeType == extNode { + if node.nodeType == ExtNode { rlp_flag := uint(raw_rlp[0]) if rlp_flag < 192 || rlp_flag >= 248 { diff --git a/geth-utils/gethutil/mpt/witness/gen_witness_transactions_test.go b/geth-utils/gethutil/mpt/witness/gen_witness_transactions_test.go index 24b3c9552f..313b5760b4 100644 --- a/geth-utils/gethutil/mpt/witness/gen_witness_transactions_test.go +++ b/geth-utils/gethutil/mpt/witness/gen_witness_transactions_test.go @@ -103,7 +103,7 @@ func transactionsStackTrieInsertionTemplate(t *testing.T, n int) { // Proof of the first tx is appended at the end of the proofs if len(tx) < 0x80 // That's why we minus 2 here. - if tx_len > 1 && tx_len < 256 { + if tx_len > 1 && tx_len < 128 { last_proofC = proofs[proof_len-2].GetProofC() } last_leaf_proof := last_proofC[len(last_proofC)-1] @@ -114,19 +114,12 @@ func transactionsStackTrieInsertionTemplate(t *testing.T, n int) { } if !bytes.Equal(last_leaf_proof, rlp_last_tx) { - fmt.Println("- last_tx ", rlp_last_tx) - fmt.Println("- last_proof ", last_leaf_proof) + fmt.Println("- last_tx\n ", rlp_last_tx) + fmt.Println("- last_proof\n ", last_leaf_proof) t.Fail() } } -func TestTransactionInsertion(t *testing.T) { - // potential ext. mod nodes - // 145, 513, 529, 785, 1041, 1297, 1553, 1809 - txs := makeTransactions(2015) - prepareStackTrieWitness("TransactionInsertion", types.Transactions(txs)) -} - func TestStackTrieInsertion_1Tx(t *testing.T) { // Only one leaf transactionsStackTrieInsertionTemplate(t, 1) @@ -233,3 +226,176 @@ func TestBatchedTxsProof_33Txs(t *testing.T) { func TestBatchedTxsProof_ManyTxs(t *testing.T) { batchedTransactionsStackTrieProofTemplate(2000) } + +// +// Generate witness and store to json files +// + +// witnessGenerationTemplate obtains the GetProof proof before and after the modification for each +// of the modification. It then converts the two proofs into an MPT circuit witness for each of +// the modifications. +func witnessGenerationTemplate(testName string, list types.DerivableList, loopAll bool) []Node { + db := rawdb.NewMemoryDatabase() + stackTrie := trie.NewStackTrie(db) + proofs, _ := stackTrie.UpdateAndGetProofs(db, list) + root, _ := stackTrie.Commit() + + var nodes []Node + var genWitness = func(idx int, proof *trie.StackProof) { + var key []byte + var subNodes []Node + subNodes = append(subNodes, GetStartNode(testName, common.Hash{}, root, 0)) + var node []Node + if (idx <= 0x80 && len(proofs) == idx) || idx == 128 { + key := rlp.AppendUint64(key[:0], uint64(0)) + node = GenerateWitness(uint(0), key, key, proof) + } else { + key := rlp.AppendUint64(key[:0], uint64(idx)) + node = GenerateWitness(uint(idx), key, key, proof) + } + subNodes = append(subNodes, node...) + subNodes = append(subNodes, GetEndNode()) + + nodes = append(nodes, subNodes...) + verifyNodeNumber(subNodes, *proof) + } + + if loopAll { + for i, proof := range proofs { + genWitness(i+1, &proof) + } + } else { + i := len(proofs) - 1 + if len(proofs) <= 128 { + // When the number of txs is less than 128, the last proof is the proof of tx0 + // and we want the last proof (not the proof of tx0). + // That's why we minus 2 here + i = len(proofs) - 2 + genWitness(i+1, &proofs[i]) + } else { + genWitness(i, &proofs[i]) + } + } + return nodes +} + +// A quick and naive way to verify nodes number, might not be accurate +func verifyNodeNumber(nodes []Node, proof trie.StackProof) { + // start and end nodes + nodeNum := len(nodes) - 2 + + proofS := proof.GetProofS() + proofC := proof.GetProofC() + len1 := len(proofS) + len2 := len(proofC) + maxLen := max(len1, len2) + minLen := min(len1, len2) + + typesS := proof.GetTypeS() + typesC := proof.GetTypeC() + var cntExtS, cntExtC int + for _, t := range typesS { + if t == trie.ExtNode { + cntExtS++ + } + } + for _, t := range typesC { + if t == trie.ExtNode { + cntExtC++ + } + } + maxExtCnt := max(cntExtS, cntExtC) + + // Most of cases + if maxLen == minLen+1 { + // ext. node won't have a node, it shares with a branch + if nodeNum != maxLen-maxExtCnt { + fmt.Println("WARNING: node number not matched: nodeNum != maxLen") + } + } else if maxLen == minLen { + typeS := proof.GetTypeS() + typeC := proof.GetTypeC() + + // [EXT - BRANCH] -> [BRANCH - LEAF] + if typeS[0] != typeC[0] { + if nodeNum == maxLen+1 { + fmt.Println("WARNING: node number not matched: typeS[0] != typeC[0] && nodeNum == maxLen+1") + } + } else { + if nodeNum != maxLen { + fmt.Println("WARNING: node number not matched: nodeNum != maxLen") + } + } + } else if maxLen > minLen+1 { + // usually it happens when a new ext. node created + // [BRANCH - BRANCH - LEAF] -> [BRANCH - BRANCH - EXT - BRANCH - LEAF] + if nodeNum == maxLen+1 { + fmt.Println("WARNING: node number not matched: typeS[0] != typeC[0] && nodeNum == maxLen+1") + } + } else { + fmt.Println("WARNING: WHERE AM I??") + } +} + +func TestTransactionsModExtNodes(t *testing.T) { + t.Skip("Not working now.") + // randomly pick 5 mod-ext nodes + txs := makeTransactions(2000) + var nodes []Node + nodes = witnessGenerationTemplate("TransactionModeExt_16", types.Transactions(txs[:16]), false) + nodes = append(nodes, witnessGenerationTemplate("TransactionModeExt_144", types.Transactions(txs[:145]), false)...) + nodes = append(nodes, witnessGenerationTemplate("TransactionModeExt_512", types.Transactions(txs[:513]), false)...) + nodes = append(nodes, witnessGenerationTemplate("TransactionModeExt_1552", types.Transactions(txs[:1553]), false)...) + nodes = append(nodes, witnessGenerationTemplate("TransactionModeExt_1808", types.Transactions(txs[:1809]), false)...) + + StoreNodes("TransactionsModExtNodes", nodes) +} + +func TestTransactionsNum256(t *testing.T) { + txs := makeTransactions(256) + nodes := witnessGenerationTemplate("TransactionsNum256", types.Transactions(txs), true) + StoreNodes("TransactionsNum256", nodes) +} + +func TestSingleTransactionNum1(t *testing.T) { + // A. [] --> [LEAF] + txs := makeTransactions(1) + nodes := witnessGenerationTemplate("SingleTransactionNum1", types.Transactions(txs), true) + StoreNodes("SingleTransactionNum1", nodes) +} + +func TestSingleTransactionNum3(t *testing.T) { + // B. [LEAF] --> [EXT - BRANCH - LEAF] + txs := makeTransactions(3) + nodes := witnessGenerationTemplate("SingleTransactionNum3", types.Transactions(txs), false) + StoreNodes("SingleTransactionNum3", nodes) +} + +func TestSingleTransactionNormal(t *testing.T) { + // C. [EXT - BRANCH] --> [EXT - BRANCH - LEAF] + txs := makeTransactions(5) + nodes := witnessGenerationTemplate("SingleTransactionNormal", types.Transactions(txs), false) + StoreNodes("SingleTransactionNormal", nodes) +} + +func TestSingleTransactionNormal2(t *testing.T) { + // C. [EXT - BRANCH] --> [EXT - BRANCH - LEAF] + // randomly pick a large number of tx + txs := makeTransactions(1500) + nodes := witnessGenerationTemplate("SingleTransactionNormal", types.Transactions(txs), false) + StoreNodes("SingleTransactionNormal", nodes) +} + +func TestSingleTransactionEndLeaf(t *testing.T) { + // D. [BRANCH - BRANCH] --> [BRANCH - BRANCH - LEAF] + txs := makeTransactions(129) + nodes := witnessGenerationTemplate("SingleTransactionEndLeaf", types.Transactions(txs), false) + StoreNodes("SingleTransactionEndLeaf", nodes) +} + +func TestSingleTransactionNewExtBraLeaf(t *testing.T) { + // E. [BRANCH - BRANCH - LEAF] --> [BRANCH - BRANCH - EXT - BRANCH - LEAF] + txs := makeTransactions(130) + nodes := witnessGenerationTemplate("SingleTransactionNewExtBraLeaf", types.Transactions(txs), false) + StoreNodes("SingleTransactionNewExtBraLeaf", nodes) +} diff --git a/geth-utils/gethutil/mpt/witness/prepare_witness.go b/geth-utils/gethutil/mpt/witness/prepare_witness.go index 9e1e0acae9..be498ca810 100644 --- a/geth-utils/gethutil/mpt/witness/prepare_witness.go +++ b/geth-utils/gethutil/mpt/witness/prepare_witness.go @@ -7,12 +7,9 @@ import ( "main/gethutil/mpt/oracle" "main/gethutil/mpt/state" "main/gethutil/mpt/trie" - "main/gethutil/mpt/types" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rlp" ) const valueLen = 34 @@ -289,110 +286,6 @@ func obtainTwoProofsAndConvertToWitness(trieModifications []TrieModification, st return nodes } -// prepareStackTrieWitness obtains the GetProof proof before and after the modification for each -// of the modification. It then converts the two proofs into an MPT circuit witness for each of -// the modifications and stores it into a file. -func prepareStackTrieWitness(testName string, list types.DerivableList, loop bool) { - db := rawdb.NewMemoryDatabase() - stackTrie := trie.NewStackTrie(db) - proofs, _ := stackTrie.UpdateAndGetProofs(db, list) - root, _ := stackTrie.Commit() - - var key []byte - var nodes []Node - for i, proof := range proofs { - idx := i + 1 - - // ==== debug section - if !loop { - i := len(proofs) - 2 - if len(proofs) > 128 { - i = len(proofs) - 1 - } - proof = proofs[i] - idx = i - - // for _, p := range proof.GetProofC() { - // fmt.Println("C: ", p) - // } - } - // ===== - - var subNodes []Node - subNodes = append(subNodes, GetStartNode(testName, common.Hash{}, root, 0)) - var node []Node - if (i <= 0x7f && len(proofs)-1 == i) || i == 127 { - key = rlp.AppendUint64(key[:0], uint64(0)) - node = GenerateWitness(uint(0), key, key, &proof) - } else { - key = rlp.AppendUint64(key[:0], uint64(idx)) - node = GenerateWitness(uint(idx), key, key, &proof) - } - subNodes = append(subNodes, node...) - subNodes = append(subNodes, GetEndNode()) - verifyNodeNumber(subNodes, proof) - - nodes = append(nodes, subNodes...) - - if !loop { - break - } - } - StoreNodes(testName, nodes) - - // check -} - -// For quick verification the json data. -// will be removed before merge. -func verifyNodeNumber(nodes []Node, proof trie.StackProof) { - // start and end nodes - nodeNum := len(nodes) - 2 - - proofS := proof.GetProofS() - proofC := proof.GetProofC() - len1 := len(proofS) - len2 := len(proofC) - maxLen := max(len1, len2) - minLen := min(len1, len2) - - typesS := proof.GetTypeS() - typesC := proof.GetTypeC() - var cntS, cntC int - for _, t := range typesS { - if t == 2 { - cntS++ - } - } - for _, t := range typesC { - if t == 2 { - cntC++ - } - } - maxExtCnt := max(cntS, cntC) - - if maxLen == minLen+1 { - if nodeNum != maxLen-maxExtCnt { - fmt.Println("WARNING: node number not matched: nodeNum != maxLen") - } - } else if maxLen == minLen { - // [EXT - BRANCH] -> [BRANCH - LEAF] - typeS := proof.GetTypeS() - typeC := proof.GetTypeC() - if typeS[0] != typeC[0] && nodeNum == maxLen+1 { - fmt.Println("WARNING: node number not matched: typeS[0] != typeC[0] && nodeNum == maxLen+1") - } - } else if maxLen > minLen+1 { - // usually it happens when a new ext. node created - // [BRANCH - BRANCH - LEAF] -> [BRANCH - BRANCH - EXT - BRANCH - LEAF] - if nodeNum == maxLen+1 { - fmt.Println("WARNING: node number not matched: typeS[0] != typeC[0] && nodeNum == maxLen+1") - } - } else { - fmt.Println("WHERE AM I??") - } -} - // prepareWitness obtains the GetProof proof before and after the modification for each // of the modification. It then converts the two proofs into an MPT circuit witness for each of // the modifications and stores it into a file. @@ -413,23 +306,22 @@ func prepareWitnessSpecial(testName string, trieModifications []TrieModification // For stack trie, we have the following combinations ([proofS] -> [proofC]) // -// -[o] [(empty)] -> [LEAF] --> 1 -// -[o] [LEAF] -> [EXT - BRANCH - LEAF] --> 2 -// -[o] [EXT - BRANCH] -> [EXT - BRANCH - LEAF] --> "< 16" -// -[M] [EXT - BRANCH] -> [BRANCH - LEAF] --> 0 under 16 txs or 16 (modified ext.) -// -[o] [BRANCH - BRANCH] -> [BRANCH - BRANCH - LEAF] --> "< 127" -// -[o] [BRANCH - LEAF] -> [BRANCH - BRANCH - LEAF] --> 129 -// -[o] [BRANCH] -> [BRANCH - LEAF] --> 0 -// -[o] [BRANCH - BRANCH - LEAF] -> [BRANCH - BRANCH - EXT - BRANCH - LEAF] --> 129 -// -[o] [BRANCH - BRANCH - EXT - BRANCH] -> [BRANCH - BRANCH - EXT - BRANCH - LEAF] --> 130 -// -[M] [BRANCH - BRANCH - EXT - BRANCH - HASHED] -> [BRANCH - BRANCH - BRANCH - LEAF] --> 144 -// -[M] [BRANCH - BRANCH - EXT - BRANCH - BRANCH - HASHED] -> [BRANCH - BRANCH - EXT - BRANCH - LEAF] --> 512 -// -[o] [BRANCH - BRANCH - (...BRANCH)] -> [BRANCH - BRANCH - (...BRANCH) - LEAF] --> 146 ~ 176 -// -[o] [BRANCH - BRANCH - EXT - (BRANCH..)] -> [BRANCH - BRANCH - EXT - (BRANCH..) - LEAF] --> 258~ -// -[o] [BRANCH - BRANCH - EXT - BRANCH - LEAF] -> [BRANCH - BRANCH - EXT - BRANCH - EXT - BRANCH - LEAF] --> 513 -// -[o] [BRANCH - BRANCH - EXT - BRANCH - EXT - BRANCH] -> [BRANCH - BRANCH - EXT - BRANCH - EXT - BRANCH - LEAF] --> 514~ +// --- special case for the first 2 txs +// A. [(empty)] -> [LEAF] --> 1 +// B. [LEAF] -> [EXT - BRANCH - LEAF] --> 2 +// +// --- most of cases +// C. [(EXT, BRANCH)] -> [(EXT, BRANCH) - LEAF] // -// TODO modified extension node +// --- both proofs end with a leaf node +// D. [BRANCH - LEAF] -> [BRANCH - BRANCH - LEAF] --> 129 +// E. [(EXT, BRANCH) - LEAF] -> [(EXT, BRANCH) - EXT - BRANCH - LEAF] --> 130, 514 +// +// --- TODO: modified extension nodes, not working now +// M. [EXT - BRANCH] -> [BRANCH - LEAF] --> 0 under 16 txs or 16 (modified ext.) +// M. [(BRANCH) - EXT - BRANCH - HASHED] -> [(BRANCH) - BRANCH - LEAF] --> 144 +// M. [(BRANCH, EXT) - BRANCH - HASHED] -> [(BRANCH, EXT) - LEAF] --> 512 +// Issue: // Take tx144 as example, the proof is // [BRANCH_S1 - BRANCH_S2 - EXT_S - BRANCH_S3 - HASHED] -> [BRANCH_C1 - BRANCH_C2 - BRANCH_C3 - LEAF] // We need to generate a json with nodes @@ -466,26 +358,27 @@ func GenerateWitness(txIdx uint, key, value []byte, proof *trie.StackProof) []No lastProofTypeS := proofTypeS[len1-1] lastProofTypeC := proofTypeC[len2-1] - // FIXME: using enum(branch, leaf...) to replace magic numbers upTo := minLen additionalBranch := true // If both of proofs end with either a leaf or a hashed node, e.g. [BRANCH - LEAF] --> [BRANCH - BRANCH - LEAF] // The 2nd BRANCH in above proofC should have a branch placeholder for it. // We handle branch placeholder in `additionalBranch` and that's why we need to minus `upTo` by 1 here. - if len1 != len2 && (lastProofTypeS == 3 || lastProofTypeS == 4) && (lastProofTypeC == 3 || lastProofTypeC == 4) { + if len1 != len2 && + (lastProofTypeS == trie.LeafNode || lastProofTypeS == trie.HashedNode) && + (lastProofTypeC == trie.LeafNode || lastProofTypeC == trie.HashedNode) { upTo-- } // The length of proofS and proofC is equal and the last element of proofS is a hashed node or a leaf - if len1 == len2 && (lastProofTypeS == 3 || lastProofTypeS == 4) { + if len1 == len2 && (lastProofTypeS == trie.LeafNode || lastProofTypeS == trie.HashedNode) { additionalBranch = false } // Special case for the 2nd tx. // In this case, proofS only contains a leaf node and proofC is [EXT - BRANCH - LEAF]. // `additionalBranch` can handle the mismatched the order of the type. - if len1 == 1 && lastProofTypeS == 3 { + if len1 == 1 && lastProofTypeS == trie.LeafNode { upTo = 0 } @@ -500,9 +393,7 @@ func GenerateWitness(txIdx uint, key, value []byte, proof *trie.StackProof) []No mismatchedIdx := -1 fmt.Println("upto", upTo, additionalBranch, proofTypeS) for i := 0; i < upTo; i++ { - if proofTypeS[i] != 1 { - // fmt.Println("extNibbleS/C", extNibblesS, "|", extNibblesC) - + if proofTypeS[i] != trie.BranchNode { // This is for the case of extension modified node due to the order of the types mismatched. // See this example, // [BRANCH - BRANCH - EXT - BRANCH - HASHED] -> [BRANCH - BRANCH - BRANCH - LEAF] @@ -553,7 +444,8 @@ func GenerateWitness(txIdx uint, key, value []byte, proof *trie.StackProof) []No // In most of cases, proofs are like this [BRANCH - (BRANCH, EXT)] -> [BRANCH - (BRANCH, EXT) - LEAF] // That means proofC only appends a leaf node to proofS. // In such cases, we don't need to add a placeholder branch - need_branch_placeholder := !(len1 == len2-1 && (lastProofTypeS != lastProofTypeC) && (lastProofTypeC == 3)) + need_branch_placeholder := + !(len1 == len2-1 && (lastProofTypeS != lastProofTypeC) && (lastProofTypeC == trie.LeafNode)) if need_branch_placeholder { var extProofS []byte if mismatchedIdx != -1 { @@ -579,7 +471,7 @@ func GenerateWitness(txIdx uint, key, value []byte, proof *trie.StackProof) []No // So, we use `mismatchedIdx` to represent the case. if mismatchedIdx == -1 { // Add a tx leaf after branch placeholder - if lastProofTypeS == 3 { + if lastProofTypeS == trie.LeafNode { leafNode = prepareTxLeafNode(txIdx, proofS[len1-1], proofC[len2-1], k, nil, isBranch(proofS[len1-1]), false, false) } else { leafNode = prepareTxLeafAndPlaceholderNode(txIdx, proofC[len2-1], k, false)