mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
trie, light: Rename Storage to PersistentMap
This commit is contained in:
parent
de5a818baa
commit
5b73f9aacd
5 changed files with 58 additions and 59 deletions
|
|
@ -191,7 +191,7 @@ func (self *StateDB) SetTxContext(blockHash common.Hash, blockNum uint64, txHash
|
||||||
if validator == nil {
|
if validator == nil {
|
||||||
validator = &trie.NullCacheValidator{}
|
validator = &trie.NullCacheValidator{}
|
||||||
}
|
}
|
||||||
storage := trie.NewDirectCache(self.trie, self.db, CachePrefix, validator, true)
|
storage := trie.NewDirectCache(self.trie, self.db, CachePrefix, &trie.NullCacheValidator{}, true)
|
||||||
self.storage = trie.NewSecure(storage, self.db)
|
self.storage = trie.NewSecure(storage, self.db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import (
|
||||||
|
|
||||||
// LightTrie is an ODR-capable wrapper around trie.SecureTrie
|
// LightTrie is an ODR-capable wrapper around trie.SecureTrie
|
||||||
type LightTrie struct {
|
type LightTrie struct {
|
||||||
storage *trie.SecureTrie
|
data *trie.SecureTrie
|
||||||
originalRoot common.Hash
|
originalRoot common.Hash
|
||||||
odr OdrBackend
|
odr OdrBackend
|
||||||
db ethdb.Database
|
db ethdb.Database
|
||||||
|
|
@ -74,16 +74,16 @@ func (t *LightTrie) do(ctx context.Context, fallbackKey []byte, fn func() error)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *LightTrie) getStorage() (ret *trie.SecureTrie, err error) {
|
func (t *LightTrie) getMap() (ret *trie.SecureTrie, err error) {
|
||||||
if t.storage == nil {
|
if t.data == nil {
|
||||||
var tr trie.Storage
|
var tr trie.PersistentMap
|
||||||
tr, err = trie.New(t.originalRoot, t.db, 0)
|
tr, err = trie.New(t.originalRoot, t.db, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t.storage = trie.NewSecure(tr, t.db)
|
t.data = trie.NewSecure(tr, t.db)
|
||||||
}
|
}
|
||||||
return t.storage, nil
|
return t.data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the value for key stored in the trie.
|
// Get returns the value for key stored in the trie.
|
||||||
|
|
@ -91,7 +91,7 @@ func (t *LightTrie) getStorage() (ret *trie.SecureTrie, err error) {
|
||||||
func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error) {
|
func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error) {
|
||||||
err = t.do(ctx, key, func() (err error) {
|
err = t.do(ctx, key, func() (err error) {
|
||||||
var st *trie.SecureTrie
|
var st *trie.SecureTrie
|
||||||
st, err = t.getStorage()
|
st, err = t.getMap()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
res, err = st.TryGet(key)
|
res, err = st.TryGet(key)
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +109,7 @@ func (t *LightTrie) Get(ctx context.Context, key []byte) (res []byte, err error)
|
||||||
func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) {
|
func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) {
|
||||||
err = t.do(ctx, key, func() (err error) {
|
err = t.do(ctx, key, func() (err error) {
|
||||||
var st *trie.SecureTrie
|
var st *trie.SecureTrie
|
||||||
st, err = t.getStorage()
|
st, err = t.getMap()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = st.TryUpdate(key, value)
|
err = st.TryUpdate(key, value)
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +122,7 @@ func (t *LightTrie) Update(ctx context.Context, key, value []byte) (err error) {
|
||||||
func (t *LightTrie) Delete(ctx context.Context, key []byte) (err error) {
|
func (t *LightTrie) Delete(ctx context.Context, key []byte) (err error) {
|
||||||
err = t.do(ctx, key, func() (err error) {
|
err = t.do(ctx, key, func() (err error) {
|
||||||
var st *trie.SecureTrie
|
var st *trie.SecureTrie
|
||||||
st, err = t.getStorage()
|
st, err = t.getMap()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = st.TryDelete(key)
|
err = st.TryDelete(key)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ type CacheValidator interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DirectCache struct {
|
type DirectCache struct {
|
||||||
storage Storage
|
data PersistentMap
|
||||||
db Database
|
db Database
|
||||||
keyPrefix []byte
|
keyPrefix []byte
|
||||||
blockNum uint64
|
blockNum uint64
|
||||||
|
|
@ -58,9 +58,9 @@ func (cv *NullCacheValidator) IsCanonChainBlock(num uint64, hash common.Hash) bo
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDirectCache(s Storage, db Database, keyPrefix []byte, validator CacheValidator, complete bool) *DirectCache {
|
func NewDirectCache(pm PersistentMap, db Database, keyPrefix []byte, validator CacheValidator, complete bool) *DirectCache {
|
||||||
return &DirectCache{
|
return &DirectCache{
|
||||||
storage: s,
|
data: pm,
|
||||||
db: db,
|
db: db,
|
||||||
keyPrefix: keyPrefix,
|
keyPrefix: keyPrefix,
|
||||||
validator: validator,
|
validator: validator,
|
||||||
|
|
@ -71,7 +71,7 @@ func NewDirectCache(s Storage, db Database, keyPrefix []byte, validator CacheVal
|
||||||
|
|
||||||
func (dc *DirectCache) Iterator() *Iterator {
|
func (dc *DirectCache) Iterator() *Iterator {
|
||||||
// Todo: If complete is true, implement an iterator over the DB instead.
|
// Todo: If complete is true, implement an iterator over the DB instead.
|
||||||
return dc.storage.Iterator()
|
return dc.data.Iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DirectCache) makeKey(key []byte) []byte {
|
func (dc *DirectCache) makeKey(key []byte) []byte {
|
||||||
|
|
@ -87,7 +87,6 @@ func (dc *DirectCache) Get(key []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DirectCache) TryGet(key []byte) ([]byte, error) {
|
func (dc *DirectCache) TryGet(key []byte) ([]byte, error) {
|
||||||
return dc.storage.TryGet(key)
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
// Use the underlying object for dirty keys
|
// Use the underlying object for dirty keys
|
||||||
|
|
@ -99,7 +98,7 @@ func (dc *DirectCache) TryGet(key []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value, err := dc.storage.TryGet(key)
|
value, err := dc.data.TryGet(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return value, err
|
return value, err
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +145,7 @@ func (dc *DirectCache) Update(key, value []byte) {
|
||||||
|
|
||||||
func (dc *DirectCache) TryUpdate(key, value []byte) error {
|
func (dc *DirectCache) TryUpdate(key, value []byte) error {
|
||||||
dc.dirty[string(key)] = true
|
dc.dirty[string(key)] = true
|
||||||
return dc.storage.TryUpdate(key, value)
|
return dc.data.TryUpdate(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DirectCache) Delete(key []byte) {
|
func (dc *DirectCache) Delete(key []byte) {
|
||||||
|
|
@ -157,7 +156,7 @@ func (dc *DirectCache) Delete(key []byte) {
|
||||||
|
|
||||||
func (dc *DirectCache) TryDelete(key []byte) error {
|
func (dc *DirectCache) TryDelete(key []byte) error {
|
||||||
dc.dirty[string(key)] = true
|
dc.dirty[string(key)] = true
|
||||||
return dc.storage.TryDelete(key)
|
return dc.data.TryDelete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dc *DirectCache) Commit() (root common.Hash, err error) {
|
func (dc *DirectCache) Commit() (root common.Hash, err error) {
|
||||||
|
|
@ -167,7 +166,7 @@ func (dc *DirectCache) Commit() (root common.Hash, err error) {
|
||||||
func (dc *DirectCache) CommitTo(dbw DatabaseWriter) (root common.Hash, err error) {
|
func (dc *DirectCache) CommitTo(dbw DatabaseWriter) (root common.Hash, err error) {
|
||||||
directCacheWrites.Inc(int64(len(dc.dirty)))
|
directCacheWrites.Inc(int64(len(dc.dirty)))
|
||||||
for k, _ := range dc.dirty {
|
for k, _ := range dc.dirty {
|
||||||
v, err := dc.storage.TryGet([]byte(k))
|
v, err := dc.data.TryGet([]byte(k))
|
||||||
if err, ok := err.(*MissingNodeError); err != nil && !ok {
|
if err, ok := err.(*MissingNodeError); err != nil && !ok {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -176,5 +175,5 @@ func (dc *DirectCache) CommitTo(dbw DatabaseWriter) (root common.Hash, err error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dc.dirty = make(map[string]bool)
|
dc.dirty = make(map[string]bool)
|
||||||
return dc.storage.CommitTo(dbw)
|
return dc.data.CommitTo(dbw)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,18 @@ var secureKeyPrefix = []byte("secure-key-")
|
||||||
|
|
||||||
const secureKeyLength = 11 + 32 // Length of the above prefix + 32byte hash
|
const secureKeyLength = 11 + 32 // Length of the above prefix + 32byte hash
|
||||||
|
|
||||||
|
type PersistentMap interface {
|
||||||
|
Iterator() *Iterator
|
||||||
|
Get(key []byte) []byte
|
||||||
|
TryGet(key []byte) ([]byte, error)
|
||||||
|
Update(key, value []byte)
|
||||||
|
TryUpdate(key, value []byte) error
|
||||||
|
Delete(key []byte)
|
||||||
|
TryDelete(key []byte) error
|
||||||
|
Commit() (root common.Hash, err error)
|
||||||
|
CommitTo(db DatabaseWriter) (root common.Hash, err error)
|
||||||
|
}
|
||||||
|
|
||||||
// SecureTrie wraps a trie with key hashing. In a secure trie, all
|
// SecureTrie wraps a trie with key hashing. In a secure trie, all
|
||||||
// access operations hash the key using keccak256. This prevents
|
// access operations hash the key using keccak256. This prevents
|
||||||
// calling code from creating long chains of nodes that
|
// calling code from creating long chains of nodes that
|
||||||
|
|
@ -37,7 +49,7 @@ const secureKeyLength = 11 + 32 // Length of the above prefix + 32byte hash
|
||||||
//
|
//
|
||||||
// SecureTrie is not safe for concurrent use.
|
// SecureTrie is not safe for concurrent use.
|
||||||
type SecureTrie struct {
|
type SecureTrie struct {
|
||||||
storage Storage
|
data PersistentMap
|
||||||
db Database
|
db Database
|
||||||
hashKeyBuf [secureKeyLength]byte
|
hashKeyBuf [secureKeyLength]byte
|
||||||
secKeyBuf [200]byte
|
secKeyBuf [200]byte
|
||||||
|
|
@ -45,57 +57,57 @@ type SecureTrie struct {
|
||||||
secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch
|
secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSecure creates a secure Storage from an existing Storage.
|
// NewSecure creates a secure persistent map from an existing map.
|
||||||
func NewSecure(s Storage, db Database) *SecureTrie {
|
func NewSecure(pm PersistentMap, db Database) *SecureTrie {
|
||||||
if s == nil {
|
if pm == nil {
|
||||||
panic("NewSecure called with nil storage")
|
panic("NewSecure called with nil persistent map")
|
||||||
}
|
}
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("NewSecure called with nil database")
|
panic("NewSecure called with nil database")
|
||||||
}
|
}
|
||||||
return &SecureTrie{storage: s, db: db}
|
return &SecureTrie{data: pm, db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the value for key stored in the storage.
|
// Get returns the value for key stored in the map.
|
||||||
// The value bytes must not be modified by the caller.
|
// The value bytes must not be modified by the caller.
|
||||||
func (t *SecureTrie) Get(key []byte) []byte {
|
func (t *SecureTrie) Get(key []byte) []byte {
|
||||||
res, err := t.TryGet(key)
|
res, err := t.TryGet(key)
|
||||||
if err != nil && glog.V(logger.Error) {
|
if err != nil && glog.V(logger.Error) {
|
||||||
glog.Errorf("Unhandled storage error: %v", err)
|
glog.Errorf("Unhandled persistent map error: %v", err)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryGet returns the value for key stored in the storage.
|
// TryGet returns the value for key stored in the map.
|
||||||
// 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.storage.TryGet(t.hashKey(key))
|
return t.data.TryGet(t.hashKey(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update associates key with value in the storage. Subsequent calls to
|
// Update associates key with value in the map. Subsequent calls to
|
||||||
// Get will return value. If value has length zero, any existing value
|
// Get will return value. If value has length zero, any existing value
|
||||||
// is deleted from the storage and calls to Get will return nil.
|
// is deleted from the map and calls to Get will return nil.
|
||||||
//
|
//
|
||||||
// The value bytes must not be modified by the caller while they are
|
// The value bytes must not be modified by the caller while they are
|
||||||
// stored in the storage.
|
// stored in the map.
|
||||||
func (t *SecureTrie) Update(key, value []byte) {
|
func (t *SecureTrie) Update(key, value []byte) {
|
||||||
if err := t.TryUpdate(key, value); err != nil && glog.V(logger.Error) {
|
if err := t.TryUpdate(key, value); err != nil && glog.V(logger.Error) {
|
||||||
glog.Errorf("Unhandled storage error: %v", err)
|
glog.Errorf("Unhandled persistent map error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryUpdate associates key with value in the storage. Subsequent calls to
|
// TryUpdate associates key with value in the map. Subsequent calls to
|
||||||
// Get will return value. If value has length zero, any existing value
|
// Get will return value. If value has length zero, any existing value
|
||||||
// is deleted from the storage and calls to Get will return nil.
|
// is deleted from the map and calls to Get will return nil.
|
||||||
//
|
//
|
||||||
// The value bytes must not be modified by the caller while they are
|
// The value bytes must not be modified by the caller while they are
|
||||||
// stored in the storage.
|
// stored in the map.
|
||||||
//
|
//
|
||||||
// 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.storage.TryUpdate(hk, value)
|
err := t.data.TryUpdate(hk, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -103,19 +115,19 @@ func (t *SecureTrie) TryUpdate(key, value []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes any existing value for key from the storage.
|
// Delete removes any existing value for key from the map.
|
||||||
func (t *SecureTrie) Delete(key []byte) {
|
func (t *SecureTrie) Delete(key []byte) {
|
||||||
if err := t.TryDelete(key); err != nil && glog.V(logger.Error) {
|
if err := t.TryDelete(key); err != nil && glog.V(logger.Error) {
|
||||||
glog.Errorf("Unhandled storage error: %v", err)
|
glog.Errorf("Unhandled persistent map error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryDelete removes any existing value for key from the storage.
|
// TryDelete removes any existing value for key from the map.
|
||||||
// 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) TryDelete(key []byte) error {
|
func (t *SecureTrie) TryDelete(key []byte) error {
|
||||||
hk := t.hashKey(key)
|
hk := t.hashKey(key)
|
||||||
delete(t.getSecKeyCache(), string(hk))
|
delete(t.getSecKeyCache(), string(hk))
|
||||||
return t.storage.TryDelete(hk)
|
return t.data.TryDelete(hk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKey returns the sha3 preimage of a hashed key that was
|
// GetKey returns the sha3 preimage of a hashed key that was
|
||||||
|
|
@ -137,11 +149,11 @@ func (t *SecureTrie) Commit() (root common.Hash, err error) {
|
||||||
if err := t.CommitPreimages(); err != nil {
|
if err := t.CommitPreimages(); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
return t.storage.Commit()
|
return t.data.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SecureTrie) Iterator() *Iterator {
|
func (t *SecureTrie) Iterator() *Iterator {
|
||||||
return t.storage.Iterator()
|
return t.data.Iterator()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|
@ -149,12 +161,12 @@ func (t *SecureTrie) Iterator() *Iterator {
|
||||||
//
|
//
|
||||||
// Committing flushes nodes from memory. Subsequent Get calls will load nodes from
|
// Committing flushes nodes from memory. Subsequent Get calls will load nodes from
|
||||||
// the database. Calling code must ensure that the changes made to db are
|
// the database. Calling code must ensure that the changes made to db are
|
||||||
// written back to the attached database before using the storage.
|
// written back to the attached database before using the map.
|
||||||
func (t *SecureTrie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
|
func (t *SecureTrie) CommitTo(db DatabaseWriter) (root common.Hash, err error) {
|
||||||
if err := t.CommitPreimages(); err != nil {
|
if err := t.CommitPreimages(); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
return t.storage.CommitTo(db)
|
return t.data.CommitTo(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *SecureTrie) CommitPreimages() error {
|
func (t *SecureTrie) CommitPreimages() error {
|
||||||
|
|
@ -191,7 +203,7 @@ func (t *SecureTrie) hashKey(key []byte) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSecKeyCache returns the current secure key cache, creating a new one if
|
// getSecKeyCache returns the current secure key cache, creating a new one if
|
||||||
// ownership changed (i.e. the current secure storage is a copy of another owning
|
// ownership changed (i.e. the current secure map is a copy of another owning
|
||||||
// the actual cache).
|
// the actual cache).
|
||||||
func (t *SecureTrie) getSecKeyCache() map[string][]byte {
|
func (t *SecureTrie) getSecKeyCache() map[string][]byte {
|
||||||
if t != t.secKeyCacheOwner {
|
if t != t.secKeyCacheOwner {
|
||||||
|
|
|
||||||
12
trie/trie.go
12
trie/trie.go
|
|
@ -78,18 +78,6 @@ type DatabaseWriter interface {
|
||||||
// Use New to create a trie that sits on top of a database.
|
// Use New to create a trie that sits on top of a database.
|
||||||
//
|
//
|
||||||
// trie is not safe for concurrent use.
|
// trie is not safe for concurrent use.
|
||||||
type Storage interface {
|
|
||||||
Iterator() *Iterator
|
|
||||||
Get(key []byte) []byte
|
|
||||||
TryGet(key []byte) ([]byte, error)
|
|
||||||
Update(key, value []byte)
|
|
||||||
TryUpdate(key, value []byte) error
|
|
||||||
Delete(key []byte)
|
|
||||||
TryDelete(key []byte) error
|
|
||||||
Commit() (root common.Hash, err error)
|
|
||||||
CommitTo(db DatabaseWriter) (root common.Hash, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Trie struct {
|
type Trie struct {
|
||||||
root node
|
root node
|
||||||
db Database
|
db Database
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue