@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
var ErrCommitDisabled = errors . New ( "no database for committing" )
@ -224,6 +223,7 @@ func (st *StackTrie) insert(key, value []byte) {
switch st . nodeType {
case branchNode : /* Branch */
idx := int ( key [ 0 ] )
// Unresolve elder siblings
for i := idx - 1 ; i >= 0 ; i -- {
if st . children [ i ] != nil {
@ -233,12 +233,14 @@ func (st *StackTrie) insert(key, value []byte) {
break
}
}
// Add new child
if st . children [ idx ] == nil {
st . children [ idx ] = newLeaf ( key [ 1 : ] , value , st . db )
} else {
st . children [ idx ] . insert ( key [ 1 : ] , value )
}
case extNode : /* Ext */
// Compare both key chunks and see where they differ
diffidx := st . getDiffIndex ( key )
@ -326,10 +328,9 @@ func (st *StackTrie) insert(key, value []byte) {
p = st . children [ 0 ]
}
// Create the two child leaves: the one containing the
// original value and the one containing the new value
// The child leave will be hashed directly in order to
// free up some memory.
// Create the two child leaves: one containing the original
// value and another containing the new value. The child leaf
// is hashed directly in order to free up some memory.
origIdx := st . key [ diffidx ]
p . children [ origIdx ] = newLeaf ( st . key [ diffidx + 1 : ] , st . val , st . db )
p . children [ origIdx ] . hash ( )
@ -341,19 +342,22 @@ 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
st . key = key
st . val = value
case hashedNode :
panic ( "trying to insert into hash" )
default :
panic ( "invalid type" )
}
}
// hash() hashes the node 'st' and converts it into 'hashedNode', if possible.
// Possible outcomes:
// hash converts st into a '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'
@ -361,119 +365,116 @@ func (st *StackTrie) insert(key, value []byte) {
// - Then the <32 byte rlp-encoded value will be accessible in 'st.val'.
// - And the 'st.type' will be 'hashedNode' AGAIN
//
// This method will also:
// set 'st.type' to hashedNode
// clear 'st.key'
// This method also sets 'st.type' to hashedNode, and clears 'st.key'.
func ( st * StackTrie ) hash ( ) {
/* Shortcut if node is already hashed */
if st . nodeType == hashedNode {
return
}
// The 'hasher' is taken from a pool, but we don't actually
// claim an instance until all children are done with their hashing,
// and we actually need one
var h * hasher
h := newHasher ( false )
defer returnHasherToPool ( h )
st . hashRec ( h )
}
func ( st * StackTrie ) hashRec ( hasher * hasher ) {
// The switch below sets this to the RLP-encoding of this node.
var encodedNode [ ] byte
switch st . nodeType {
case hashedNode :
return
case emptyNode :
st . val = emptyRoot . Bytes ( )
st . key = st . key [ : 0 ]
st . nodeType = hashedNode
return
case branchNode :
var nodes [ 17 ] node
var nodes rawFullN ode
for i , child := range st . children {
if child == nil {
nodes [ i ] = nilValueNode
continue
}
child . hash ( )
child . hashRec ( hasher )
if len ( child . val ) < 32 {
nodes [ i ] = rawNode ( child . val )
} else {
nodes [ i ] = hashNode ( child . val )
}
st . children [ i ] = nil // Reclaim mem from subtree
// Release child back to pool.
st . children [ i ] = nil
returnToPool ( child )
}
nodes [ 16 ] = nilValueNode
h = newHasher ( false )
defer returnHasherToPool ( h )
h . tmp . Reset ( )
if err := rlp . Encode ( & h . tmp , nodes ) ; err != nil {
panic ( err )
}
nodes . encode ( hasher . encbuf )
encodedNode = hasher . encodedBytes ( )
case extNode :
st . children [ 0 ] . hash ( )
h = newHasher ( false )
defer returnHasherToPool ( h )
h . tmp . Reset ( )
var valuenode node
st . children [ 0 ] . hashRec ( hasher )
sz := hexToCompactInPlace ( st . key )
n := rawShortNode { Key : st . key [ : sz ] }
if len ( st . children [ 0 ] . val ) < 32 {
valuenode = rawNode ( st . children [ 0 ] . val )
n . Val = rawNode ( st . children [ 0 ] . val )
} else {
valuenode = hashNode ( st . children [ 0 ] . val )
}
n := struct {
Key [ ] byte
Val node
} {
Key : hexToCompact ( st . key ) ,
Val : valuenode ,
}
if err := rlp . Encode ( & h . tmp , n ) ; err != nil {
panic ( err )
n . Val = hashNode ( st . children [ 0 ] . val )
}
n . encode ( hasher . encbuf )
encodedNode = hasher . encodedBytes ( )
// Release child back to pool.
returnToPool ( st . children [ 0 ] )
st . children [ 0 ] = nil // Reclaim mem from subtree
st . children [ 0 ] = nil
case leafNode :
h = newHasher ( false )
defer returnHasherToPool ( h )
h . tmp . Reset ( )
st . key = append ( st . key , byte ( 16 ) )
sz := hexToCompactInPlace ( st . key )
n := [ ] [ ] byte { st . key [ : sz ] , st . val }
if err := rlp . Encode ( & h . tmp , n ) ; err != nil {
panic ( err )
}
case emptyNode :
st . val = emptyRoot . Bytes ( )
st . key = st . key [ : 0 ]
st . nodeType = hashedNode
return
n := rawShortNode { Key : st . key [ : sz ] , Val : valueNode ( st . val ) }
n . encode ( hasher . encbuf )
encodedNode = hasher . encodedBytes ( )
default :
panic ( "I nvalid node type" )
panic ( "invalid node type" )
}
st . key = st . key [ : 0 ]
st . nodeType = hashedNode
if len ( h . tmp ) < 32 {
st . val = common . CopyBytes ( h . tmp )
st . key = st . key [ : 0 ]
if len ( encodedNode ) < 32 {
st . val = common . CopyBytes ( encodedNode )
return
}
// Write the hash to the 'val'. We allocate a new val here to not mutate
// input values
st . val = make ( [ ] byte , 32 )
h . sha . Reset ( )
h . sha . Write ( h . tmp )
h . sha . Read ( st . val )
st . val = hasher . hashData ( encodedNode )
if st . db != nil {
// TODO! Is it safe to Put the slice here?
// Do all db implementations copy the value provided?
st . db . Put ( st . val , h . tmp )
st . db . Put ( st . val , encodedNode )
}
}
// Hash returns the hash of the current node
// Hash returns the hash of the current node.
func ( st * StackTrie ) Hash ( ) ( h common . Hash ) {
st . hash ( )
if len ( st . val ) != 32 {
// If the node's RLP isn't 32 bytes long, the node will not
// be hashed, and instead contain the rlp-encoding of the
// node. For the top level node, we need to force the hashing.
ret := make ( [ ] byte , 32 )
h := newHasher ( false )
defer returnHasherToPool ( h )
h . sha . Reset ( )
h . sha . Write ( st . val )
h . sha . Read ( ret )
return common . BytesToHash ( ret )
hasher := newHasher ( false )
defer returnHasherToPool ( hasher )
st . hashRec ( hasher )
if len ( st . val ) == 32 {
copy ( h [ : ] , st . val )
return h
}
return common . BytesToHash ( st . val )
// If the node's RLP isn't 32 bytes long, the node will not
// be hashed, and instead contain the rlp-encoding of the
// node. For the top level node, we need to force the hashing.
hasher . sha . Reset ( )
hasher . sha . Write ( st . val )
hasher . sha . Read ( h [ : ] )
return h
}
// Commit will firstly hash the entrie trie if it's still not hashed
@ -483,23 +484,26 @@ func (st *StackTrie) Hash() (h common.Hash) {
//
// The associated database is expected, otherwise the whole commit
// functionality should be disabled.
func ( st * StackTrie ) Commit ( ) ( common . Hash , error ) {
func ( st * StackTrie ) Commit ( ) ( h common . Hash , err error ) {
if st . db == nil {
return common . Hash { } , ErrCommitDisabled
}
st . hash ( )
if len ( st . val ) != 32 {
// If the node's RLP isn't 32 bytes long, the node will not
// be hashed (and committed), and instead contain the rlp-encoding of the
// node. For the top level node, we need to force the hashing+commit.
ret := make ( [ ] byte , 32 )
h := newHasher ( false )
defer returnHasherToPool ( h )
h . sha . Reset ( )
h . sha . Write ( st . val )
h . sha . Read ( ret )
st . db . Put ( ret , st . val )
return common . BytesToHash ( ret ) , nil
hasher := newHasher ( false )
defer returnHasherToPool ( hasher )
st . hashRec ( hasher )
if len ( st . val ) == 32 {
copy ( h [ : ] , st . val )
return h , nil
}
return common . BytesToHash ( st . val ) , nil
// If the node's RLP isn't 32 bytes long, the node will not
// be hashed (and committed), and instead contain the rlp-encoding of the
// node. For the top level node, we need to force the hashing+commit.
hasher . sha . Reset ( )
hasher . sha . Write ( st . val )
hasher . sha . Read ( h [ : ] )
st . db . Put ( h [ : ] , st . val )
return h , nil
}