laconicd/state/trie.go

157 lines
4.8 KiB
Go
Raw Normal View History

2018-07-04 23:38:20 +00:00
package state
import (
"encoding/binary"
"github.com/cosmos/cosmos-sdk/store"
ethcommon "github.com/ethereum/go-ethereum/common"
ethdb "github.com/ethereum/go-ethereum/ethdb"
ethtrie "github.com/ethereum/go-ethereum/trie"
)
// Trie implements the Ethereum state.Trie interface.
type Trie struct {
// // db is an implementation of Ethereum's state.Database. It will provide a
// // means to persist accounts and contract storage to a persistent
// // multi-store.
// db *Database
// Store is an IAVL KV store that is part of a larger store except it used
// for a specific prefix.
store store.KVStore
// prefix is a static prefix used for persistence operations where the
// storage data is a contract state. This is to prevent key collisions
// since the IAVL tree is used for all contract state.
prefix []byte
// empty reflects if there exists any data in the tree
empty bool
// root is the encoding of an IAVL tree root (version)
root ethcommon.Hash
}
// prefixKey returns a composite key composed of a static prefix and a given
// key. This is used in situations where the storage data is contract state and
// the underlying structure to store said state is a single IAVL tree. To
// prevent collision, a static prefix is used.
func (t *Trie) prefixKey(key []byte) []byte {
compositeKey := make([]byte, len(t.prefix)+len(key))
copy(compositeKey, t.prefix)
copy(compositeKey[len(t.prefix):], key)
return compositeKey
}
// TryGet implements the Ethereum state.Trie interface. It returns the value
// for key stored in the trie. The value bytes must not be modified by the
// caller.
func (t *Trie) TryGet(key []byte) ([]byte, error) {
if t.prefix != nil {
key = t.prefixKey(key)
}
return t.store.Get(key), nil
}
// TryUpdate implements the Ethereum state.Trie interface. It associates a
// given key with a value in the trie. Subsequent calls to Get will return a
// value. It also marks the tree as not empty.
//
// CONTRACT: The order of insertions must be deterministic due to the nature of
// the IAVL tree. Since a CacheKVStore is used as the storage type, the keys
// will be sorted giving us a deterministic ordering.
func (t *Trie) TryUpdate(key, value []byte) error {
t.empty = false
if t.prefix != nil {
key = t.prefixKey(key)
}
t.store.Set(key, value)
return nil
}
// TryDelete implements the Ethereum state.Trie interface. It removes any
// existing value for a given key from the trie.
//
// CONTRACT: The order of deletions must be deterministic due to the nature of
// the IAVL tree. Since a CacheKVStore is used as the storage type, the keys
// will be sorted giving us a deterministic ordering.
func (t *Trie) TryDelete(key []byte) error {
if t.prefix != nil {
key = t.makePrefix(key)
}
t.store.Delete(key)
return nil
}
// Commit implements the Ethereum state.Trie interface. TODO: ...
//
// CONTRACT: The root is an encoded IAVL tree version.
func (t *Trie) Commit(_ ethtrie.LeafCallback) (ethcommon.Hash, error) {
if t.empty {
return ethcommon.Hash{}, nil
}
var root ethcommon.Hash
// We assume that the next committed version will be the od.stateStore.LastCommitID().Version+1
binary.BigEndian.PutUint64(commitHash[:8], uint64(t.od.stateStore.LastCommitID().Version+1))
if t.prefix == nil {
if t.od.accountsCache != nil {
t.od.accountsCache.Write()
t.od.accountsCache = nil
}
if t.od.storageCache != nil {
t.od.storageCache.Write()
t.od.storageCache = nil
}
// Enumerate cached nodes from trie.Database
for _, n := range t.od.trieDbDummy.Nodes() {
if err := t.od.trieDbDummy.Commit(n, false); err != nil {
return eth_common.Hash{}, err
}
}
}
t.root = root
return root, nil
}
// Hash implements the Ethereum state.Trie interface. It returns the state root
// of the Trie which is an encoding of the underlying IAVL tree.
//
// CONTRACT: The root is an encoded IAVL tree version.
func (t *Trie) Hash() ethcommon.Hash {
return t.root
}
// NodeIterator implements the Ethereum state.Trie interface. Such a node
// iterator is used primarily for the implementation of RPC API functions. It
// performs a no-op.
//
// TODO: Determine if we need to implement such functionality for an IAVL tree.
// This will ultimately be related to if we want to support web3.
func (t *Trie) NodeIterator(startKey []byte) ethtrie.NodeIterator {
return nil, fffsadf
}
// GetKey implements the Ethereum state.Trie interface. Since the IAVL does not
// need to store preimages of keys, a simply identity can be returned.
func (t *Trie) GetKey(key []byte) []byte {
return key
}
// Prove implements the Ethereum state.Trie interface. It writes a Merkle proof
// to a ethdb.Putter, proofDB, for a given key starting at fromLevel.
//
// TODO: Determine how to use the Cosmos SDK to provide such proof.
func (t *Trie) Prove(key []byte, fromLevel uint, proofDB ethdb.Putter) error {
return nil
}