Merge pull request #2585 from karalabe/trie-dirty-tracking
core, core/state, trie: enterprise hand-tuned multi-level caching
This commit is contained in:
		
						commit
						5c39a1bb26
					
				| @ -819,6 +819,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { | |||||||
| 		tstart        = time.Now() | 		tstart        = time.Now() | ||||||
| 
 | 
 | ||||||
| 		nonceChecked = make([]bool, len(chain)) | 		nonceChecked = make([]bool, len(chain)) | ||||||
|  | 		statedb      *state.StateDB | ||||||
| 	) | 	) | ||||||
| 
 | 
 | ||||||
| 	// Start the parallel nonce verifier.
 | 	// Start the parallel nonce verifier.
 | ||||||
| @ -885,7 +886,11 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { | |||||||
| 
 | 
 | ||||||
| 		// Create a new statedb using the parent block and report an
 | 		// Create a new statedb using the parent block and report an
 | ||||||
| 		// error if it fails.
 | 		// error if it fails.
 | ||||||
| 		statedb, err := state.New(self.GetBlock(block.ParentHash()).Root(), self.chainDb) | 		if statedb == nil { | ||||||
|  | 			statedb, err = state.New(self.GetBlock(block.ParentHash()).Root(), self.chainDb) | ||||||
|  | 		} else { | ||||||
|  | 			err = statedb.Reset(chain[i-1].Root()) | ||||||
|  | 		} | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			reportBlock(block, err) | 			reportBlock(block, err) | ||||||
| 			return i, err | 			return i, err | ||||||
|  | |||||||
| @ -68,6 +68,28 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) { | |||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Reset clears out all emphemeral state objects from the state db, but keeps
 | ||||||
|  | // the underlying state trie to avoid reloading data for the next operations.
 | ||||||
|  | func (self *StateDB) Reset(root common.Hash) error { | ||||||
|  | 	var ( | ||||||
|  | 		err error | ||||||
|  | 		tr  = self.trie | ||||||
|  | 	) | ||||||
|  | 	if self.trie.Hash() != root { | ||||||
|  | 		if tr, err = trie.NewSecure(root, self.db); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	*self = StateDB{ | ||||||
|  | 		db:           self.db, | ||||||
|  | 		trie:         tr, | ||||||
|  | 		stateObjects: make(map[string]*StateObject), | ||||||
|  | 		refund:       new(big.Int), | ||||||
|  | 		logs:         make(map[common.Hash]vm.Logs), | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { | func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { | ||||||
| 	self.thash = thash | 	self.thash = thash | ||||||
| 	self.bhash = bhash | 	self.bhash = bhash | ||||||
|  | |||||||
| @ -62,7 +62,7 @@ func (self *Iterator) next(node interface{}, key []byte, isIterStart bool) []byt | |||||||
| 	switch node := node.(type) { | 	switch node := node.(type) { | ||||||
| 	case fullNode: | 	case fullNode: | ||||||
| 		if len(key) > 0 { | 		if len(key) > 0 { | ||||||
| 			k := self.next(node[key[0]], key[1:], isIterStart) | 			k := self.next(node.Children[key[0]], key[1:], isIterStart) | ||||||
| 			if k != nil { | 			if k != nil { | ||||||
| 				return append([]byte{key[0]}, k...) | 				return append([]byte{key[0]}, k...) | ||||||
| 			} | 			} | ||||||
| @ -74,7 +74,7 @@ func (self *Iterator) next(node interface{}, key []byte, isIterStart bool) []byt | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for i := r; i < 16; i++ { | 		for i := r; i < 16; i++ { | ||||||
| 			k := self.key(node[i]) | 			k := self.key(node.Children[i]) | ||||||
| 			if k != nil { | 			if k != nil { | ||||||
| 				return append([]byte{i}, k...) | 				return append([]byte{i}, k...) | ||||||
| 			} | 			} | ||||||
| @ -130,12 +130,12 @@ func (self *Iterator) key(node interface{}) []byte { | |||||||
| 		} | 		} | ||||||
| 		return append(k, self.key(node.Val)...) | 		return append(k, self.key(node.Val)...) | ||||||
| 	case fullNode: | 	case fullNode: | ||||||
| 		if node[16] != nil { | 		if node.Children[16] != nil { | ||||||
| 			self.Value = node[16].(valueNode) | 			self.Value = node.Children[16].(valueNode) | ||||||
| 			return []byte{16} | 			return []byte{16} | ||||||
| 		} | 		} | ||||||
| 		for i := 0; i < 16; i++ { | 		for i := 0; i < 16; i++ { | ||||||
| 			k := self.key(node[i]) | 			k := self.key(node.Children[i]) | ||||||
| 			if k != nil { | 			if k != nil { | ||||||
| 				return append([]byte{byte(i)}, k...) | 				return append([]byte{byte(i)}, k...) | ||||||
| 			} | 			} | ||||||
| @ -175,7 +175,7 @@ type NodeIterator struct { | |||||||
| 
 | 
 | ||||||
| // NewNodeIterator creates an post-order trie iterator.
 | // NewNodeIterator creates an post-order trie iterator.
 | ||||||
| func NewNodeIterator(trie *Trie) *NodeIterator { | func NewNodeIterator(trie *Trie) *NodeIterator { | ||||||
| 	if bytes.Compare(trie.Root(), emptyRoot.Bytes()) == 0 { | 	if trie.Hash() == emptyState { | ||||||
| 		return new(NodeIterator) | 		return new(NodeIterator) | ||||||
| 	} | 	} | ||||||
| 	return &NodeIterator{trie: trie} | 	return &NodeIterator{trie: trie} | ||||||
| @ -205,9 +205,11 @@ func (it *NodeIterator) step() error { | |||||||
| 	} | 	} | ||||||
| 	// Initialize the iterator if we've just started, or pop off the old node otherwise
 | 	// Initialize the iterator if we've just started, or pop off the old node otherwise
 | ||||||
| 	if len(it.stack) == 0 { | 	if len(it.stack) == 0 { | ||||||
| 		it.stack = append(it.stack, &nodeIteratorState{node: it.trie.root, child: -1}) | 		// Always start with a collapsed root
 | ||||||
|  | 		root := it.trie.Hash() | ||||||
|  | 		it.stack = append(it.stack, &nodeIteratorState{node: hashNode(root[:]), child: -1}) | ||||||
| 		if it.stack[0].node == nil { | 		if it.stack[0].node == nil { | ||||||
| 			return fmt.Errorf("root node missing: %x", it.trie.Root()) | 			return fmt.Errorf("root node missing: %x", it.trie.Hash()) | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		it.stack = it.stack[:len(it.stack)-1] | 		it.stack = it.stack[:len(it.stack)-1] | ||||||
| @ -225,11 +227,11 @@ func (it *NodeIterator) step() error { | |||||||
| 		} | 		} | ||||||
| 		if node, ok := parent.node.(fullNode); ok { | 		if node, ok := parent.node.(fullNode); ok { | ||||||
| 			// Full node, traverse all children, then the node itself
 | 			// Full node, traverse all children, then the node itself
 | ||||||
| 			if parent.child >= len(node) { | 			if parent.child >= len(node.Children) { | ||||||
| 				break | 				break | ||||||
| 			} | 			} | ||||||
| 			for parent.child++; parent.child < len(node); parent.child++ { | 			for parent.child++; parent.child < len(node.Children); parent.child++ { | ||||||
| 				if current := node[parent.child]; current != nil { | 				if current := node.Children[parent.child]; current != nil { | ||||||
| 					it.stack = append(it.stack, &nodeIteratorState{node: current, parent: ancestor, child: -1}) | 					it.stack = append(it.stack, &nodeIteratorState{node: current, parent: ancestor, child: -1}) | ||||||
| 					break | 					break | ||||||
| 				} | 				} | ||||||
|  | |||||||
							
								
								
									
										60
									
								
								trie/node.go
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								trie/node.go
									
									
									
									
									
								
							| @ -29,18 +29,36 @@ var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b | |||||||
| 
 | 
 | ||||||
| type node interface { | type node interface { | ||||||
| 	fstring(string) string | 	fstring(string) string | ||||||
|  | 	cache() (hashNode, bool) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ( | type ( | ||||||
| 	fullNode  [17]node | 	fullNode struct { | ||||||
|  | 		Children [17]node // Actual trie node data to encode/decode (needs custom encoder)
 | ||||||
|  | 		hash     hashNode // Cached hash of the node to prevent rehashing (may be nil)
 | ||||||
|  | 		dirty    bool     // Cached flag whether the node's new or already stored
 | ||||||
|  | 	} | ||||||
| 	shortNode struct { | 	shortNode struct { | ||||||
| 		Key []byte | 		Key   []byte | ||||||
| 		Val node | 		Val   node | ||||||
|  | 		hash  hashNode // Cached hash of the node to prevent rehashing (may be nil)
 | ||||||
|  | 		dirty bool     // Cached flag whether the node's new or already stored
 | ||||||
| 	} | 	} | ||||||
| 	hashNode  []byte | 	hashNode  []byte | ||||||
| 	valueNode []byte | 	valueNode []byte | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // EncodeRLP encodes a full node into the consensus RLP format.
 | ||||||
|  | func (n fullNode) EncodeRLP(w io.Writer) error { | ||||||
|  | 	return rlp.Encode(w, n.Children) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Cache accessors to retrieve precalculated values (avoid lengthy type switches).
 | ||||||
|  | func (n fullNode) cache() (hashNode, bool)  { return n.hash, n.dirty } | ||||||
|  | func (n shortNode) cache() (hashNode, bool) { return n.hash, n.dirty } | ||||||
|  | func (n hashNode) cache() (hashNode, bool)  { return nil, true } | ||||||
|  | func (n valueNode) cache() (hashNode, bool) { return nil, true } | ||||||
|  | 
 | ||||||
| // Pretty printing.
 | // Pretty printing.
 | ||||||
| func (n fullNode) String() string  { return n.fstring("") } | func (n fullNode) String() string  { return n.fstring("") } | ||||||
| func (n shortNode) String() string { return n.fstring("") } | func (n shortNode) String() string { return n.fstring("") } | ||||||
| @ -49,7 +67,7 @@ func (n valueNode) String() string { return n.fstring("") } | |||||||
| 
 | 
 | ||||||
| func (n fullNode) fstring(ind string) string { | func (n fullNode) fstring(ind string) string { | ||||||
| 	resp := fmt.Sprintf("[\n%s  ", ind) | 	resp := fmt.Sprintf("[\n%s  ", ind) | ||||||
| 	for i, node := range n { | 	for i, node := range n.Children { | ||||||
| 		if node == nil { | 		if node == nil { | ||||||
| 			resp += fmt.Sprintf("%s: <nil> ", indices[i]) | 			resp += fmt.Sprintf("%s: <nil> ", indices[i]) | ||||||
| 		} else { | 		} else { | ||||||
| @ -68,16 +86,16 @@ func (n valueNode) fstring(ind string) string { | |||||||
| 	return fmt.Sprintf("%x ", []byte(n)) | 	return fmt.Sprintf("%x ", []byte(n)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func mustDecodeNode(dbkey, buf []byte) node { | func mustDecodeNode(hash, buf []byte) node { | ||||||
| 	n, err := decodeNode(buf) | 	n, err := decodeNode(hash, buf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(fmt.Sprintf("node %x: %v", dbkey, err)) | 		panic(fmt.Sprintf("node %x: %v", hash, err)) | ||||||
| 	} | 	} | ||||||
| 	return n | 	return n | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // decodeNode parses the RLP encoding of a trie node.
 | // decodeNode parses the RLP encoding of a trie node.
 | ||||||
| func decodeNode(buf []byte) (node, error) { | func decodeNode(hash, buf []byte) (node, error) { | ||||||
| 	if len(buf) == 0 { | 	if len(buf) == 0 { | ||||||
| 		return nil, io.ErrUnexpectedEOF | 		return nil, io.ErrUnexpectedEOF | ||||||
| 	} | 	} | ||||||
| @ -87,18 +105,18 @@ func decodeNode(buf []byte) (node, error) { | |||||||
| 	} | 	} | ||||||
| 	switch c, _ := rlp.CountValues(elems); c { | 	switch c, _ := rlp.CountValues(elems); c { | ||||||
| 	case 2: | 	case 2: | ||||||
| 		n, err := decodeShort(elems) | 		n, err := decodeShort(hash, buf, elems) | ||||||
| 		return n, wrapError(err, "short") | 		return n, wrapError(err, "short") | ||||||
| 	case 17: | 	case 17: | ||||||
| 		n, err := decodeFull(elems) | 		n, err := decodeFull(hash, buf, elems) | ||||||
| 		return n, wrapError(err, "full") | 		return n, wrapError(err, "full") | ||||||
| 	default: | 	default: | ||||||
| 		return nil, fmt.Errorf("invalid number of list elements: %v", c) | 		return nil, fmt.Errorf("invalid number of list elements: %v", c) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func decodeShort(buf []byte) (node, error) { | func decodeShort(hash, buf, elems []byte) (node, error) { | ||||||
| 	kbuf, rest, err := rlp.SplitString(buf) | 	kbuf, rest, err := rlp.SplitString(elems) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @ -109,30 +127,30 @@ func decodeShort(buf []byte) (node, error) { | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("invalid value node: %v", err) | 			return nil, fmt.Errorf("invalid value node: %v", err) | ||||||
| 		} | 		} | ||||||
| 		return shortNode{key, valueNode(val)}, nil | 		return shortNode{key, valueNode(val), hash, false}, nil | ||||||
| 	} | 	} | ||||||
| 	r, _, err := decodeRef(rest) | 	r, _, err := decodeRef(rest) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, wrapError(err, "val") | 		return nil, wrapError(err, "val") | ||||||
| 	} | 	} | ||||||
| 	return shortNode{key, r}, nil | 	return shortNode{key, r, hash, false}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func decodeFull(buf []byte) (fullNode, error) { | func decodeFull(hash, buf, elems []byte) (fullNode, error) { | ||||||
| 	var n fullNode | 	n := fullNode{hash: hash} | ||||||
| 	for i := 0; i < 16; i++ { | 	for i := 0; i < 16; i++ { | ||||||
| 		cld, rest, err := decodeRef(buf) | 		cld, rest, err := decodeRef(elems) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return n, wrapError(err, fmt.Sprintf("[%d]", i)) | 			return n, wrapError(err, fmt.Sprintf("[%d]", i)) | ||||||
| 		} | 		} | ||||||
| 		n[i], buf = cld, rest | 		n.Children[i], elems = cld, rest | ||||||
| 	} | 	} | ||||||
| 	val, _, err := rlp.SplitString(buf) | 	val, _, err := rlp.SplitString(elems) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return n, err | 		return n, err | ||||||
| 	} | 	} | ||||||
| 	if len(val) > 0 { | 	if len(val) > 0 { | ||||||
| 		n[16] = valueNode(val) | 		n.Children[16] = valueNode(val) | ||||||
| 	} | 	} | ||||||
| 	return n, nil | 	return n, nil | ||||||
| } | } | ||||||
| @ -152,7 +170,7 @@ func decodeRef(buf []byte) (node, []byte, error) { | |||||||
| 			err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen) | 			err := fmt.Errorf("oversized embedded node (size is %d bytes, want size < %d)", size, hashLen) | ||||||
| 			return nil, buf, err | 			return nil, buf, err | ||||||
| 		} | 		} | ||||||
| 		n, err := decodeNode(buf) | 		n, err := decodeNode(nil, buf) | ||||||
| 		return n, rest, err | 		return n, rest, err | ||||||
| 	case kind == rlp.String && len(val) == 0: | 	case kind == rlp.String && len(val) == 0: | ||||||
| 		// empty node
 | 		// empty node
 | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue { | |||||||
| 			} | 			} | ||||||
| 			nodes = append(nodes, n) | 			nodes = append(nodes, n) | ||||||
| 		case fullNode: | 		case fullNode: | ||||||
| 			tn = n[key[0]] | 			tn = n.Children[key[0]] | ||||||
| 			key = key[1:] | 			key = key[1:] | ||||||
| 			nodes = append(nodes, n) | 			nodes = append(nodes, n) | ||||||
| 		case hashNode: | 		case hashNode: | ||||||
| @ -77,7 +77,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue { | |||||||
| 	for i, n := range nodes { | 	for i, n := range nodes { | ||||||
| 		// Don't bother checking for errors here since hasher panics
 | 		// Don't bother checking for errors here since hasher panics
 | ||||||
| 		// if encoding doesn't work and we're not writing to any database.
 | 		// if encoding doesn't work and we're not writing to any database.
 | ||||||
| 		n, _ = t.hasher.replaceChildren(n, nil) | 		n, _, _ = t.hasher.hashChildren(n, nil) | ||||||
| 		hn, _ := t.hasher.store(n, nil, false) | 		hn, _ := t.hasher.store(n, nil, false) | ||||||
| 		if _, ok := hn.(hashNode); ok || i == 0 { | 		if _, ok := hn.(hashNode); ok || i == 0 { | ||||||
| 			// If the node's database encoding is a hash (or is the
 | 			// If the node's database encoding is a hash (or is the
 | ||||||
| @ -103,7 +103,7 @@ func VerifyProof(rootHash common.Hash, key []byte, proof []rlp.RawValue) (value | |||||||
| 		if !bytes.Equal(sha.Sum(nil), wantHash) { | 		if !bytes.Equal(sha.Sum(nil), wantHash) { | ||||||
| 			return nil, fmt.Errorf("bad proof node %d: hash mismatch", i) | 			return nil, fmt.Errorf("bad proof node %d: hash mismatch", i) | ||||||
| 		} | 		} | ||||||
| 		n, err := decodeNode(buf) | 		n, err := decodeNode(wantHash, buf) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, fmt.Errorf("bad proof node %d: %v", i, err) | 			return nil, fmt.Errorf("bad proof node %d: %v", i, err) | ||||||
| 		} | 		} | ||||||
| @ -139,7 +139,7 @@ func get(tn node, key []byte) ([]byte, node) { | |||||||
| 			tn = n.Val | 			tn = n.Val | ||||||
| 			key = key[len(n.Key):] | 			key = key[len(n.Key):] | ||||||
| 		case fullNode: | 		case fullNode: | ||||||
| 			tn = n[key[0]] | 			tn = n.Children[key[0]] | ||||||
| 			key = key[1:] | 			key = key[1:] | ||||||
| 		case hashNode: | 		case hashNode: | ||||||
| 			return key, n | 			return key, n | ||||||
|  | |||||||
| @ -162,11 +162,11 @@ func (t *SecureTrie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { | |||||||
| 		} | 		} | ||||||
| 		t.secKeyCache = make(map[string][]byte) | 		t.secKeyCache = make(map[string][]byte) | ||||||
| 	} | 	} | ||||||
| 	n, err := t.hashRoot(db) | 	n, clean, err := t.hashRoot(db) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return (common.Hash{}), err | 		return (common.Hash{}), err | ||||||
| 	} | 	} | ||||||
| 	t.root = n | 	t.root = clean | ||||||
| 	return common.BytesToHash(n.(hashNode)), nil | 	return common.BytesToHash(n.(hashNode)), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								trie/sync.go
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								trie/sync.go
									
									
									
									
									
								
							| @ -75,8 +75,9 @@ func (s *TrieSync) AddSubTrie(root common.Hash, depth int, parent common.Hash, c | |||||||
| 	if root == emptyRoot { | 	if root == emptyRoot { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	blob, _ := s.database.Get(root.Bytes()) | 	key := root.Bytes() | ||||||
| 	if local, err := decodeNode(blob); local != nil && err == nil { | 	blob, _ := s.database.Get(key) | ||||||
|  | 	if local, err := decodeNode(key, blob); local != nil && err == nil { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	// Assemble the new sub-trie sync request
 | 	// Assemble the new sub-trie sync request
 | ||||||
| @ -152,7 +153,7 @@ func (s *TrieSync) Process(results []SyncResult) (int, error) { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		// Decode the node data content and update the request
 | 		// Decode the node data content and update the request
 | ||||||
| 		node, err := decodeNode(item.Data) | 		node, err := decodeNode(item.Hash[:], item.Data) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return i, err | 			return i, err | ||||||
| 		} | 		} | ||||||
| @ -213,9 +214,9 @@ func (s *TrieSync) children(req *request) ([]*request, error) { | |||||||
| 		}} | 		}} | ||||||
| 	case fullNode: | 	case fullNode: | ||||||
| 		for i := 0; i < 17; i++ { | 		for i := 0; i < 17; i++ { | ||||||
| 			if node[i] != nil { | 			if node.Children[i] != nil { | ||||||
| 				children = append(children, child{ | 				children = append(children, child{ | ||||||
| 					node:  &node[i], | 					node:  &node.Children[i], | ||||||
| 					depth: req.depth + 1, | 					depth: req.depth + 1, | ||||||
| 				}) | 				}) | ||||||
| 			} | 			} | ||||||
| @ -238,7 +239,7 @@ func (s *TrieSync) children(req *request) ([]*request, error) { | |||||||
| 		if node, ok := (*child.node).(hashNode); ok { | 		if node, ok := (*child.node).(hashNode); ok { | ||||||
| 			// Try to resolve the node from the local database
 | 			// Try to resolve the node from the local database
 | ||||||
| 			blob, _ := s.database.Get(node) | 			blob, _ := s.database.Get(node) | ||||||
| 			if local, err := decodeNode(blob); local != nil && err == nil { | 			if local, err := decodeNode(node[:], blob); local != nil && err == nil { | ||||||
| 				*child.node = local | 				*child.node = local | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  | |||||||
							
								
								
									
										239
									
								
								trie/trie.go
									
									
									
									
									
								
							
							
						
						
									
										239
									
								
								trie/trie.go
									
									
									
									
									
								
							| @ -129,7 +129,7 @@ func (t *Trie) TryGet(key []byte) ([]byte, error) { | |||||||
| 			tn = n.Val | 			tn = n.Val | ||||||
| 			pos += len(n.Key) | 			pos += len(n.Key) | ||||||
| 		case fullNode: | 		case fullNode: | ||||||
| 			tn = n[key[pos]] | 			tn = n.Children[key[pos]] | ||||||
| 			pos++ | 			pos++ | ||||||
| 		case nil: | 		case nil: | ||||||
| 			return nil, nil | 			return nil, nil | ||||||
| @ -169,13 +169,13 @@ func (t *Trie) Update(key, value []byte) { | |||||||
| func (t *Trie) TryUpdate(key, value []byte) error { | func (t *Trie) TryUpdate(key, value []byte) error { | ||||||
| 	k := compactHexDecode(key) | 	k := compactHexDecode(key) | ||||||
| 	if len(value) != 0 { | 	if len(value) != 0 { | ||||||
| 		n, err := t.insert(t.root, nil, k, valueNode(value)) | 		_, n, err := t.insert(t.root, nil, k, valueNode(value)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		t.root = n | 		t.root = n | ||||||
| 	} else { | 	} else { | ||||||
| 		n, err := t.delete(t.root, nil, k) | 		_, n, err := t.delete(t.root, nil, k) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -184,9 +184,12 @@ func (t *Trie) TryUpdate(key, value []byte) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (t *Trie) insert(n node, prefix, key []byte, value node) (node, error) { | func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error) { | ||||||
| 	if len(key) == 0 { | 	if len(key) == 0 { | ||||||
| 		return value, nil | 		if v, ok := n.(valueNode); ok { | ||||||
|  | 			return !bytes.Equal(v, value.(valueNode)), value, nil | ||||||
|  | 		} | ||||||
|  | 		return true, value, nil | ||||||
| 	} | 	} | ||||||
| 	switch n := n.(type) { | 	switch n := n.(type) { | ||||||
| 	case shortNode: | 	case shortNode: | ||||||
| @ -194,53 +197,63 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (node, error) { | |||||||
| 		// If the whole key matches, keep this short node as is
 | 		// If the whole key matches, keep this short node as is
 | ||||||
| 		// and only update the value.
 | 		// and only update the value.
 | ||||||
| 		if matchlen == len(n.Key) { | 		if matchlen == len(n.Key) { | ||||||
| 			nn, err := t.insert(n.Val, append(prefix, key[:matchlen]...), key[matchlen:], value) | 			dirty, nn, err := t.insert(n.Val, append(prefix, key[:matchlen]...), key[matchlen:], value) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, err | 				return false, nil, err | ||||||
| 			} | 			} | ||||||
| 			return shortNode{n.Key, nn}, nil | 			if !dirty { | ||||||
|  | 				return false, n, nil | ||||||
|  | 			} | ||||||
|  | 			return true, shortNode{n.Key, nn, nil, true}, nil | ||||||
| 		} | 		} | ||||||
| 		// Otherwise branch out at the index where they differ.
 | 		// Otherwise branch out at the index where they differ.
 | ||||||
| 		var branch fullNode | 		branch := fullNode{dirty: true} | ||||||
| 		var err error | 		var err error | ||||||
| 		branch[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) | 		_, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 		branch[key[matchlen]], err = t.insert(nil, append(prefix, key[:matchlen+1]...), key[matchlen+1:], value) | 		_, branch.Children[key[matchlen]], err = t.insert(nil, append(prefix, key[:matchlen+1]...), key[matchlen+1:], value) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 		// Replace this shortNode with the branch if it occurs at index 0.
 | 		// Replace this shortNode with the branch if it occurs at index 0.
 | ||||||
| 		if matchlen == 0 { | 		if matchlen == 0 { | ||||||
| 			return branch, nil | 			return true, branch, nil | ||||||
| 		} | 		} | ||||||
| 		// Otherwise, replace it with a short node leading up to the branch.
 | 		// Otherwise, replace it with a short node leading up to the branch.
 | ||||||
| 		return shortNode{key[:matchlen], branch}, nil | 		return true, shortNode{key[:matchlen], branch, nil, true}, nil | ||||||
| 
 | 
 | ||||||
| 	case fullNode: | 	case fullNode: | ||||||
| 		nn, err := t.insert(n[key[0]], append(prefix, key[0]), key[1:], value) | 		dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 		n[key[0]] = nn | 		if !dirty { | ||||||
| 		return n, nil | 			return false, n, nil | ||||||
|  | 		} | ||||||
|  | 		n.Children[key[0]], n.hash, n.dirty = nn, nil, true | ||||||
|  | 		return true, n, nil | ||||||
| 
 | 
 | ||||||
| 	case nil: | 	case nil: | ||||||
| 		return shortNode{key, value}, nil | 		return true, shortNode{key, value, nil, true}, nil | ||||||
| 
 | 
 | ||||||
| 	case hashNode: | 	case hashNode: | ||||||
| 		// We've hit a part of the trie that isn't loaded yet. Load
 | 		// We've hit a part of the trie that isn't loaded yet. Load
 | ||||||
| 		// the node and insert into it. This leaves all child nodes on
 | 		// the node and insert into it. This leaves all child nodes on
 | ||||||
| 		// the path to the value in the trie.
 | 		// the path to the value in the trie.
 | ||||||
| 		//
 |  | ||||||
| 		// TODO: track whether insertion changed the value and keep
 |  | ||||||
| 		// n as a hash node if it didn't.
 |  | ||||||
| 		rn, err := t.resolveHash(n, prefix, key) | 		rn, err := t.resolveHash(n, prefix, key) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 		return t.insert(rn, prefix, key, value) | 		dirty, nn, err := t.insert(rn, prefix, key, value) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 		if !dirty { | ||||||
|  | 			return false, rn, nil | ||||||
|  | 		} | ||||||
|  | 		return true, nn, nil | ||||||
| 
 | 
 | ||||||
| 	default: | 	default: | ||||||
| 		panic(fmt.Sprintf("%T: invalid node: %v", n, n)) | 		panic(fmt.Sprintf("%T: invalid node: %v", n, n)) | ||||||
| @ -258,7 +271,7 @@ func (t *Trie) Delete(key []byte) { | |||||||
| // If a node was not found in the database, a MissingNodeError is returned.
 | // If a node was not found in the database, a MissingNodeError is returned.
 | ||||||
| func (t *Trie) TryDelete(key []byte) error { | func (t *Trie) TryDelete(key []byte) error { | ||||||
| 	k := compactHexDecode(key) | 	k := compactHexDecode(key) | ||||||
| 	n, err := t.delete(t.root, nil, k) | 	_, n, err := t.delete(t.root, nil, k) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -269,23 +282,26 @@ func (t *Trie) TryDelete(key []byte) error { | |||||||
| // delete returns the new root of the trie with key deleted.
 | // delete returns the new root of the trie with key deleted.
 | ||||||
| // It reduces the trie to minimal form by simplifying
 | // It reduces the trie to minimal form by simplifying
 | ||||||
| // nodes on the way up after deleting recursively.
 | // nodes on the way up after deleting recursively.
 | ||||||
| func (t *Trie) delete(n node, prefix, key []byte) (node, error) { | func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { | ||||||
| 	switch n := n.(type) { | 	switch n := n.(type) { | ||||||
| 	case shortNode: | 	case shortNode: | ||||||
| 		matchlen := prefixLen(key, n.Key) | 		matchlen := prefixLen(key, n.Key) | ||||||
| 		if matchlen < len(n.Key) { | 		if matchlen < len(n.Key) { | ||||||
| 			return n, nil // don't replace n on mismatch
 | 			return false, n, nil // don't replace n on mismatch
 | ||||||
| 		} | 		} | ||||||
| 		if matchlen == len(key) { | 		if matchlen == len(key) { | ||||||
| 			return nil, nil // remove n entirely for whole matches
 | 			return true, nil, nil // remove n entirely for whole matches
 | ||||||
| 		} | 		} | ||||||
| 		// The key is longer than n.Key. Remove the remaining suffix
 | 		// The key is longer than n.Key. Remove the remaining suffix
 | ||||||
| 		// from the subtrie. Child can never be nil here since the
 | 		// from the subtrie. Child can never be nil here since the
 | ||||||
| 		// subtrie must contain at least two other values with keys
 | 		// subtrie must contain at least two other values with keys
 | ||||||
| 		// longer than n.Key.
 | 		// longer than n.Key.
 | ||||||
| 		child, err := t.delete(n.Val, append(prefix, key[:len(n.Key)]...), key[len(n.Key):]) | 		dirty, child, err := t.delete(n.Val, append(prefix, key[:len(n.Key)]...), key[len(n.Key):]) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 		if !dirty { | ||||||
|  | 			return false, n, nil | ||||||
| 		} | 		} | ||||||
| 		switch child := child.(type) { | 		switch child := child.(type) { | ||||||
| 		case shortNode: | 		case shortNode: | ||||||
| @ -295,17 +311,21 @@ func (t *Trie) delete(n node, prefix, key []byte) (node, error) { | |||||||
| 			// always creates a new slice) instead of append to
 | 			// always creates a new slice) instead of append to
 | ||||||
| 			// avoid modifying n.Key since it might be shared with
 | 			// avoid modifying n.Key since it might be shared with
 | ||||||
| 			// other nodes.
 | 			// other nodes.
 | ||||||
| 			return shortNode{concat(n.Key, child.Key...), child.Val}, nil | 			return true, shortNode{concat(n.Key, child.Key...), child.Val, nil, true}, nil | ||||||
| 		default: | 		default: | ||||||
| 			return shortNode{n.Key, child}, nil | 			return true, shortNode{n.Key, child, nil, true}, nil | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 	case fullNode: | 	case fullNode: | ||||||
| 		nn, err := t.delete(n[key[0]], append(prefix, key[0]), key[1:]) | 		dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:]) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 		n[key[0]] = nn | 		if !dirty { | ||||||
|  | 			return false, n, nil | ||||||
|  | 		} | ||||||
|  | 		n.Children[key[0]], n.hash, n.dirty = nn, nil, true | ||||||
|  | 
 | ||||||
| 		// Check how many non-nil entries are left after deleting and
 | 		// Check how many non-nil entries are left after deleting and
 | ||||||
| 		// reduce the full node to a short node if only one entry is
 | 		// reduce the full node to a short node if only one entry is
 | ||||||
| 		// left. Since n must've contained at least two children
 | 		// left. Since n must've contained at least two children
 | ||||||
| @ -316,7 +336,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (node, error) { | |||||||
| 		// value that is left in n or -2 if n contains at least two
 | 		// value that is left in n or -2 if n contains at least two
 | ||||||
| 		// values.
 | 		// values.
 | ||||||
| 		pos := -1 | 		pos := -1 | ||||||
| 		for i, cld := range n { | 		for i, cld := range n.Children { | ||||||
| 			if cld != nil { | 			if cld != nil { | ||||||
| 				if pos == -1 { | 				if pos == -1 { | ||||||
| 					pos = i | 					pos = i | ||||||
| @ -334,37 +354,41 @@ func (t *Trie) delete(n node, prefix, key []byte) (node, error) { | |||||||
| 				// shortNode{..., shortNode{...}}.  Since the entry
 | 				// shortNode{..., shortNode{...}}.  Since the entry
 | ||||||
| 				// might not be loaded yet, resolve it just for this
 | 				// might not be loaded yet, resolve it just for this
 | ||||||
| 				// check.
 | 				// check.
 | ||||||
| 				cnode, err := t.resolve(n[pos], prefix, []byte{byte(pos)}) | 				cnode, err := t.resolve(n.Children[pos], prefix, []byte{byte(pos)}) | ||||||
| 				if err != nil { | 				if err != nil { | ||||||
| 					return nil, err | 					return false, nil, err | ||||||
| 				} | 				} | ||||||
| 				if cnode, ok := cnode.(shortNode); ok { | 				if cnode, ok := cnode.(shortNode); ok { | ||||||
| 					k := append([]byte{byte(pos)}, cnode.Key...) | 					k := append([]byte{byte(pos)}, cnode.Key...) | ||||||
| 					return shortNode{k, cnode.Val}, nil | 					return true, shortNode{k, cnode.Val, nil, true}, nil | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			// Otherwise, n is replaced by a one-nibble short node
 | 			// Otherwise, n is replaced by a one-nibble short node
 | ||||||
| 			// containing the child.
 | 			// containing the child.
 | ||||||
| 			return shortNode{[]byte{byte(pos)}, n[pos]}, nil | 			return true, shortNode{[]byte{byte(pos)}, n.Children[pos], nil, true}, nil | ||||||
| 		} | 		} | ||||||
| 		// n still contains at least two values and cannot be reduced.
 | 		// n still contains at least two values and cannot be reduced.
 | ||||||
| 		return n, nil | 		return true, n, nil | ||||||
| 
 | 
 | ||||||
| 	case nil: | 	case nil: | ||||||
| 		return nil, nil | 		return false, nil, nil | ||||||
| 
 | 
 | ||||||
| 	case hashNode: | 	case hashNode: | ||||||
| 		// We've hit a part of the trie that isn't loaded yet. Load
 | 		// We've hit a part of the trie that isn't loaded yet. Load
 | ||||||
| 		// the node and delete from it. This leaves all child nodes on
 | 		// the node and delete from it. This leaves all child nodes on
 | ||||||
| 		// the path to the value in the trie.
 | 		// the path to the value in the trie.
 | ||||||
| 		//
 |  | ||||||
| 		// TODO: track whether deletion actually hit a key and keep
 |  | ||||||
| 		// n as a hash node if it didn't.
 |  | ||||||
| 		rn, err := t.resolveHash(n, prefix, key) | 		rn, err := t.resolveHash(n, prefix, key) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return false, nil, err | ||||||
| 		} | 		} | ||||||
| 		return t.delete(rn, prefix, key) | 		dirty, nn, err := t.delete(rn, prefix, key) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return false, nil, err | ||||||
|  | 		} | ||||||
|  | 		if !dirty { | ||||||
|  | 			return false, rn, nil | ||||||
|  | 		} | ||||||
|  | 		return true, nn, nil | ||||||
| 
 | 
 | ||||||
| 	default: | 	default: | ||||||
| 		panic(fmt.Sprintf("%T: invalid node: %v (%v)", n, n, key)) | 		panic(fmt.Sprintf("%T: invalid node: %v (%v)", n, n, key)) | ||||||
| @ -413,8 +437,9 @@ func (t *Trie) Root() []byte { return t.Hash().Bytes() } | |||||||
| // Hash returns the root hash of the trie. It does not write to the
 | // Hash returns the root hash of the trie. It does not write to the
 | ||||||
| // database and can be used even if the trie doesn't have one.
 | // database and can be used even if the trie doesn't have one.
 | ||||||
| func (t *Trie) Hash() common.Hash { | func (t *Trie) Hash() common.Hash { | ||||||
| 	root, _ := t.hashRoot(nil) | 	hash, cached, _ := t.hashRoot(nil) | ||||||
| 	return common.BytesToHash(root.(hashNode)) | 	t.root = cached | ||||||
|  | 	return common.BytesToHash(hash.(hashNode)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Commit writes all nodes to the trie's database.
 | // Commit writes all nodes to the trie's database.
 | ||||||
| @ -437,17 +462,17 @@ func (t *Trie) Commit() (root common.Hash, err error) { | |||||||
| // the changes made to db are written back to the trie's attached
 | // the changes made to db are written back to the trie's attached
 | ||||||
| // database before using the trie.
 | // database before using the trie.
 | ||||||
| func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { | func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { | ||||||
| 	n, err := t.hashRoot(db) | 	hash, cached, err := t.hashRoot(db) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return (common.Hash{}), err | 		return (common.Hash{}), err | ||||||
| 	} | 	} | ||||||
| 	t.root = n | 	t.root = cached | ||||||
| 	return common.BytesToHash(n.(hashNode)), nil | 	return common.BytesToHash(hash.(hashNode)), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (t *Trie) hashRoot(db DatabaseWriter) (node, error) { | func (t *Trie) hashRoot(db DatabaseWriter) (node, node, error) { | ||||||
| 	if t.root == nil { | 	if t.root == nil { | ||||||
| 		return hashNode(emptyRoot.Bytes()), nil | 		return hashNode(emptyRoot.Bytes()), nil, nil | ||||||
| 	} | 	} | ||||||
| 	if t.hasher == nil { | 	if t.hasher == nil { | ||||||
| 		t.hasher = newHasher() | 		t.hasher = newHasher() | ||||||
| @ -464,51 +489,87 @@ func newHasher() *hasher { | |||||||
| 	return &hasher{tmp: new(bytes.Buffer), sha: sha3.NewKeccak256()} | 	return &hasher{tmp: new(bytes.Buffer), sha: sha3.NewKeccak256()} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, error) { | // hash collapses a node down into a hash node, also returning a copy of the
 | ||||||
| 	hashed, err := h.replaceChildren(n, db) | // original node initialzied with the computed hash to replace the original one.
 | ||||||
|  | func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) { | ||||||
|  | 	// If we're not storing the node, just hashing, use avaialble cached data
 | ||||||
|  | 	if hash, dirty := n.cache(); hash != nil && (db == nil || !dirty) { | ||||||
|  | 		return hash, n, nil | ||||||
|  | 	} | ||||||
|  | 	// Trie not processed yet or needs storage, walk the children
 | ||||||
|  | 	collapsed, cached, err := h.hashChildren(n, db) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return hashNode{}, err | 		return hashNode{}, n, err | ||||||
| 	} | 	} | ||||||
| 	if n, err = h.store(hashed, db, force); err != nil { | 	hashed, err := h.store(collapsed, db, force) | ||||||
| 		return hashNode{}, err | 	if err != nil { | ||||||
|  | 		return hashNode{}, n, err | ||||||
| 	} | 	} | ||||||
| 	return n, nil | 	// Cache the hash and RLP blob of the ndoe for later reuse
 | ||||||
|  | 	if hash, ok := hashed.(hashNode); ok && !force { | ||||||
|  | 		switch cached := cached.(type) { | ||||||
|  | 		case shortNode: | ||||||
|  | 			cached.hash = hash | ||||||
|  | 			if db != nil { | ||||||
|  | 				cached.dirty = false | ||||||
|  | 			} | ||||||
|  | 			return hashed, cached, nil | ||||||
|  | 		case fullNode: | ||||||
|  | 			cached.hash = hash | ||||||
|  | 			if db != nil { | ||||||
|  | 				cached.dirty = false | ||||||
|  | 			} | ||||||
|  | 			return hashed, cached, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return hashed, cached, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // hashChildren replaces child nodes of n with their hashes if the encoded
 | // hashChildren replaces the children of a node with their hashes if the encoded
 | ||||||
| // size of the child is larger than a hash.
 | // size of the child is larger than a hash, returning the collapsed node as well
 | ||||||
| func (h *hasher) replaceChildren(n node, db DatabaseWriter) (node, error) { | // as a replacement for the original node with the child hashes cached in.
 | ||||||
|  | func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, error) { | ||||||
| 	var err error | 	var err error | ||||||
| 	switch n := n.(type) { | 
 | ||||||
|  | 	switch n := original.(type) { | ||||||
| 	case shortNode: | 	case shortNode: | ||||||
|  | 		// Hash the short node's child, caching the newly hashed subtree
 | ||||||
|  | 		cached := n | ||||||
|  | 		cached.Key = common.CopyBytes(cached.Key) | ||||||
|  | 
 | ||||||
| 		n.Key = compactEncode(n.Key) | 		n.Key = compactEncode(n.Key) | ||||||
| 		if _, ok := n.Val.(valueNode); !ok { | 		if _, ok := n.Val.(valueNode); !ok { | ||||||
| 			if n.Val, err = h.hash(n.Val, db, false); err != nil { | 			if n.Val, cached.Val, err = h.hash(n.Val, db, false); err != nil { | ||||||
| 				return n, err | 				return n, original, err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if n.Val == nil { | 		if n.Val == nil { | ||||||
| 			// Ensure that nil children are encoded as empty strings.
 | 			n.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings.
 | ||||||
| 			n.Val = valueNode(nil) |  | ||||||
| 		} | 		} | ||||||
| 		return n, nil | 		return n, cached, nil | ||||||
|  | 
 | ||||||
| 	case fullNode: | 	case fullNode: | ||||||
|  | 		// Hash the full node's children, caching the newly hashed subtrees
 | ||||||
|  | 		cached := fullNode{dirty: n.dirty} | ||||||
|  | 
 | ||||||
| 		for i := 0; i < 16; i++ { | 		for i := 0; i < 16; i++ { | ||||||
| 			if n[i] != nil { | 			if n.Children[i] != nil { | ||||||
| 				if n[i], err = h.hash(n[i], db, false); err != nil { | 				if n.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false); err != nil { | ||||||
| 					return n, err | 					return n, original, err | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				// Ensure that nil children are encoded as empty strings.
 | 				n.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings.
 | ||||||
| 				n[i] = valueNode(nil) |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if n[16] == nil { | 		cached.Children[16] = n.Children[16] | ||||||
| 			n[16] = valueNode(nil) | 		if n.Children[16] == nil { | ||||||
|  | 			n.Children[16] = valueNode(nil) | ||||||
| 		} | 		} | ||||||
| 		return n, nil | 		return n, cached, nil | ||||||
|  | 
 | ||||||
| 	default: | 	default: | ||||||
| 		return n, nil | 		// Value and hash nodes don't have children so they're left as were
 | ||||||
|  | 		return n, original, nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -517,21 +578,23 @@ func (h *hasher) store(n node, db DatabaseWriter, force bool) (node, error) { | |||||||
| 	if _, isHash := n.(hashNode); n == nil || isHash { | 	if _, isHash := n.(hashNode); n == nil || isHash { | ||||||
| 		return n, nil | 		return n, nil | ||||||
| 	} | 	} | ||||||
|  | 	// Generate the RLP encoding of the node
 | ||||||
| 	h.tmp.Reset() | 	h.tmp.Reset() | ||||||
| 	if err := rlp.Encode(h.tmp, n); err != nil { | 	if err := rlp.Encode(h.tmp, n); err != nil { | ||||||
| 		panic("encode error: " + err.Error()) | 		panic("encode error: " + err.Error()) | ||||||
| 	} | 	} | ||||||
| 	if h.tmp.Len() < 32 && !force { | 	if h.tmp.Len() < 32 && !force { | ||||||
| 		// Nodes smaller than 32 bytes are stored inside their parent.
 | 		return n, nil // Nodes smaller than 32 bytes are stored inside their parent
 | ||||||
| 		return n, nil |  | ||||||
| 	} | 	} | ||||||
| 	// Larger nodes are replaced by their hash and stored in the database.
 | 	// Larger nodes are replaced by their hash and stored in the database.
 | ||||||
| 	h.sha.Reset() | 	hash, _ := n.cache() | ||||||
| 	h.sha.Write(h.tmp.Bytes()) | 	if hash == nil { | ||||||
| 	key := hashNode(h.sha.Sum(nil)) | 		h.sha.Reset() | ||||||
| 	if db != nil { | 		h.sha.Write(h.tmp.Bytes()) | ||||||
| 		err := db.Put(key, h.tmp.Bytes()) | 		hash = hashNode(h.sha.Sum(nil)) | ||||||
| 		return key, err |  | ||||||
| 	} | 	} | ||||||
| 	return key, nil | 	if db != nil { | ||||||
|  | 		return hash, db.Put(hash, h.tmp.Bytes()) | ||||||
|  | 	} | ||||||
|  | 	return hash, nil | ||||||
| } | } | ||||||
|  | |||||||
| @ -295,7 +295,7 @@ func TestReplication(t *testing.T) { | |||||||
| 	for _, val := range vals2 { | 	for _, val := range vals2 { | ||||||
| 		updateString(trie2, val.k, val.v) | 		updateString(trie2, val.k, val.v) | ||||||
| 	} | 	} | ||||||
| 	if trie2.Hash() != exp { | 	if hash := trie2.Hash(); hash != exp { | ||||||
| 		t.Errorf("root failure. expected %x got %x", exp, hash) | 		t.Errorf("root failure. expected %x got %x", exp, hash) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user