Merge pull request #453: Core/State Unit Tests
This commit is contained in:
parent
024325e981
commit
0cebfeb759
137
Gopkg.lock
generated
137
Gopkg.lock
generated
@ -3,23 +3,30 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9881039571249d9ff92d4a3383a015c233a4c172f6b5a3d6d71e6c4bfdb70efc"
|
||||
name = "github.com/aristanetworks/goarista"
|
||||
packages = ["monotime"]
|
||||
pruneopts = "T"
|
||||
revision = "32f94db2e6faa2c7250286dfb4c7ad3dc0f3ead2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:cafb561ce87d0eaa309ad6853380d437df3c1142561c5afa700311825aa38df1"
|
||||
name = "github.com/btcsuite/btcd"
|
||||
packages = ["btcec"]
|
||||
pruneopts = "T"
|
||||
revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:20d11bf9fd5c6d8f7bb393229fdd981db8b4350aa9a05f28856b64640851c9b8"
|
||||
name = "github.com/btcsuite/btcutil"
|
||||
packages = ["bech32"]
|
||||
pruneopts = "T"
|
||||
revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:83f4d10d8cbc8174248ac57b9788ff94f9e3af1999e8708fc50f80b7b91949fb"
|
||||
name = "github.com/cosmos/cosmos-sdk"
|
||||
packages = [
|
||||
"baseapp",
|
||||
@ -27,24 +34,30 @@
|
||||
"types",
|
||||
"version",
|
||||
"wire",
|
||||
"x/auth"
|
||||
"x/auth",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "1a1373cc220e402397ad536aee6b8f5b068914c6"
|
||||
version = "v0.21.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3aa953edddec96fd00285789ccd4a31efaff0a2979a3e35b77f5c19d5eaa37f7"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
pruneopts = "T"
|
||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:67d0b50be0549e610017cb91e0b0b745ec0cad7c613bc8e18ff2d1c1fc8825a7"
|
||||
name = "github.com/edsrzf/mmap-go"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "0bce6a6887123b67a60366d2c9fe2dfb74289d2e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:24ae9f4a9d6e2bed9aca667af245834c9a80c39d5ae32e3fc99a2ace91287047"
|
||||
name = "github.com/ethereum/go-ethereum"
|
||||
packages = [
|
||||
"common",
|
||||
@ -74,34 +87,42 @@
|
||||
"params",
|
||||
"rlp",
|
||||
"rpc",
|
||||
"trie"
|
||||
"trie",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "dea1ce052a10cd7d401a5c04f83f371a06fe293c"
|
||||
version = "v1.8.11"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b18534450f89f7007960ff1804d63fb0cc6e7d1989446fcb05d77fb24afc51fc"
|
||||
name = "github.com/go-kit/kit"
|
||||
packages = [
|
||||
"log",
|
||||
"log/level",
|
||||
"log/term"
|
||||
"log/term",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "4dc7be5d2d12881735283bcab7352178e190fc71"
|
||||
version = "v0.6.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:31a18dae27a29aa074515e43a443abfd2ba6deb6d69309d8d7ce789c45f34659"
|
||||
name = "github.com/go-logfmt/logfmt"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c4a2528ccbcabf90f9f3c464a5fc9e302d592861bbfd0b7135a7de8a943d0406"
|
||||
name = "github.com/go-stack/stack"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2a1db9bae44464f781d3637b67df38e896c6e1b9c902e27d24ee9037cb50f23b"
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = [
|
||||
"gogoproto",
|
||||
@ -109,82 +130,123 @@
|
||||
"proto",
|
||||
"protoc-gen-gogo/descriptor",
|
||||
"sortkeys",
|
||||
"types"
|
||||
"types",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6f3df7b8eccb559fa1bda8dae71fdb5f24da5e9aec2696e21f19e6d24062602f"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"proto",
|
||||
"ptypes",
|
||||
"ptypes/any",
|
||||
"ptypes/duration",
|
||||
"ptypes/timestamp"
|
||||
"ptypes/timestamp",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:968462840e6d86b12990015ac6ab297c022ccde102953040724be1df0e9e6c96"
|
||||
name = "github.com/golang/snappy"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:cf296baa185baae04a9a7004efee8511d08e2f5f51d4cbe5375da89722d681db"
|
||||
name = "github.com/hashicorp/golang-lru"
|
||||
packages = [
|
||||
".",
|
||||
"simplelru"
|
||||
"simplelru",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
|
||||
name = "github.com/inconshreveable/mousetrap"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:14f2079ea27e7c67ecdab4f35e774463abc4f9d1806b5d674c0594b52127ab1d"
|
||||
name = "github.com/jmhodges/levigo"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:a64e323dc06b73892e5bb5d040ced475c4645d456038333883f58934abbf6f72"
|
||||
name = "github.com/kr/logfmt"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:22aa691fe0213cb5c07d103f9effebcb7ad04bee45a0ce5fe5369d0ca2ec3a1f"
|
||||
name = "github.com/pmezard/go-difflib"
|
||||
packages = ["difflib"]
|
||||
pruneopts = "T"
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:540558c17f78ee4f056aa043cf3389c283b56754db79112a2d64172e80e685db"
|
||||
name = "github.com/rs/cors"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "ca016a06a5753f8ba03029c0aa5e54afb1bf713f"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:daab027a0bfb143afb503f7b63673bfa8d44f69ce9484c6d19b97957aadc1252"
|
||||
name = "github.com/spf13/cobra"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6de2f73eb31e80d74f84ce1c861e4c0c8f00ca5fb41a25901f987e63a0647c28"
|
||||
name = "github.com/spf13/pflag"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c7f05297d9ad389d81e6d764388d97c4b6a64665eff9fd2550fbdd8545430b80"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"require",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
|
||||
version = "v1.2.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9c39a878048f4a5468675b814fb7d2528d622f8c3612511ff0b5e2a48d451ad2"
|
||||
name = "github.com/syndtr/goleveldb"
|
||||
packages = [
|
||||
"leveldb",
|
||||
@ -198,33 +260,41 @@
|
||||
"leveldb/opt",
|
||||
"leveldb/storage",
|
||||
"leveldb/table",
|
||||
"leveldb/util"
|
||||
"leveldb/util",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:8403202d034640f399279a4f735faabefeb6ee64bbcb03c9c93be1d4c7230382"
|
||||
name = "github.com/tendermint/ed25519"
|
||||
packages = [
|
||||
".",
|
||||
"edwards25519",
|
||||
"extra25519"
|
||||
"extra25519",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4431caadcd2cc6a245bf0f6f61884029f5cc70833a8cc458cd1ba4a578b18c71"
|
||||
name = "github.com/tendermint/go-amino"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "2106ca61d91029c931fd54968c2bb02dc96b1412"
|
||||
version = "0.10.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f11b64e85907d8909a820d0cd793dff19dc268432626411398aa0e26e8a61338"
|
||||
name = "github.com/tendermint/iavl"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9"
|
||||
version = "v0.9.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:f056bee4848f0fff6c92e6b99d4972b175d8a8eec9700df30b143b2e6cc48ea8"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/server",
|
||||
@ -238,13 +308,15 @@
|
||||
"libs/log",
|
||||
"libs/pubsub",
|
||||
"libs/pubsub/query",
|
||||
"types"
|
||||
"types",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "5ff65274b84ea905787a48512cc3124385bddf2f"
|
||||
version = "v0.22.2"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:2c4971d2da7bb27fa225a119dc96af2119dd096869c1228438a0b5fda5f6fe15"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"internal/subtle",
|
||||
@ -253,12 +325,14 @@
|
||||
"openpgp/errors",
|
||||
"poly1305",
|
||||
"ripemd160",
|
||||
"salsa20/salsa"
|
||||
"salsa20/salsa",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:501f63fec0206818ab3dac086383bd2146841951c6bd6f3c4f72613f113f25fd"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"context",
|
||||
@ -268,11 +342,13 @@
|
||||
"idna",
|
||||
"internal/timeseries",
|
||||
"trace",
|
||||
"websocket"
|
||||
"websocket",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:24db346d9931fe01f1e9a02aba78ba22c1ecd55bf0f79dd10ba5169719cf002d"
|
||||
name = "golang.org/x/text"
|
||||
packages = [
|
||||
"collate",
|
||||
@ -288,17 +364,21 @@
|
||||
"unicode/bidi",
|
||||
"unicode/cldr",
|
||||
"unicode/norm",
|
||||
"unicode/rangetable"
|
||||
"unicode/rangetable",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:cfa1bbb9ee86ade0914bd5f8e8516386cf7d573957191ecb5163d8f6e023ca0c"
|
||||
name = "google.golang.org/genproto"
|
||||
packages = ["googleapis/rpc/status"]
|
||||
pruneopts = "T"
|
||||
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:1faab7c2380bc84698a62531c4af8c9475fbc7b3b1b2696f2f94feff97c47a49"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
@ -323,32 +403,61 @@
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
"transport"
|
||||
"transport",
|
||||
]
|
||||
pruneopts = "T"
|
||||
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
|
||||
version = "v1.11.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3ccd10c863188cfe0d936fcfe6a055c95362e43af8e7039e33baade846928e74"
|
||||
name = "gopkg.in/fatih/set.v0"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "57907de300222151a123d29255ed17f5ed43fad3"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:35056a4c53d0b725735422545c3c11bdc9007da2fdb644fee96f3a6b7c42c69f"
|
||||
name = "gopkg.in/karalabe/cookiejar.v2"
|
||||
packages = ["collections/prque"]
|
||||
pruneopts = "T"
|
||||
revision = "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
digest = "1:3d3f9391ab615be8655ae0d686a1564f3fec413979bb1aaf018bac1ec1bb1cc7"
|
||||
name = "gopkg.in/natefinch/npipe.v2"
|
||||
packages = ["."]
|
||||
pruneopts = "T"
|
||||
revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "6c999da3cbcf5eac93468232147f2d8e372236a297ddd09275edb065f1bc23ae"
|
||||
input-imports = [
|
||||
"github.com/cosmos/cosmos-sdk/baseapp",
|
||||
"github.com/cosmos/cosmos-sdk/store",
|
||||
"github.com/cosmos/cosmos-sdk/types",
|
||||
"github.com/cosmos/cosmos-sdk/wire",
|
||||
"github.com/ethereum/go-ethereum/common",
|
||||
"github.com/ethereum/go-ethereum/common/math",
|
||||
"github.com/ethereum/go-ethereum/consensus",
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash",
|
||||
"github.com/ethereum/go-ethereum/consensus/misc",
|
||||
"github.com/ethereum/go-ethereum/core",
|
||||
"github.com/ethereum/go-ethereum/core/state",
|
||||
"github.com/ethereum/go-ethereum/core/types",
|
||||
"github.com/ethereum/go-ethereum/core/vm",
|
||||
"github.com/ethereum/go-ethereum/ethdb",
|
||||
"github.com/ethereum/go-ethereum/params",
|
||||
"github.com/ethereum/go-ethereum/rlp",
|
||||
"github.com/ethereum/go-ethereum/rpc",
|
||||
"github.com/ethereum/go-ethereum/trie",
|
||||
"github.com/hashicorp/golang-lru",
|
||||
"github.com/stretchr/testify/require",
|
||||
"github.com/tendermint/tendermint/libs/db",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -21,5 +21,9 @@
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "=0.22.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "=1.2.2"
|
||||
|
||||
[prune]
|
||||
go-tests = true
|
||||
|
95
Makefile
95
Makefile
@ -20,26 +20,6 @@ DOCKER_IMAGE = tendermint/ethermint
|
||||
ETHERMINT_DAEMON_BINARY = emintd
|
||||
ETHERMINT_CLI_BINARY = emintcli
|
||||
|
||||
DEP = github.com/golang/dep/cmd/dep
|
||||
GOLINT = github.com/tendermint/lint/golint
|
||||
GOMETALINTER = gopkg.in/alecthomas/gometalinter.v2
|
||||
UNCONVERT = github.com/mdempsky/unconvert
|
||||
INEFFASSIGN = github.com/gordonklaus/ineffassign
|
||||
MISSPELL = github.com/client9/misspell/cmd/misspell
|
||||
ERRCHECK = github.com/kisielk/errcheck
|
||||
UNPARAM = mvdan.cc/unparam
|
||||
GOCYCLO = github.com/alecthomas/gocyclo
|
||||
|
||||
DEP_CHECK := $(shell command -v dep 2> /dev/null)
|
||||
GOLINT_CHECK := $(shell command -v golint 2> /dev/null)
|
||||
GOMETALINTER_CHECK := $(shell command -v gometalinter.v2 2> /dev/null)
|
||||
UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null)
|
||||
INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null)
|
||||
MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null)
|
||||
ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null)
|
||||
UNPARAM_CHECK := $(shell command -v unparam 2> /dev/null)
|
||||
GOCYCLO_CHECK := $(shell command -v gocyclo 2> /dev/null)
|
||||
|
||||
all: tools deps install
|
||||
|
||||
#######################
|
||||
@ -60,69 +40,93 @@ install:
|
||||
go install $(BUILD_FLAGS) ./cmd/ethermintcli
|
||||
|
||||
clean:
|
||||
rm -rf ./build ./vendor
|
||||
@rm -rf ./build ./vendor
|
||||
|
||||
update-tools:
|
||||
@echo "Updating golang dependencies"
|
||||
@echo "--> Updating golang dependencies"
|
||||
go get -u -v $(DEP) $(GOLINT) $(GOMETALINTER) $(UNCONVERT) $(INEFFASSIGN) $(MISSPELL) $(ERRCHECK) $(UNPARAM) $(GOCYCLO)
|
||||
|
||||
############################
|
||||
### Tools / Dependencies ###
|
||||
############################
|
||||
|
||||
##########################################################
|
||||
### TODO: Move tool depedencies to a separate makefile ###
|
||||
##########################################################
|
||||
|
||||
DEP = github.com/golang/dep/cmd/dep
|
||||
GOLINT = github.com/tendermint/lint/golint
|
||||
GOMETALINTER = gopkg.in/alecthomas/gometalinter.v2
|
||||
UNCONVERT = github.com/mdempsky/unconvert
|
||||
INEFFASSIGN = github.com/gordonklaus/ineffassign
|
||||
MISSPELL = github.com/client9/misspell/cmd/misspell
|
||||
ERRCHECK = github.com/kisielk/errcheck
|
||||
UNPARAM = mvdan.cc/unparam
|
||||
GOCYCLO = github.com/alecthomas/gocyclo
|
||||
|
||||
DEP_CHECK := $(shell command -v dep 2> /dev/null)
|
||||
GOLINT_CHECK := $(shell command -v golint 2> /dev/null)
|
||||
GOMETALINTER_CHECK := $(shell command -v gometalinter.v2 2> /dev/null)
|
||||
UNCONVERT_CHECK := $(shell command -v unconvert 2> /dev/null)
|
||||
INEFFASSIGN_CHECK := $(shell command -v ineffassign 2> /dev/null)
|
||||
MISSPELL_CHECK := $(shell command -v misspell 2> /dev/null)
|
||||
ERRCHECK_CHECK := $(shell command -v errcheck 2> /dev/null)
|
||||
UNPARAM_CHECK := $(shell command -v unparam 2> /dev/null)
|
||||
GOCYCLO_CHECK := $(shell command -v gocyclo 2> /dev/null)
|
||||
|
||||
tools:
|
||||
ifdef DEP_CHECK
|
||||
@echo "Dep is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing dep"
|
||||
@echo "--> Installing dep"
|
||||
go get -v $(DEP)
|
||||
endif
|
||||
ifdef GOLINT_CHECK
|
||||
@echo "Golint is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing golint"
|
||||
@echo "--> Installing golint"
|
||||
go get -v $(GOLINT)
|
||||
endif
|
||||
ifdef GOMETALINTER_CHECK
|
||||
@echo "Gometalinter.v2 is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing gometalinter.v2"
|
||||
@echo "--> Installing gometalinter.v2"
|
||||
go get -v $(GOMETALINTER)
|
||||
endif
|
||||
ifdef UNCONVERT_CHECK
|
||||
@echo "Unconvert is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing unconvert"
|
||||
@echo "--> Installing unconvert"
|
||||
go get -v $(UNCONVERT)
|
||||
endif
|
||||
ifdef INEFFASSIGN_CHECK
|
||||
@echo "Ineffassign is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing ineffassign"
|
||||
@echo "--> Installing ineffassign"
|
||||
go get -v $(INEFFASSIGN)
|
||||
endif
|
||||
ifdef MISSPELL_CHECK
|
||||
@echo "misspell is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing misspell"
|
||||
@echo "--> Installing misspell"
|
||||
go get -v $(MISSPELL)
|
||||
endif
|
||||
ifdef ERRCHECK_CHECK
|
||||
@echo "errcheck is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing errcheck"
|
||||
@echo "--> Installing errcheck"
|
||||
go get -v $(ERRCHECK)
|
||||
endif
|
||||
ifdef UNPARAM_CHECK
|
||||
@echo "unparam is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing unparam"
|
||||
@echo "--> Installing unparam"
|
||||
go get -v $(UNPARAM)
|
||||
endif
|
||||
ifdef GOCYCLO_CHECK
|
||||
@echo "goyclo is already installed. Run 'make update-tools' to update."
|
||||
else
|
||||
@echo "Installing goyclo"
|
||||
@echo "--> Installing goyclo"
|
||||
go get -v $(GOCYCLO)
|
||||
endif
|
||||
|
||||
@ -135,6 +139,27 @@ deps:
|
||||
### Testing / Misc. ###
|
||||
#######################
|
||||
|
||||
TEST_PACKAGES=$(shell go list ./... | grep -v github.com/cosmos/ethermint/cmd/test)
|
||||
|
||||
test: test-unit
|
||||
|
||||
test-unit:
|
||||
@go test -v $(TEST_PACKAGES)
|
||||
|
||||
test-race:
|
||||
@go test -v -race $(TEST_PACKAGES)
|
||||
|
||||
test-cli:
|
||||
@echo "NO CLI TESTS"
|
||||
|
||||
test-lint:
|
||||
@echo "--> Running gometalinter"
|
||||
@gometalinter.v2 --config=gometalinter.json ./...
|
||||
@!(gometalinter.v2 --disable-all --enable='errcheck' --vendor ./... | grep -v "client/")
|
||||
@find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s
|
||||
@dep status >/dev/null 2>&1
|
||||
@!(grep -n branch Gopkg.toml)
|
||||
|
||||
godocs:
|
||||
@echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/ethermint"
|
||||
godoc -http=:6060
|
||||
@ -144,4 +169,10 @@ docker:
|
||||
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:latest
|
||||
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:${COMMIT_HASH}
|
||||
|
||||
.PHONY: build install update-tools tools deps godocs clean
|
||||
format:
|
||||
@echo "--> Formatting go files"
|
||||
@find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -w -s
|
||||
@find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs misspell -w
|
||||
|
||||
.PHONY: build install update-tools tools deps godocs clean format test-lint \
|
||||
test-cli test-race test-unit test
|
||||
|
@ -3,8 +3,8 @@ package core
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||
ethconsensus "github.com/ethereum/go-ethereum/consensus"
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
ethcons "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"
|
||||
@ -20,7 +20,7 @@ import (
|
||||
// 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
|
||||
Coinbase ethcmn.Address
|
||||
headersByNumber map[uint64]*ethtypes.Header
|
||||
}
|
||||
|
||||
@ -32,23 +32,25 @@ func NewChainContext() *ChainContext {
|
||||
|
||||
// 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 {
|
||||
func (cc *ChainContext) Engine() ethcons.Engine {
|
||||
return cc
|
||||
}
|
||||
|
||||
// SetHeader implements Ethereum's core.ChainContext interface. It sets the
|
||||
// header for the given block number.
|
||||
func (cc *ChainContext) SetHeader(number uint64, header *ethtypes.Header) {
|
||||
cc.headersByNumber[number] = header
|
||||
}
|
||||
|
||||
// GetHeader implements Ethereum's core.ChainContext interface. It currently
|
||||
// performs a no-op.
|
||||
// GetHeader implements Ethereum's core.ChainContext interface.
|
||||
//
|
||||
// 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(parentHash ethcommon.Hash, number uint64) *ethtypes.Header {
|
||||
func (cc *ChainContext) GetHeader(_ ethcmn.Hash, number uint64) *ethtypes.Header {
|
||||
if header, ok := cc.headersByNumber[number]; ok {
|
||||
return header
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -58,7 +60,7 @@ func (cc *ChainContext) GetHeader(parentHash ethcommon.Hash, number uint64) *eth
|
||||
//
|
||||
// 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) {
|
||||
func (cc *ChainContext) Author(_ *ethtypes.Header) (ethcmn.Address, error) {
|
||||
return cc.Coinbase, nil
|
||||
}
|
||||
|
||||
@ -67,13 +69,13 @@ func (cc *ChainContext) Author(_ *ethtypes.Header) (ethcommon.Address, error) {
|
||||
//
|
||||
// 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 {
|
||||
func (cc *ChainContext) APIs(_ ethcons.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 {
|
||||
func (cc *ChainContext) CalcDifficulty(_ ethcons.ChainReader, _ uint64, _ *ethtypes.Header) *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -82,7 +84,7 @@ func (cc *ChainContext) CalcDifficulty(_ ethconsensus.ChainReader, _ uint64, _ *
|
||||
//
|
||||
// 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,
|
||||
_ ethcons.ChainReader, _ *ethtypes.Header, _ *ethstate.StateDB,
|
||||
_ []*ethtypes.Transaction, _ []*ethtypes.Header, _ []*ethtypes.Receipt,
|
||||
) (*ethtypes.Block, error) {
|
||||
return nil, nil
|
||||
@ -92,7 +94,7 @@ func (cc *ChainContext) Finalize(
|
||||
// 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 {
|
||||
func (cc *ChainContext) Prepare(_ ethcons.ChainReader, _ *ethtypes.Header) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -100,7 +102,7 @@ func (cc *ChainContext) Prepare(_ ethconsensus.ChainReader, _ *ethtypes.Header)
|
||||
// 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) {
|
||||
func (cc *ChainContext) Seal(_ ethcons.ChainReader, _ *ethtypes.Block, _ <-chan struct{}) (*ethtypes.Block, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -109,7 +111,7 @@ func (cc *ChainContext) Seal(_ ethconsensus.ChainReader, _ *ethtypes.Block, _ <-
|
||||
//
|
||||
// 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 {
|
||||
func (cc *ChainContext) VerifyHeader(_ ethcons.ChainReader, _ *ethtypes.Header, _ bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -118,7 +120,7 @@ func (cc *ChainContext) VerifyHeader(_ ethconsensus.ChainReader, _ *ethtypes.Hea
|
||||
//
|
||||
// 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) {
|
||||
func (cc *ChainContext) VerifyHeaders(_ ethcons.ChainReader, _ []*ethtypes.Header, _ []bool) (chan<- struct{}, <-chan error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@ -127,12 +129,12 @@ func (cc *ChainContext) VerifyHeaders(_ ethconsensus.ChainReader, _ []*ethtypes.
|
||||
//
|
||||
// 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 {
|
||||
func (cc *ChainContext) VerifySeal(_ ethcons.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 {
|
||||
func (cc *ChainContext) VerifyUncles(_ ethcons.ChainReader, _ *ethtypes.Block) error {
|
||||
return nil
|
||||
}
|
||||
|
121
core/chain_test.go
Normal file
121
core/chain_test.go
Normal file
@ -0,0 +1,121 @@
|
||||
package core
|
||||
|
||||
// NOTE: A bulk of these unit tests will change and evolve as the context and
|
||||
// implementation of ChainConext evolves.
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
ethcons "github.com/ethereum/go-ethereum/consensus"
|
||||
ethcore "github.com/ethereum/go-ethereum/core"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestChainContextInterface(t *testing.T) {
|
||||
require.Implements(t, (*ethcore.ChainContext)(nil), new(ChainContext))
|
||||
require.Implements(t, (*ethcons.Engine)(nil), new(ChainContext))
|
||||
}
|
||||
|
||||
func TestNewChainContext(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
require.NotNil(t, cc.headersByNumber)
|
||||
}
|
||||
|
||||
func TestChainContextEngine(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
require.Equal(t, cc, cc.Engine())
|
||||
}
|
||||
|
||||
func TestChainContextSetHeader(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
header := ðtypes.Header{
|
||||
Number: big.NewInt(64),
|
||||
}
|
||||
|
||||
cc.SetHeader(uint64(header.Number.Int64()), header)
|
||||
require.Equal(t, header, cc.headersByNumber[uint64(header.Number.Int64())])
|
||||
}
|
||||
|
||||
func TestChainContextGetHeader(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
header := ðtypes.Header{
|
||||
Number: big.NewInt(64),
|
||||
}
|
||||
|
||||
cc.SetHeader(uint64(header.Number.Int64()), header)
|
||||
require.Equal(t, header, cc.GetHeader(ethcmn.Hash{}, uint64(header.Number.Int64())))
|
||||
require.Nil(t, cc.GetHeader(ethcmn.Hash{}, 0))
|
||||
}
|
||||
|
||||
func TestChainContextAuthor(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
cb, err := cc.Author(nil)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, cc.Coinbase, cb)
|
||||
}
|
||||
|
||||
func TestChainContextAPIs(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
require.Nil(t, cc.APIs(nil))
|
||||
}
|
||||
|
||||
func TestChainContextCalcDifficulty(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
require.Nil(t, cc.CalcDifficulty(nil, 0, nil))
|
||||
}
|
||||
|
||||
func TestChainContextFinalize(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
block, err := cc.Finalize(nil, nil, nil, nil, nil, nil)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, block)
|
||||
}
|
||||
|
||||
func TestChainContextPrepare(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
err := cc.Prepare(nil, nil)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestChainContextSeal(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
block, err := cc.Seal(nil, nil, nil)
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, block)
|
||||
}
|
||||
|
||||
func TestChainContextVerifyHeader(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
err := cc.VerifyHeader(nil, nil, false)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestChainContextVerifyHeaders(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
ch, err := cc.VerifyHeaders(nil, nil, []bool{false})
|
||||
require.Nil(t, err)
|
||||
require.Nil(t, ch)
|
||||
}
|
||||
|
||||
func TestChainContextVerifySeal(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
err := cc.VerifySeal(nil, nil)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestChainContextVerifyUncles(t *testing.T) {
|
||||
cc := NewChainContext()
|
||||
|
||||
err := cc.VerifyUncles(nil, nil)
|
||||
require.Nil(t, err)
|
||||
}
|
147
core/ethdb_test.go
Normal file
147
core/ethdb_test.go
Normal file
@ -0,0 +1,147 @@
|
||||
package core
|
||||
|
||||
// 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"
|
||||
)
|
||||
|
||||
type (
|
||||
kvPair struct {
|
||||
key, value []byte
|
||||
}
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
9
gometalinter.json
Normal file
9
gometalinter.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Linters": {
|
||||
"vet": "go tool vet -composites=false :PATH:LINE:MESSAGE"
|
||||
},
|
||||
"Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell", "gocyclo"],
|
||||
"Deadline": "500s",
|
||||
"Vendor": true,
|
||||
"Cyclo": 11
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/cosmos/ethermint/core"
|
||||
|
||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
ethstate "github.com/ethereum/go-ethereum/core/state"
|
||||
ethtrie "github.com/ethereum/go-ethereum/trie"
|
||||
|
||||
@ -111,11 +111,9 @@ func (db *Database) LatestVersion() int64 {
|
||||
//
|
||||
// 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) {
|
||||
version := db.stateStore.LastCommitID().Version
|
||||
|
||||
func (db *Database) OpenTrie(root ethcmn.Hash) (ethstate.Trie, error) {
|
||||
if !isRootEmpty(root) {
|
||||
version = versionFromRootHash(root)
|
||||
version := versionFromRootHash(root)
|
||||
|
||||
if db.stateStore.LastCommitID().Version != version {
|
||||
if err := db.stateStore.LoadVersion(version); err != nil {
|
||||
@ -152,7 +150,7 @@ func (db *Database) OpenTrie(root ethcommon.Hash) (ethstate.Trie, error) {
|
||||
//
|
||||
// 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) {
|
||||
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{
|
||||
@ -175,17 +173,20 @@ func (db *Database) CopyTrie(ethstate.Trie) ethstate.Trie {
|
||||
|
||||
// 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) {
|
||||
func (db *Database) ContractCode(addrHash, codeHash ethcmn.Hash) ([]byte, error) {
|
||||
code := db.codeDB.Get(codeHash[:])
|
||||
|
||||
db.codeSizeCache.Add(codeHash, len(code))
|
||||
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 ethcommon.Hash) (int, error) {
|
||||
func (db *Database) ContractCodeSize(addrHash, codeHash ethcmn.Hash) (int, error) {
|
||||
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
||||
return cached.(int), nil
|
||||
}
|
||||
@ -209,6 +210,6 @@ func (db *Database) TrieDB() *ethtrie.Database {
|
||||
}
|
||||
|
||||
// isRootEmpty returns true if a given root hash is empty or false otherwise.
|
||||
func isRootEmpty(root ethcommon.Hash) bool {
|
||||
return root == ethcommon.Hash{}
|
||||
func isRootEmpty(root ethcmn.Hash) bool {
|
||||
return root == ethcmn.Hash{}
|
||||
}
|
||||
|
132
state/database_test.go
Normal file
132
state/database_test.go
Normal file
@ -0,0 +1,132 @@
|
||||
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"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
)
|
||||
|
||||
func newDatabase() *Database {
|
||||
memDB := dbm.NewMemDB()
|
||||
db, _ := NewDatabase(memDB, memDB)
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func TestDatabaseInterface(t *testing.T) {
|
||||
require.Implements(t, (*ethstate.Database)(nil), new(Database))
|
||||
}
|
||||
|
||||
func TestDatabaseLatestVersion(t *testing.T) {
|
||||
testDB := newDatabase()
|
||||
|
||||
var version int64
|
||||
|
||||
version = testDB.LatestVersion()
|
||||
require.Equal(t, int64(0), version)
|
||||
|
||||
testDB.Commit()
|
||||
version = testDB.LatestVersion()
|
||||
require.Equal(t, int64(1), version)
|
||||
}
|
||||
|
||||
// func TestDatabaseOpenTrie(t *testing.T) {
|
||||
// testDB := newDatabase()
|
||||
|
||||
// testTrie, err := testDB.OpenTrie(rootHashFromVersion(0))
|
||||
// require.Nil(t, err)
|
||||
// require.IsType(t, &Trie{}, testTrie)
|
||||
// require.NotNil(t, testTrie.(*Trie).store)
|
||||
// require.NotNil(t, testTrie.(*Trie).accountsCache)
|
||||
// require.NotNil(t, testTrie.(*Trie).storageCache)
|
||||
// require.NotNil(t, testTrie.(*Trie).ethTrieDB)
|
||||
// require.False(t, testTrie.(*Trie).empty)
|
||||
|
||||
// }
|
||||
|
||||
func TestDatabaseCopyTrie(t *testing.T) {
|
||||
// TODO: Implement once CopyTrie is implemented
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
func TestDatabaseContractCode(t *testing.T) {
|
||||
testDB := newDatabase()
|
||||
|
||||
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 := newDatabase()
|
||||
|
||||
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 := newDatabase()
|
||||
|
||||
db := testDB.TrieDB()
|
||||
require.Equal(t, testDB.ethTrieDB, db)
|
||||
}
|
23
state/test_utils.go
Normal file
23
state/test_utils.go
Normal file
@ -0,0 +1,23 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
type (
|
||||
kvPair struct {
|
||||
key, value []byte
|
||||
}
|
||||
|
||||
code struct {
|
||||
hash ethcmn.Hash
|
||||
blob []byte
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
|
||||
ethcommon "github.com/ethereum/go-ethereum/common"
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
ethdb "github.com/ethereum/go-ethereum/ethdb"
|
||||
ethtrie "github.com/ethereum/go-ethereum/trie"
|
||||
)
|
||||
@ -39,7 +39,7 @@ type Trie struct {
|
||||
empty bool
|
||||
|
||||
// root is the encoding of an IAVL tree root (version)
|
||||
root ethcommon.Hash
|
||||
root ethcmn.Hash
|
||||
|
||||
ethTrieDB *ethtrie.Database
|
||||
}
|
||||
@ -61,7 +61,7 @@ func (t *Trie) prefixKey(key []byte) []byte {
|
||||
// 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 {
|
||||
if t.IsStorageTrie() {
|
||||
key = t.prefixKey(key)
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ func (t *Trie) TryGet(key []byte) ([]byte, error) {
|
||||
func (t *Trie) TryUpdate(key, value []byte) error {
|
||||
t.empty = false
|
||||
|
||||
if t.prefix != nil {
|
||||
if t.IsStorageTrie() {
|
||||
key = t.prefixKey(key)
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ func (t *Trie) TryUpdate(key, value []byte) error {
|
||||
// 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 {
|
||||
if t.IsStorageTrie() {
|
||||
key = t.prefixKey(key)
|
||||
}
|
||||
|
||||
@ -112,14 +112,14 @@ func (t *Trie) TryDelete(key []byte) error {
|
||||
//
|
||||
// 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) {
|
||||
func (t *Trie) Commit(_ ethtrie.LeafCallback) (ethcmn.Hash, error) {
|
||||
if t.empty {
|
||||
return ethcommon.Hash{}, nil
|
||||
return ethcmn.Hash{}, nil
|
||||
}
|
||||
|
||||
newRoot := rootHashFromVersion(versionFromRootHash(t.root) + 1)
|
||||
|
||||
if t.prefix == nil {
|
||||
if !t.IsStorageTrie() {
|
||||
if t.accountsCache != nil {
|
||||
t.accountsCache.Write()
|
||||
t.accountsCache = nil
|
||||
@ -133,7 +133,7 @@ func (t *Trie) Commit(_ ethtrie.LeafCallback) (ethcommon.Hash, error) {
|
||||
// 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
|
||||
return ethcmn.Hash{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +146,7 @@ func (t *Trie) Commit(_ ethtrie.LeafCallback) (ethcommon.Hash, error) {
|
||||
// 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 {
|
||||
func (t *Trie) Hash() ethcmn.Hash {
|
||||
return t.root
|
||||
}
|
||||
|
||||
@ -175,17 +175,23 @@ 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 ethcommon.Hash) int64 {
|
||||
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 ethcommon.Hash) {
|
||||
func rootHashFromVersion(version int64) (root ethcmn.Hash) {
|
||||
binary.BigEndian.PutUint64(root[:versionLen], uint64(version))
|
||||
return
|
||||
}
|
||||
|
259
state/trie_test.go
Normal file
259
state/trie_test.go
Normal file
@ -0,0 +1,259 @@
|
||||
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"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
)
|
||||
|
||||
func newTestTrie() *Trie {
|
||||
memDB := dbm.NewMemDB()
|
||||
testDB, _ := NewDatabase(memDB, memDB)
|
||||
testTrie, _ := testDB.OpenTrie(rootHashFromVersion(0))
|
||||
|
||||
return testTrie.(*Trie)
|
||||
}
|
||||
|
||||
func newTestPrefixTrie() *Trie {
|
||||
memDB := dbm.NewMemDB()
|
||||
testDB, _ := NewDatabase(memDB, memDB)
|
||||
|
||||
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.Insert(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()
|
||||
}
|
@ -40,6 +40,7 @@ type Importer struct {
|
||||
|
||||
// Import performs an import given an Importer that has a Geth stateDB
|
||||
// implementation and a blockchain exported file.
|
||||
// nolint
|
||||
func (imp *Importer) Import() {
|
||||
// only create genesis if it is a brand new database
|
||||
if imp.EthermintDB.LatestVersion() == 0 {
|
||||
|
Loading…
Reference in New Issue
Block a user