Skip to content

Commit 4525032

Browse files
committed
implement crypto for tree; add govendor;
1 parent ce6769f commit 4525032

31 files changed

+2861
-297
lines changed

database.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
1-
// TODO: need to implement DB feature
1+
// TODO: need to implement database functional
22
package mpt
33

4+
import (
5+
"github.com/begmaroman/mpt/enc"
6+
"github.com/begmaroman/mpt/node"
7+
"sync"
8+
)
9+
410
type Database struct {
11+
sync.Mutex
12+
}
13+
14+
func NewDatabase() *Database {
15+
return &Database{}
16+
}
17+
18+
func (db *Database) GetNode(hash enc.Hash, cGen uint16) node.Node {
19+
return nil
20+
}
21+
22+
func (db *Database) Insert(hash enc.Hash, blob []byte, node node.Node) {
23+
db.Lock()
24+
defer db.Unlock()
25+
// TODO: need to implement storing logic
526
}

enc/encoding.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package enc
2+
3+
// BytesToHex encoding byte array to hex
4+
func BytesToHex(str []byte) []byte {
5+
l := len(str)*2 + 1
6+
var nibbles = make([]byte, l)
7+
for i, b := range str {
8+
nibbles[i*2] = b / 16
9+
nibbles[i*2+1] = b % 16
10+
}
11+
nibbles[l-1] = 16
12+
return nibbles
13+
}
14+
15+
// PrefixLen returns the length of the common prefix of a and b.
16+
func PrefixLen(a, b []byte) int {
17+
var i, length = 0, len(a)
18+
if len(b) < length {
19+
length = len(b)
20+
}
21+
for ; i < length; i++ {
22+
if a[i] != b[i] {
23+
break
24+
}
25+
}
26+
return i
27+
}
28+
29+
func HexToCompact(hex []byte) []byte {
30+
terminator := byte(0)
31+
if hasTerm(hex) {
32+
terminator = 1
33+
hex = hex[:len(hex)-1]
34+
}
35+
buf := make([]byte, len(hex)/2+1)
36+
buf[0] = terminator << 5 // the flag byte
37+
if len(hex)&1 == 1 {
38+
buf[0] |= 1 << 4 // odd flag
39+
buf[0] |= hex[0] // first nibble is contained in the first byte
40+
hex = hex[1:]
41+
}
42+
decodeNibbles(hex, buf[1:])
43+
return buf
44+
}
45+
46+
func CopyBytes(b []byte) (copiedBytes []byte) {
47+
if b == nil {
48+
return nil
49+
}
50+
copiedBytes = make([]byte, len(b))
51+
copy(copiedBytes, b)
52+
53+
return
54+
}
55+
56+
func hasTerm(s []byte) bool {
57+
return len(s) > 0 && s[len(s)-1] == 16
58+
}
59+
60+
func decodeNibbles(nibbles []byte, bytes []byte) {
61+
for bi, ni := 0, 0; ni < len(nibbles); bi, ni = bi+1, ni+2 {
62+
bytes[bi] = nibbles[ni]<<4 | nibbles[ni+1]
63+
}
64+
}

type.go enc/type.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package mpt
1+
package enc
22

33
import (
44
"encoding/hex"
@@ -92,6 +92,18 @@ func (h *Hash) Scan(src interface{}) error {
9292
return nil
9393
}
9494

95+
// Useful type :)
96+
type SliceBuffer []byte
97+
98+
func (b *SliceBuffer) Write(data []byte) (n int, err error) {
99+
*b = append(*b, data...)
100+
return len(data), nil
101+
}
102+
103+
func (b *SliceBuffer) Reset() {
104+
*b = (*b)[:0]
105+
}
106+
95107
// FromHex returns the bytes represented by the hexadecimal string s.
96108
// s may be prefixed with "0x".
97109
func FromHex(s string) []byte {

encoding.go

-26
This file was deleted.

error.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package mpt
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/begmaroman/mpt/enc"
7+
)
8+
9+
type ErrNodeNotFound struct {
10+
Key []byte
11+
Hash enc.Hash
12+
}
13+
14+
func NewErrNodeNotFound(key []byte, hash enc.Hash) *ErrNodeNotFound {
15+
return &ErrNodeNotFound{
16+
Key: key,
17+
Hash: hash,
18+
}
19+
}
20+
21+
func (e *ErrNodeNotFound) Error() string {
22+
return fmt.Sprintf("node not found: hash %v key %v", e.Hash, e.Key)
23+
}

example/simple.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,24 @@ func main() {
2121
fmt.Println()
2222

2323
// try to update value
24-
ok = trie.Update([]byte("key_new"), []byte("val_new_updated"))
25-
fmt.Println("updated:", ok)
26-
fmt.Println()
24+
//ok, _ = trie.Update([]byte("key_new"), []byte("val_new_updated"))
25+
//fmt.Println("updated:", ok)
26+
//fmt.Println()
2727

2828
// try to find value
2929
found, ok = trie.Get([]byte("key_new"))
3030
fmt.Println("value:", string(found))
3131
fmt.Println("found:", ok)
3232
fmt.Println()
3333

34-
ok = trie.Delete([]byte("key_new"))
34+
ok, _ = trie.Delete([]byte("key_new"))
3535
fmt.Println("deleted:", ok)
3636
found, ok = trie.Get([]byte("key_new"))
3737
fmt.Println("value:", string(found))
3838
fmt.Println("found:", ok)
39+
fmt.Println()
40+
41+
h, err := trie.Hash()
42+
fmt.Println("hash of the tree:", h.String())
43+
fmt.Println("error of hash:", err)
3944
}

hasher.go

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package mpt
2+
3+
import (
4+
"hash"
5+
"sync"
6+
7+
"github.com/begmaroman/mpt/enc"
8+
"github.com/begmaroman/mpt/node"
9+
"github.com/ethereum/go-ethereum/crypto/sha3"
10+
"github.com/ethereum/go-ethereum/rlp"
11+
)
12+
13+
var (
14+
hPool = sync.Pool{
15+
New: func() interface{} {
16+
return &Encryptor{
17+
rlpBuf: make(enc.SliceBuffer, 0, 550),
18+
sha: sha3.NewKeccak256().(keccakState),
19+
}
20+
},
21+
}
22+
)
23+
24+
type keccakState interface {
25+
hash.Hash
26+
Read([]byte) (int, error)
27+
}
28+
29+
type Encryptor struct {
30+
rlpBuf enc.SliceBuffer
31+
sha keccakState
32+
}
33+
34+
func NewEncryptor() *Encryptor {
35+
h := hPool.Get().(*Encryptor)
36+
return h
37+
}
38+
39+
// hash recursive hash the trie based on keccak256 and sha3
40+
func (sh *Encryptor) hash(n node.Node, db *Database, force bool) (node.Node, node.Node, error) {
41+
// If we're not storing the node, just hashing, use available cached data
42+
if cHach, dirty := n.Cache(); cHach != nil && !dirty {
43+
return node.NewHashNode(cHach), n, nil
44+
}
45+
46+
// Trie not processed yet or needs storage, walk the children
47+
collapsed, cached, err := sh.getChildHash(n, db)
48+
if err != nil {
49+
return node.NewHashNode(nil), n, err
50+
}
51+
52+
hashed, err := sh.store(collapsed, db, force)
53+
if err != nil {
54+
return node.NewHashNode(nil), n, err
55+
}
56+
57+
cachedHash, _ := hashed.(node.HashNode)
58+
switch cn := cached.(type) {
59+
case *node.ExtensionNode:
60+
cn.Hash = cachedHash
61+
if db != nil {
62+
cn.Dirty = false
63+
}
64+
case *node.BranchNode:
65+
cn.Hash = cachedHash
66+
if db != nil {
67+
cn.Dirty = false
68+
}
69+
}
70+
71+
return hashed, cached, nil
72+
}
73+
74+
// getChildHash hash children nodes
75+
func (sh *Encryptor) getChildHash(original node.Node, db *Database) (node.Node, node.Node, error) {
76+
var err error
77+
78+
switch n := original.(type) {
79+
case *node.ExtensionNode:
80+
// Hash the short node's child, caching the newly hashed subtree
81+
collapsed, cached := n.Copy(), n.Copy()
82+
collapsed.Key = enc.HexToCompact(n.Key)
83+
cached.Key = enc.CopyBytes(n.Key)
84+
85+
switch n.Value.(type) {
86+
case node.LeafNode:
87+
default:
88+
if collapsed.Value, cached.Value, err = sh.hash(n.Value, db, false); err != nil {
89+
return original, original, err
90+
}
91+
}
92+
93+
return collapsed, cached, nil
94+
95+
case *node.BranchNode:
96+
// Hash the full node's children, caching the newly hashed subtrees
97+
collapsed, cached := n.Copy(), n.Copy()
98+
99+
for i := 0; i < 16; i++ {
100+
if n.Children[i] == nil {
101+
continue
102+
}
103+
104+
if collapsed.Children[i], cached.Children[i], err = sh.hash(n.Children[i], db, false); err != nil {
105+
return original, original, err
106+
}
107+
}
108+
109+
cached.Children[16] = n.Children[16]
110+
111+
return collapsed, cached, nil
112+
113+
default:
114+
// Value and hash nodes don't have children so they're left as were
115+
return n, original, nil
116+
}
117+
}
118+
119+
func (sh *Encryptor) store(n node.Node, db *Database, force bool) (node.Node, error) {
120+
// Don't store hashes or empty nodes.
121+
if _, isHash := n.(node.HashNode); n == nil || isHash {
122+
return n, nil
123+
}
124+
125+
// Generate the RLP encoding of the node
126+
sh.rlpBuf.Reset()
127+
if err := rlp.Encode(&sh.rlpBuf, n); err != nil {
128+
return n, err
129+
}
130+
131+
// Nodes smaller than 32 bytes are stored inside their parent
132+
if len(sh.rlpBuf) < 32 && !force {
133+
return n, nil
134+
}
135+
136+
// Larger nodes are replaced by their hash and stored in the database.
137+
hash, dirty := n.Cache()
138+
if hash == nil || dirty {
139+
hash = sh.makeHashNode(sh.rlpBuf)
140+
}
141+
142+
if db != nil {
143+
// We are pooling the trie nodes into an intermediate memory cache
144+
db.Insert(enc.BytesToHash(hash), sh.rlpBuf, n)
145+
}
146+
147+
return node.NewHashNode(hash), nil
148+
}
149+
150+
func (sh *Encryptor) makeHashNode(data []byte) node.HashNode {
151+
n := make(node.HashNode, sh.sha.Size())
152+
sh.sha.Reset()
153+
sh.sha.Write(data)
154+
sh.sha.Read(n)
155+
return n
156+
}

0 commit comments

Comments
 (0)