Merge pull request #1 from alexanderbez/master
Restructure and Documentation
This commit is contained in:
commit
126d39c562
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Vendor deps
|
||||||
|
.glide/
|
||||||
|
vendor/
|
77
Gopkg.lock
generated
77
Gopkg.lock
generated
@ -5,7 +5,7 @@
|
|||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/aristanetworks/goarista"
|
name = "github.com/aristanetworks/goarista"
|
||||||
packages = ["monotime"]
|
packages = ["monotime"]
|
||||||
revision = "59944ff78bc1de686b0aba1444dfd380f48f03d4"
|
revision = "2c5933638c5ef1bc320b01486100788c81d57b99"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -14,14 +14,20 @@
|
|||||||
revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
|
revision = "86fed781132ac890ee03e906e4ecd5d6fa180c64"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/btcsuite/btcutil"
|
||||||
|
packages = ["bech32"]
|
||||||
|
revision = "d4cc87b860166d00d6b5b9e0d3b3d71d6088d4d4"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "develop"
|
||||||
name = "github.com/cosmos/cosmos-sdk"
|
name = "github.com/cosmos/cosmos-sdk"
|
||||||
packages = [
|
packages = [
|
||||||
"store",
|
"store",
|
||||||
"types",
|
"types",
|
||||||
"wire"
|
"wire"
|
||||||
]
|
]
|
||||||
revision = "cf46be225b7f3853e36af0feac04e29188cd4c95"
|
revision = "08625633c62555cbd4ddc61238d35da520d942cb"
|
||||||
version = "v0.17.5"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/davecgh/go-spew"
|
name = "github.com/davecgh/go-spew"
|
||||||
@ -173,13 +179,7 @@
|
|||||||
"leveldb/table",
|
"leveldb/table",
|
||||||
"leveldb/util"
|
"leveldb/util"
|
||||||
]
|
]
|
||||||
revision = "e2150783cd35f5b607daca48afd8c57ec54cc995"
|
revision = "0d5a0ceb10cf9ab89fdd744cc8c50a83134f6697"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/tendermint/abci"
|
|
||||||
packages = ["types"]
|
|
||||||
revision = "78a8905690ef54f9d57e3b2b0ee7ad3a04ef3f1f"
|
|
||||||
version = "v0.10.3"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -194,39 +194,38 @@
|
|||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/go-amino"
|
name = "github.com/tendermint/go-amino"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "ed62928576cfcaf887209dc96142cd79cdfff389"
|
revision = "2106ca61d91029c931fd54968c2bb02dc96b1412"
|
||||||
version = "0.9.9"
|
version = "0.10.1"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
name = "github.com/tendermint/go-crypto"
|
|
||||||
packages = ["."]
|
|
||||||
revision = "915416979bf70efa4bcbf1c6cd5d64c5fff9fc19"
|
|
||||||
version = "v0.6.2"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/iavl"
|
name = "github.com/tendermint/iavl"
|
||||||
packages = [
|
packages = ["."]
|
||||||
".",
|
revision = "9e5dc3e61f70b285bb25414452d47aca1ff34c1d"
|
||||||
"sha256truncated"
|
version = "v0.8.2-rc0"
|
||||||
]
|
|
||||||
revision = "c9206995e8f948e99927f5084a88a7e94ca256da"
|
|
||||||
version = "v0.8.0-rc0"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tendermint"
|
||||||
packages = [
|
packages = [
|
||||||
"common",
|
"abci/types",
|
||||||
"db",
|
"crypto",
|
||||||
"log",
|
"crypto/merkle",
|
||||||
"merkle"
|
"crypto/tmhash",
|
||||||
|
"libs/bech32",
|
||||||
|
"libs/common",
|
||||||
|
"libs/db",
|
||||||
|
"libs/log",
|
||||||
|
"libs/pubsub",
|
||||||
|
"libs/pubsub/query",
|
||||||
|
"types"
|
||||||
]
|
]
|
||||||
revision = "692f1d86a6e2c0efa698fd1e4541b68c74ffaf38"
|
revision = "5923b6288fe8ce9581936ee97c2bf9cf9c02c2f4"
|
||||||
version = "v0.8.4"
|
version = "v0.22.0-rc2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = [
|
packages = [
|
||||||
|
"internal/subtle",
|
||||||
"nacl/secretbox",
|
"nacl/secretbox",
|
||||||
"openpgp/armor",
|
"openpgp/armor",
|
||||||
"openpgp/errors",
|
"openpgp/errors",
|
||||||
@ -234,7 +233,7 @@
|
|||||||
"ripemd160",
|
"ripemd160",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "8ac0e0d97ce45cd83d1d7243c060cb8461dda5e9"
|
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
@ -249,7 +248,7 @@
|
|||||||
"trace",
|
"trace",
|
||||||
"websocket"
|
"websocket"
|
||||||
]
|
]
|
||||||
revision = "db08ff08e8622530d9ed3a0e8ac279f6d4c02196"
|
revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
@ -282,9 +281,13 @@
|
|||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"balancer",
|
"balancer",
|
||||||
|
"balancer/base",
|
||||||
|
"balancer/roundrobin",
|
||||||
"codes",
|
"codes",
|
||||||
"connectivity",
|
"connectivity",
|
||||||
"credentials",
|
"credentials",
|
||||||
|
"encoding",
|
||||||
|
"encoding/proto",
|
||||||
"grpclb/grpc_lb_v1/messages",
|
"grpclb/grpc_lb_v1/messages",
|
||||||
"grpclog",
|
"grpclog",
|
||||||
"internal",
|
"internal",
|
||||||
@ -293,13 +296,15 @@
|
|||||||
"naming",
|
"naming",
|
||||||
"peer",
|
"peer",
|
||||||
"resolver",
|
"resolver",
|
||||||
|
"resolver/dns",
|
||||||
|
"resolver/passthrough",
|
||||||
"stats",
|
"stats",
|
||||||
"status",
|
"status",
|
||||||
"tap",
|
"tap",
|
||||||
"transport"
|
"transport"
|
||||||
]
|
]
|
||||||
revision = "5b3c4e850e90a4cf6a20ebd46c8b32a0a3afcb9e"
|
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
|
||||||
version = "v1.7.5"
|
version = "v1.11.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "gopkg.in/fatih/set.v0"
|
name = "gopkg.in/fatih/set.v0"
|
||||||
@ -322,6 +327,6 @@
|
|||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "c70e98edb879cb6bb6dbea237d8b58d872aea54a8217f895afdcf8efdd962601"
|
inputs-digest = "d2bdf0662ff705902bb01ca73dc55e89a4eb0b7f323b96d1ce84afa5d1253c0a"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
47
Gopkg.toml
47
Gopkg.toml
@ -1,41 +1,24 @@
|
|||||||
# Gopkg.toml example
|
[[constraint]]
|
||||||
#
|
name = "github.com/cosmos/cosmos-sdk"
|
||||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
# TODO: Replace with a stable tagged version
|
||||||
# for detailed Gopkg.toml documentation.
|
branch = "develop"
|
||||||
#
|
|
||||||
# required = ["github.com/user/thing/cmd/thing"]
|
|
||||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project"
|
|
||||||
# version = "1.0.0"
|
|
||||||
#
|
|
||||||
# [[constraint]]
|
|
||||||
# name = "github.com/user/project2"
|
|
||||||
# branch = "dev"
|
|
||||||
# source = "github.com/myfork/project2"
|
|
||||||
#
|
|
||||||
# [[override]]
|
|
||||||
# name = "github.com/x/y"
|
|
||||||
# version = "2.4.0"
|
|
||||||
#
|
|
||||||
# [prune]
|
|
||||||
# non-go = false
|
|
||||||
# go-tests = true
|
|
||||||
# unused-packages = true
|
|
||||||
|
|
||||||
[[override]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/iavl"
|
name = "github.com/ethereum/go-ethereum"
|
||||||
version = "0.8.0-rc0"
|
version = "1.8.11"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/tendermint/tendermint"
|
||||||
|
version = "=0.22.0-rc2"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "google.golang.org/genproto"
|
name = "google.golang.org/genproto"
|
||||||
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
||||||
|
|
||||||
#[[constraint]]
|
[[override]]
|
||||||
# name = "github.com/cosmos/cosmos-sdk"
|
name = "github.com/tendermint/go-wire"
|
||||||
# version = "0.18.0"
|
version = "0.7.3"
|
||||||
|
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
|
unused-packages = true
|
||||||
|
@ -6,10 +6,10 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ type StructLogRes struct {
|
|||||||
Storage *map[string]string `json:"storage,omitempty"`
|
Storage *map[string]string `json:"storage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// formatLogs formats EVM returned structured logs for json output
|
// formatLogs formats EVM returned structured logs for json output
|
||||||
func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
||||||
formatted := make([]StructLogRes, len(logs))
|
formatted := make([]StructLogRes, len(logs))
|
||||||
for index, trace := range logs {
|
for index, trace := range logs {
|
||||||
|
124
core/chain.go
Normal file
124
core/chain.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
ethconsensus "github.com/ethereum/go-ethereum/consensus"
|
||||||
|
ethstate "github.com/ethereum/go-ethereum/core/state"
|
||||||
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
ethrpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChainContext implements Ethereum's core.ChainContext and consensus.Engine
|
||||||
|
// interfaces. It is needed in order to apply and process Ethereum
|
||||||
|
// transactions. There should only be a single implementation in Ethermint. For
|
||||||
|
// the purposes of Ethermint, it should be support retrieving headers and
|
||||||
|
// consensus parameters from the current blockchain to be used during
|
||||||
|
// transaction processing.
|
||||||
|
//
|
||||||
|
// NOTE: Ethermint will distribute the fees out to validators, so the structure
|
||||||
|
// and functionality of this is a WIP and subject to change.
|
||||||
|
type ChainContext struct {
|
||||||
|
Coinbase ethcommon.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
// Engine implements Ethereum's core.ChainContext interface. As a ChainContext
|
||||||
|
// implements the consensus.Engine interface, it is simply returned.
|
||||||
|
func (cc *ChainContext) Engine() ethconsensus.Engine {
|
||||||
|
return cc
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeader implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: The Cosmos SDK supports retreiving such information in contexts and
|
||||||
|
// multi-store, so this will be need to be integrated.
|
||||||
|
func (cc *ChainContext) GetHeader(ethcommon.Hash, uint64) *ethtypes.Header {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author implements Ethereum's consensus.Engine interface. It is responsible
|
||||||
|
// for returned the address of the validtor to receive any fees. This function
|
||||||
|
// is only invoked if the given author in the ApplyTransaction call is nil.
|
||||||
|
//
|
||||||
|
// NOTE: Ethermint will distribute the fees out to validators, so the structure
|
||||||
|
// and functionality of this is a WIP and subject to change.
|
||||||
|
func (cc *ChainContext) Author(_ *ethtypes.Header) (ethcommon.Address, error) {
|
||||||
|
return cc.Coinbase, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIs implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Do we need to support such RPC APIs? This will tie into a bigger
|
||||||
|
// discussion on if we want to support web3.
|
||||||
|
func (cc *ChainContext) APIs(_ ethconsensus.ChainReader) []ethrpc.API {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalcDifficulty implements Ethereum's core.ChainContext interface. It
|
||||||
|
// currently performs a no-op.
|
||||||
|
func (cc *ChainContext) CalcDifficulty(_ ethconsensus.ChainReader, _ uint64, _ *ethtypes.Header) *big.Int {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Figure out if this needs to be hooked up to any part of the ABCI?
|
||||||
|
func (cc *ChainContext) Finalize(
|
||||||
|
_ ethconsensus.ChainReader, _ *ethtypes.Header, _ *ethstate.StateDB,
|
||||||
|
_ []*ethtypes.Transaction, _ []*ethtypes.Header, _ []*ethtypes.Receipt,
|
||||||
|
) (*ethtypes.Block, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Figure out if this needs to be hooked up to any part of the ABCI?
|
||||||
|
func (cc *ChainContext) Prepare(_ ethconsensus.ChainReader, _ *ethtypes.Header) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seal implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Figure out if this needs to be hooked up to any part of the ABCI?
|
||||||
|
func (cc *ChainContext) Seal(_ ethconsensus.ChainReader, _ *ethtypes.Block, _ <-chan struct{}) (*ethtypes.Block, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyHeader implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
|
||||||
|
// handlers?
|
||||||
|
func (cc *ChainContext) VerifyHeader(_ ethconsensus.ChainReader, _ *ethtypes.Header, _ bool) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyHeaders implements Ethereum's core.ChainContext interface. It
|
||||||
|
// currently performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
|
||||||
|
// handlers?
|
||||||
|
func (cc *ChainContext) VerifyHeaders(_ ethconsensus.ChainReader, _ []*ethtypes.Header, _ []bool) (chan<- struct{}, <-chan error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySeal implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
//
|
||||||
|
// TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
|
||||||
|
// handlers?
|
||||||
|
func (cc *ChainContext) VerifySeal(_ ethconsensus.ChainReader, _ *ethtypes.Header) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyUncles implements Ethereum's core.ChainContext interface. It currently
|
||||||
|
// performs a no-op.
|
||||||
|
func (cc *ChainContext) VerifyUncles(_ ethconsensus.ChainReader, _ *ethtypes.Block) error {
|
||||||
|
return nil
|
||||||
|
}
|
65
core/ethdb.go
Normal file
65
core/ethdb.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
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() {
|
||||||
|
}
|
488
main.go
488
main.go
@ -1,443 +1,235 @@
|
|||||||
|
// The implementation below is to be considered highly unstable and a continual
|
||||||
|
// WIP. It is a means to replicate and test replaying Ethereum transactions
|
||||||
|
// using the Cosmos SDK and the EVM. The ultimate result will be what is known
|
||||||
|
// as Ethermint.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
eth_common "github.com/ethereum/go-ethereum/common"
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
eth_core "github.com/ethereum/go-ethereum/core"
|
ethmisc "github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
eth_state "github.com/ethereum/go-ethereum/core/state"
|
ethcore "github.com/ethereum/go-ethereum/core"
|
||||||
eth_types "github.com/ethereum/go-ethereum/core/types"
|
ethstate "github.com/ethereum/go-ethereum/core/state"
|
||||||
eth_vm "github.com/ethereum/go-ethereum/core/vm"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
eth_rlp "github.com/ethereum/go-ethereum/rlp"
|
ethvm "github.com/ethereum/go-ethereum/core/vm"
|
||||||
eth_ethdb "github.com/ethereum/go-ethereum/ethdb"
|
ethparams "github.com/ethereum/go-ethereum/params"
|
||||||
eth_params "github.com/ethereum/go-ethereum/params"
|
ethrlp "github.com/ethereum/go-ethereum/rlp"
|
||||||
eth_rpc "github.com/ethereum/go-ethereum/rpc"
|
"github.com/ledgerwatch/ethermint/core"
|
||||||
eth_trie "github.com/ethereum/go-ethereum/trie"
|
"github.com/ledgerwatch/ethermint/state"
|
||||||
eth_consensus "github.com/ethereum/go-ethereum/consensus"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
eth_misc "github.com/ethereum/go-ethereum/consensus/misc"
|
|
||||||
|
|
||||||
dbm "github.com/tendermint/tmlibs/db"
|
|
||||||
"github.com/cosmos/cosmos-sdk/store"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Key for the sub-store with Ethereum accounts
|
// TODO: Document...
|
||||||
AccountsKey = types.NewKVStoreKey("account")
|
miner501 = ethcommon.HexToAddress("0x35e8e5dC5FBd97c5b421A80B596C030a2Be2A04D")
|
||||||
// Key for the sub-store with storage data of Ethereum contracts
|
genInvestor = ethcommon.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0")
|
||||||
StorageKey = types.NewKVStoreKey("storage")
|
|
||||||
// Key for the sub-store with the code for contracts
|
|
||||||
CodeKey = types.NewKVStoreKey("code")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type CommitHashPreimage struct {
|
// TODO: Document...
|
||||||
VersionId int64
|
|
||||||
Prefix []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
var miner501 = eth_common.HexToAddress("0x35e8e5dC5FBd97c5b421A80B596C030a2Be2A04D")
|
|
||||||
|
|
||||||
// Implementation of eth_state.Database
|
|
||||||
type OurDatabase struct {
|
|
||||||
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)
|
|
||||||
accountsCache store.CacheKVStore
|
|
||||||
storageCache store.CacheKVStore
|
|
||||||
codeDb dbm.DB // Mapping [codeHash] -> <code>
|
|
||||||
tracing bool
|
|
||||||
trieDbDummy *eth_trie.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
func OurNewDatabase(stateDb, codeDb dbm.DB) (*OurDatabase, error) {
|
|
||||||
od := &OurDatabase{}
|
|
||||||
od.stateStore = store.NewCommitMultiStore(stateDb)
|
|
||||||
od.stateStore.MountStoreWithDB(AccountsKey, types.StoreTypeIAVL, nil)
|
|
||||||
od.stateStore.MountStoreWithDB(StorageKey, types.StoreTypeIAVL, nil)
|
|
||||||
if err := od.stateStore.LoadLatestVersion(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
od.codeDb = codeDb
|
|
||||||
od.trieDbDummy = eth_trie.NewDatabase(&OurEthDb{codeDb: codeDb})
|
|
||||||
return od, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// root is not interpreted as a hash, but as an encoding of version
|
|
||||||
func (od *OurDatabase) OpenTrie(root eth_common.Hash) (eth_state.Trie, error) {
|
|
||||||
// Look up version id to use
|
|
||||||
hasData := root != (eth_common.Hash{})
|
|
||||||
versionId := od.stateStore.LastCommitID().Version
|
|
||||||
if hasData {
|
|
||||||
// First 8 bytes encode version
|
|
||||||
versionId = int64(binary.BigEndian.Uint64(root[:8]))
|
|
||||||
if od.stateStore.LastCommitID().Version != versionId {
|
|
||||||
if err := od.stateStore.LoadVersion(versionId); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
od.accountsCache = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if od.accountsCache == nil {
|
|
||||||
od.accountsCache = store.NewCacheKVStore(od.stateStore.GetCommitKVStore(AccountsKey))
|
|
||||||
od.storageCache = store.NewCacheKVStore(od.stateStore.GetCommitKVStore(StorageKey))
|
|
||||||
}
|
|
||||||
return &OurTrie{od: od, st: od.accountsCache, prefix: nil, hasData: hasData}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (od *OurDatabase) OpenStorageTrie(addrHash, root eth_common.Hash) (eth_state.Trie, error) {
|
|
||||||
hasData := root != (eth_common.Hash{})
|
|
||||||
return &OurTrie{od:od, st: od.storageCache, prefix: addrHash[:], hasData: hasData}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (od *OurDatabase) CopyTrie(eth_state.Trie) eth_state.Trie {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (od *OurDatabase) ContractCode(addrHash, codeHash eth_common.Hash) ([]byte, error) {
|
|
||||||
code := od.codeDb.Get(codeHash[:])
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (od *OurDatabase) ContractCodeSize(addrHash, codeHash eth_common.Hash) (int, error) {
|
|
||||||
code := od.codeDb.Get(codeHash[:])
|
|
||||||
return len(code), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (od *OurDatabase) TrieDB() *eth_trie.Database {
|
|
||||||
return od.trieDbDummy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of state.Trie from go-ethereum
|
|
||||||
type OurTrie struct {
|
|
||||||
od *OurDatabase
|
|
||||||
// This is essentially part of the KVStore for a specific prefix
|
|
||||||
st store.KVStore
|
|
||||||
prefix []byte
|
|
||||||
hasData bool
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ot *OurTrie) TryGet(key []byte) ([]byte, error) {
|
|
||||||
if ot.prefix == nil {
|
|
||||||
return ot.st.Get(key), nil
|
|
||||||
}
|
|
||||||
return ot.st.Get(ot.makePrefix(key)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ot *OurTrie) TryUpdate(key, value []byte) error {
|
|
||||||
ot.hasData = true
|
|
||||||
if ot.prefix == nil {
|
|
||||||
ot.st.Set(key, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ot.st.Set(ot.makePrefix(key), value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ot *OurTrie) TryDelete(key []byte) error {
|
|
||||||
if ot.prefix == nil {
|
|
||||||
ot.st.Delete(key)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ot.st.Delete(ot.makePrefix(key))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ot *OurTrie) Commit(onleaf eth_trie.LeafCallback) (eth_common.Hash, error) {
|
|
||||||
if !ot.hasData {
|
|
||||||
return eth_common.Hash{}, nil
|
|
||||||
}
|
|
||||||
var commitHash eth_common.Hash
|
|
||||||
// We assume here that the next committed version will be od.stateStore.LastCommitID().Version+1
|
|
||||||
binary.BigEndian.PutUint64(commitHash[:8], uint64(ot.od.stateStore.LastCommitID().Version+1))
|
|
||||||
if ot.prefix == nil {
|
|
||||||
if ot.od.accountsCache != nil {
|
|
||||||
ot.od.accountsCache.Write()
|
|
||||||
ot.od.accountsCache = nil
|
|
||||||
}
|
|
||||||
if ot.od.storageCache != nil {
|
|
||||||
ot.od.storageCache.Write()
|
|
||||||
ot.od.storageCache = nil
|
|
||||||
}
|
|
||||||
// Enumerate cached nodes from trie.Database
|
|
||||||
for _, n := range ot.od.trieDbDummy.Nodes() {
|
|
||||||
if err := ot.od.trieDbDummy.Commit(n, false); err != nil {
|
|
||||||
return eth_common.Hash{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commitHash, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dummy implementation of core.ChainContext and consensus Engine from go-ethereum
|
|
||||||
type OurChainContext struct {
|
|
||||||
coinbase eth_common.Address // This is where the transaction fees will go
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) Engine() eth_consensus.Engine {
|
|
||||||
return occ
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) GetHeader(eth_common.Hash, uint64) *eth_types.Header {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) Author(header *eth_types.Header) (eth_common.Address, error) {
|
|
||||||
return occ.coinbase, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) APIs(chain eth_consensus.ChainReader) []eth_rpc.API {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) CalcDifficulty(chain eth_consensus.ChainReader, time uint64, parent *eth_types.Header) *big.Int {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) Finalize(chain eth_consensus.ChainReader, header *eth_types.Header, state *eth_state.StateDB, txs []*eth_types.Transaction,
|
|
||||||
uncles []*eth_types.Header, receipts []*eth_types.Receipt) (*eth_types.Block, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) Prepare(chain eth_consensus.ChainReader, header *eth_types.Header) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) Seal(chain eth_consensus.ChainReader, block *eth_types.Block, stop <-chan struct{}) (*eth_types.Block, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) VerifyHeader(chain eth_consensus.ChainReader, header *eth_types.Header, seal bool) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) VerifyHeaders(chain eth_consensus.ChainReader, headers []*eth_types.Header, seals []bool) (chan<- struct{}, <-chan error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) VerifySeal(chain eth_consensus.ChainReader, header *eth_types.Header) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (occ *OurChainContext) VerifyUncles(chain eth_consensus.ChainReader, block *eth_types.Block) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implementation of ethdb.Database and ethdb.Batch from go-ethereum
|
|
||||||
type OurEthDb struct {
|
|
||||||
codeDb dbm.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Put(key []byte, value []byte) error {
|
|
||||||
oedb.codeDb.Set(key, value)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Get(key []byte) ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Has(key []byte) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Delete(key []byte) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Close() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) NewBatch() eth_ethdb.Batch {
|
|
||||||
return oedb
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) ValueSize() int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Write() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (oedb *OurEthDb) Reset() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
stateDb := dbm.NewDB("state" /* name */, dbm.MemDBBackend, "" /* dir */)
|
stateDB := dbm.NewDB("state", dbm.MemDBBackend, "")
|
||||||
codeDb := dbm.NewDB("code" /* name */, dbm.MemDBBackend, "" /* dir */)
|
codeDB := dbm.NewDB("code", dbm.MemDBBackend, "")
|
||||||
d, err := OurNewDatabase(stateDb, codeDb)
|
|
||||||
|
ethermintDB, err := state.NewDatabase(stateDB, codeDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
fmt.Printf("Instantiating state.StateDB\n")
|
|
||||||
// With empty root hash, i.e. empty state
|
fmt.Println("instantiating new geth state.StateDB")
|
||||||
statedb, err := eth_state.New(eth_common.Hash{}, d)
|
|
||||||
|
// start with empty root hash (i.e. empty state)
|
||||||
|
gethStateDB, err := ethstate.New(ethcommon.Hash{}, ethermintDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
g := eth_core.DefaultGenesisBlock()
|
|
||||||
for addr, account := range g.Alloc {
|
genBlock := ethcore.DefaultGenesisBlock()
|
||||||
statedb.AddBalance(addr, account.Balance)
|
for addr, account := range genBlock.Alloc {
|
||||||
statedb.SetCode(addr, account.Code)
|
gethStateDB.AddBalance(addr, account.Balance)
|
||||||
statedb.SetNonce(addr, account.Nonce)
|
gethStateDB.SetCode(addr, account.Code)
|
||||||
|
gethStateDB.SetNonce(addr, account.Nonce)
|
||||||
|
|
||||||
for key, value := range account.Storage {
|
for key, value := range account.Storage {
|
||||||
statedb.SetState(addr, key, value)
|
gethStateDB.SetState(addr, key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// One of the genesis account having 200 ETH
|
// get balance of one of the genesis account having 200 ETH
|
||||||
b := statedb.GetBalance(eth_common.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0"))
|
b := gethStateDB.GetBalance(genInvestor)
|
||||||
fmt.Printf("Balance: %s\n", b)
|
fmt.Printf("balance of %s: %s\n", genInvestor.String(), b)
|
||||||
genesis_root, err := statedb.Commit(false /* deleteEmptyObjects */)
|
|
||||||
|
// commit the geth stateDB with 'false' to delete empty objects
|
||||||
|
genRoot, err := gethStateDB.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
commitID := d.stateStore.Commit()
|
|
||||||
fmt.Printf("CommitID after genesis: %v\n", commitID)
|
commitID := ethermintDB.Commit()
|
||||||
fmt.Printf("Genesis state root hash: %x\n", genesis_root[:])
|
|
||||||
// File with blockchain data exported from geth by using "geth expordb" command
|
fmt.Printf("commitID after genesis: %v\n", commitID)
|
||||||
|
fmt.Printf("genesis state root hash: %x\n", genRoot[:])
|
||||||
|
|
||||||
|
// file with blockchain data exported from geth by using "geth exportdb"
|
||||||
|
// command.
|
||||||
|
//
|
||||||
|
// TODO: Allow this to be configurable
|
||||||
input, err := os.Open("/Users/alexeyakhunov/mygit/blockchain")
|
input, err := os.Open("/Users/alexeyakhunov/mygit/blockchain")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer input.Close()
|
defer input.Close()
|
||||||
// Ethereum mainnet config
|
|
||||||
chainConfig := eth_params.MainnetChainConfig
|
// ethereum mainnet config
|
||||||
stream := eth_rlp.NewStream(input, 0)
|
chainConfig := ethparams.MainnetChainConfig
|
||||||
var block eth_types.Block
|
|
||||||
|
// create RLP stream for exported blocks
|
||||||
|
stream := ethrlp.NewStream(input, 0)
|
||||||
|
|
||||||
|
var (
|
||||||
|
block ethtypes.Block
|
||||||
|
root500 ethcommon.Hash // root hash after block 500
|
||||||
|
root501 ethcommon.Hash // root hash after block 501
|
||||||
|
)
|
||||||
|
|
||||||
|
prevRoot := genRoot
|
||||||
|
ethermintDB.Tracing = true
|
||||||
|
chainContext := &core.ChainContext{}
|
||||||
|
vmConfig := ethvm.Config{}
|
||||||
|
|
||||||
n := 0
|
n := 0
|
||||||
var root500 eth_common.Hash // Root hash after block 500
|
|
||||||
var root501 eth_common.Hash // Root hash after block 501
|
|
||||||
prev_root := genesis_root
|
|
||||||
d.tracing = true
|
|
||||||
chainContext := &OurChainContext{}
|
|
||||||
vmConfig := eth_vm.Config{}
|
|
||||||
for {
|
for {
|
||||||
if err = stream.Decode(&block); err == io.EOF {
|
if err = stream.Decode(&block); err == io.EOF {
|
||||||
err = nil // Clear it
|
err = nil
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
panic(fmt.Errorf("at block %d: %v", block.NumberU64(), err))
|
panic(fmt.Errorf("failed to decode at block %d: %s", block.NumberU64(), err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't import first block
|
// don't import first block
|
||||||
if block.NumberU64() == 0 {
|
if block.NumberU64() == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
chainContext.coinbase = header.Coinbase
|
chainContext.Coinbase = header.Coinbase
|
||||||
statedb, err := eth_state.New(prev_root, d)
|
|
||||||
|
gethStateDB, err := ethstate.New(prevRoot, ethermintDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("at block %d: %v", block.NumberU64(), err))
|
panic(fmt.Errorf("failed to instantiate geth state.StateDB at block %d: %v", block.NumberU64(), err))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
receipts eth_types.Receipts
|
receipts ethtypes.Receipts
|
||||||
usedGas = new(uint64)
|
usedGas = new(uint64)
|
||||||
allLogs []*eth_types.Log
|
allLogs []*ethtypes.Log
|
||||||
gp = new(eth_core.GasPool).AddGas(block.GasLimit())
|
gp = new(ethcore.GasPool).AddGas(block.GasLimit())
|
||||||
)
|
)
|
||||||
|
|
||||||
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
|
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||||
eth_misc.ApplyDAOHardFork(statedb)
|
ethmisc.ApplyDAOHardFork(gethStateDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
statedb.Prepare(tx.Hash(), block.Hash(), i)
|
gethStateDB.Prepare(tx.Hash(), block.Hash(), i)
|
||||||
var h eth_common.Hash = tx.Hash()
|
|
||||||
if bytes.Equal(h[:], eth_common.FromHex("0xc438cfcc3b74a28741bda361032f1c6362c34aa0e1cedff693f31ec7d6a12717")) {
|
txHash := tx.Hash()
|
||||||
vmConfig.Tracer = eth_vm.NewStructLogger(ð_vm.LogConfig{})
|
// TODO: Why this address?
|
||||||
|
if bytes.Equal(txHash[:], ethcommon.FromHex("0xc438cfcc3b74a28741bda361032f1c6362c34aa0e1cedff693f31ec7d6a12717")) {
|
||||||
|
vmConfig.Tracer = ethvm.NewStructLogger(ðvm.LogConfig{})
|
||||||
vmConfig.Debug = true
|
vmConfig.Debug = true
|
||||||
}
|
}
|
||||||
receipt, _, err := eth_core.ApplyTransaction(chainConfig, chainContext, nil, gp, statedb, header, tx, usedGas, vmConfig)
|
|
||||||
|
receipt, _, err := ethcore.ApplyTransaction(chainConfig, chainContext, nil, gp, gethStateDB, header, tx, usedGas, vmConfig)
|
||||||
if vmConfig.Tracer != nil {
|
if vmConfig.Tracer != nil {
|
||||||
w, err := os.Create("structlogs.txt")
|
w, err := os.Create("structlogs.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
encoder := json.NewEncoder(w)
|
||||||
logs := FormatLogs(vmConfig.Tracer.(*eth_vm.StructLogger).StructLogs())
|
logs := FormatLogs(vmConfig.Tracer.(*ethvm.StructLogger).StructLogs())
|
||||||
|
|
||||||
if err := encoder.Encode(logs); err != nil {
|
if err := encoder.Encode(logs); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := w.Close(); err != nil {
|
if err := w.Close(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vmConfig.Debug = false
|
vmConfig.Debug = false
|
||||||
vmConfig.Tracer = nil
|
vmConfig.Tracer = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("at block %d, tx %x: %v", block.NumberU64(), tx.Hash(), err))
|
panic(fmt.Errorf("at block %d, tx %x: %v", block.NumberU64(), tx.Hash(), err))
|
||||||
}
|
}
|
||||||
|
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
// Apply mining rewards to the statedb
|
|
||||||
accumulateRewards(chainConfig, statedb, header, block.Uncles())
|
// apply mining rewards to the geth stateDB
|
||||||
// Commit block
|
accumulateRewards(chainConfig, gethStateDB, header, block.Uncles())
|
||||||
prev_root, err = statedb.Commit(chainConfig.IsEIP158(block.Number()) /* deleteEmptyObjects */)
|
|
||||||
|
// commit block in geth
|
||||||
|
prevRoot, err = gethStateDB.Commit(chainConfig.IsEIP158(block.Number()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("at block %d: %v", block.NumberU64(), err))
|
panic(fmt.Errorf("at block %d: %v", block.NumberU64(), err))
|
||||||
}
|
}
|
||||||
//fmt.Printf("State root after block %d: %x\n", block.NumberU64(), prev_root)
|
|
||||||
d.stateStore.Commit()
|
// commit block in Ethermint
|
||||||
//fmt.Printf("CommitID after block %d: %v\n", block.NumberU64(), commitID)
|
ethermintDB.Commit()
|
||||||
|
|
||||||
switch block.NumberU64() {
|
switch block.NumberU64() {
|
||||||
case 500:
|
case 500:
|
||||||
root500 = prev_root
|
root500 = prevRoot
|
||||||
case 501:
|
case 501:
|
||||||
root501 = prev_root
|
root501 = prevRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
n++
|
n++
|
||||||
if n % 10000 == 0 {
|
if n%10000 == 0 {
|
||||||
fmt.Printf("Processed %d blocks\n", n)
|
fmt.Printf("processed %d blocks\n", n)
|
||||||
}
|
}
|
||||||
if n >= 100000 {
|
if n >= 100000 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Printf("Processed %d blocks\n", n)
|
|
||||||
d.tracing = true
|
fmt.Printf("processed %d blocks\n", n)
|
||||||
genesis_state, err := eth_state.New(genesis_root, d)
|
|
||||||
fmt.Printf("Balance of one of the genesis investors: %s\n", genesis_state.GetBalance(eth_common.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0")))
|
ethermintDB.Tracing = true
|
||||||
//miner501 := eth_common.HexToAddress("0x35e8e5dC5FBd97c5b421A80B596C030a2Be2A04D") // Miner of the block 501
|
|
||||||
// Try to create a new statedb from root of the block 500
|
genState, err := ethstate.New(genRoot, ethermintDB)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("balance of one of the genesis investors: %s\n", genState.GetBalance(genInvestor))
|
||||||
|
|
||||||
|
// try to create a new geth stateDB from root of the block 500
|
||||||
fmt.Printf("root500: %x\n", root500[:])
|
fmt.Printf("root500: %x\n", root500[:])
|
||||||
state500, err := eth_state.New(root500, d)
|
|
||||||
|
state500, err := ethstate.New(root500, ethermintDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
miner501_balance_at_500 := state500.GetBalance(miner501)
|
miner501BalanceAt500 := state500.GetBalance(miner501)
|
||||||
state501, err := eth_state.New(root501, d)
|
|
||||||
|
state501, err := ethstate.New(root501, ethermintDB)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
miner501_balance_at_501 := state501.GetBalance(miner501)
|
miner501BalanceAt501 := state501.GetBalance(miner501)
|
||||||
fmt.Printf("Investor's balance after block 500: %d\n", state500.GetBalance(eth_common.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0")))
|
|
||||||
fmt.Printf("Miner of block 501's balance after block 500: %d\n", miner501_balance_at_500)
|
fmt.Printf("investor's balance after block 500: %d\n", state500.GetBalance(genInvestor))
|
||||||
fmt.Printf("Miner of block 501's balance after block 501: %d\n", miner501_balance_at_501)
|
fmt.Printf("miner of block 501's balance after block 500: %d\n", miner501BalanceAt500)
|
||||||
}
|
fmt.Printf("miner of block 501's balance after block 501: %d\n", miner501BalanceAt501)
|
||||||
|
}
|
||||||
|
185
state/database.go
Normal file
185
state/database.go
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
|
"github.com/cosmos/cosmos-sdk/types"
|
||||||
|
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
ethstate "github.com/ethereum/go-ethereum/core/state"
|
||||||
|
ethtrie "github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/ledgerwatch/ethermint/core"
|
||||||
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// AccountsKey is the key used for storing Ethereum accounts in the Cosmos
|
||||||
|
// SDK multi-store.
|
||||||
|
AccountsKey = types.NewKVStoreKey("account")
|
||||||
|
|
||||||
|
// StorageKey is the key used for storing Ethereum contract storage in the
|
||||||
|
// Cosmos SDK multi-store.
|
||||||
|
StorageKey = types.NewKVStoreKey("storage")
|
||||||
|
|
||||||
|
// CodeKey is the key used for storing Ethereum contract code in the Cosmos
|
||||||
|
// SDK multi-store.
|
||||||
|
CodeKey = types.NewKVStoreKey("code")
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// TODO: Do we need this/document?
|
||||||
|
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(stateDB, codeDB dbm.DB) (*Database, error) {
|
||||||
|
// Initialize an implementation of Ethereum state.Database and create a
|
||||||
|
// Cosmos SDK multi-store.
|
||||||
|
db := &Database{
|
||||||
|
stateStore: store.NewCommitMultiStore(stateDB),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the underlying multi-store stores that will persist account and
|
||||||
|
// account storage data.
|
||||||
|
db.stateStore.MountStoreWithDB(AccountsKey, types.StoreTypeIAVL, nil)
|
||||||
|
db.stateStore.MountStoreWithDB(StorageKey, types.StoreTypeIAVL, nil)
|
||||||
|
|
||||||
|
// Load the latest account state from the Cosmos SDK multi-store.
|
||||||
|
if err := db.stateStore.LoadLatestVersion(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(&core.EthereumDB{CodeDB: codeDB})
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ethcommon.Hash) (ethstate.Trie, error) {
|
||||||
|
var loadedState bool
|
||||||
|
version := db.stateStore.LastCommitID().Version
|
||||||
|
|
||||||
|
if !isRootEmpty(root) {
|
||||||
|
version = versionFromRootHash(root)
|
||||||
|
|
||||||
|
if db.stateStore.LastCommitID().Version != version {
|
||||||
|
if err := db.stateStore.LoadVersion(version); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedState = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the cache if the state was loaded for an older version
|
||||||
|
if loadedState {
|
||||||
|
db.accountsCache = store.NewCacheKVStore(db.stateStore.GetCommitKVStore(AccountsKey))
|
||||||
|
db.storageCache = store.NewCacheKVStore(db.stateStore.GetCommitKVStore(StorageKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
// binary.BigEndian.PutUint64(commitHash[:8], uint64(t.od.stateStore.LastCommitID().Version+1))
|
||||||
|
|
||||||
|
return &Trie{
|
||||||
|
store: db.accountsCache,
|
||||||
|
accountsCache: db.accountsCache,
|
||||||
|
storageCache: db.storageCache,
|
||||||
|
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 ethcommon.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,
|
||||||
|
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 ethcommon.Hash) ([]byte, error) {
|
||||||
|
return db.codeDB.Get(codeHash[:]), 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 ethcommon.Hash) (int, error) {
|
||||||
|
return len(db.codeDB.Get(codeHash[:])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit commits the underlying Cosmos SDK multi-store returning the commit
|
||||||
|
// ID.
|
||||||
|
func (db *Database) Commit() types.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 ethcommon.Hash) bool {
|
||||||
|
return root == ethcommon.Hash{}
|
||||||
|
}
|
190
state/trie.go
Normal file
190
state/trie.go
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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 ethcommon.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.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.prefixKey(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.store.Delete(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) (ethcommon.Hash, error) {
|
||||||
|
if t.empty {
|
||||||
|
return ethcommon.Hash{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newRoot := rootHashFromVersion(versionFromRootHash(t.root) + 1)
|
||||||
|
|
||||||
|
if t.prefix == nil {
|
||||||
|
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 ethcommon.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() 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ethcommon.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 ethcommon.Hash) {
|
||||||
|
binary.BigEndian.PutUint64(root[:versionLen], uint64(version))
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user