Merge pull request #453: Core/State Unit Tests

This commit is contained in:
Aleksandr Bezobchuk 2018-07-26 09:36:01 -04:00
parent 024325e981
commit 0cebfeb759
13 changed files with 931 additions and 86 deletions

137
Gopkg.lock generated
View File

@ -3,23 +3,30 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:9881039571249d9ff92d4a3383a015c233a4c172f6b5a3d6d71e6c4bfdb70efc"
name = "github.com/aristanetworks/goarista" name = "github.com/aristanetworks/goarista"
packages = ["monotime"] packages = ["monotime"]
pruneopts = "T"
revision = "32f94db2e6faa2c7250286dfb4c7ad3dc0f3ead2" revision = "32f94db2e6faa2c7250286dfb4c7ad3dc0f3ead2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:cafb561ce87d0eaa309ad6853380d437df3c1142561c5afa700311825aa38df1"
name = "github.com/btcsuite/btcd" name = "github.com/btcsuite/btcd"
packages = ["btcec"] packages = ["btcec"]
pruneopts = "T"
revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898" revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:20d11bf9fd5c6d8f7bb393229fdd981db8b4350aa9a05f28856b64640851c9b8"
name = "github.com/btcsuite/btcutil" name = "github.com/btcsuite/btcutil"
packages = ["bech32"] packages = ["bech32"]
pruneopts = "T"
revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b" revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b"
[[projects]] [[projects]]
digest = "1:83f4d10d8cbc8174248ac57b9788ff94f9e3af1999e8708fc50f80b7b91949fb"
name = "github.com/cosmos/cosmos-sdk" name = "github.com/cosmos/cosmos-sdk"
packages = [ packages = [
"baseapp", "baseapp",
@ -27,24 +34,30 @@
"types", "types",
"version", "version",
"wire", "wire",
"x/auth" "x/auth",
] ]
pruneopts = "T"
revision = "1a1373cc220e402397ad536aee6b8f5b068914c6" revision = "1a1373cc220e402397ad536aee6b8f5b068914c6"
version = "v0.21.0" version = "v0.21.0"
[[projects]] [[projects]]
digest = "1:3aa953edddec96fd00285789ccd4a31efaff0a2979a3e35b77f5c19d5eaa37f7"
name = "github.com/davecgh/go-spew" name = "github.com/davecgh/go-spew"
packages = ["spew"] packages = ["spew"]
pruneopts = "T"
revision = "346938d642f2ec3594ed81d874461961cd0faa76" revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0" version = "v1.1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:67d0b50be0549e610017cb91e0b0b745ec0cad7c613bc8e18ff2d1c1fc8825a7"
name = "github.com/edsrzf/mmap-go" name = "github.com/edsrzf/mmap-go"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "0bce6a6887123b67a60366d2c9fe2dfb74289d2e" revision = "0bce6a6887123b67a60366d2c9fe2dfb74289d2e"
[[projects]] [[projects]]
digest = "1:24ae9f4a9d6e2bed9aca667af245834c9a80c39d5ae32e3fc99a2ace91287047"
name = "github.com/ethereum/go-ethereum" name = "github.com/ethereum/go-ethereum"
packages = [ packages = [
"common", "common",
@ -74,34 +87,42 @@
"params", "params",
"rlp", "rlp",
"rpc", "rpc",
"trie" "trie",
] ]
pruneopts = "T"
revision = "dea1ce052a10cd7d401a5c04f83f371a06fe293c" revision = "dea1ce052a10cd7d401a5c04f83f371a06fe293c"
version = "v1.8.11" version = "v1.8.11"
[[projects]] [[projects]]
digest = "1:b18534450f89f7007960ff1804d63fb0cc6e7d1989446fcb05d77fb24afc51fc"
name = "github.com/go-kit/kit" name = "github.com/go-kit/kit"
packages = [ packages = [
"log", "log",
"log/level", "log/level",
"log/term" "log/term",
] ]
pruneopts = "T"
revision = "4dc7be5d2d12881735283bcab7352178e190fc71" revision = "4dc7be5d2d12881735283bcab7352178e190fc71"
version = "v0.6.0" version = "v0.6.0"
[[projects]] [[projects]]
digest = "1:31a18dae27a29aa074515e43a443abfd2ba6deb6d69309d8d7ce789c45f34659"
name = "github.com/go-logfmt/logfmt" name = "github.com/go-logfmt/logfmt"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5"
version = "v0.3.0" version = "v0.3.0"
[[projects]] [[projects]]
digest = "1:c4a2528ccbcabf90f9f3c464a5fc9e302d592861bbfd0b7135a7de8a943d0406"
name = "github.com/go-stack/stack" name = "github.com/go-stack/stack"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc"
version = "v1.7.0" version = "v1.7.0"
[[projects]] [[projects]]
digest = "1:2a1db9bae44464f781d3637b67df38e896c6e1b9c902e27d24ee9037cb50f23b"
name = "github.com/gogo/protobuf" name = "github.com/gogo/protobuf"
packages = [ packages = [
"gogoproto", "gogoproto",
@ -109,82 +130,123 @@
"proto", "proto",
"protoc-gen-gogo/descriptor", "protoc-gen-gogo/descriptor",
"sortkeys", "sortkeys",
"types" "types",
] ]
pruneopts = "T"
revision = "1adfc126b41513cc696b209667c8656ea7aac67c" revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:6f3df7b8eccb559fa1bda8dae71fdb5f24da5e9aec2696e21f19e6d24062602f"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = [ packages = [
"proto", "proto",
"ptypes", "ptypes",
"ptypes/any", "ptypes/any",
"ptypes/duration", "ptypes/duration",
"ptypes/timestamp" "ptypes/timestamp",
] ]
pruneopts = "T"
revision = "925541529c1fa6821df4e44ce2723319eb2be768" revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:968462840e6d86b12990015ac6ab297c022ccde102953040724be1df0e9e6c96"
name = "github.com/golang/snappy" name = "github.com/golang/snappy"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:cf296baa185baae04a9a7004efee8511d08e2f5f51d4cbe5375da89722d681db"
name = "github.com/hashicorp/golang-lru" name = "github.com/hashicorp/golang-lru"
packages = [ packages = [
".", ".",
"simplelru" "simplelru",
] ]
pruneopts = "T"
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
[[projects]] [[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap" name = "github.com/inconshreveable/mousetrap"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0" version = "v1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:14f2079ea27e7c67ecdab4f35e774463abc4f9d1806b5d674c0594b52127ab1d"
name = "github.com/jmhodges/levigo" name = "github.com/jmhodges/levigo"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:a64e323dc06b73892e5bb5d040ced475c4645d456038333883f58934abbf6f72"
name = "github.com/kr/logfmt" name = "github.com/kr/logfmt"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0"
[[projects]] [[projects]]
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
name = "github.com/pkg/errors" name = "github.com/pkg/errors"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "645ef00459ed84a119197bfb8d8205042c6df63d" revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0" version = "v0.8.0"
[[projects]] [[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" name = "github.com/rs/cors"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "ca016a06a5753f8ba03029c0aa5e54afb1bf713f" revision = "ca016a06a5753f8ba03029c0aa5e54afb1bf713f"
version = "v1.4.0" version = "v1.4.0"
[[projects]] [[projects]]
digest = "1:daab027a0bfb143afb503f7b63673bfa8d44f69ce9484c6d19b97957aadc1252"
name = "github.com/spf13/cobra" name = "github.com/spf13/cobra"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3" version = "v0.0.3"
[[projects]] [[projects]]
digest = "1:6de2f73eb31e80d74f84ce1c861e4c0c8f00ca5fb41a25901f987e63a0647c28"
name = "github.com/spf13/pflag" name = "github.com/spf13/pflag"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "583c0c0531f06d5278b7d917446061adc344b5cd" revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
version = "v1.0.1" 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]] [[projects]]
branch = "master" branch = "master"
digest = "1:9c39a878048f4a5468675b814fb7d2528d622f8c3612511ff0b5e2a48d451ad2"
name = "github.com/syndtr/goleveldb" name = "github.com/syndtr/goleveldb"
packages = [ packages = [
"leveldb", "leveldb",
@ -198,33 +260,41 @@
"leveldb/opt", "leveldb/opt",
"leveldb/storage", "leveldb/storage",
"leveldb/table", "leveldb/table",
"leveldb/util" "leveldb/util",
] ]
pruneopts = "T"
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445" revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:8403202d034640f399279a4f735faabefeb6ee64bbcb03c9c93be1d4c7230382"
name = "github.com/tendermint/ed25519" name = "github.com/tendermint/ed25519"
packages = [ packages = [
".", ".",
"edwards25519", "edwards25519",
"extra25519" "extra25519",
] ]
pruneopts = "T"
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
[[projects]] [[projects]]
digest = "1:4431caadcd2cc6a245bf0f6f61884029f5cc70833a8cc458cd1ba4a578b18c71"
name = "github.com/tendermint/go-amino" name = "github.com/tendermint/go-amino"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "2106ca61d91029c931fd54968c2bb02dc96b1412" revision = "2106ca61d91029c931fd54968c2bb02dc96b1412"
version = "0.10.1" version = "0.10.1"
[[projects]] [[projects]]
digest = "1:f11b64e85907d8909a820d0cd793dff19dc268432626411398aa0e26e8a61338"
name = "github.com/tendermint/iavl" name = "github.com/tendermint/iavl"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9" revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9"
version = "v0.9.2" version = "v0.9.2"
[[projects]] [[projects]]
digest = "1:f056bee4848f0fff6c92e6b99d4972b175d8a8eec9700df30b143b2e6cc48ea8"
name = "github.com/tendermint/tendermint" name = "github.com/tendermint/tendermint"
packages = [ packages = [
"abci/server", "abci/server",
@ -238,13 +308,15 @@
"libs/log", "libs/log",
"libs/pubsub", "libs/pubsub",
"libs/pubsub/query", "libs/pubsub/query",
"types" "types",
] ]
pruneopts = "T"
revision = "5ff65274b84ea905787a48512cc3124385bddf2f" revision = "5ff65274b84ea905787a48512cc3124385bddf2f"
version = "v0.22.2" version = "v0.22.2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:2c4971d2da7bb27fa225a119dc96af2119dd096869c1228438a0b5fda5f6fe15"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = [ packages = [
"internal/subtle", "internal/subtle",
@ -253,12 +325,14 @@
"openpgp/errors", "openpgp/errors",
"poly1305", "poly1305",
"ripemd160", "ripemd160",
"salsa20/salsa" "salsa20/salsa",
] ]
pruneopts = "T"
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:501f63fec0206818ab3dac086383bd2146841951c6bd6f3c4f72613f113f25fd"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
@ -268,11 +342,13 @@
"idna", "idna",
"internal/timeseries", "internal/timeseries",
"trace", "trace",
"websocket" "websocket",
] ]
pruneopts = "T"
revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0" revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0"
[[projects]] [[projects]]
digest = "1:24db346d9931fe01f1e9a02aba78ba22c1ecd55bf0f79dd10ba5169719cf002d"
name = "golang.org/x/text" name = "golang.org/x/text"
packages = [ packages = [
"collate", "collate",
@ -288,17 +364,21 @@
"unicode/bidi", "unicode/bidi",
"unicode/cldr", "unicode/cldr",
"unicode/norm", "unicode/norm",
"unicode/rangetable" "unicode/rangetable",
] ]
pruneopts = "T"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0" version = "v0.3.0"
[[projects]] [[projects]]
digest = "1:cfa1bbb9ee86ade0914bd5f8e8516386cf7d573957191ecb5163d8f6e023ca0c"
name = "google.golang.org/genproto" name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"] packages = ["googleapis/rpc/status"]
pruneopts = "T"
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
[[projects]] [[projects]]
digest = "1:1faab7c2380bc84698a62531c4af8c9475fbc7b3b1b2696f2f94feff97c47a49"
name = "google.golang.org/grpc" name = "google.golang.org/grpc"
packages = [ packages = [
".", ".",
@ -323,32 +403,61 @@
"stats", "stats",
"status", "status",
"tap", "tap",
"transport" "transport",
] ]
pruneopts = "T"
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
version = "v1.11.3" version = "v1.11.3"
[[projects]] [[projects]]
digest = "1:3ccd10c863188cfe0d936fcfe6a055c95362e43af8e7039e33baade846928e74"
name = "gopkg.in/fatih/set.v0" name = "gopkg.in/fatih/set.v0"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "57907de300222151a123d29255ed17f5ed43fad3" revision = "57907de300222151a123d29255ed17f5ed43fad3"
version = "v0.1.0" version = "v0.1.0"
[[projects]] [[projects]]
branch = "v2" branch = "v2"
digest = "1:35056a4c53d0b725735422545c3c11bdc9007da2fdb644fee96f3a6b7c42c69f"
name = "gopkg.in/karalabe/cookiejar.v2" name = "gopkg.in/karalabe/cookiejar.v2"
packages = ["collections/prque"] packages = ["collections/prque"]
pruneopts = "T"
revision = "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57" revision = "8dcd6a7f4951f6ff3ee9cbb919a06d8925822e57"
[[projects]] [[projects]]
branch = "v2" branch = "v2"
digest = "1:3d3f9391ab615be8655ae0d686a1564f3fec413979bb1aaf018bac1ec1bb1cc7"
name = "gopkg.in/natefinch/npipe.v2" name = "gopkg.in/natefinch/npipe.v2"
packages = ["."] packages = ["."]
pruneopts = "T"
revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6" revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 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-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -21,5 +21,9 @@
name = "github.com/tendermint/tendermint" name = "github.com/tendermint/tendermint"
version = "=0.22.2" version = "=0.22.2"
[[constraint]]
name = "github.com/stretchr/testify"
version = "=1.2.2"
[prune] [prune]
go-tests = true go-tests = true

View File

@ -20,26 +20,6 @@ DOCKER_IMAGE = tendermint/ethermint
ETHERMINT_DAEMON_BINARY = emintd ETHERMINT_DAEMON_BINARY = emintd
ETHERMINT_CLI_BINARY = emintcli 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 all: tools deps install
####################### #######################
@ -60,69 +40,93 @@ install:
go install $(BUILD_FLAGS) ./cmd/ethermintcli go install $(BUILD_FLAGS) ./cmd/ethermintcli
clean: clean:
rm -rf ./build ./vendor @rm -rf ./build ./vendor
update-tools: update-tools:
@echo "Updating golang dependencies" @echo "--> Updating golang dependencies"
go get -u -v $(DEP) $(GOLINT) $(GOMETALINTER) $(UNCONVERT) $(INEFFASSIGN) $(MISSPELL) $(ERRCHECK) $(UNPARAM) $(GOCYCLO) go get -u -v $(DEP) $(GOLINT) $(GOMETALINTER) $(UNCONVERT) $(INEFFASSIGN) $(MISSPELL) $(ERRCHECK) $(UNPARAM) $(GOCYCLO)
############################ ############################
### Tools / Dependencies ### ### 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: tools:
ifdef DEP_CHECK ifdef DEP_CHECK
@echo "Dep is already installed. Run 'make update-tools' to update." @echo "Dep is already installed. Run 'make update-tools' to update."
else else
@echo "Installing dep" @echo "--> Installing dep"
go get -v $(DEP) go get -v $(DEP)
endif endif
ifdef GOLINT_CHECK ifdef GOLINT_CHECK
@echo "Golint is already installed. Run 'make update-tools' to update." @echo "Golint is already installed. Run 'make update-tools' to update."
else else
@echo "Installing golint" @echo "--> Installing golint"
go get -v $(GOLINT) go get -v $(GOLINT)
endif endif
ifdef GOMETALINTER_CHECK ifdef GOMETALINTER_CHECK
@echo "Gometalinter.v2 is already installed. Run 'make update-tools' to update." @echo "Gometalinter.v2 is already installed. Run 'make update-tools' to update."
else else
@echo "Installing gometalinter.v2" @echo "--> Installing gometalinter.v2"
go get -v $(GOMETALINTER) go get -v $(GOMETALINTER)
endif endif
ifdef UNCONVERT_CHECK ifdef UNCONVERT_CHECK
@echo "Unconvert is already installed. Run 'make update-tools' to update." @echo "Unconvert is already installed. Run 'make update-tools' to update."
else else
@echo "Installing unconvert" @echo "--> Installing unconvert"
go get -v $(UNCONVERT) go get -v $(UNCONVERT)
endif endif
ifdef INEFFASSIGN_CHECK ifdef INEFFASSIGN_CHECK
@echo "Ineffassign is already installed. Run 'make update-tools' to update." @echo "Ineffassign is already installed. Run 'make update-tools' to update."
else else
@echo "Installing ineffassign" @echo "--> Installing ineffassign"
go get -v $(INEFFASSIGN) go get -v $(INEFFASSIGN)
endif endif
ifdef MISSPELL_CHECK ifdef MISSPELL_CHECK
@echo "misspell is already installed. Run 'make update-tools' to update." @echo "misspell is already installed. Run 'make update-tools' to update."
else else
@echo "Installing misspell" @echo "--> Installing misspell"
go get -v $(MISSPELL) go get -v $(MISSPELL)
endif endif
ifdef ERRCHECK_CHECK ifdef ERRCHECK_CHECK
@echo "errcheck is already installed. Run 'make update-tools' to update." @echo "errcheck is already installed. Run 'make update-tools' to update."
else else
@echo "Installing errcheck" @echo "--> Installing errcheck"
go get -v $(ERRCHECK) go get -v $(ERRCHECK)
endif endif
ifdef UNPARAM_CHECK ifdef UNPARAM_CHECK
@echo "unparam is already installed. Run 'make update-tools' to update." @echo "unparam is already installed. Run 'make update-tools' to update."
else else
@echo "Installing unparam" @echo "--> Installing unparam"
go get -v $(UNPARAM) go get -v $(UNPARAM)
endif endif
ifdef GOCYCLO_CHECK ifdef GOCYCLO_CHECK
@echo "goyclo is already installed. Run 'make update-tools' to update." @echo "goyclo is already installed. Run 'make update-tools' to update."
else else
@echo "Installing goyclo" @echo "--> Installing goyclo"
go get -v $(GOCYCLO) go get -v $(GOCYCLO)
endif endif
@ -135,6 +139,27 @@ deps:
### Testing / Misc. ### ### 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: godocs:
@echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/ethermint" @echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/ethermint"
godoc -http=:6060 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}:latest
docker tag ${DOCKER_IMAGE}:${DOCKER_TAG} ${DOCKER_IMAGE}:${COMMIT_HASH} 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

View File

@ -3,8 +3,8 @@ package core
import ( import (
"math/big" "math/big"
ethcommon "github.com/ethereum/go-ethereum/common" ethcmn "github.com/ethereum/go-ethereum/common"
ethconsensus "github.com/ethereum/go-ethereum/consensus" ethcons "github.com/ethereum/go-ethereum/consensus"
ethstate "github.com/ethereum/go-ethereum/core/state" ethstate "github.com/ethereum/go-ethereum/core/state"
ethtypes "github.com/ethereum/go-ethereum/core/types" ethtypes "github.com/ethereum/go-ethereum/core/types"
ethrpc "github.com/ethereum/go-ethereum/rpc" ethrpc "github.com/ethereum/go-ethereum/rpc"
@ -20,7 +20,7 @@ import (
// NOTE: Ethermint will distribute the fees out to validators, so the structure // NOTE: Ethermint will distribute the fees out to validators, so the structure
// and functionality of this is a WIP and subject to change. // and functionality of this is a WIP and subject to change.
type ChainContext struct { type ChainContext struct {
Coinbase ethcommon.Address Coinbase ethcmn.Address
headersByNumber map[uint64]*ethtypes.Header headersByNumber map[uint64]*ethtypes.Header
} }
@ -32,23 +32,25 @@ func NewChainContext() *ChainContext {
// Engine implements Ethereum's core.ChainContext interface. As a ChainContext // Engine implements Ethereum's core.ChainContext interface. As a ChainContext
// implements the consensus.Engine interface, it is simply returned. // implements the consensus.Engine interface, it is simply returned.
func (cc *ChainContext) Engine() ethconsensus.Engine { func (cc *ChainContext) Engine() ethcons.Engine {
return cc 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) { func (cc *ChainContext) SetHeader(number uint64, header *ethtypes.Header) {
cc.headersByNumber[number] = header cc.headersByNumber[number] = header
} }
// GetHeader implements Ethereum's core.ChainContext interface. It currently // GetHeader implements Ethereum's core.ChainContext interface.
// performs a no-op.
// //
// TODO: The Cosmos SDK supports retreiving such information in contexts and // TODO: The Cosmos SDK supports retreiving such information in contexts and
// multi-store, so this will be need to be integrated. // 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 { if header, ok := cc.headersByNumber[number]; ok {
return header return header
} }
return nil 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 // NOTE: Ethermint will distribute the fees out to validators, so the structure
// and functionality of this is a WIP and subject to change. // 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 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 // TODO: Do we need to support such RPC APIs? This will tie into a bigger
// discussion on if we want to support web3. // 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 return nil
} }
// CalcDifficulty implements Ethereum's core.ChainContext interface. It // CalcDifficulty implements Ethereum's core.ChainContext interface. It
// currently performs a no-op. // 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 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? // TODO: Figure out if this needs to be hooked up to any part of the ABCI?
func (cc *ChainContext) Finalize( func (cc *ChainContext) Finalize(
_ ethconsensus.ChainReader, _ *ethtypes.Header, _ *ethstate.StateDB, _ ethcons.ChainReader, _ *ethtypes.Header, _ *ethstate.StateDB,
_ []*ethtypes.Transaction, _ []*ethtypes.Header, _ []*ethtypes.Receipt, _ []*ethtypes.Transaction, _ []*ethtypes.Header, _ []*ethtypes.Receipt,
) (*ethtypes.Block, error) { ) (*ethtypes.Block, error) {
return nil, nil return nil, nil
@ -92,7 +94,7 @@ func (cc *ChainContext) Finalize(
// performs a no-op. // performs a no-op.
// //
// TODO: Figure out if this needs to be hooked up to any part of the ABCI? // 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 return nil
} }
@ -100,7 +102,7 @@ func (cc *ChainContext) Prepare(_ ethconsensus.ChainReader, _ *ethtypes.Header)
// performs a no-op. // performs a no-op.
// //
// TODO: Figure out if this needs to be hooked up to any part of the ABCI? // 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 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 // TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
// handlers? // handlers?
func (cc *ChainContext) VerifyHeader(_ ethconsensus.ChainReader, _ *ethtypes.Header, _ bool) error { func (cc *ChainContext) VerifyHeader(_ ethcons.ChainReader, _ *ethtypes.Header, _ bool) error {
return nil 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 // TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
// handlers? // 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 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 // TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
// handlers? // handlers?
func (cc *ChainContext) VerifySeal(_ ethconsensus.ChainReader, _ *ethtypes.Header) error { func (cc *ChainContext) VerifySeal(_ ethcons.ChainReader, _ *ethtypes.Header) error {
return nil return nil
} }
// VerifyUncles implements Ethereum's core.ChainContext interface. It currently // VerifyUncles implements Ethereum's core.ChainContext interface. It currently
// performs a no-op. // performs a no-op.
func (cc *ChainContext) VerifyUncles(_ ethconsensus.ChainReader, _ *ethtypes.Block) error { func (cc *ChainContext) VerifyUncles(_ ethcons.ChainReader, _ *ethtypes.Block) error {
return nil return nil
} }

121
core/chain_test.go Normal file
View 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 := &ethtypes.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 := &ethtypes.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
View 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
View 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
}

View File

@ -6,7 +6,7 @@ import (
"github.com/cosmos/ethermint/core" "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" ethstate "github.com/ethereum/go-ethereum/core/state"
ethtrie "github.com/ethereum/go-ethereum/trie" 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 // CONTRACT: The root parameter is not interpreted as a state root hash, but as
// an encoding of an Cosmos SDK IAVL tree version. // an encoding of an Cosmos SDK IAVL tree version.
func (db *Database) OpenTrie(root ethcommon.Hash) (ethstate.Trie, error) { func (db *Database) OpenTrie(root ethcmn.Hash) (ethstate.Trie, error) {
version := db.stateStore.LastCommitID().Version
if !isRootEmpty(root) { if !isRootEmpty(root) {
version = versionFromRootHash(root) version := versionFromRootHash(root)
if db.stateStore.LastCommitID().Version != version { if db.stateStore.LastCommitID().Version != version {
if err := db.stateStore.LoadVersion(version); err != nil { 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 // CONTRACT: The root parameter is not interpreted as a state root hash, but as
// an encoding of an IAVL tree version. // 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 // a contract storage trie does not need an accountCache, storageCache or
// an Ethereum trie because it will not be used upon commitment. // an Ethereum trie because it will not be used upon commitment.
return &Trie{ return &Trie{
@ -175,17 +173,20 @@ func (db *Database) CopyTrie(ethstate.Trie) ethstate.Trie {
// ContractCode implements Ethereum's state.Database interface. It will return // 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. // 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[:]) 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 return code, nil
} }
// ContractCodeSize implements Ethereum's state.Database interface. It will // ContractCodeSize implements Ethereum's state.Database interface. It will
// return the contract byte code size for a given code hash. It will not return // return the contract byte code size for a given code hash. It will not return
// an error. // 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 { if cached, ok := db.codeSizeCache.Get(codeHash); ok {
return cached.(int), nil 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. // isRootEmpty returns true if a given root hash is empty or false otherwise.
func isRootEmpty(root ethcommon.Hash) bool { func isRootEmpty(root ethcmn.Hash) bool {
return root == ethcommon.Hash{} return root == ethcmn.Hash{}
} }

132
state/database_test.go Normal file
View 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
View 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())
}

View File

@ -5,7 +5,7 @@ import (
"github.com/cosmos/cosmos-sdk/store" "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" ethdb "github.com/ethereum/go-ethereum/ethdb"
ethtrie "github.com/ethereum/go-ethereum/trie" ethtrie "github.com/ethereum/go-ethereum/trie"
) )
@ -39,7 +39,7 @@ type Trie struct {
empty bool empty bool
// root is the encoding of an IAVL tree root (version) // root is the encoding of an IAVL tree root (version)
root ethcommon.Hash root ethcmn.Hash
ethTrieDB *ethtrie.Database 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 // for key stored in the trie. The value bytes must not be modified by the
// caller. // caller.
func (t *Trie) TryGet(key []byte) ([]byte, error) { func (t *Trie) TryGet(key []byte) ([]byte, error) {
if t.prefix != nil { if t.IsStorageTrie() {
key = t.prefixKey(key) key = t.prefixKey(key)
} }
@ -78,7 +78,7 @@ func (t *Trie) TryGet(key []byte) ([]byte, error) {
func (t *Trie) TryUpdate(key, value []byte) error { func (t *Trie) TryUpdate(key, value []byte) error {
t.empty = false t.empty = false
if t.prefix != nil { if t.IsStorageTrie() {
key = t.prefixKey(key) 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 // the IAVL tree. Since a CacheKVStore is used as the storage type, the keys
// will be sorted giving us a deterministic ordering. // will be sorted giving us a deterministic ordering.
func (t *Trie) TryDelete(key []byte) error { func (t *Trie) TryDelete(key []byte) error {
if t.prefix != nil { if t.IsStorageTrie() {
key = t.prefixKey(key) 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 // CONTRACT: The root is an encoded IAVL tree version and each new commitment
// increments the version by one. // 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 { if t.empty {
return ethcommon.Hash{}, nil return ethcmn.Hash{}, nil
} }
newRoot := rootHashFromVersion(versionFromRootHash(t.root) + 1) newRoot := rootHashFromVersion(versionFromRootHash(t.root) + 1)
if t.prefix == nil { if !t.IsStorageTrie() {
if t.accountsCache != nil { if t.accountsCache != nil {
t.accountsCache.Write() t.accountsCache.Write()
t.accountsCache = nil t.accountsCache = nil
@ -133,7 +133,7 @@ func (t *Trie) Commit(_ ethtrie.LeafCallback) (ethcommon.Hash, error) {
// persist the mappings of codeHash => code // persist the mappings of codeHash => code
for _, n := range t.ethTrieDB.Nodes() { for _, n := range t.ethTrieDB.Nodes() {
if err := t.ethTrieDB.Commit(n, false); err != nil { 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. // of the Trie which is an encoding of the underlying IAVL tree.
// //
// CONTRACT: The root is an encoded IAVL tree version. // CONTRACT: The root is an encoded IAVL tree version.
func (t *Trie) Hash() ethcommon.Hash { func (t *Trie) Hash() ethcmn.Hash {
return t.root return t.root
} }
@ -175,17 +175,23 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDB ethdb.Putter) error {
return nil 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 // versionFromRootHash returns a Cosmos SDK IAVL version from an Ethereum state
// root hash. // root hash.
// //
// CONTRACT: The encoded version is the eight MSB bytes of the 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])) return int64(binary.BigEndian.Uint64(root[:versionLen]))
} }
// rootHashFromVersion returns a state root hash from a Cosmos SDK IAVL // rootHashFromVersion returns a state root hash from a Cosmos SDK IAVL
// version. // version.
func rootHashFromVersion(version int64) (root ethcommon.Hash) { func rootHashFromVersion(version int64) (root ethcmn.Hash) {
binary.BigEndian.PutUint64(root[:versionLen], uint64(version)) binary.BigEndian.PutUint64(root[:versionLen], uint64(version))
return return
} }

259
state/trie_test.go Normal file
View 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()
}

View File

@ -40,6 +40,7 @@ type Importer struct {
// Import performs an import given an Importer that has a Geth stateDB // Import performs an import given an Importer that has a Geth stateDB
// implementation and a blockchain exported file. // implementation and a blockchain exported file.
// nolint
func (imp *Importer) Import() { func (imp *Importer) Import() {
// only create genesis if it is a brand new database // only create genesis if it is a brand new database
if imp.EthermintDB.LatestVersion() == 0 { if imp.EthermintDB.LatestVersion() == 0 {