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
|
// Initialize the iterator if we've just started
|
||||||
if it.stateIt == nil {
|
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 we had data nodes previously, we surely have at least state nodes
|
||||||
if it.dataIt != nil {
|
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))
|
panic(fmt.Sprintf("%T: invalid node: %v", tn, tn))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t.hasher == nil {
|
hasher := newHasher()
|
||||||
t.hasher = newHasher()
|
|
||||||
}
|
|
||||||
proof := make([]rlp.RawValue, 0, len(nodes))
|
proof := make([]rlp.RawValue, 0, len(nodes))
|
||||||
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.hashChildren(n, nil)
|
n, _, _ = hasher.hashChildren(n, nil)
|
||||||
hn, _ := t.hasher.store(n, nil, false)
|
hn, _ := 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
|
||||||
// root node), it becomes a proof element.
|
// root node), it becomes a proof element.
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@
|
||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"hash"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
|
|
@ -38,11 +36,9 @@ var secureKeyPrefix = []byte("secure-key-")
|
||||||
//
|
//
|
||||||
// SecureTrie is not safe for concurrent use.
|
// SecureTrie is not safe for concurrent use.
|
||||||
type SecureTrie struct {
|
type SecureTrie struct {
|
||||||
*Trie
|
trie Trie
|
||||||
|
|
||||||
hash hash.Hash
|
|
||||||
hashKeyBuf []byte
|
hashKeyBuf []byte
|
||||||
secKeyBuf []byte
|
secKeyBuf [64]byte
|
||||||
secKeyCache map[string][]byte
|
secKeyCache map[string][]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +57,7 @@ func NewSecure(root common.Hash, db Database) (*SecureTrie, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &SecureTrie{
|
return &SecureTrie{
|
||||||
Trie: trie,
|
trie: *trie,
|
||||||
secKeyCache: make(map[string][]byte),
|
secKeyCache: make(map[string][]byte),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +76,7 @@ func (t *SecureTrie) Get(key []byte) []byte {
|
||||||
// The value bytes must not be modified by the caller.
|
// The value bytes must not be modified by the caller.
|
||||||
// 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 *SecureTrie) TryGet(key []byte) ([]byte, error) {
|
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
|
// 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.
|
// If a node was not found in the database, a MissingNodeError is returned.
|
||||||
func (t *SecureTrie) TryUpdate(key, value []byte) error {
|
func (t *SecureTrie) TryUpdate(key, value []byte) error {
|
||||||
hk := t.hashKey(key)
|
hk := t.hashKey(key)
|
||||||
err := t.Trie.TryUpdate(hk, value)
|
err := t.trie.TryUpdate(hk, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +121,7 @@ func (t *SecureTrie) Delete(key []byte) {
|
||||||
func (t *SecureTrie) TryDelete(key []byte) error {
|
func (t *SecureTrie) TryDelete(key []byte) error {
|
||||||
hk := t.hashKey(key)
|
hk := t.hashKey(key)
|
||||||
delete(t.secKeyCache, string(hk))
|
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
|
// 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 {
|
if key, ok := t.secKeyCache[string(shaKey)]; ok {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
key, _ := t.Trie.db.Get(t.secKey(shaKey))
|
key, _ := t.trie.db.Get(t.secKey(shaKey))
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,7 +140,23 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte {
|
||||||
// Committing flushes nodes from memory. Subsequent Get calls will load nodes
|
// Committing flushes nodes from memory. Subsequent Get calls will load nodes
|
||||||
// from the database.
|
// from the database.
|
||||||
func (t *SecureTrie) Commit() (root common.Hash, err error) {
|
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.
|
// 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)
|
t.secKeyCache = make(map[string][]byte)
|
||||||
}
|
}
|
||||||
n, clean, err := t.hashRoot(db)
|
n, clean, err := t.trie.hashRoot(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return (common.Hash{}), err
|
return (common.Hash{}), err
|
||||||
}
|
}
|
||||||
t.root = clean
|
t.trie.root = clean
|
||||||
return common.BytesToHash(n.(hashNode)), nil
|
return common.BytesToHash(n.(hashNode)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SecureTrie) secKey(key []byte) []byte {
|
func (t *SecureTrie) secKey(key []byte) []byte {
|
||||||
t.secKeyBuf = append(t.secKeyBuf[:0], secureKeyPrefix...)
|
buf := append(t.secKeyBuf[:0], secureKeyPrefix...)
|
||||||
t.secKeyBuf = append(t.secKeyBuf, key...)
|
buf = append(buf, key...)
|
||||||
return t.secKeyBuf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SecureTrie) hashKey(key []byte) []byte {
|
func (t *SecureTrie) hashKey(key []byte) []byte {
|
||||||
if t.hash == nil {
|
hash := sha3.NewKeccak256()
|
||||||
t.hash = sha3.NewKeccak256()
|
hash.Reset()
|
||||||
t.hashKeyBuf = make([]byte, 32)
|
hash.Write(key)
|
||||||
}
|
buf := hash.Sum(t.hashKeyBuf[:0])
|
||||||
t.hash.Reset()
|
return buf
|
||||||
t.hash.Write(key)
|
|
||||||
t.hashKeyBuf = t.hash.Sum(t.hashKeyBuf[:0])
|
|
||||||
return t.hashKeyBuf
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@ type Trie struct {
|
||||||
root node
|
root node
|
||||||
db Database
|
db Database
|
||||||
originalRoot common.Hash
|
originalRoot common.Hash
|
||||||
*hasher
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a trie with an existing root node from db.
|
// 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 {
|
if t.root == nil {
|
||||||
return hashNode(emptyRoot.Bytes()), nil, nil
|
return hashNode(emptyRoot.Bytes()), nil, nil
|
||||||
}
|
}
|
||||||
if t.hasher == nil {
|
hasher := newHasher()
|
||||||
t.hasher = newHasher()
|
return hasher.hash(t.root, db, true)
|
||||||
}
|
|
||||||
return t.hasher.hash(t.root, db, true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type hasher struct {
|
type hasher struct {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue