mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 14:16:44 +00:00
trie: ensure shallow copies of Trie can be used concurrently (WIP)
This commit is contained in:
parent
863d166c7b
commit
e7394723e2
4 changed files with 40 additions and 36 deletions
|
|
@ -76,7 +76,7 @@ func (it *NodeIterator) step() error {
|
|||
}
|
||||
// Initialize the iterator if we've just started
|
||||
if it.stateIt == nil {
|
||||
it.stateIt = trie.NewNodeIterator(it.state.trie.Trie)
|
||||
it.stateIt = it.state.trie.NodeIterator()
|
||||
}
|
||||
// If we had data nodes previously, we surely have at least state nodes
|
||||
if it.dataIt != nil {
|
||||
|
|
|
|||
|
|
@ -70,15 +70,13 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
|
|||
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))
|
||||
}
|
||||
}
|
||||
if t.hasher == nil {
|
||||
t.hasher = newHasher()
|
||||
}
|
||||
hasher := newHasher()
|
||||
proof := make([]rlp.RawValue, 0, len(nodes))
|
||||
for i, n := range nodes {
|
||||
// Don't bother checking for errors here since hasher panics
|
||||
// if encoding doesn't work and we're not writing to any database.
|
||||
n, _, _ = t.hasher.hashChildren(n, nil)
|
||||
hn, _ := t.hasher.store(n, nil, false)
|
||||
n, _, _ = hasher.hashChildren(n, nil)
|
||||
hn, _ := hasher.store(n, nil, false)
|
||||
if _, ok := hn.(hashNode); ok || i == 0 {
|
||||
// If the node's database encoding is a hash (or is the
|
||||
// root node), it becomes a proof element.
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
|
|
@ -38,11 +36,9 @@ var secureKeyPrefix = []byte("secure-key-")
|
|||
//
|
||||
// SecureTrie is not safe for concurrent use.
|
||||
type SecureTrie struct {
|
||||
*Trie
|
||||
|
||||
hash hash.Hash
|
||||
trie Trie
|
||||
hashKeyBuf []byte
|
||||
secKeyBuf []byte
|
||||
secKeyBuf [64]byte
|
||||
secKeyCache map[string][]byte
|
||||
}
|
||||
|
||||
|
|
@ -61,7 +57,7 @@ func NewSecure(root common.Hash, db Database) (*SecureTrie, error) {
|
|||
return nil, err
|
||||
}
|
||||
return &SecureTrie{
|
||||
Trie: trie,
|
||||
trie: *trie,
|
||||
secKeyCache: make(map[string][]byte),
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -80,7 +76,7 @@ func (t *SecureTrie) Get(key []byte) []byte {
|
|||
// The value bytes must not be modified by the caller.
|
||||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (t *SecureTrie) TryGet(key []byte) ([]byte, error) {
|
||||
return t.Trie.TryGet(t.hashKey(key))
|
||||
return t.trie.TryGet(t.hashKey(key))
|
||||
}
|
||||
|
||||
// Update associates key with value in the trie. Subsequent calls to
|
||||
|
|
@ -105,7 +101,7 @@ func (t *SecureTrie) Update(key, value []byte) {
|
|||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (t *SecureTrie) TryUpdate(key, value []byte) error {
|
||||
hk := t.hashKey(key)
|
||||
err := t.Trie.TryUpdate(hk, value)
|
||||
err := t.trie.TryUpdate(hk, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -125,7 +121,7 @@ func (t *SecureTrie) Delete(key []byte) {
|
|||
func (t *SecureTrie) TryDelete(key []byte) error {
|
||||
hk := t.hashKey(key)
|
||||
delete(t.secKeyCache, string(hk))
|
||||
return t.Trie.TryDelete(hk)
|
||||
return t.trie.TryDelete(hk)
|
||||
}
|
||||
|
||||
// GetKey returns the sha3 preimage of a hashed key that was
|
||||
|
|
@ -134,7 +130,7 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte {
|
|||
if key, ok := t.secKeyCache[string(shaKey)]; ok {
|
||||
return key
|
||||
}
|
||||
key, _ := t.Trie.db.Get(t.secKey(shaKey))
|
||||
key, _ := t.trie.db.Get(t.secKey(shaKey))
|
||||
return key
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +140,23 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte {
|
|||
// Committing flushes nodes from memory. Subsequent Get calls will load nodes
|
||||
// from the database.
|
||||
func (t *SecureTrie) Commit() (root common.Hash, err error) {
|
||||
return t.CommitTo(t.db)
|
||||
return t.CommitTo(t.trie.db)
|
||||
}
|
||||
|
||||
func (t *SecureTrie) Hash() common.Hash {
|
||||
return t.trie.Hash()
|
||||
}
|
||||
|
||||
func (t *SecureTrie) Root() []byte {
|
||||
return t.trie.Root()
|
||||
}
|
||||
|
||||
func (t *SecureTrie) Iterator() *Iterator {
|
||||
return t.trie.Iterator()
|
||||
}
|
||||
|
||||
func (t *SecureTrie) NodeIterator() *NodeIterator {
|
||||
return NewNodeIterator(&t.trie)
|
||||
}
|
||||
|
||||
// CommitTo writes all nodes and the secure hash pre-images to the given database.
|
||||
|
|
@ -162,27 +174,24 @@ func (t *SecureTrie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
|
|||
}
|
||||
t.secKeyCache = make(map[string][]byte)
|
||||
}
|
||||
n, clean, err := t.hashRoot(db)
|
||||
n, clean, err := t.trie.hashRoot(db)
|
||||
if err != nil {
|
||||
return (common.Hash{}), err
|
||||
}
|
||||
t.root = clean
|
||||
t.trie.root = clean
|
||||
return common.BytesToHash(n.(hashNode)), nil
|
||||
}
|
||||
|
||||
func (t *SecureTrie) secKey(key []byte) []byte {
|
||||
t.secKeyBuf = append(t.secKeyBuf[:0], secureKeyPrefix...)
|
||||
t.secKeyBuf = append(t.secKeyBuf, key...)
|
||||
return t.secKeyBuf
|
||||
buf := append(t.secKeyBuf[:0], secureKeyPrefix...)
|
||||
buf = append(buf, key...)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (t *SecureTrie) hashKey(key []byte) []byte {
|
||||
if t.hash == nil {
|
||||
t.hash = sha3.NewKeccak256()
|
||||
t.hashKeyBuf = make([]byte, 32)
|
||||
}
|
||||
t.hash.Reset()
|
||||
t.hash.Write(key)
|
||||
t.hashKeyBuf = t.hash.Sum(t.hashKeyBuf[:0])
|
||||
return t.hashKeyBuf
|
||||
hash := sha3.NewKeccak256()
|
||||
hash.Reset()
|
||||
hash.Write(key)
|
||||
buf := hash.Sum(t.hashKeyBuf[:0])
|
||||
return buf
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ type Trie struct {
|
|||
root node
|
||||
db Database
|
||||
originalRoot common.Hash
|
||||
*hasher
|
||||
}
|
||||
|
||||
// New creates a trie with an existing root node from db.
|
||||
|
|
@ -474,10 +473,8 @@ func (t *Trie) hashRoot(db DatabaseWriter) (node, node, error) {
|
|||
if t.root == nil {
|
||||
return hashNode(emptyRoot.Bytes()), nil, nil
|
||||
}
|
||||
if t.hasher == nil {
|
||||
t.hasher = newHasher()
|
||||
}
|
||||
return t.hasher.hash(t.root, db, true)
|
||||
hasher := newHasher()
|
||||
return hasher.hash(t.root, db, true)
|
||||
}
|
||||
|
||||
type hasher struct {
|
||||
|
|
|
|||
Loading…
Reference in a new issue