diff --git a/state/database.go b/state/database.go deleted file mode 100644 index a8a5da68..00000000 --- a/state/database.go +++ /dev/null @@ -1,208 +0,0 @@ -package state - -import ( - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/cosmos/ethermint/types" - - ethcmn "github.com/ethereum/go-ethereum/common" - ethstate "github.com/ethereum/go-ethereum/core/state" - ethtrie "github.com/ethereum/go-ethereum/trie" - - lru "github.com/hashicorp/golang-lru" - - dbm "github.com/tendermint/tendermint/libs/db" -) - -// TODO: This functionality and implementation may be deprecated - -var ( - // CodeKey is the key used for storing Ethereum contract code in the Cosmos - // SDK multi-store. - CodeKey = sdk.NewKVStoreKey("code") -) - -const ( - // DefaultStoreCacheSize defines the default number of key/value pairs for - // the state stored in memory. - DefaultStoreCacheSize = 1024 * 1024 - - // codeSizeCacheSize is the number of codehash to size associations to - // keep in cached memory. This is to address any DoS attempts on - // EXTCODESIZE calls. - codeSizeCacheSize = 100000 -) - -// Database implements the Ethereum state.Database interface. -type Database struct { - // stateStore will be used for the history of accounts (balance, nonce, - // storage root hash, code hash) and for the history of contract data - // (effects of SSTORE instruction). - stateStore store.CommitMultiStore - accountsCache store.CacheKVStore - storageCache store.CacheKVStore - - // codeDB contains mappings of codeHash => code - // - // NOTE: This database will store the information in memory until is it - // committed, using the function Commit. This function is called outside of - // the ApplyTransaction function, therefore in Ethermint we need to make - // sure this commit is invoked somewhere after each block or whatever the - // appropriate time for it. - codeDB dbm.DB - ethTrieDB *ethtrie.Database - - // codeSizeCache contains an LRU cache of a specified capacity to cache - // EXTCODESIZE calls. - codeSizeCache *lru.Cache - - storeCache *lru.Cache - - Tracing bool -} - -// NewDatabase returns a reference to an initialized Database type which -// implements Ethereum's state.Database interface. An error is returned if the -// latest state failed to load. The underlying storage structure is defined by -// the Cosmos SDK IAVL tree. -func NewDatabase(stateStore store.CommitMultiStore, codeDB dbm.DB, storeCacheSize int) (*Database, error) { - db := &Database{stateStore: stateStore} - - // Set the persistent Cosmos SDK Database and initialize an Ethereum - // trie.Database using an EthereumDB as the underlying implementation of - // the ethdb.Database interface. It will be used to facilitate persistence - // of contract byte code when committing state. - db.codeDB = codeDB - db.ethTrieDB = ethtrie.NewDatabase(&EthereumDB{CodeDB: codeDB}) - - var err error - - if db.codeSizeCache, err = lru.New(codeSizeCacheSize); err != nil { - return nil, err - } - - if db.storeCache, err = lru.New(storeCacheSize); err != nil { - return nil, err - } - - return db, nil -} - -// LatestVersion returns the latest version of the underlying mult-store. -func (db *Database) LatestVersion() int64 { - return db.stateStore.LastCommitID().Version -} - -// OpenTrie implements Ethereum's state.Database interface. It returns a Trie -// type which implements the Ethereum state.Trie interface. It us used for -// storage of accounts. An error is returned if state cannot load for a -// given version. The account cache is reset if the state is successfully -// loaded and the version is not the latest. -// -// CONTRACT: The root parameter is not interpreted as a state root hash, but as -// an encoding of an Cosmos SDK IAVL tree version. -func (db *Database) OpenTrie(root ethcmn.Hash) (ethstate.Trie, error) { - if !isRootEmpty(root) { - version := versionFromRootHash(root) - - if db.stateStore.LastCommitID().Version != version { - if err := db.stateStore.LoadVersion(version); err != nil { - return nil, err - } - - db.accountsCache = nil - } - } - - if db.accountsCache == nil { - db.accountsCache = store.NewCacheKVStore(db.stateStore.GetCommitKVStore(types.StoreKeyAccount)) - db.storageCache = store.NewCacheKVStore(db.stateStore.GetCommitKVStore(types.StoreKeyStorage)) - } - - return &Trie{ - store: db.accountsCache, - accountsCache: db.accountsCache, - storageCache: db.storageCache, - storeCache: db.storeCache, - ethTrieDB: db.ethTrieDB, - empty: isRootEmpty(root), - root: rootHashFromVersion(db.stateStore.LastCommitID().Version), - }, nil -} - -// OpenStorageTrie implements Ethereum's state.Database interface. It returns -// a Trie type which implements the Ethereum state.Trie interface. It is used -// for storage of contract storage (state). Also, this trie is never committed -// separately as all the data is in a single multi-store and is committed when -// the account IAVL tree is committed. -// -// NOTE: It is assumed that the account state has already been loaded via -// OpenTrie. -// -// CONTRACT: The root parameter is not interpreted as a state root hash, but as -// an encoding of an IAVL tree version. -func (db *Database) OpenStorageTrie(addrHash, root ethcmn.Hash) (ethstate.Trie, error) { - // a contract storage trie does not need an accountCache, storageCache or - // an Ethereum trie because it will not be used upon commitment. - return &Trie{ - store: db.storageCache, - storeCache: db.storeCache, - prefix: addrHash.Bytes(), - empty: isRootEmpty(root), - root: rootHashFromVersion(db.stateStore.LastCommitID().Version), - }, nil -} - -// CopyTrie implements Ethereum's state.Database interface. For now, it -// performs a no-op as the underlying Cosmos SDK IAVL tree does not support -// such an operation. -// -// TODO: Does the IAVL tree need to support this operation? If so, why and -// how? -func (db *Database) CopyTrie(ethstate.Trie) ethstate.Trie { - return nil -} - -// ContractCode implements Ethereum's state.Database interface. It will return -// the contract byte code for a given code hash. It will not return an error. -func (db *Database) ContractCode(addrHash, codeHash ethcmn.Hash) ([]byte, error) { - code := db.codeDB.Get(codeHash[:]) - - if codeLen := len(code); codeLen != 0 { - db.codeSizeCache.Add(codeHash, codeLen) - } - - return code, nil -} - -// ContractCodeSize implements Ethereum's state.Database interface. It will -// return the contract byte code size for a given code hash. It will not return -// an error. -func (db *Database) ContractCodeSize(addrHash, codeHash ethcmn.Hash) (int, error) { - if cached, ok := db.codeSizeCache.Get(codeHash); ok { - return cached.(int), nil - } - - code, err := db.ContractCode(addrHash, codeHash) - return len(code), err -} - -// Commit commits the underlying Cosmos SDK multi-store returning the commit -// ID. -func (db *Database) Commit() sdk.CommitID { - return db.stateStore.Commit() -} - -// TrieDB implements Ethereum's state.Database interface. It returns Ethereum's -// trie.Database low level trie database used for contract state storage. In -// the context of Ethermint, it'll be used to solely store mappings of -// codeHash => code. -func (db *Database) TrieDB() *ethtrie.Database { - return db.ethTrieDB -} - -// isRootEmpty returns true if a given root hash is empty or false otherwise. -func isRootEmpty(root ethcmn.Hash) bool { - return root == ethcmn.Hash{} -} diff --git a/state/database_test.go b/state/database_test.go deleted file mode 100644 index b300d33d..00000000 --- a/state/database_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package state - -import ( - "fmt" - "testing" - - ethcmn "github.com/ethereum/go-ethereum/common" - ethstate "github.com/ethereum/go-ethereum/core/state" - "github.com/stretchr/testify/require" -) - -func TestDatabaseInterface(t *testing.T) { - require.Implements(t, (*ethstate.Database)(nil), new(Database)) -} - -func TestDatabaseLatestVersion(t *testing.T) { - var version int64 - - testDB := newTestDatabase() - - version = testDB.LatestVersion() - require.Equal(t, int64(0), version) - - testDB.Commit() - version = testDB.LatestVersion() - require.Equal(t, int64(1), version) -} - -func TestDatabaseCopyTrie(t *testing.T) { - // TODO: Implement once CopyTrie is implemented - t.SkipNow() -} - -func TestDatabaseContractCode(t *testing.T) { - testDB := newTestDatabase() - - testCases := []struct { - db *Database - data *code - codeHash ethcmn.Hash - expectedCode []byte - }{ - { - db: testDB, - codeHash: ethcmn.BytesToHash([]byte("code hash")), - expectedCode: nil, - }, - { - db: testDB, - data: &code{ethcmn.BytesToHash([]byte("code hash")), []byte("some awesome code")}, - codeHash: ethcmn.BytesToHash([]byte("code hash")), - expectedCode: []byte("some awesome code"), - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.db.codeDB.Set(tc.data.hash[:], tc.data.blob) - } - - code, err := tc.db.ContractCode(ethcmn.Hash{}, tc.codeHash) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Equal(t, tc.expectedCode, code, fmt.Sprintf("unexpected result: test case #%d", i)) - } -} - -func TestDatabaseContractCodeSize(t *testing.T) { - testDB := newTestDatabase() - - testCases := []struct { - db *Database - data *code - codeHash ethcmn.Hash - expectedCodeLen int - }{ - { - db: testDB, - codeHash: ethcmn.BytesToHash([]byte("code hash")), - expectedCodeLen: 0, - }, - { - db: testDB, - data: &code{ethcmn.BytesToHash([]byte("code hash")), []byte("some awesome code")}, - codeHash: ethcmn.BytesToHash([]byte("code hash")), - expectedCodeLen: 17, - }, - { - db: testDB, - codeHash: ethcmn.BytesToHash([]byte("code hash")), - expectedCodeLen: 17, - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.db.codeDB.Set(tc.data.hash[:], tc.data.blob) - } - - codeLen, err := tc.db.ContractCodeSize(ethcmn.Hash{}, tc.codeHash) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Equal(t, tc.expectedCodeLen, codeLen, fmt.Sprintf("unexpected result: test case #%d", i)) - } -} - -func TestDatabaseTrieDB(t *testing.T) { - testDB := newTestDatabase() - - db := testDB.TrieDB() - require.Equal(t, testDB.ethTrieDB, db) -} diff --git a/state/ethdb.go b/state/ethdb.go deleted file mode 100644 index f05e3fa9..00000000 --- a/state/ethdb.go +++ /dev/null @@ -1,66 +0,0 @@ -package state - -import ( - ethdb "github.com/ethereum/go-ethereum/ethdb" - - dbm "github.com/tendermint/tendermint/libs/db" -) - -// EthereumDB implements Ethereum's ethdb.Database and ethdb.Batch interfaces. -// It will be used to facilitate persistence of codeHash => code mappings. -type EthereumDB struct { - CodeDB dbm.DB -} - -// Put implements Ethereum's ethdb.Putter interface. It wraps the database -// write operation supported by both batches and regular databases. -func (edb *EthereumDB) Put(key []byte, value []byte) error { - edb.CodeDB.Set(key, value) - return nil -} - -// Get implements Ethereum's ethdb.Database interface. It returns a value for a -// given key. -func (edb *EthereumDB) Get(key []byte) ([]byte, error) { - return edb.CodeDB.Get(key), nil -} - -// Has implements Ethereum's ethdb.Database interface. It returns a boolean -// determining if the underlying database has the given key or not. -func (edb *EthereumDB) Has(key []byte) (bool, error) { - return edb.CodeDB.Has(key), nil -} - -// Delete implements Ethereum's ethdb.Database interface. It removes a given -// key from the underlying database. -func (edb *EthereumDB) Delete(key []byte) error { - edb.CodeDB.Delete(key) - return nil -} - -// Close implements Ethereum's ethdb.Database interface. It closes the -// underlying database. -func (edb *EthereumDB) Close() { - edb.CodeDB.Close() -} - -// NewBatch implements Ethereum's ethdb.Database interface. It returns a new -// Batch object used for batch database operations. -func (edb *EthereumDB) NewBatch() ethdb.Batch { - return edb -} - -// ValueSize implements Ethereum's ethdb.Database interface. It performs a -// no-op. -func (edb *EthereumDB) ValueSize() int { - return 0 -} - -// Write implements Ethereum's ethdb.Database interface. It performs a no-op. -func (edb *EthereumDB) Write() error { - return nil -} - -// Reset implements Ethereum's ethdb.Database interface. It performs a no-op. -func (edb *EthereumDB) Reset() { -} diff --git a/state/ethdb_test.go b/state/ethdb_test.go deleted file mode 100644 index d27fbc2d..00000000 --- a/state/ethdb_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package state - -// NOTE: A bulk of these unit tests will change and evolve as the context and -// implementation of ChainConext evolves. - -import ( - "fmt" - "testing" - - ethdb "github.com/ethereum/go-ethereum/ethdb" - "github.com/stretchr/testify/require" - dbm "github.com/tendermint/tendermint/libs/db" -) - -func newEthereumDB() *EthereumDB { - memDB := dbm.NewMemDB() - return &EthereumDB{CodeDB: memDB} -} - -func TestEthereumDBInterface(t *testing.T) { - require.Implements(t, (*ethdb.Database)(nil), new(EthereumDB)) - require.Implements(t, (*ethdb.Batch)(nil), new(EthereumDB)) -} - -func TestEthereumDBGet(t *testing.T) { - testEDB := newEthereumDB() - - testCases := []struct { - edb *EthereumDB - data *kvPair - key []byte - expectedValue []byte - }{ - { - edb: testEDB, - key: []byte("foo"), - expectedValue: nil, - }, - { - edb: testEDB, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - expectedValue: []byte("bar"), - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.edb.Put(tc.data.key, tc.data.value) - } - - value, err := tc.edb.Get(tc.key) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Equal(t, tc.expectedValue, value, fmt.Sprintf("unexpected result: test case #%d", i)) - } -} - -func TestEthereumDBHas(t *testing.T) { - testEDB := newEthereumDB() - - testCases := []struct { - edb *EthereumDB - data *kvPair - key []byte - expectedValue bool - }{ - { - edb: testEDB, - key: []byte("foo"), - expectedValue: false, - }, - { - edb: testEDB, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - expectedValue: true, - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.edb.Put(tc.data.key, tc.data.value) - } - - ok, err := tc.edb.Has(tc.key) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Equal(t, tc.expectedValue, ok, fmt.Sprintf("unexpected result: test case #%d", i)) - } -} - -func TestEthereumDBDelete(t *testing.T) { - testEDB := newEthereumDB() - - testCases := []struct { - edb *EthereumDB - data *kvPair - key []byte - }{ - { - edb: testEDB, - key: []byte("foo"), - }, - { - edb: testEDB, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.edb.Put(tc.data.key, tc.data.value) - } - - err := tc.edb.Delete(tc.key) - ok, _ := tc.edb.Has(tc.key) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.False(t, ok, fmt.Sprintf("unexpected existence of key: test case #%d", i)) - } -} - -func TestEthereumDBNewBatch(t *testing.T) { - edb := newEthereumDB() - - batch := edb.NewBatch() - require.Equal(t, edb, batch) -} - -func TestEthereumDBValueSize(t *testing.T) { - edb := newEthereumDB() - - size := edb.ValueSize() - require.Equal(t, 0, size) -} - -func TestEthereumDBWrite(t *testing.T) { - edb := newEthereumDB() - - err := edb.Write() - require.Nil(t, err) -} diff --git a/state/test_utils.go b/state/test_utils.go deleted file mode 100644 index 105e7931..00000000 --- a/state/test_utils.go +++ /dev/null @@ -1,47 +0,0 @@ -package state - -import ( - "fmt" - "math/rand" - "time" - - "github.com/cosmos/cosmos-sdk/store" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ethermint/types" - ethcmn "github.com/ethereum/go-ethereum/common" - - dbm "github.com/tendermint/tendermint/libs/db" -) - -type ( - kvPair struct { - key, value []byte - } - - code struct { - hash ethcmn.Hash - blob []byte - } -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -func newTestDatabase() *Database { - memDB := dbm.NewMemDB() - - cms := store.NewCommitMultiStore(memDB) - cms.SetPruning(sdk.PruneNothing) - cms.MountStoreWithDB(types.StoreKeyAccount, sdk.StoreTypeIAVL, nil) - cms.MountStoreWithDB(types.StoreKeyStorage, sdk.StoreTypeIAVL, nil) - - testDB, err := NewDatabase(cms, memDB, 100) - if err != nil { - panic(fmt.Sprintf("failed to create database: %v", err)) - } - - testDB.stateStore.LoadLatestVersion() - - return testDB -} diff --git a/state/trie.go b/state/trie.go deleted file mode 100644 index 6c078c4b..00000000 --- a/state/trie.go +++ /dev/null @@ -1,210 +0,0 @@ -package state - -import ( - "encoding/binary" - - "github.com/cosmos/cosmos-sdk/store" - - ethcmn "github.com/ethereum/go-ethereum/common" - ethdb "github.com/ethereum/go-ethereum/ethdb" - ethtrie "github.com/ethereum/go-ethereum/trie" - - lru "github.com/hashicorp/golang-lru" -) - -// TODO: This functionality and implementation may be deprecated - -const ( - versionLen = 8 -) - -// Trie implements the Ethereum state.Trie interface. -type Trie struct { - // accountsCache contains all the accounts in memory to persit when - // committing the trie. A CacheKVStore is used to provide deterministic - // ordering. - accountsCache store.CacheKVStore - // storageCache contains all the contract storage in memory to persit when - // committing the trie. A CacheKVStore is used to provide deterministic - // ordering. - storageCache store.CacheKVStore - - storeCache *lru.Cache - - // Store is an IAVL KV store that is part of a larger store except it used - // for a specific prefix. It will either be an accountsCache or a - // storageCache. - 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 ethcmn.Hash - - ethTrieDB *ethtrie.Database -} - -// 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.IsStorageTrie() { - key = t.prefixKey(key) - } - keyStr := string(key) - if cached, ok := t.storeCache.Get(keyStr); ok { - return cached.([]byte), nil - } - value := t.store.Get(key) - t.storeCache.Add(keyStr, value) - return value, 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.IsStorageTrie() { - key = t.prefixKey(key) - } - - t.store.Set(key, value) - t.storeCache.Add(string(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.IsStorageTrie() { - key = t.prefixKey(key) - } - - t.store.Delete(key) - t.storeCache.Remove(string(key)) - return nil -} - -// Commit implements the Ethereum state.Trie interface. It persists transient -// state. State is held by a merkelized multi-store IAVL tree. Commitment will -// only occur through an account trie, in other words, when the prefix of the -// trie is nil. In such a case, if either the accountCache or the storageCache -// are not nil, they are persisted. In addition, all the mappings of -// codeHash => code are also persisted. All these operations are performed in a -// deterministic order. Transient state is built up in a CacheKVStore. Finally, -// a root hash is returned or an error if any operation fails. -// -// CONTRACT: The root is an encoded IAVL tree version and each new commitment -// increments the version by one. -func (t *Trie) Commit(_ ethtrie.LeafCallback) (ethcmn.Hash, error) { - if t.empty { - return ethcmn.Hash{}, nil - } - - newRoot := rootHashFromVersion(versionFromRootHash(t.root) + 1) - - if !t.IsStorageTrie() { - if t.accountsCache != nil { - t.accountsCache.Write() - t.accountsCache = nil - } - - if t.storageCache != nil { - t.storageCache.Write() - t.storageCache = nil - } - - // persist the mappings of codeHash => code - for _, n := range t.ethTrieDB.Nodes() { - if err := t.ethTrieDB.Commit(n, false); err != nil { - return ethcmn.Hash{}, err - } - } - } - - t.root = newRoot - return newRoot, 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() ethcmn.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 -} - -// GetKey implements the Ethereum state.Trie interface. Since the IAVL does not -// need to store preimages of keys, a simple 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 integrate this with Cosmos SDK to provide such -// proofs. -func (t *Trie) Prove(key []byte, fromLevel uint, proofDB ethdb.Putter) error { - return nil -} - -// IsStorageTrie returns a boolean reflecting if the Trie is created for -// contract storage. -func (t *Trie) IsStorageTrie() bool { - return t.prefix != nil -} - -// versionFromRootHash returns a Cosmos SDK IAVL version from an Ethereum state -// root hash. -// -// CONTRACT: The encoded version is the eight MSB bytes of the root hash. -func versionFromRootHash(root ethcmn.Hash) int64 { - return int64(binary.BigEndian.Uint64(root[:versionLen])) -} - -// rootHashFromVersion returns a state root hash from a Cosmos SDK IAVL -// version. -func rootHashFromVersion(version int64) (root ethcmn.Hash) { - binary.BigEndian.PutUint64(root[:versionLen], uint64(version)) - return -} diff --git a/state/trie_test.go b/state/trie_test.go deleted file mode 100644 index 51a30787..00000000 --- a/state/trie_test.go +++ /dev/null @@ -1,256 +0,0 @@ -package state - -import ( - "fmt" - "math/rand" - "testing" - - ethcmn "github.com/ethereum/go-ethereum/common" - ethstate "github.com/ethereum/go-ethereum/core/state" - "github.com/stretchr/testify/require" -) - -func newTestTrie() *Trie { - testDB := newTestDatabase() - testTrie, _ := testDB.OpenTrie(rootHashFromVersion(0)) - - return testTrie.(*Trie) -} - -func newTestPrefixTrie() *Trie { - testDB := newTestDatabase() - - prefix := make([]byte, ethcmn.HashLength) - rand.Read(prefix) - - testDB.OpenTrie(rootHashFromVersion(0)) - testTrie, _ := testDB.OpenStorageTrie(ethcmn.BytesToHash(prefix), rootHashFromVersion(0)) - - return testTrie.(*Trie) -} - -func TestTrieInterface(t *testing.T) { - require.Implements(t, (*ethstate.Trie)(nil), new(Trie)) -} - -func TestTrieTryGet(t *testing.T) { - testTrie := newTestTrie() - testPrefixTrie := newTestPrefixTrie() - - testCases := []struct { - trie *Trie - data *kvPair - key []byte - expectedValue []byte - }{ - { - trie: testTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - expectedValue: []byte("bar"), - }, - { - trie: testTrie, - key: []byte("baz"), - expectedValue: nil, - }, - { - trie: testPrefixTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - expectedValue: []byte("bar"), - }, - { - trie: testPrefixTrie, - key: []byte("baz"), - expectedValue: nil, - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.trie.TryUpdate(tc.data.key, tc.data.value) - } - - value, err := tc.trie.TryGet(tc.key) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Equal(t, tc.expectedValue, value, fmt.Sprintf("unexpected value: test case #%d", i)) - } -} - -func TestTrieTryUpdate(t *testing.T) { - testTrie := newTestTrie() - testPrefixTrie := newTestPrefixTrie() - kv := &kvPair{[]byte("foo"), []byte("bar")} - - var err error - - err = testTrie.TryUpdate(kv.key, kv.value) - require.Nil(t, err) - - err = testPrefixTrie.TryUpdate(kv.key, kv.value) - require.Nil(t, err) -} - -func TestTrieTryDelete(t *testing.T) { - testTrie := newTestTrie() - testPrefixTrie := newTestPrefixTrie() - - testCases := []struct { - trie *Trie - data *kvPair - key []byte - }{ - { - trie: testTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - }, - { - trie: testTrie, - key: []byte("baz"), - }, - { - trie: testPrefixTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - key: []byte("foo"), - }, - { - trie: testPrefixTrie, - key: []byte("baz"), - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.trie.TryUpdate(tc.data.key, tc.data.value) - } - - err := tc.trie.TryDelete(tc.key) - value, _ := tc.trie.TryGet(tc.key) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Nil(t, value, fmt.Sprintf("unexpected value: test case #%d", i)) - } -} - -func TestTrieCommit(t *testing.T) { - testTrie := newTestTrie() - testPrefixTrie := newTestPrefixTrie() - - testCases := []struct { - trie *Trie - data *kvPair - code *code - expectedRoot ethcmn.Hash - }{ - { - trie: &Trie{empty: true}, - expectedRoot: ethcmn.Hash{}, - }, - { - trie: testTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - expectedRoot: rootHashFromVersion(1), - }, - { - trie: testTrie, - data: &kvPair{[]byte("baz"), []byte("cat")}, - code: &code{ethcmn.BytesToHash([]byte("code hash")), []byte("code hash")}, - expectedRoot: rootHashFromVersion(2), - }, - { - trie: testTrie, - expectedRoot: rootHashFromVersion(3), - }, - { - trie: testPrefixTrie, - expectedRoot: rootHashFromVersion(0), - }, - { - trie: testPrefixTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - expectedRoot: rootHashFromVersion(1), - }, - { - trie: testPrefixTrie, - expectedRoot: rootHashFromVersion(2), - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.trie.TryUpdate(tc.data.key, tc.data.value) - } - if tc.code != nil { - tc.trie.ethTrieDB.InsertBlob(tc.code.hash, tc.code.blob) - } - - root, err := tc.trie.Commit(nil) - require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i)) - require.Equal(t, tc.expectedRoot, root, fmt.Sprintf("unexpected root: test case #%d", i)) - } -} - -func TestTrieHash(t *testing.T) { - testTrie := newTestTrie() - testPrefixTrie := newTestPrefixTrie() - - testCases := []struct { - trie *Trie - data *kvPair - expectedRoot ethcmn.Hash - }{ - { - trie: testTrie, - expectedRoot: rootHashFromVersion(0), - }, - { - trie: testTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - expectedRoot: rootHashFromVersion(1), - }, - { - trie: testPrefixTrie, - expectedRoot: rootHashFromVersion(0), - }, - { - trie: testPrefixTrie, - data: &kvPair{[]byte("foo"), []byte("bar")}, - expectedRoot: rootHashFromVersion(1), - }, - } - - for i, tc := range testCases { - if tc.data != nil { - tc.trie.TryUpdate(tc.data.key, tc.data.value) - tc.trie.Commit(nil) - } - - root := tc.trie.Hash() - require.Equal(t, tc.expectedRoot, root, fmt.Sprintf("unexpected root: test case #%d", i)) - } -} - -func TestTrieNodeIterator(t *testing.T) { - // TODO: Implement once NodeIterator is implemented - t.SkipNow() -} - -func TestTrieGetKey(t *testing.T) { - testTrie := newTestTrie() - testPrefixTrie := newTestPrefixTrie() - - var key []byte - expectedKey := []byte("foo") - - key = testTrie.GetKey(expectedKey) - require.Equal(t, expectedKey, key) - - key = testPrefixTrie.GetKey(expectedKey) - require.Equal(t, expectedKey, key) -} - -func TestTrieProve(t *testing.T) { - // TODO: Implement once Prove is implemented - t.SkipNow() -} diff --git a/x/.keep b/x/.keep deleted file mode 100644 index e69de29b..00000000