light: implemented odr-capable trie and state structures
This commit is contained in:
@ -69,6 +69,27 @@ func compactHexDecode(str []byte) []byte {
|
||||
return nibbles
|
||||
}
|
||||
|
||||
// compactHexEncode encodes a series of nibbles into a byte array
|
||||
func compactHexEncode(nibbles []byte) []byte {
|
||||
nl := len(nibbles)
|
||||
if nl == 0 {
|
||||
return nil
|
||||
}
|
||||
if nibbles[nl-1] == 16 {
|
||||
nl--
|
||||
}
|
||||
l := (nl + 1) / 2
|
||||
var str = make([]byte, l)
|
||||
for i, _ := range str {
|
||||
b := nibbles[i*2] * 16
|
||||
if nl > i*2 {
|
||||
b += nibbles[i*2+1]
|
||||
}
|
||||
str[i] = b
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func decodeCompact(key []byte) []byte {
|
||||
l := len(key) / 2
|
||||
var res = make([]byte, l)
|
||||
|
@ -57,6 +57,12 @@ func (s *TrieEncodingSuite) TestCompactHexDecode(c *checker.C) {
|
||||
c.Assert(res, checker.DeepEquals, exp)
|
||||
}
|
||||
|
||||
func (s *TrieEncodingSuite) TestCompactHexEncode(c *checker.C) {
|
||||
exp := []byte("verb")
|
||||
res := compactHexEncode([]byte{7, 6, 6, 5, 7, 2, 6, 2, 16})
|
||||
c.Assert(res, checker.DeepEquals, exp)
|
||||
}
|
||||
|
||||
func (s *TrieEncodingSuite) TestCompactDecode(c *checker.C) {
|
||||
// odd compact decode
|
||||
exp := []byte{1, 2, 3, 4, 5}
|
||||
|
@ -27,13 +27,23 @@ import (
|
||||
// information necessary for retrieving the missing node through an ODR service.
|
||||
//
|
||||
// NodeHash is the hash of the missing node
|
||||
//
|
||||
// RootHash is the original root of the trie that contains the node
|
||||
// KeyPrefix is the prefix that leads from the root to the missing node (hex encoded)
|
||||
// KeySuffix (optional) contains the rest of the key we were looking for, gives a
|
||||
// hint on which further nodes should also be retrieved (hex encoded)
|
||||
//
|
||||
// Key is a binary-encoded key that contains the prefix that leads to the first
|
||||
// missing node and optionally a suffix that hints on which further nodes should
|
||||
// also be retrieved
|
||||
//
|
||||
// PrefixLen is the nibble length of the key prefix that leads from the root to
|
||||
// the missing node
|
||||
//
|
||||
// SuffixLen is the nibble length of the remaining part of the key that hints on
|
||||
// which further nodes should also be retrieved (can be zero when there are no
|
||||
// such hints in the error message)
|
||||
type MissingNodeError struct {
|
||||
RootHash, NodeHash common.Hash
|
||||
KeyPrefix, KeySuffix []byte
|
||||
Key []byte
|
||||
PrefixLen, SuffixLen int
|
||||
}
|
||||
|
||||
func (err *MissingNodeError) Error() string {
|
||||
|
@ -17,29 +17,30 @@ import (
|
||||
// also included in the last node and can be retrieved by verifying
|
||||
// the proof.
|
||||
//
|
||||
// The returned proof is nil if the trie does not contain a value for key.
|
||||
// For existing keys, the proof will have at least one element.
|
||||
// If the trie does not contain a value for key, the returned proof
|
||||
// contains all nodes of the longest existing prefix of the key
|
||||
// (at least the root node), ending with the node that proves the
|
||||
// absence of the key.
|
||||
func (t *Trie) Prove(key []byte) []rlp.RawValue {
|
||||
// Collect all nodes on the path to key.
|
||||
key = compactHexDecode(key)
|
||||
nodes := []node{}
|
||||
tn := t.root
|
||||
for len(key) > 0 {
|
||||
for len(key) > 0 && tn != nil {
|
||||
switch n := tn.(type) {
|
||||
case shortNode:
|
||||
if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) {
|
||||
// The trie doesn't contain the key.
|
||||
return nil
|
||||
tn = nil
|
||||
} else {
|
||||
tn = n.Val
|
||||
key = key[len(n.Key):]
|
||||
}
|
||||
tn = n.Val
|
||||
key = key[len(n.Key):]
|
||||
nodes = append(nodes, n)
|
||||
case fullNode:
|
||||
tn = n[key[0]]
|
||||
key = key[1:]
|
||||
nodes = append(nodes, n)
|
||||
case nil:
|
||||
return nil
|
||||
case hashNode:
|
||||
var err error
|
||||
tn, err = t.resolveHash(n, nil, nil)
|
||||
@ -93,7 +94,12 @@ func VerifyProof(rootHash common.Hash, key []byte, proof []rlp.RawValue) (value
|
||||
keyrest, cld := get(n, key)
|
||||
switch cld := cld.(type) {
|
||||
case nil:
|
||||
return nil, fmt.Errorf("key mismatch at proof node %d", i)
|
||||
if i != len(proof)-1 {
|
||||
return nil, fmt.Errorf("key mismatch at proof node %d", i)
|
||||
} else {
|
||||
// The trie doesn't contain the key.
|
||||
return nil, nil
|
||||
}
|
||||
case hashNode:
|
||||
key = keyrest
|
||||
wantHash = cld
|
||||
|
@ -394,8 +394,9 @@ func (t *Trie) resolveHash(n hashNode, prefix, suffix []byte) (node, error) {
|
||||
return nil, &MissingNodeError{
|
||||
RootHash: t.originalRoot,
|
||||
NodeHash: common.BytesToHash(n),
|
||||
KeyPrefix: prefix,
|
||||
KeySuffix: suffix,
|
||||
Key: compactHexEncode(append(prefix, suffix...)),
|
||||
PrefixLen: len(prefix),
|
||||
SuffixLen: len(suffix),
|
||||
}
|
||||
}
|
||||
dec := mustDecodeNode(n, enc)
|
||||
|
Reference in New Issue
Block a user