2018-06-13 09:56:01 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-06-15 13:26:06 +00:00
|
|
|
"bytes"
|
2018-06-13 09:56:01 +00:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
eth_common "github.com/ethereum/go-ethereum/common"
|
2018-06-18 21:10:29 +00:00
|
|
|
eth_core "github.com/ethereum/go-ethereum/core"
|
2018-06-13 09:56:01 +00:00
|
|
|
eth_state "github.com/ethereum/go-ethereum/core/state"
|
|
|
|
eth_ethdb "github.com/ethereum/go-ethereum/ethdb"
|
|
|
|
eth_trie "github.com/ethereum/go-ethereum/trie"
|
|
|
|
|
|
|
|
dbm "github.com/tendermint/tmlibs/db"
|
2018-06-15 13:26:06 +00:00
|
|
|
"github.com/tendermint/go-amino"
|
2018-06-13 14:29:22 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/store"
|
2018-06-15 10:05:12 +00:00
|
|
|
"github.com/cosmos/cosmos-sdk/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// Key for the sub-store with Ethereum accounts
|
2018-06-18 15:33:07 +00:00
|
|
|
AccountsKey = types.NewKVStoreKey("account")
|
2018-06-15 10:05:12 +00:00
|
|
|
// Key for the sub-store with storage data of Ethereum contracts
|
|
|
|
StorageKey = types.NewKVStoreKey("storage")
|
2018-06-18 15:33:07 +00:00
|
|
|
// Key for the sub-store with the code for contracts
|
|
|
|
CodeKey = types.NewKVStoreKey("code")
|
2018-06-13 09:56:01 +00:00
|
|
|
)
|
|
|
|
|
2018-06-15 13:26:06 +00:00
|
|
|
// This is what stored in the lookupDb
|
|
|
|
type LookupValue struct {
|
|
|
|
VersionId int64
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:56:01 +00:00
|
|
|
// Implementation of eth_state.Database
|
|
|
|
type OurDatabase struct {
|
2018-06-15 10:05:12 +00:00
|
|
|
stateStore store.CommitMultiStore // For the history of accounts <balance, nonce, storage root hash, code hash>
|
|
|
|
// Also, for the history of contract data (effects of SSTORE instruction)
|
2018-06-15 21:32:35 +00:00
|
|
|
lookupDb dbm.DB // Maping [trie_root_hash] => <version_id>.
|
|
|
|
// This mapping exists so that we can implement OpenTrie and OpenStorageTrie functions
|
|
|
|
// of the state.Database interface
|
2018-06-18 15:33:07 +00:00
|
|
|
codeDb dbm.DB // Mapping [codeHash] -> <code>
|
2018-06-15 21:32:35 +00:00
|
|
|
addrPreimageDb dbm.DB // Mapping [contract_address_hash] -> <contract_address>
|
2018-06-15 13:26:06 +00:00
|
|
|
cdc *amino.Codec // Amino codec to encode the values forthe lookupDb
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
2018-06-18 15:33:07 +00:00
|
|
|
func OurNewDatabase(stateDb, lookupDb, addrPreimageDb, codeDb dbm.DB) (*OurDatabase, error) {
|
2018-06-15 10:05:12 +00:00
|
|
|
od := &OurDatabase{}
|
|
|
|
od.stateStore = store.NewCommitMultiStore(stateDb)
|
|
|
|
od.stateStore.MountStoreWithDB(AccountsKey, types.StoreTypeIAVL, nil)
|
|
|
|
od.stateStore.MountStoreWithDB(StorageKey, types.StoreTypeIAVL, nil)
|
2018-06-18 15:33:07 +00:00
|
|
|
if err := od.stateStore.LoadLatestVersion(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-06-15 10:05:12 +00:00
|
|
|
od.lookupDb = lookupDb
|
2018-06-18 15:33:07 +00:00
|
|
|
od.addrPreimageDb = addrPreimageDb
|
|
|
|
od.codeDb = codeDb
|
2018-06-15 13:26:06 +00:00
|
|
|
od.cdc = amino.NewCodec()
|
2018-06-18 15:33:07 +00:00
|
|
|
return od, nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (od *OurDatabase) OpenTrie(root eth_common.Hash) (eth_state.Trie, error) {
|
2018-06-15 13:26:06 +00:00
|
|
|
// Look up version id to use
|
2018-06-18 15:33:07 +00:00
|
|
|
if root != (eth_common.Hash{}) {
|
|
|
|
val := od.lookupDb.Get(root[:])
|
|
|
|
if val == nil {
|
|
|
|
return nil, fmt.Errorf("Could not find version with root hash %x", root[:])
|
|
|
|
}
|
|
|
|
var versionId int64
|
|
|
|
_, err := od.cdc.UnmarshalBinaryReader(bytes.NewBuffer(val), &versionId, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
od.stateStore.LoadVersion(versionId)
|
2018-06-15 13:26:06 +00:00
|
|
|
}
|
|
|
|
st := od.stateStore.GetCommitKVStore(AccountsKey)
|
2018-06-15 21:32:35 +00:00
|
|
|
return &OurTrie{od: od, st: st, prefix: nil}, nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (od *OurDatabase) OpenStorageTrie(addrHash, root eth_common.Hash) (eth_state.Trie, error) {
|
2018-06-18 15:33:07 +00:00
|
|
|
if root != (eth_common.Hash{}) {
|
|
|
|
val := od.lookupDb.Get(root[:])
|
|
|
|
if val == nil {
|
|
|
|
return nil, fmt.Errorf("Could not find version with root hash %x", root[:])
|
|
|
|
}
|
|
|
|
var versionId int64
|
|
|
|
_, err := od.cdc.UnmarshalBinaryReader(bytes.NewBuffer(val), &versionId, 0)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
od.stateStore.LoadVersion(versionId) // This might not be required,
|
|
|
|
// we just need to check that accounts and storage are consistent
|
2018-06-15 13:26:06 +00:00
|
|
|
}
|
|
|
|
st := od.stateStore.GetCommitKVStore(StorageKey)
|
2018-06-15 21:32:35 +00:00
|
|
|
return &OurTrie{od:od, st: st, prefix: addrHash[:]}, nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (od *OurDatabase) CopyTrie(eth_state.Trie) eth_state.Trie {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (od *OurDatabase) ContractCode(addrHash, codeHash eth_common.Hash) ([]byte, error) {
|
2018-06-18 15:33:07 +00:00
|
|
|
code := od.codeDb.Get(codeHash[:])
|
|
|
|
return code, nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (od *OurDatabase) ContractCodeSize(addrHash, codeHash eth_common.Hash) (int, error) {
|
2018-06-18 15:33:07 +00:00
|
|
|
code := od.codeDb.Get(codeHash[:])
|
|
|
|
return len(code), nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (od *OurDatabase) TrieDB() *eth_trie.Database {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implementation of eth_state.Trie
|
|
|
|
type OurTrie struct {
|
2018-06-15 21:32:35 +00:00
|
|
|
od *OurDatabase
|
2018-06-15 10:05:12 +00:00
|
|
|
// This is essentially part of the KVStore for a specific prefix
|
2018-06-15 20:51:55 +00:00
|
|
|
st store.CommitKVStore
|
2018-06-15 10:05:12 +00:00
|
|
|
prefix []byte
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
2018-06-15 20:51:55 +00:00
|
|
|
func (ot *OurTrie) makePrefix(key []byte) []byte {
|
|
|
|
kk := make([]byte, len(ot.prefix)+len(key))
|
|
|
|
copy(kk, ot.prefix)
|
|
|
|
copy(kk[len(ot.prefix):], key)
|
|
|
|
return kk
|
|
|
|
}
|
|
|
|
|
2018-06-13 09:56:01 +00:00
|
|
|
func (ot *OurTrie) TryGet(key []byte) ([]byte, error) {
|
2018-06-15 20:51:55 +00:00
|
|
|
if ot.prefix == nil {
|
|
|
|
return ot.st.Get(key), nil
|
|
|
|
}
|
|
|
|
return ot.st.Get(ot.makePrefix(key)), nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) TryUpdate(key, value []byte) error {
|
2018-06-15 20:51:55 +00:00
|
|
|
if ot.prefix == nil {
|
|
|
|
ot.st.Set(key, value)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ot.st.Set(ot.makePrefix(key), value)
|
2018-06-13 09:56:01 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) TryDelete(key []byte) error {
|
2018-06-15 20:51:55 +00:00
|
|
|
if ot.prefix == nil {
|
|
|
|
ot.st.Delete(key)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
ot.st.Delete(ot.makePrefix(key))
|
2018-06-13 09:56:01 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) Commit(onleaf eth_trie.LeafCallback) (eth_common.Hash, error) {
|
2018-06-15 21:32:35 +00:00
|
|
|
commitId := ot.st.Commit()
|
|
|
|
var hash eth_common.Hash
|
|
|
|
copy(hash[:], commitId.Hash)
|
|
|
|
b, err := ot.od.cdc.MarshalBinary(commitId.Version)
|
|
|
|
if err != nil {
|
|
|
|
return hash, err
|
|
|
|
}
|
|
|
|
ot.od.lookupDb.Set(hash[:], b)
|
|
|
|
return hash, nil
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) Hash() eth_common.Hash {
|
|
|
|
return eth_common.Hash{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) NodeIterator(startKey []byte) eth_trie.NodeIterator {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) GetKey([]byte) []byte {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ot *OurTrie) Prove(key []byte, fromLevel uint, proofDb eth_ethdb.Putter) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
fmt.Printf("Instantiating state.Database\n")
|
2018-06-15 10:05:12 +00:00
|
|
|
stateDb := dbm.NewDB("state" /* name */, dbm.MemDBBackend, "" /* dir */)
|
|
|
|
lookupDb := dbm.NewDB("lookup" /* name */, dbm.MemDBBackend, "" /* dir */)
|
2018-06-18 15:33:07 +00:00
|
|
|
addrPreimageDb := dbm.NewDB("addrPreimage" /* name */, dbm.MemDBBackend, "" /* dir */)
|
|
|
|
codeDb := dbm.NewDB("code" /* name */, dbm.MemDBBackend, "" /* dir */)
|
2018-06-18 21:10:29 +00:00
|
|
|
d, err := OurNewDatabase(stateDb, lookupDb, addrPreimageDb, codeDb)
|
2018-06-18 15:33:07 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Instantiating state.StateDB\n")
|
|
|
|
// With empty root hash, i.e. empty state
|
|
|
|
statedb, err := eth_state.New(eth_common.Hash{}, d)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2018-06-18 21:10:29 +00:00
|
|
|
g := eth_core.DefaultGenesisBlock()
|
|
|
|
for addr, account := range g.Alloc {
|
|
|
|
statedb.AddBalance(addr, account.Balance)
|
|
|
|
statedb.SetCode(addr, account.Code)
|
|
|
|
statedb.SetNonce(addr, account.Nonce)
|
|
|
|
for key, value := range account.Storage {
|
|
|
|
statedb.SetState(addr, key, value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// One of the genesis account having 200 ETH
|
|
|
|
b := statedb.GetBalance(eth_common.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0"))
|
2018-06-18 15:33:07 +00:00
|
|
|
fmt.Printf("Balance: %s\n", b)
|
2018-06-18 21:10:29 +00:00
|
|
|
root, err := statedb.Commit(false /* deleteEmptyObjects */)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Genesis state root hash: %x\n", root[:])
|
|
|
|
// Try to create a new statedb from genesis hash
|
|
|
|
genesis_state, err := eth_state.New(root, d)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
b1 := genesis_state.GetBalance(eth_common.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0"))
|
|
|
|
fmt.Printf("Balance reloaded: %s\n", b1)
|
2018-06-13 09:56:01 +00:00
|
|
|
}
|