Fixed a copy issue in the trie which could cause a consensus failure
This commit is contained in:
parent
6fecb150d6
commit
3c7181d28f
@ -37,6 +37,14 @@ func (self *Cache) Flush() {
|
|||||||
//self.Reset()
|
//self.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Cache) Reset() {
|
func (self *Cache) Copy() *Cache {
|
||||||
self.store = make(map[string][]byte)
|
cache := NewCache(self.backend)
|
||||||
|
for k, v := range self.store {
|
||||||
|
cache.store[k] = v
|
||||||
|
}
|
||||||
|
return cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Cache) Reset() {
|
||||||
|
//self.store = make(map[string][]byte)
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,11 @@ func (self *FullNode) Branches() []Node {
|
|||||||
return self.nodes[:16]
|
return self.nodes[:16]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *FullNode) Copy() Node {
|
func (self *FullNode) Copy(t *Trie) Node {
|
||||||
nnode := NewFullNode(self.trie)
|
nnode := NewFullNode(t)
|
||||||
for i, node := range self.nodes {
|
for i, node := range self.nodes {
|
||||||
if node != nil {
|
if node != nil {
|
||||||
nnode.nodes[i] = node
|
nnode.nodes[i] = node.Copy(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package trie
|
package trie
|
||||||
|
|
||||||
|
import "github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
|
||||||
type HashNode struct {
|
type HashNode struct {
|
||||||
key []byte
|
key []byte
|
||||||
|
trie *Trie
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHash(key []byte) *HashNode {
|
func NewHash(key []byte, trie *Trie) *HashNode {
|
||||||
return &HashNode{key}
|
return &HashNode{key, trie}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *HashNode) RlpData() interface{} {
|
func (self *HashNode) RlpData() interface{} {
|
||||||
@ -19,4 +22,4 @@ func (self *HashNode) Hash() interface{} {
|
|||||||
// These methods will never be called but we have to satisfy Node interface
|
// These methods will never be called but we have to satisfy Node interface
|
||||||
func (self *HashNode) Value() Node { return nil }
|
func (self *HashNode) Value() Node { return nil }
|
||||||
func (self *HashNode) Dirty() bool { return true }
|
func (self *HashNode) Dirty() bool { return true }
|
||||||
func (self *HashNode) Copy() Node { return self }
|
func (self *HashNode) Copy(t *Trie) Node { return NewHash(ethutil.CopyBytes(self.key), t) }
|
||||||
|
@ -6,7 +6,7 @@ var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b
|
|||||||
|
|
||||||
type Node interface {
|
type Node interface {
|
||||||
Value() Node
|
Value() Node
|
||||||
Copy() Node // All nodes, for now, return them self
|
Copy(*Trie) Node // All nodes, for now, return them self
|
||||||
Dirty() bool
|
Dirty() bool
|
||||||
fstring(string) string
|
fstring(string) string
|
||||||
Hash() interface{}
|
Hash() interface{}
|
||||||
@ -18,7 +18,11 @@ func (self *ValueNode) String() string { return self.fstring("") }
|
|||||||
func (self *FullNode) String() string { return self.fstring("") }
|
func (self *FullNode) String() string { return self.fstring("") }
|
||||||
func (self *ShortNode) String() string { return self.fstring("") }
|
func (self *ShortNode) String() string { return self.fstring("") }
|
||||||
func (self *ValueNode) fstring(ind string) string { return fmt.Sprintf("%x ", self.data) }
|
func (self *ValueNode) fstring(ind string) string { return fmt.Sprintf("%x ", self.data) }
|
||||||
func (self *HashNode) fstring(ind string) string { return fmt.Sprintf("< %x > ", self.key) }
|
|
||||||
|
//func (self *HashNode) fstring(ind string) string { return fmt.Sprintf("< %x > ", self.key) }
|
||||||
|
func (self *HashNode) fstring(ind string) string {
|
||||||
|
return fmt.Sprintf("%v", self.trie.trans(self))
|
||||||
|
}
|
||||||
|
|
||||||
// Full node
|
// Full node
|
||||||
func (self *FullNode) fstring(ind string) string {
|
func (self *FullNode) fstring(ind string) string {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package trie
|
package trie
|
||||||
|
|
||||||
|
import "github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
|
||||||
type ShortNode struct {
|
type ShortNode struct {
|
||||||
trie *Trie
|
trie *Trie
|
||||||
key []byte
|
key []byte
|
||||||
@ -15,7 +17,11 @@ func (self *ShortNode) Value() Node {
|
|||||||
return self.value
|
return self.value
|
||||||
}
|
}
|
||||||
func (self *ShortNode) Dirty() bool { return true }
|
func (self *ShortNode) Dirty() bool { return true }
|
||||||
func (self *ShortNode) Copy() Node { return NewShortNode(self.trie, self.key, self.value) }
|
func (self *ShortNode) Copy(t *Trie) Node {
|
||||||
|
node := &ShortNode{t, nil, self.value.Copy(t)}
|
||||||
|
node.key = ethutil.CopyBytes(self.key)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
func (self *ShortNode) RlpData() interface{} {
|
func (self *ShortNode) RlpData() interface{} {
|
||||||
return []interface{}{self.key, self.value.Hash()}
|
return []interface{}{self.key, self.value.Hash()}
|
||||||
|
19
trie/trie.go
19
trie/trie.go
@ -34,7 +34,9 @@ func New(root []byte, backend Backend) *Trie {
|
|||||||
trie := &Trie{}
|
trie := &Trie{}
|
||||||
trie.revisions = list.New()
|
trie.revisions = list.New()
|
||||||
trie.roothash = root
|
trie.roothash = root
|
||||||
|
if backend != nil {
|
||||||
trie.cache = NewCache(backend)
|
trie.cache = NewCache(backend)
|
||||||
|
}
|
||||||
|
|
||||||
if root != nil {
|
if root != nil {
|
||||||
value := ethutil.NewValueFromBytes(trie.cache.Get(root))
|
value := ethutil.NewValueFromBytes(trie.cache.Get(root))
|
||||||
@ -49,7 +51,15 @@ func (self *Trie) Iterator() *Iterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *Trie) Copy() *Trie {
|
func (self *Trie) Copy() *Trie {
|
||||||
return New(self.roothash, self.cache.backend)
|
cpy := make([]byte, 32)
|
||||||
|
copy(cpy, self.roothash)
|
||||||
|
trie := New(nil, nil)
|
||||||
|
trie.cache = self.cache.Copy()
|
||||||
|
if self.root != nil {
|
||||||
|
trie.root = self.root.Copy(trie)
|
||||||
|
}
|
||||||
|
|
||||||
|
return trie
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy support
|
// Legacy support
|
||||||
@ -177,7 +187,7 @@ func (self *Trie) insert(node Node, key []byte, value Node) Node {
|
|||||||
return NewShortNode(self, key[:matchlength], n)
|
return NewShortNode(self, key[:matchlength], n)
|
||||||
|
|
||||||
case *FullNode:
|
case *FullNode:
|
||||||
cpy := node.Copy().(*FullNode)
|
cpy := node.Copy(self).(*FullNode)
|
||||||
cpy.set(key[0], self.insert(node.branch(key[0]), key[1:], value))
|
cpy.set(key[0], self.insert(node.branch(key[0]), key[1:], value))
|
||||||
|
|
||||||
return cpy
|
return cpy
|
||||||
@ -244,7 +254,7 @@ func (self *Trie) delete(node Node, key []byte) Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case *FullNode:
|
case *FullNode:
|
||||||
n := node.Copy().(*FullNode)
|
n := node.Copy(self).(*FullNode)
|
||||||
n.set(key[0], self.delete(n.branch(key[0]), key[1:]))
|
n.set(key[0], self.delete(n.branch(key[0]), key[1:]))
|
||||||
|
|
||||||
pos := -1
|
pos := -1
|
||||||
@ -301,7 +311,7 @@ func (self *Trie) mknode(value *ethutil.Value) Node {
|
|||||||
}
|
}
|
||||||
return fnode
|
return fnode
|
||||||
case 32:
|
case 32:
|
||||||
return &HashNode{value.Bytes()}
|
return &HashNode{value.Bytes(), self}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ValueNode{self, value.Bytes()}
|
return &ValueNode{self, value.Bytes()}
|
||||||
@ -331,4 +341,5 @@ func (self *Trie) store(node Node) interface{} {
|
|||||||
|
|
||||||
func (self *Trie) PrintRoot() {
|
func (self *Trie) PrintRoot() {
|
||||||
fmt.Println(self.root)
|
fmt.Println(self.root)
|
||||||
|
fmt.Printf("root=%x\n", self.Root())
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package trie
|
package trie
|
||||||
|
|
||||||
|
import "github.com/ethereum/go-ethereum/ethutil"
|
||||||
|
|
||||||
type ValueNode struct {
|
type ValueNode struct {
|
||||||
trie *Trie
|
trie *Trie
|
||||||
data []byte
|
data []byte
|
||||||
@ -8,6 +10,6 @@ type ValueNode struct {
|
|||||||
func (self *ValueNode) Value() Node { return self } // Best not to call :-)
|
func (self *ValueNode) Value() Node { return self } // Best not to call :-)
|
||||||
func (self *ValueNode) Val() []byte { return self.data }
|
func (self *ValueNode) Val() []byte { return self.data }
|
||||||
func (self *ValueNode) Dirty() bool { return true }
|
func (self *ValueNode) Dirty() bool { return true }
|
||||||
func (self *ValueNode) Copy() Node { return &ValueNode{self.trie, self.data} }
|
func (self *ValueNode) Copy(t *Trie) Node { return &ValueNode{t, ethutil.CopyBytes(self.data)} }
|
||||||
func (self *ValueNode) RlpData() interface{} { return self.data }
|
func (self *ValueNode) RlpData() interface{} { return self.data }
|
||||||
func (self *ValueNode) Hash() interface{} { return self.data }
|
func (self *ValueNode) Hash() interface{} { return self.data }
|
||||||
|
Loading…
Reference in New Issue
Block a user