This repository was archived by the owner on Jul 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 839
Feat/#1752 fix witness generation - adding testing #1784
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
05f358f
adding more testings and refactor getNodeFromBranchRLP
KimiWu123 056fa7f
test: added proof equality check
KimiWu123 169b8c3
fix: number of txs is larger than 256 and input an ext node into getN…
KimiWu123 414e228
Merge branch 'main' into feat/#1752-fix-witness-generation-test
KimiWu123 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -243,16 +243,17 @@ func (st *StackTrie) insert(key, value []byte) { | |
break | ||
} | ||
} | ||
|
||
// Add new child | ||
if st.children[idx] == nil { | ||
st.children[idx] = stackTrieFromPool(st.db) | ||
st.children[idx].keyOffset = st.keyOffset + 1 | ||
st.children[idx] = newLeaf(st.keyOffset+1, key, value, st.db) | ||
} else { | ||
st.children[idx].insert(key, value) | ||
} | ||
st.children[idx].insert(key, value) | ||
|
||
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 | ||
// the child node. Otherwise, the key has to be split | ||
// into 1) an optional common prefix, 2) the fullnode | ||
|
@@ -551,57 +552,85 @@ func (st *StackTrie) Commit() (common.Hash, error) { | |
return common.BytesToHash(st.val), nil | ||
} | ||
|
||
func (st *StackTrie) getNodeFromBranchRLP(branch []byte, ind byte) []byte { | ||
start := 2 // when branch[0] == 248 | ||
if branch[0] == 249 { | ||
start = 3 | ||
} | ||
|
||
i := 0 | ||
insideInd := -1 | ||
cInd := byte(0) | ||
for { | ||
if start+i == len(branch)-1 { // -1 because of the last 128 (branch value) | ||
return []byte{0} | ||
} | ||
b := branch[start+i] | ||
if insideInd == -1 && b == 128 { | ||
if cInd == ind { | ||
const RLP_SHORT_STR_FLAG = 128 | ||
const RLP_SHORT_LIST_FLAG = 192 | ||
const RLP_LONG_LIST_FLAG = 248 | ||
const LEN_OF_HASH = 32 | ||
|
||
// Note: | ||
// In RLP encoding, if the value is between [0x80, 0xb7] ([128, 183]), | ||
// it means following data is a short string (0 - 55bytes). | ||
// Which implies if the value is 128, it's an empty string. | ||
func (st *StackTrie) getNodeFromBranchRLP(branch []byte, idx int) []byte { | ||
|
||
start := int(branch[0]) | ||
start_idx := 0 | ||
if start >= RLP_SHORT_LIST_FLAG && start < RLP_LONG_LIST_FLAG { | ||
// In RLP encoding, length in the range of [192 248] is a short list. | ||
// In stack trie, it usually means an extension node and the first byte is nibble | ||
// and that's why we start from 2 | ||
start_idx = 2 | ||
} else if start >= RLP_LONG_LIST_FLAG { | ||
// In RLP encoding, length in the range of [248 ~ ] is a long list. | ||
// The RLP byte minus 248 (branch[0] - 248) is the length in bytes of the length of the payload | ||
// and the payload is right after the length. | ||
// That's why we add 2 here | ||
// e.g. [248 81 128 160 ...] | ||
// `81` is the length of the payload and payload starts from `128` | ||
start_idx = start - RLP_LONG_LIST_FLAG + 2 | ||
} | ||
|
||
// If 1st node is neither 128(empty node) nor 160, it should be a leaf | ||
b := int(branch[start_idx]) | ||
if b != RLP_SHORT_STR_FLAG && b != (RLP_SHORT_STR_FLAG+LEN_OF_HASH) { | ||
return []byte{0} | ||
} | ||
|
||
current_idx := 0 | ||
for i := start_idx; i < len(branch); i++ { | ||
b = int(branch[i]) | ||
switch b { | ||
case RLP_SHORT_STR_FLAG: // 128 | ||
// if the current index is we're looking for, return an empty node directly | ||
if current_idx == idx { | ||
return []byte{128} | ||
} else { | ||
cInd += 1 | ||
} | ||
} else if insideInd == -1 && b != 128 { | ||
if b == 160 { | ||
if cInd == ind { | ||
return branch[start+i+1 : start+i+1+32] | ||
} | ||
insideInd = 32 | ||
} else { | ||
// non-hashed node | ||
if cInd == ind { | ||
return branch[start+i+1 : start+i+1+int(b)-192] | ||
} | ||
insideInd = int(b) - 192 | ||
current_idx++ | ||
case RLP_SHORT_STR_FLAG + LEN_OF_HASH: // 160 | ||
KimiWu123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if current_idx == idx { | ||
return branch[i+1 : i+1+LEN_OF_HASH] | ||
} | ||
cInd += 1 | ||
} else { | ||
if insideInd == 1 { | ||
insideInd = -1 | ||
} else { | ||
insideInd-- | ||
// jump to next encoded element | ||
i += LEN_OF_HASH | ||
current_idx++ | ||
default: | ||
if b >= 192 && b < 248 { | ||
length := b - 192 | ||
if current_idx == idx { | ||
return branch[i+1 : i+1+length] | ||
} | ||
i += length | ||
current_idx++ | ||
} | ||
} | ||
|
||
i++ | ||
} | ||
|
||
return []byte{0} | ||
} | ||
|
||
type StackProof struct { | ||
proofS [][]byte | ||
proofC [][]byte | ||
} | ||
|
||
func (sp *StackProof) GetProofS() [][]byte { | ||
return sp.proofS | ||
} | ||
|
||
func (sp *StackProof) GetProofC() [][]byte { | ||
return sp.proofC | ||
} | ||
|
||
func (st *StackTrie) UpdateAndGetProof(db ethdb.KeyValueReader, indexBuf, value []byte) (StackProof, error) { | ||
proofS, err := st.GetProof(db, indexBuf) | ||
if err != nil { | ||
|
@@ -618,6 +647,8 @@ func (st *StackTrie) UpdateAndGetProof(db ethdb.KeyValueReader, indexBuf, value | |
return StackProof{proofS, proofC}, nil | ||
} | ||
|
||
// We refer to the link below for this function. | ||
// https://github.com/ethereum/go-ethereum/blob/00905f7dc406cfb67f64cd74113777044fb886d8/core/types/hashing.go#L105-L134 | ||
func (st *StackTrie) UpdateAndGetProofs(db ethdb.KeyValueReader, list types.DerivableList) ([]StackProof, error) { | ||
valueBuf := types.EncodeBufferPool.Get().(*bytes.Buffer) | ||
defer types.EncodeBufferPool.Put(valueBuf) | ||
|
@@ -631,33 +662,40 @@ func (st *StackTrie) UpdateAndGetProofs(db ethdb.KeyValueReader, list types.Deri | |
for i := 1; i < list.Len() && i <= 0x7f; i++ { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No change is requested here. I just comment to inform the future reviewers. I saw the duplicated code chunks in L662's loop body, L674's condition body, and L684's loop body. |
||
indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) | ||
value := types.EncodeForDerive(list, i, valueBuf) | ||
|
||
proof, err := st.UpdateAndGetProof(db, indexBuf, value) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
proofs = append(proofs, proof) | ||
} | ||
|
||
// special case when index is 0 | ||
// rlp.AppendUint64() encodes index 0 to [128] | ||
if list.Len() > 0 { | ||
indexBuf = rlp.AppendUint64(indexBuf[:0], 0) | ||
value := types.EncodeForDerive(list, 0, valueBuf) | ||
// TODO: get proof | ||
st.Update(indexBuf, value) | ||
proof, err := st.UpdateAndGetProof(db, indexBuf, value) | ||
if err != nil { | ||
return nil, err | ||
} | ||
proofs = append(proofs, proof) | ||
} | ||
|
||
for i := 0x80; i < list.Len(); i++ { | ||
indexBuf = rlp.AppendUint64(indexBuf[:0], uint64(i)) | ||
value := types.EncodeForDerive(list, i, valueBuf) | ||
// TODO: get proof | ||
st.Update(indexBuf, value) | ||
proof, err := st.UpdateAndGetProof(db, indexBuf, value) | ||
if err != nil { | ||
return nil, err | ||
} | ||
proofs = append(proofs, proof) | ||
} | ||
|
||
return proofs, nil | ||
} | ||
|
||
func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, error) { | ||
k := KeybytesToHex(key) | ||
|
||
if st.nodeType == emptyNode { | ||
return [][]byte{}, nil | ||
} | ||
|
@@ -682,7 +720,8 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, er | |
for i := 0; i < len(k); i++ { | ||
if c.nodeType == extNode { | ||
nodes = append(nodes, c) | ||
c = st.children[0] | ||
c = c.children[0] | ||
|
||
} else if c.nodeType == branchNode { | ||
nodes = append(nodes, c) | ||
c = c.children[k[i]] | ||
|
@@ -700,11 +739,11 @@ func (st *StackTrie) GetProof(db ethdb.KeyValueReader, key []byte) ([][]byte, er | |
} | ||
|
||
proof = append(proof, c_rlp) | ||
branchChild := st.getNodeFromBranchRLP(c_rlp, k[i]) | ||
branchChild := st.getNodeFromBranchRLP(c_rlp, int(k[i])) | ||
|
||
// branchChild is of length 1 when there is no child at this position in the branch | ||
// (`branchChild = [128]` in this case), but it is also of length 1 when `c_rlp` is a leaf. | ||
if len(branchChild) == 1 { | ||
if len(branchChild) == 1 && (branchChild[0] == 128 || branchChild[0] == 0) { | ||
// no child at this position - 128 is RLP encoding for nil object | ||
break | ||
} | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what's the reason for this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I just followed how geth implemented it (https://github.com/ethereum/go-ethereum/blob/00905f7dc406cfb67f64cd74113777044fb886d8/trie/stacktrie.go#L211-L215). Besides, it looks more self-explanation for me, one case is to new a leaf and the other is to insert a node. The original one seems too optimized and not easy to understand.