From 8ec7edf5bdb619231c8f4f17fda5bc29b4c88237 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 23 Apr 2020 11:49:25 -0400 Subject: [PATCH] x/evm: unit tests and fixes (#223) * evm: move Keeper and Querier to /keeper package * keeper: update keeper_test.go * fix format * evm: use aliased types * bump SDK version to v0.38.1 * app: updates from new version * errors: switch sdk.Error -> error * errors: switch sdk.Error -> error. Continuation * more fixes * update app/ * update keys and client pkgs * build * fix tests * lint * minor changes * changelog * address @austinbell comments * Fix keyring usage in rpc API and CLI * fix keyring * break line * Misc cleanup (#188) * evm: move Begin and EndBlock to abci.go * evm: use expected keeper interfaces * app: use EthermintApp for integration and unit test setup * evm: remove count type; update codec * go mod verify * evm: rename msgs for consistency * evm: events * minor cleanup * lint * ante: update tests * changelog * nolint * evm: update statedb to create ethermint Account instead of BaseAccount * fix importer test * address @austinabell comments * update README * changelog * evm: update codec * rename GasLimit->Gas and Price ->GasPrice * msg cleanup and tests * cleanup TxData * fix marshaling * revert rename * move types * evm/keeper: querier tests * switch MarshalLengthPrefixed -> BinaryBare; remove panics * fix event sender * fix panic * try fix txDecoder error * evm: handler tests * evm: handler MsgEthermint test * fix tests * store logs in keeper after transition (#210) * add some comments * begin log handler test * update TransitionCSDB to return ReturnData * use rlp for result data encode/decode * update tests * implement SetBlockLogs * implement GetBlockLogs * test log set/get * update keeper get/set logs to use hash as key * fix test * move logsKey to csdb * attempt to fix test * attempt to fix test * attempt to fix test * lint * lint * lint * save logs after handling msg * update k.Logs * cleanup * remove unused * fix issues * comment out handler test * address comments * lint * fix handler test * address comments * use amino * lint * address comments * merge * fix encoding bug * minor fix * rpc: error handling * rpc: simulate only returns gasConsumed * rpc: error ineffassign * evm: handler test * go: bump version to 1.14 and SDK version to latest master * rpc: fix simulation return value * breaking changes from SDK * sdk: breaking changes; build * tests: fixes * minor fix * proto: ethermint types attempt * proto: define EthAccount proto type and extend sdk std.Codec * evm: fix panic on handler test * evm: minor state object changes * cleanup * tests: update test-importer * fix evm test * fix pubkey registration * lint * cleanup * more test checks for importer * minor change * codec fixes * rm init func * fix importer test build * fixes * test fixes * fix bloom key * rm unnecesary func * remove comment Co-authored-by: austinabell Co-authored-by: noot <36753753+noot@users.noreply.github.com> --- app/ante/ante_test.go | 23 +- app/ante/utils_test.go | 14 +- codec/codec.proto | 2 +- go.sum | 56 ----- rpc/eth_api.go | 4 +- .../proto/tendermint/abci/types/types.proto | 12 +- utils/int.go | 25 +- utils/int_test.go | 18 ++ x/evm/abci.go | 9 +- x/evm/handler.go | 11 +- x/evm/handler_test.go | 159 ++++++++++++- x/evm/keeper/keeper.go | 55 ++--- x/evm/keeper/keeper_test.go | 20 +- x/evm/keeper/querier.go | 21 +- x/evm/keeper/querier_test.go | 52 +++++ x/evm/types/codec.go | 2 +- x/evm/types/emint_msg.go | 88 ------- x/evm/types/emint_msg_test.go | 76 ------ x/evm/types/genesis_test.go | 45 ++++ x/evm/types/msg.go | 216 +++++++++--------- x/evm/types/msg_test.go | 176 +++++++------- x/evm/types/{msg_encoding.go => tx_data.go} | 93 +++++--- x/evm/types/tx_data_test.go | 56 +++++ x/evm/types/utils.go | 67 ++++++ 24 files changed, 780 insertions(+), 520 deletions(-) create mode 100644 utils/int_test.go create mode 100644 x/evm/keeper/querier_test.go delete mode 100644 x/evm/types/emint_msg.go delete mode 100644 x/evm/types/emint_msg_test.go create mode 100644 x/evm/types/genesis_test.go rename x/evm/types/{msg_encoding.go => tx_data.go} (56%) create mode 100644 x/evm/types/tx_data_test.go diff --git a/app/ante/ante_test.go b/app/ante/ante_test.go index 2e918342..db5f9ff1 100644 --- a/app/ante/ante_test.go +++ b/app/ante/ante_test.go @@ -57,7 +57,8 @@ func (suite *AnteTestSuite) TestValidEthTx() { gas := big.NewInt(20) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 34910, gas, []byte("test")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) requireValidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false) } @@ -183,7 +184,9 @@ func (suite *AnteTestSuite) TestEthInvalidSig() { gas := big.NewInt(20) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) + ctx := suite.ctx.WithChainID("4") requireInvalidTx(suite.T(), suite.anteHandler, ctx, tx, false) } @@ -208,7 +211,8 @@ func (suite *AnteTestSuite) TestEthInvalidNonce() { gas := big.NewInt(20) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false) } @@ -227,7 +231,8 @@ func (suite *AnteTestSuite) TestEthInsufficientBalance() { gas := big.NewInt(20) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false) } @@ -249,7 +254,8 @@ func (suite *AnteTestSuite) TestEthInvalidIntrinsicGas() { gasLimit := uint64(1000) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, gasLimit, gas, []byte("test")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false) } @@ -274,7 +280,8 @@ func (suite *AnteTestSuite) TestEthInvalidMempoolFees() { gas := big.NewInt(20) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("payload")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false) } @@ -295,7 +302,9 @@ func (suite *AnteTestSuite) TestEthInvalidChainID() { gas := big.NewInt(20) ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test")) - tx := newTestEthTx(suite.ctx, ethMsg, priv1) + tx, err := newTestEthTx(suite.ctx, ethMsg, priv1) + suite.Require().NoError(err) + ctx := suite.ctx.WithChainID("bad-chain-id") requireInvalidTx(suite.T(), suite.anteHandler, ctx, tx, false) } diff --git a/app/ante/utils_test.go b/app/ante/utils_test.go index fa6deb91..8f4efec3 100644 --- a/app/ante/utils_test.go +++ b/app/ante/utils_test.go @@ -88,17 +88,21 @@ func newTestSDKTx( return auth.NewStdTx(msgs, fee, sigs, "") } -func newTestEthTx(ctx sdk.Context, msg evmtypes.MsgEthereumTx, priv tmcrypto.PrivKey) sdk.Tx { +func newTestEthTx(ctx sdk.Context, msg evmtypes.MsgEthereumTx, priv tmcrypto.PrivKey) (sdk.Tx, error) { chainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) if !ok { - panic(fmt.Sprintf("invalid chainID: %s", ctx.ChainID())) + return nil, fmt.Errorf("invalid chainID: %s", ctx.ChainID()) } privkey, ok := priv.(crypto.PrivKeySecp256k1) if !ok { - panic(fmt.Sprintf("invalid private key type: %T", priv)) + return nil, fmt.Errorf("invalid private key type: %T", priv) } - msg.Sign(chainID, privkey.ToECDSA()) - return msg + err := msg.Sign(chainID, privkey.ToECDSA()) + if err != nil { + return nil, err + } + + return msg, nil } diff --git a/codec/codec.proto b/codec/codec.proto index 1772da1a..ef979be5 100644 --- a/codec/codec.proto +++ b/codec/codec.proto @@ -22,4 +22,4 @@ message Account { cosmos_sdk.x.supply.v1.ModuleAccount module_account = 5; ethermint.v1.EthAccount eth_account = 6; } -} \ No newline at end of file +} diff --git a/go.sum b/go.sum index dbb9c52a..70624b99 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/99designs/keyring v1.1.4 h1:x0g0zQ9bQKgNsLo0XSXAy1H8Q1RG/td+5OXJt+Ci8b8= github.com/99designs/keyring v1.1.4/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw= github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= @@ -11,7 +10,6 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.26.1/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= @@ -58,7 +56,6 @@ github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46f github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= @@ -81,14 +78,11 @@ github.com/cosmos/cosmos-sdk v0.34.4-0.20200403200637-7f78e61b93a5 h1:Up28KmvitV github.com/cosmos/cosmos-sdk v0.34.4-0.20200403200637-7f78e61b93a5/go.mod h1:J2RTB23kBgFKwtKd7J/gk4WwG363cA/xM0GU1Gfztw4= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= -github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= -github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -105,7 +99,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/gosigar v0.10.3 h1:xA7TJmJgaVgqEnQpYAijMI4J9V1ZM2a9z8+5gAc5FMs= github.com/elastic/gosigar v0.10.3/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= @@ -117,16 +110,11 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/go-ethereum v1.9.0 h1:9Kaf7UfDkV3aIUJlf14hI/GgEgRAUq60u4fBlb9dLWw= github.com/ethereum/go-ethereum v1.9.0/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= -github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= -github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= -github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c= github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= @@ -134,7 +122,6 @@ github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03D github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff h1:tY80oXqGNY4FhTFhk+o9oFHGINQ/+vhlm8HFzi6znCI= github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gibson042/canonicaljson-go v1.0.3 h1:EAyF8L74AWabkyUmrvEFHEt/AGFQeD6RfwbAuf0j1bI= @@ -150,7 +137,6 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -163,7 +149,6 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= @@ -185,15 +170,12 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= @@ -211,7 +193,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM1FuF+3Ad3YIbgirjdMiVA0eUkaM= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s= @@ -242,21 +223,16 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo= github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA= github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -264,10 +240,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karalabe/usb v0.0.0-20190703133951-9be757f914c0 h1:S8kWZLXHpcOq3nGAvIs0oDgd4CXxkxE3hkDVRjTu7ro= github.com/karalabe/usb v0.0.0-20190703133951-9be757f914c0/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= @@ -281,12 +255,9 @@ github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= @@ -298,7 +269,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= @@ -344,11 +314,9 @@ github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXW github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/openconfig/gnmi v0.0.0-20190823184014-89b2bf29312c/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc= @@ -361,13 +329,10 @@ github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxS github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/otiai10/copy v1.1.1 h1:PH7IFlRQ6Fv9vYmuXbDRLdgTHoP1w483kPNUP2bskpo= github.com/otiai10/copy v1.1.1/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= -github.com/otiai10/mint v1.3.1 h1:BCmzIS3n71sGfHB5NMNDB3lHYPz8fWSkCAErHed//qc= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -414,7 +379,6 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.10 h1:QJQN3jYQhkamO4mhfUWqdDH2asK7ONOI9MTWjyAxNKM= github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= @@ -442,9 +406,7 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -468,11 +430,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs= github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= -github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48 h1:ju5UTwk5Odtm4trrY+4Ca4RMj5OyXbmVeDAVad2T0Jw= github.com/status-im/keycard-go v0.0.0-20190424133014-d95853db0f48/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE= github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= @@ -483,7 +443,6 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3 github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -494,7 +453,6 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= -github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= @@ -507,7 +465,6 @@ github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk= github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA= -github.com/tendermint/tendermint v0.33.2 h1:NzvRMTuXJxqSsFed2J7uHmMU5N1CVzSpfi3nCc882KY= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= github.com/tendermint/tendermint v0.33.3 h1:6lMqjEoCGejCzAghbvfQgmw87snGSqEhDTo/jw+W8CI= github.com/tendermint/tendermint v0.33.3/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk= @@ -518,12 +475,10 @@ github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpX github.com/tjfoc/gmsm v1.3.0/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tyler-smith/go-bip39 v1.0.0 h1:FOHg9gaQLeBBRbHE/QrTLfEiBHy5pQ/yXzf9JG5pYFM= github.com/tyler-smith/go-bip39 v1.0.0/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 h1:1cngl9mPEoITZG8s8cVcUy5CeIBYhEESkOB7m6Gmkrk= github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= @@ -531,10 +486,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= -github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -555,7 +508,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -619,7 +571,6 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ= golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -648,7 +599,6 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -659,7 +609,6 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5 h1:jB9+PJSvu5tBfmJHy/OVapFdjDF3WvpkqRhxqrmzoEU= google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -687,11 +636,9 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= @@ -701,13 +648,10 @@ gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eR gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/redis.v4 v4.2.4/go.mod h1:8KREHdypkCEojGKQcjMqAODMICIVwZAONWq8RowTITA= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0= gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= diff --git a/rpc/eth_api.go b/rpc/eth_api.go index 95dfdb7e..000d87e4 100644 --- a/rpc/eth_api.go +++ b/rpc/eth_api.go @@ -290,7 +290,9 @@ func (e *PublicEthAPI) SendTransaction(args params.SendTxArgs) (common.Hash, err } // Sign transaction - tx.Sign(intChainID, e.key.ToECDSA()) + if err := tx.Sign(intChainID, e.key.ToECDSA()); err != nil { + return common.Hash{}, err + } // Encode transaction by default Tx encoder txEncoder := authclient.GetTxEncoder(e.cliCtx.Codec) diff --git a/third_party/proto/tendermint/abci/types/types.proto b/third_party/proto/tendermint/abci/types/types.proto index 9280e5a7..7fb4b1bd 100644 --- a/third_party/proto/tendermint/abci/types/types.proto +++ b/third_party/proto/tendermint/abci/types/types.proto @@ -61,8 +61,8 @@ message RequestSetOption { } message RequestInitChain { - google.protobuf.Timestamp time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - string chain_id = 2; + google.protobuf.Timestamp time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + string chain_id = 2; ConsensusParams consensus_params = 3; repeated ValidatorUpdate validators = 4 [(gogoproto.nullable) = false]; bytes app_state_bytes = 5; @@ -321,10 +321,10 @@ message PubKey { } message Evidence { - string type = 1; - Validator validator = 2 [(gogoproto.nullable) = false]; - int64 height = 3; - google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + string type = 1; + Validator validator = 2 [(gogoproto.nullable) = false]; + int64 height = 3; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; int64 total_voting_power = 5; } diff --git a/utils/int.go b/utils/int.go index c059bc8b..5a493e59 100644 --- a/utils/int.go +++ b/utils/int.go @@ -3,25 +3,38 @@ package utils import "math/big" // MarshalBigInt marshalls big int into text string for consistent encoding -func MarshalBigInt(i *big.Int) string { +func MarshalBigInt(i *big.Int) (string, error) { bz, err := i.MarshalText() + if err != nil { + return "", err + } + return string(bz), nil +} + +// MustMarshalBigInt marshalls big int into text string for consistent encoding. +// It panics if an error is encountered. +func MustMarshalBigInt(i *big.Int) string { + str, err := MarshalBigInt(i) if err != nil { panic(err) } - return string(bz) + return str } // UnmarshalBigInt unmarshalls string from *big.Int func UnmarshalBigInt(s string) (*big.Int, error) { ret := new(big.Int) err := ret.UnmarshalText([]byte(s)) - return ret, err + if err != nil { + return nil, err + } + return ret, nil } -// MustUnmarshalBigInt unmarshalls string from *big.Int +// MustUnmarshalBigInt unmarshalls string from *big.Int. +// It panics if an error is encountered. func MustUnmarshalBigInt(s string) *big.Int { - ret := new(big.Int) - err := ret.UnmarshalText([]byte(s)) + ret, err := UnmarshalBigInt(s) if err != nil { panic(err) } diff --git a/utils/int_test.go b/utils/int_test.go new file mode 100644 index 00000000..263d0802 --- /dev/null +++ b/utils/int_test.go @@ -0,0 +1,18 @@ +package utils + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMarshalAndUnmarshalInt(t *testing.T) { + i := big.NewInt(3) + m, err := MarshalBigInt(i) + require.NoError(t, err) + + i2, err := UnmarshalBigInt(m) + require.NoError(t, err) + require.Equal(t, i, i2) +} diff --git a/x/evm/abci.go b/x/evm/abci.go index daf8d91b..6aac78ea 100644 --- a/x/evm/abci.go +++ b/x/evm/abci.go @@ -13,12 +13,13 @@ import ( // BeginBlock sets the Bloom and Hash mappings and resets the Bloom filter and // the transaction count to 0. func BeginBlock(k Keeper, ctx sdk.Context, req abci.RequestBeginBlock) { + if req.Header.LastBlockId.GetHash() == nil || req.Header.GetHeight() < 1 { + return + } + // Consider removing this when using evm as module without web3 API bloom := ethtypes.BytesToBloom(k.Bloom.Bytes()) - err := k.SetBlockBloomMapping(ctx, bloom, req.Header.GetHeight()-1) - if err != nil { - panic(err) - } + k.SetBlockBloomMapping(ctx, bloom, req.Header.GetHeight()-1) k.SetBlockHashMapping(ctx, req.Header.LastBlockId.GetHash(), req.Header.GetHeight()-1) k.Bloom = big.NewInt(0) k.TxCount = 0 diff --git a/x/evm/handler.go b/x/evm/handler.go index 5fff95af..617448be 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -19,17 +19,17 @@ func NewHandler(k Keeper) sdk.Handler { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { case types.MsgEthereumTx: - return HandleMsgEthereumTx(ctx, k, msg) + return handleMsgEthereumTx(ctx, k, msg) case types.MsgEthermint: - return HandleMsgEthermint(ctx, k, msg) + return handleMsgEthermint(ctx, k, msg) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } } } -// HandleMsgEthereumTx handles an Ethereum specific tx -func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) { +// handleMsgEthereumTx handles an Ethereum specific tx +func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) { // parse the chainID from a string to a base-10 integer intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) if !ok { @@ -105,7 +105,8 @@ func HandleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s return returnData.Result, nil } -func HandleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk.Result, error) { +// handleMsgEthermint handles an sdk.StdTx for an Ethereum state transition +func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk.Result, error) { // parse the chainID from a string to a base-10 integer intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10) if !ok { diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 02e80941..181fe5eb 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -8,18 +8,20 @@ import ( "github.com/stretchr/testify/suite" + "github.com/ethereum/go-ethereum/common" + ethcmn "github.com/ethereum/go-ethereum/common" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/cosmos/ethermint/app" + "github.com/cosmos/ethermint/crypto" "github.com/cosmos/ethermint/x/evm" "github.com/cosmos/ethermint/x/evm/keeper" "github.com/cosmos/ethermint/x/evm/types" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/secp256k1" ) type EvmTestSuite struct { @@ -46,7 +48,150 @@ func TestEvmTestSuite(t *testing.T) { suite.Run(t, new(EvmTestSuite)) } -func (suite *EvmTestSuite) TestHandler_Logs() { +func (suite *EvmTestSuite) TestHandleMsgEthereumTx() { + privkey, err := crypto.GenerateKey() + suite.Require().NoError(err) + sender := ethcmn.HexToAddress(privkey.PubKey().Address().String()) + + var ( + tx types.MsgEthereumTx + chainID *big.Int + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "passed", + func() { + suite.app.EvmKeeper.SetBalance(suite.ctx, sender, big.NewInt(100)) + tx = types.NewMsgEthereumTx(0, &sender, big.NewInt(100), 0, big.NewInt(10000), nil) + + // parse context chain ID to big.Int + var ok bool + chainID, ok = new(big.Int).SetString(suite.ctx.ChainID(), 10) + suite.Require().True(ok) + + // sign transaction + err = tx.Sign(chainID, privkey.ToECDSA()) + suite.Require().NoError(err) + }, + true, + }, + { + "insufficient balance", + func() { + tx = types.NewMsgEthereumTxContract(0, big.NewInt(100), 0, big.NewInt(10000), nil) + + // parse context chain ID to big.Int + var ok bool + chainID, ok = new(big.Int).SetString(suite.ctx.ChainID(), 10) + suite.Require().True(ok) + + // sign transaction + err = tx.Sign(chainID, privkey.ToECDSA()) + suite.Require().NoError(err) + }, + false, + }, + { + "tx encoding failed", + func() { + tx = types.NewMsgEthereumTxContract(0, big.NewInt(100), 0, big.NewInt(10000), nil) + }, + false, + }, + { + "invalid chain ID", + func() { + suite.ctx = suite.ctx.WithChainID("chainID") + }, + false, + }, + { + "VerifySig failed", + func() { + tx = types.NewMsgEthereumTxContract(0, big.NewInt(100), 0, big.NewInt(10000), nil) + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run("", func() { + suite.SetupTest() // reset + tc.malleate() + + res, err := suite.handler(suite.ctx, tx) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + }) + } +} + +func (suite *EvmTestSuite) TestMsgEthermint() { + var ( + tx types.MsgEthermint + from = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + to = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()) + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "passed", + func() { + tx = types.NewMsgEthermint(0, &to, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), from) + suite.app.EvmKeeper.SetBalance(suite.ctx, ethcmn.BytesToAddress(from.Bytes()), big.NewInt(100)) + }, + true, + }, + { + "invalid state transition", + func() { + tx = types.NewMsgEthermint(0, &to, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), from) + }, + false, + }, + { + "invalid chain ID", + func() { + suite.ctx = suite.ctx.WithChainID("chainID") + }, + false, + }, + } + + for _, tc := range testCases { + suite.Run("", func() { + suite.SetupTest() // reset + tc.malleate() + + res, err := suite.handler(suite.ctx, tx) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(res) + } else { + suite.Require().Error(err) + suite.Require().Nil(res) + } + }) + } +} + +func (suite *EvmTestSuite) TestHandlerLogs() { // Test contract: // pragma solidity ^0.5.1; @@ -74,7 +219,8 @@ func (suite *EvmTestSuite) TestHandler_Logs() { bytecode := common.FromHex("0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029") tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode) - tx.Sign(big.NewInt(3), priv) + err = tx.Sign(big.NewInt(3), priv.ToECDSA()) + suite.Require().NoError(err) result, err := suite.handler(suite.ctx, tx) suite.Require().NoError(err, "failed to handle eth tx msg") @@ -105,7 +251,8 @@ func (suite *EvmTestSuite) TestQueryTxLogs() { // send contract deployment transaction with an event in the constructor bytecode := common.FromHex("0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029") tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode) - tx.Sign(big.NewInt(3), priv) + err = tx.Sign(big.NewInt(3), priv.ToECDSA()) + suite.Require().NoError(err) // result, err := evm.HandleEthTxMsg(suite.ctx, suite.app.EvmKeeper, tx) // suite.Require().NoError(err, "failed to handle eth tx msg") diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 0208e22d..ac12c15d 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -1,7 +1,6 @@ package keeper import ( - "bytes" "encoding/binary" "errors" "fmt" @@ -50,25 +49,23 @@ func NewKeeper( // May be removed when using only as module (only required by rpc api) // ---------------------------------------------------------------------------- -// SetBlockHashMapping sets the mapping from block consensus hash to block height -func (k *Keeper) SetBlockHashMapping(ctx sdk.Context, hash []byte, height int64) { - store := ctx.KVStore(k.blockKey) - if !bytes.Equal(hash, []byte{}) { - bz := sdk.Uint64ToBigEndian(uint64(height)) - store.Set(hash, bz) - } -} - // GetBlockHashMapping gets block height from block consensus hash -func (k *Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (height int64) { +func (k Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (int64, error) { store := ctx.KVStore(k.blockKey) bz := store.Get(hash) - if bytes.Equal(bz, []byte{}) { - panic(fmt.Errorf("block with hash %s not found", ethcmn.BytesToHash(hash))) + if len(bz) == 0 { + return 0, fmt.Errorf("block with hash '%s' not found", ethcmn.BytesToHash(hash)) } - height = int64(binary.BigEndian.Uint64(bz)) - return height + height := binary.BigEndian.Uint64(bz) + return int64(height), nil +} + +// SetBlockHashMapping sets the mapping from block consensus hash to block height +func (k Keeper) SetBlockHashMapping(ctx sdk.Context, hash []byte, height int64) { + store := ctx.KVStore(k.blockKey) + bz := sdk.Uint64ToBigEndian(uint64(height)) + store.Set(hash, bz) } // ---------------------------------------------------------------------------- @@ -76,28 +73,23 @@ func (k *Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (height int64 // May be removed when using only as module (only required by rpc api) // ---------------------------------------------------------------------------- -// SetBlockBloomMapping sets the mapping from block height to bloom bits -func (k *Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, height int64) error { +// GetBlockBloomMapping gets bloombits from block height +func (k Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) (ethtypes.Bloom, error) { store := ctx.KVStore(k.blockKey) - bz := sdk.Uint64ToBigEndian(uint64(height)) + heightBz := sdk.Uint64ToBigEndian(uint64(height)) + bz := store.Get(types.BloomKey(heightBz)) if len(bz) == 0 { - return fmt.Errorf("block with bloombits %v not found", bloom) + return ethtypes.Bloom{}, fmt.Errorf("block at height %d not found", height) } - store.Set(types.BloomKey(bz), bloom.Bytes()) - return nil + return ethtypes.BytesToBloom(bz), nil } -// GetBlockBloomMapping gets bloombits from block height -func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) (ethtypes.Bloom, error) { +// SetBlockBloomMapping sets the mapping from block height to bloom bits +func (k Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, height int64) { store := ctx.KVStore(k.blockKey) - bz := sdk.Uint64ToBigEndian(uint64(height)) - if len(bz) == 0 { - return ethtypes.BytesToBloom([]byte{}), fmt.Errorf("block with height %d not found", height) - } - - bloom := store.Get(types.BloomKey(bz)) - return ethtypes.BytesToBloom(bloom), nil + heightBz := sdk.Uint64ToBigEndian(uint64(height)) + store.Set(types.BloomKey(heightBz), bloom.Bytes()) } // SetTransactionLogs sets the transaction's logs in the KVStore @@ -107,8 +99,8 @@ func (k *Keeper) SetTransactionLogs(ctx sdk.Context, logs []*ethtypes.Log, hash if err != nil { return err } - store.Set(types.LogsKey(hash), encLogs) + store.Set(types.LogsKey(hash), encLogs) return nil } @@ -135,7 +127,6 @@ func (k *Keeper) CreateGenesisAccount(ctx sdk.Context, account types.GenesisAcco for _, key := range account.Storage { csdb.SetState(account.Address, key, account.Storage[key]) } - } // ---------------------------------------------------------------------------- diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index 108a45f2..c521d978 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -18,7 +18,9 @@ import ( abci "github.com/tendermint/tendermint/abci/types" ) -var address = ethcmn.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b4c1") +const addrHex = "0x756F45E3FA69347A9A973A725E3C98bC4db0b4c1" + +var address = ethcmn.HexToAddress(addrHex) type KeeperTestSuite struct { suite.Suite @@ -50,12 +52,15 @@ func (suite *KeeperTestSuite) TestDBStorage() { // Test block hash mapping functionality suite.app.EvmKeeper.SetBlockHashMapping(suite.ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68"), 7) + height, err := suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68")) + suite.Require().NoError(err) + suite.Require().Equal(int64(7), height) + suite.app.EvmKeeper.SetBlockHashMapping(suite.ctx, []byte{0x43, 0x32}, 8) // Test block height mapping functionality testBloom := ethtypes.BytesToBloom([]byte{0x1, 0x3}) - err := suite.app.EvmKeeper.SetBlockBloomMapping(suite.ctx, testBloom, 4) - suite.Require().NoError(err, "failed to set block bloom mapping") + suite.app.EvmKeeper.SetBlockBloomMapping(suite.ctx, testBloom, 4) // Get those state transitions suite.Require().Equal(suite.app.EvmKeeper.GetBalance(suite.ctx, address).Cmp(big.NewInt(5)), 0) @@ -63,8 +68,13 @@ func (suite *KeeperTestSuite) TestDBStorage() { suite.Require().Equal(suite.app.EvmKeeper.GetState(suite.ctx, address, ethcmn.HexToHash("0x2")), ethcmn.HexToHash("0x3")) suite.Require().Equal(suite.app.EvmKeeper.GetCode(suite.ctx, address), []byte{0x1}) - suite.Require().Equal(suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68")), int64(7)) - suite.Require().Equal(suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, []byte{0x43, 0x32}), int64(8)) + height, err = suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68")) + suite.Require().NoError(err) + suite.Require().Equal(height, int64(7)) + height, err = suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, []byte{0x43, 0x32}) + suite.Require().NoError(err) + suite.Require().Equal(height, int64(8)) + bloom, err := suite.app.EvmKeeper.GetBlockBloomMapping(suite.ctx, 4) suite.Require().NoError(err) suite.Require().Equal(bloom, testBloom) diff --git a/x/evm/keeper/querier.go b/x/evm/keeper/querier.go index d888f043..aac88c13 100644 --- a/x/evm/keeper/querier.go +++ b/x/evm/keeper/querier.go @@ -7,11 +7,14 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/ethermint/utils" "github.com/cosmos/ethermint/version" "github.com/cosmos/ethermint/x/evm/types" + ethcmn "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + abci "github.com/tendermint/tendermint/abci/types" ) @@ -61,8 +64,12 @@ func queryProtocolVersion(keeper Keeper) ([]byte, error) { func queryBalance(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { addr := ethcmn.HexToAddress(path[1]) balance := keeper.GetBalance(ctx, addr) + balanceStr, err := utils.MarshalBigInt(balance) + if err != nil { + return nil, err + } - res := types.QueryResBalance{Balance: utils.MarshalBigInt(balance)} + res := types.QueryResBalance{Balance: balanceStr} bz, err := codec.MarshalJSONIndent(keeper.cdc, res) if err != nil { return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) @@ -120,7 +127,10 @@ func queryNonce(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { func queryHashToHeight(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) { blockHash := ethcmn.FromHex(path[1]) - blockNumber := keeper.GetBlockHashMapping(ctx, blockHash) + blockNumber, err := keeper.GetBlockHashMapping(ctx, blockHash) + if err != nil { + return []byte{}, err + } res := types.QueryResBlockNumber{Number: blockNumber} bz, err := codec.MarshalJSONIndent(keeper.cdc, res) @@ -182,8 +192,13 @@ func queryAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) addr := ethcmn.HexToAddress(path[1]) so := keeper.GetOrNewStateObject(ctx, addr) + balance, err := utils.MarshalBigInt(so.Balance()) + if err != nil { + return nil, err + } + res := types.QueryResAccount{ - Balance: utils.MarshalBigInt(so.Balance()), + Balance: balance, CodeHash: so.CodeHash(), Nonce: so.Nonce(), } diff --git a/x/evm/keeper/querier_test.go b/x/evm/keeper/querier_test.go new file mode 100644 index 00000000..2d1f8c66 --- /dev/null +++ b/x/evm/keeper/querier_test.go @@ -0,0 +1,52 @@ +package keeper_test + +import ( + "math/big" + + "github.com/cosmos/ethermint/x/evm/types" + + abci "github.com/tendermint/tendermint/abci/types" +) + +func (suite *KeeperTestSuite) TestQuerier() { + + testCases := []struct { + msg string + path []string + malleate func() + expPass bool + }{ + {"protocol version", []string{types.QueryProtocolVersion}, func() {}, true}, + {"balance", []string{types.QueryBalance, addrHex}, func() { + suite.app.EvmKeeper.SetBalance(suite.ctx, address, big.NewInt(5)) + }, true}, + // {"balance", []string{types.QueryBalance, "0x01232"}, func() {}, false}, + {"block number", []string{types.QueryBlockNumber, "0x0"}, func() {}, true}, + {"storage", []string{types.QueryStorage, "0x0", "0x0"}, func() {}, true}, + {"code", []string{types.QueryCode, "0x0"}, func() {}, true}, + {"nonce", []string{types.QueryNonce, "0x0"}, func() {}, true}, + // {"hash to height", []string{types.QueryHashToHeight, "0x0"}, func() {}, true}, + {"tx logs", []string{types.QueryTxLogs, "0x0"}, func() {}, true}, + // {"logs bloom", []string{types.QueryLogsBloom, "0x0"}, func() {}, true}, + {"logs", []string{types.QueryLogs, "0x0"}, func() {}, true}, + {"account", []string{types.QueryAccount, "0x0"}, func() {}, true}, + {"unknown request", []string{"other"}, func() {}, false}, + } + + for i, tc := range testCases { + suite.Run("", func() { + tc := tc + suite.SetupTest() // reset + tc.malleate() + + bz, err := suite.querier(suite.ctx, tc.path, abci.RequestQuery{}) + + if tc.expPass { + suite.Require().NoError(err, "valid test %d failed: %s", i, tc.msg) + suite.Require().NotZero(len(bz)) + } else { + suite.Require().Error(err, "invalid test %d passed: %s", i, tc.msg) + } + }) + } +} diff --git a/x/evm/types/codec.go b/x/evm/types/codec.go index bdfe5121..d1010867 100644 --- a/x/evm/types/codec.go +++ b/x/evm/types/codec.go @@ -12,7 +12,7 @@ var ModuleCdc = codec.New() func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgEthereumTx{}, "ethermint/MsgEthereumTx", nil) cdc.RegisterConcrete(MsgEthermint{}, "ethermint/MsgEthermint", nil) - cdc.RegisterConcrete(EncodableTxData{}, "ethermint/EncodableTxData", nil) + cdc.RegisterConcrete(TxData{}, "ethermint/TxData", nil) } func init() { diff --git a/x/evm/types/emint_msg.go b/x/evm/types/emint_msg.go deleted file mode 100644 index 1394b818..00000000 --- a/x/evm/types/emint_msg.go +++ /dev/null @@ -1,88 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/cosmos/ethermint/types" - ethcmn "github.com/ethereum/go-ethereum/common" -) - -var ( - _ sdk.Msg = MsgEthermint{} -) - -const ( - // TypeMsgEthermint defines the type string of Ethermint message - TypeMsgEthermint = "ethermint" -) - -// MsgEthermint implements a cosmos equivalent structure for Ethereum transactions -type MsgEthermint struct { - AccountNonce uint64 `json:"nonce"` - Price sdk.Int `json:"gasPrice"` - GasLimit uint64 `json:"gas"` - Recipient *sdk.AccAddress `json:"to" rlp:"nil"` // nil means contract creation - Amount sdk.Int `json:"value"` - Payload []byte `json:"input"` - - // From address (formerly derived from signature) - From sdk.AccAddress `json:"from"` -} - -// NewMsgEthermint returns a reference to a new Ethermint transaction -func NewMsgEthermint( - nonce uint64, to *sdk.AccAddress, amount sdk.Int, - gasLimit uint64, gasPrice sdk.Int, payload []byte, from sdk.AccAddress, -) MsgEthermint { - return MsgEthermint{ - AccountNonce: nonce, - Price: gasPrice, - GasLimit: gasLimit, - Recipient: to, - Amount: amount, - Payload: payload, - From: from, - } -} - -// Route should return the name of the module -func (msg MsgEthermint) Route() string { return RouterKey } - -// Type returns the action of the message -func (msg MsgEthermint) Type() string { return TypeMsgEthermint } - -// GetSignBytes encodes the message for signing -func (msg MsgEthermint) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -// ValidateBasic runs stateless checks on the message -func (msg MsgEthermint) ValidateBasic() error { - if msg.Price.Sign() != 1 { - return sdkerrors.Wrapf(types.ErrInvalidValue, "price must be positive %s", msg.Price) - } - - // Amount can be 0 - if msg.Amount.Sign() == -1 { - return sdkerrors.Wrapf(types.ErrInvalidValue, "amount cannot be negative %s", msg.Amount) - } - - return nil -} - -// GetSigners defines whose signature is required -func (msg MsgEthermint) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.From} -} - -// To returns the recipient address of the transaction. It returns nil if the -// transaction is a contract creation. -func (msg MsgEthermint) To() *ethcmn.Address { - if msg.Recipient == nil { - return nil - } - - addr := ethcmn.BytesToAddress(msg.Recipient.Bytes()) - return &addr -} diff --git a/x/evm/types/emint_msg_test.go b/x/evm/types/emint_msg_test.go deleted file mode 100644 index d1886cea..00000000 --- a/x/evm/types/emint_msg_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package types - -import ( - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/secp256k1" -) - -func TestMsgEthermint(t *testing.T) { - addr := newSdkAddress() - fromAddr := newSdkAddress() - - msg := NewMsgEthermint(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr) - require.NotNil(t, msg) - require.Equal(t, msg.Recipient, &addr) - - require.Equal(t, msg.Route(), RouterKey) - require.Equal(t, msg.Type(), TypeMsgEthermint) -} - -func TestMsgEthermintValidation(t *testing.T) { - testCases := []struct { - nonce uint64 - to *sdk.AccAddress - amount sdk.Int - gasLimit uint64 - gasPrice sdk.Int - payload []byte - expectPass bool - from sdk.AccAddress - }{ - {amount: sdk.NewInt(100), gasPrice: sdk.NewInt(100000), expectPass: true}, - {amount: sdk.NewInt(0), gasPrice: sdk.NewInt(100000), expectPass: true}, - {amount: sdk.NewInt(-1), gasPrice: sdk.NewInt(100000), expectPass: false}, - {amount: sdk.NewInt(100), gasPrice: sdk.NewInt(-1), expectPass: false}, - } - - for i, tc := range testCases { - msg := NewMsgEthermint(tc.nonce, tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload, tc.from) - - if tc.expectPass { - require.Nil(t, msg.ValidateBasic(), "test: %v", i) - } else { - require.NotNil(t, msg.ValidateBasic(), "test: %v", i) - } - } -} - -func TestEmintEncodingAndDecoding(t *testing.T) { - addr := newSdkAddress() - fromAddr := newSdkAddress() - - msg := NewMsgEthermint(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr) - - raw, err := ModuleCdc.MarshalBinaryBare(msg) - require.NoError(t, err) - - var msg2 MsgEthermint - err = ModuleCdc.UnmarshalBinaryBare(raw, &msg2) - require.NoError(t, err) - - require.Equal(t, msg.AccountNonce, msg2.AccountNonce) - require.Equal(t, msg.Recipient, msg2.Recipient) - require.Equal(t, msg.Amount, msg2.Amount) - require.Equal(t, msg.GasLimit, msg2.GasLimit) - require.Equal(t, msg.Price, msg2.Price) - require.Equal(t, msg.Payload, msg2.Payload) - require.Equal(t, msg.From, msg2.From) -} - -func newSdkAddress() sdk.AccAddress { - tmpKey := secp256k1.GenPrivKey().PubKey() - return sdk.AccAddress(tmpKey.Address().Bytes()) -} diff --git a/x/evm/types/genesis_test.go b/x/evm/types/genesis_test.go new file mode 100644 index 00000000..503eea61 --- /dev/null +++ b/x/evm/types/genesis_test.go @@ -0,0 +1,45 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestValidateGenesis(t *testing.T) { + testCases := []struct { + msg string + genstate GenesisState + expPass bool + }{ + { + msg: "pass with defaultState ", + genstate: DefaultGenesisState(), + expPass: true, + }, + { + msg: "empty address", + genstate: GenesisState{ + Accounts: []GenesisAccount{{}}, + }, + expPass: false, + }, + { + msg: "empty balance", + genstate: GenesisState{ + Accounts: []GenesisAccount{{Balance: nil}}, + }, + expPass: false, + }, + } + for i, tc := range testCases { + + err := ValidateGenesis(tc.genstate) + if tc.expPass { + require.NoError(t, err, "test (%d) %s", i, tc.msg) + } else { + require.Error(t, err, "test (%d): %s", i, tc.msg) + } + } + +} diff --git a/x/evm/types/msg.go b/x/evm/types/msg.go index 7c5102c9..a3727603 100644 --- a/x/evm/types/msg.go +++ b/x/evm/types/msg.go @@ -8,7 +8,6 @@ import ( "math/big" "sync/atomic" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/ethermint/types" @@ -20,6 +19,7 @@ import ( ) var ( + _ sdk.Msg = MsgEthermint{} _ sdk.Msg = MsgEthereumTx{} _ sdk.Tx = MsgEthereumTx{} ) @@ -28,52 +28,104 @@ var big8 = big.NewInt(8) // message type and route constants const ( + // TypeMsgEthereumTx defines the type string of an Ethereum tranasction TypeMsgEthereumTx = "ethereum" + // TypeMsgEthermint defines the type string of Ethermint message + TypeMsgEthermint = "ethermint" ) +// MsgEthermint implements a cosmos equivalent structure for Ethereum transactions +type MsgEthermint struct { + AccountNonce uint64 `json:"nonce"` + Price sdk.Int `json:"gasPrice"` + GasLimit uint64 `json:"gas"` + Recipient *sdk.AccAddress `json:"to" rlp:"nil"` // nil means contract creation + Amount sdk.Int `json:"value"` + Payload []byte `json:"input"` + + // From address (formerly derived from signature) + From sdk.AccAddress `json:"from"` +} + +// NewMsgEthermint returns a reference to a new Ethermint transaction +func NewMsgEthermint( + nonce uint64, to *sdk.AccAddress, amount sdk.Int, + gasLimit uint64, gasPrice sdk.Int, payload []byte, from sdk.AccAddress, +) MsgEthermint { + return MsgEthermint{ + AccountNonce: nonce, + Price: gasPrice, + GasLimit: gasLimit, + Recipient: to, + Amount: amount, + Payload: payload, + From: from, + } +} + +// Route should return the name of the module +func (msg MsgEthermint) Route() string { return RouterKey } + +// Type returns the action of the message +func (msg MsgEthermint) Type() string { return TypeMsgEthermint } + +// GetSignBytes encodes the message for signing +func (msg MsgEthermint) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// ValidateBasic runs stateless checks on the message +func (msg MsgEthermint) ValidateBasic() error { + if msg.Price.Sign() != 1 { + return sdkerrors.Wrapf(types.ErrInvalidValue, "price must be positive %s", msg.Price) + } + + // Amount can be 0 + if msg.Amount.Sign() == -1 { + return sdkerrors.Wrapf(types.ErrInvalidValue, "amount cannot be negative %s", msg.Amount) + } + + return nil +} + +// GetSigners defines whose signature is required +func (msg MsgEthermint) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{msg.From} +} + +// To returns the recipient address of the transaction. It returns nil if the +// transaction is a contract creation. +func (msg MsgEthermint) To() *ethcmn.Address { + if msg.Recipient == nil { + return nil + } + + addr := ethcmn.BytesToAddress(msg.Recipient.Bytes()) + return &addr +} + // MsgEthereumTx encapsulates an Ethereum transaction as an SDK message. -type ( - MsgEthereumTx struct { - Data TxData +type MsgEthereumTx struct { + Data TxData - // caches - size atomic.Value - from atomic.Value - } + // caches + hash atomic.Value + size atomic.Value + from atomic.Value +} - // TxData implements the Ethereum transaction data structure. It is used - // solely as intended in Ethereum abiding by the protocol. - TxData struct { - AccountNonce uint64 `json:"nonce"` - Price *big.Int `json:"gasPrice"` - GasLimit uint64 `json:"gas"` - Recipient *ethcmn.Address `json:"to" rlp:"nil"` // nil means contract creation - Amount *big.Int `json:"value"` - Payload []byte `json:"input"` - - // signature values - V *big.Int `json:"v"` - R *big.Int `json:"r"` - S *big.Int `json:"s"` - - // hash is only used when marshaling to JSON - Hash *ethcmn.Hash `json:"hash" rlp:"-"` - } - - // sigCache is used to cache the derived sender and contains the signer used - // to derive it. - sigCache struct { - signer ethtypes.Signer - from ethcmn.Address - } -) +// sigCache is used to cache the derived sender and contains the signer used +// to derive it. +type sigCache struct { + signer ethtypes.Signer + from ethcmn.Address +} // NewMsgEthereumTx returns a reference to a new Ethereum transaction message. func NewMsgEthereumTx( nonce uint64, to *ethcmn.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, payload []byte, ) MsgEthereumTx { - return newMsgEthereumTx(nonce, to, amount, gasLimit, gasPrice, payload) } @@ -82,7 +134,6 @@ func NewMsgEthereumTx( func NewMsgEthereumTxContract( nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, payload []byte, ) MsgEthereumTx { - return newMsgEthereumTx(nonce, nil, amount, gasLimit, gasPrice, payload) } @@ -90,7 +141,6 @@ func newMsgEthereumTx( nonce uint64, to *ethcmn.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, payload []byte, ) MsgEthereumTx { - if len(payload) > 0 { payload = ethcmn.CopyBytes(payload) } @@ -191,30 +241,34 @@ func (msg *MsgEthereumTx) EncodeRLP(w io.Writer) error { // DecodeRLP implements the rlp.Decoder interface. func (msg *MsgEthereumTx) DecodeRLP(s *rlp.Stream) error { - _, size, _ := s.Kind() - - err := s.Decode(&msg.Data) - if err == nil { - msg.size.Store(ethcmn.StorageSize(rlp.ListSize(size))) + _, size, err := s.Kind() + if err != nil { + // return error if stream is too large + return err } - return err + if err := s.Decode(&msg.Data); err != nil { + return err + } + + msg.size.Store(ethcmn.StorageSize(rlp.ListSize(size))) + return nil } // Sign calculates a secp256k1 ECDSA signature and signs the transaction. It // takes a private key and chainID to sign an Ethereum transaction according to // EIP155 standard. It mutates the transaction as it populates the V, R, S // fields of the Transaction's Signature. -func (msg *MsgEthereumTx) Sign(chainID *big.Int, priv *ecdsa.PrivateKey) { +func (msg *MsgEthereumTx) Sign(chainID *big.Int, priv *ecdsa.PrivateKey) error { txHash := msg.RLPSignBytes(chainID) sig, err := ethcrypto.Sign(txHash[:], priv) if err != nil { - panic(err) + return err } if len(sig) != 65 { - panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig))) + return fmt.Errorf("wrong size for signature: got %d, want 65", len(sig)) } r := new(big.Int).SetBytes(sig[:32]) @@ -234,6 +288,7 @@ func (msg *MsgEthereumTx) Sign(chainID *big.Int, priv *ecdsa.PrivateKey) { msg.Data.V = v msg.Data.R = r msg.Data.S = s + return nil } // VerifySig attempts to verify a Transaction's signature for a given chainID. @@ -291,6 +346,12 @@ func (msg MsgEthereumTx) Cost() *big.Int { return total } +// RawSignatureValues returns the V, R, S signature values of the transaction. +// The return values should not be modified by the caller. +func (msg MsgEthereumTx) RawSignatureValues() (v, r, s *big.Int) { + return msg.Data.V, msg.Data.R, msg.Data.S +} + // From loads the ethereum sender address from the sigcache and returns an // sdk.AccAddress from its bytes func (msg *MsgEthereumTx) From() sdk.AccAddress { @@ -320,66 +381,3 @@ func deriveChainID(v *big.Int) *big.Int { v = new(big.Int).Sub(v, big.NewInt(35)) return v.Div(v, big.NewInt(2)) } - -// ---------------------------------------------------------------------------- -// Auxiliary - -// TxDecoder returns an sdk.TxDecoder that can decode both auth.StdTx and -// MsgEthereumTx transactions. -func TxDecoder(cdc *codec.Codec) sdk.TxDecoder { - return func(txBytes []byte) (sdk.Tx, error) { - var tx sdk.Tx - - if len(txBytes) == 0 { - return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") - } - - // sdk.Tx is an interface. The concrete message types - // are registered by MakeTxCodec - err := cdc.UnmarshalBinaryBare(txBytes, &tx) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) - } - - return tx, nil - } -} - -// recoverEthSig recovers a signature according to the Ethereum specification and -// returns the sender or an error. -// -// Ref: Ethereum Yellow Paper (BYZANTIUM VERSION 69351d5) Appendix F -// nolint: gocritic -func recoverEthSig(R, S, Vb *big.Int, sigHash ethcmn.Hash) (ethcmn.Address, error) { - if Vb.BitLen() > 8 { - return ethcmn.Address{}, errors.New("invalid signature") - } - - V := byte(Vb.Uint64() - 27) - if !ethcrypto.ValidateSignatureValues(V, R, S, true) { - return ethcmn.Address{}, errors.New("invalid signature") - } - - // encode the signature in uncompressed format - r, s := R.Bytes(), S.Bytes() - sig := make([]byte, 65) - - copy(sig[32-len(r):32], r) - copy(sig[64-len(s):64], s) - sig[64] = V - - // recover the public key from the signature - pub, err := ethcrypto.Ecrecover(sigHash[:], sig) - if err != nil { - return ethcmn.Address{}, err - } - - if len(pub) == 0 || pub[0] != 4 { - return ethcmn.Address{}, errors.New("invalid public key") - } - - var addr ethcmn.Address - copy(addr[:], ethcrypto.Keccak256(pub[1:])[12:]) - - return addr, nil -} diff --git a/x/evm/types/msg_test.go b/x/evm/types/msg_test.go index 13cc89f0..0b6528d9 100644 --- a/x/evm/types/msg_test.go +++ b/x/evm/types/msg_test.go @@ -6,50 +6,51 @@ import ( "math/big" "testing" + "github.com/stretchr/testify/require" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ethermint/crypto" - "github.com/cosmos/ethermint/utils" + ethcmn "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" - "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/crypto/secp256k1" ) -func TestMsgEthereumTx(t *testing.T) { - addr := GenerateEthAddress() +func TestMsgEthermint(t *testing.T) { + addr := newSdkAddress() + fromAddr := newSdkAddress() - msg1 := NewMsgEthereumTx(0, &addr, nil, 100000, nil, []byte("test")) - require.NotNil(t, msg1) - require.Equal(t, *msg1.Data.Recipient, addr) + msg := NewMsgEthermint(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr) + require.NotNil(t, msg) + require.Equal(t, msg.Recipient, &addr) - msg2 := NewMsgEthereumTxContract(0, nil, 100000, nil, []byte("test")) - require.NotNil(t, msg2) - require.Nil(t, msg2.Data.Recipient) - - msg3 := NewMsgEthereumTx(0, &addr, nil, 100000, nil, []byte("test")) - require.Equal(t, msg3.Route(), RouterKey) - require.Equal(t, msg3.Type(), TypeMsgEthereumTx) - require.Panics(t, func() { msg3.GetSigners() }) - require.Panics(t, func() { msg3.GetSignBytes() }) + require.Equal(t, msg.Route(), RouterKey) + require.Equal(t, msg.Type(), TypeMsgEthermint) } -func TestMsgEthereumTxValidation(t *testing.T) { +func TestMsgEthermintValidation(t *testing.T) { testCases := []struct { - payload []byte - amount *big.Int - gasPrice *big.Int - gasLimit uint64 nonce uint64 - to ethcmn.Address + to *sdk.AccAddress + amount sdk.Int + gasLimit uint64 + gasPrice sdk.Int + payload []byte expectPass bool + from sdk.AccAddress }{ - {amount: big.NewInt(100), gasPrice: big.NewInt(100000), expectPass: true}, - {amount: big.NewInt(-1), gasPrice: big.NewInt(100000), expectPass: false}, - {amount: big.NewInt(100), gasPrice: big.NewInt(-1), expectPass: false}, + {amount: sdk.NewInt(100), gasPrice: sdk.NewInt(100000), expectPass: true}, + {amount: sdk.NewInt(0), gasPrice: sdk.NewInt(100000), expectPass: true}, + {amount: sdk.NewInt(-1), gasPrice: sdk.NewInt(100000), expectPass: false}, + {amount: sdk.NewInt(100), gasPrice: sdk.NewInt(-1), expectPass: false}, } for i, tc := range testCases { - msg := NewMsgEthereumTx(tc.nonce, &tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload) + msg := NewMsgEthermint(tc.nonce, tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload, tc.from) if tc.expectPass { require.Nil(t, msg.ValidateBasic(), "test: %v", i) @@ -59,6 +60,75 @@ func TestMsgEthereumTxValidation(t *testing.T) { } } +func TestMsgEthermintEncodingAndDecoding(t *testing.T) { + addr := newSdkAddress() + fromAddr := newSdkAddress() + + msg := NewMsgEthermint(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr) + + raw, err := ModuleCdc.MarshalBinaryBare(msg) + require.NoError(t, err) + + var msg2 MsgEthermint + err = ModuleCdc.UnmarshalBinaryBare(raw, &msg2) + require.NoError(t, err) + + require.Equal(t, msg.AccountNonce, msg2.AccountNonce) + require.Equal(t, msg.Recipient, msg2.Recipient) + require.Equal(t, msg.Amount, msg2.Amount) + require.Equal(t, msg.GasLimit, msg2.GasLimit) + require.Equal(t, msg.Price, msg2.Price) + require.Equal(t, msg.Payload, msg2.Payload) + require.Equal(t, msg.From, msg2.From) +} + +func newSdkAddress() sdk.AccAddress { + tmpKey := secp256k1.GenPrivKey().PubKey() + return sdk.AccAddress(tmpKey.Address().Bytes()) +} + +func TestMsgEthereumTx(t *testing.T) { + addr := GenerateEthAddress() + + msg := NewMsgEthereumTx(0, &addr, nil, 100000, nil, []byte("test")) + require.NotNil(t, msg) + require.Equal(t, *msg.Data.Recipient, addr) + require.Equal(t, msg.Route(), RouterKey) + require.Equal(t, msg.Type(), TypeMsgEthereumTx) + require.NotNil(t, msg.To()) + require.Equal(t, msg.GetMsgs(), []sdk.Msg{msg}) + require.Panics(t, func() { msg.GetSigners() }) + require.Panics(t, func() { msg.GetSignBytes() }) + + msg = NewMsgEthereumTxContract(0, nil, 100000, nil, []byte("test")) + require.NotNil(t, msg) + require.Nil(t, msg.Data.Recipient) + require.Nil(t, msg.To()) +} + +func TestMsgEthereumTxValidation(t *testing.T) { + testCases := []struct { + msg string + amount *big.Int + gasPrice *big.Int + expectPass bool + }{ + {msg: "pass", amount: big.NewInt(100), gasPrice: big.NewInt(100000), expectPass: true}, + {msg: "invalid amount", amount: big.NewInt(-1), gasPrice: big.NewInt(100000), expectPass: false}, + {msg: "invalid gas price", amount: big.NewInt(100), gasPrice: big.NewInt(-1), expectPass: false}, + } + + for i, tc := range testCases { + msg := NewMsgEthereumTx(0, nil, tc.amount, 0, tc.gasPrice, nil) + + if tc.expectPass { + require.Nil(t, msg.ValidateBasic(), "valid test %d failed: %s", i, tc.msg) + } else { + require.NotNil(t, msg.ValidateBasic(), "invalid test %d passed: %s", i, tc.msg) + } + } +} + func TestMsgEthereumTxRLPSignBytes(t *testing.T) { addr := ethcmn.BytesToAddress([]byte("test_address")) chainID := big.NewInt(3) @@ -115,60 +185,6 @@ func TestMsgEthereumTxSig(t *testing.T) { require.Equal(t, ethcmn.Address{}, signer) } -func TestMsgEthereumTxAmino(t *testing.T) { - addr := GenerateEthAddress() - msg := NewMsgEthereumTx(5, &addr, big.NewInt(1), 100000, big.NewInt(3), []byte("test")) - - msg.Data.V = big.NewInt(1) - msg.Data.R = big.NewInt(2) - msg.Data.S = big.NewInt(3) - - raw, err := ModuleCdc.MarshalBinaryBare(msg) - require.NoError(t, err) - - var msg2 MsgEthereumTx - - err = ModuleCdc.UnmarshalBinaryBare(raw, &msg2) - require.NoError(t, err) - require.Equal(t, msg.Data, msg2.Data) -} - -func TestMarshalAndUnmarshalInt(t *testing.T) { - i := big.NewInt(3) - m := utils.MarshalBigInt(i) - i2, err := utils.UnmarshalBigInt(m) - require.NoError(t, err) - - require.Equal(t, i, i2) -} - -func TestMarshalAndUnmarshalData(t *testing.T) { - addr := GenerateEthAddress() - hash := ethcmn.BigToHash(big.NewInt(2)) - e := EncodableTxData{ - AccountNonce: 2, - Price: utils.MarshalBigInt(big.NewInt(3)), - GasLimit: 1, - Recipient: &addr, - Amount: utils.MarshalBigInt(big.NewInt(4)), - Payload: []byte("test"), - - V: utils.MarshalBigInt(big.NewInt(5)), - R: utils.MarshalBigInt(big.NewInt(6)), - S: utils.MarshalBigInt(big.NewInt(7)), - - Hash: &hash, - } - str, err := marshalAmino(e) - require.NoError(t, err) - - e2 := new(EncodableTxData) - - err = unmarshalAmino(e2, str) - require.NoError(t, err) - require.Equal(t, e, *e2) -} - func TestMarshalAndUnmarshalLogs(t *testing.T) { var cdc = codec.New() diff --git a/x/evm/types/msg_encoding.go b/x/evm/types/tx_data.go similarity index 56% rename from x/evm/types/msg_encoding.go rename to x/evm/types/tx_data.go index ddbf16da..1ee433af 100644 --- a/x/evm/types/msg_encoding.go +++ b/x/evm/types/tx_data.go @@ -1,14 +1,35 @@ package types import ( + "math/big" + "github.com/cosmos/ethermint/utils" ethcmn "github.com/ethereum/go-ethereum/common" ) -// EncodableTxData implements the Ethereum transaction data structure. It is used +// TxData implements the Ethereum transaction data structure. It is used // solely as intended in Ethereum abiding by the protocol. -type EncodableTxData struct { +type TxData struct { + AccountNonce uint64 `json:"nonce"` + Price *big.Int `json:"gasPrice"` + GasLimit uint64 `json:"gas"` + Recipient *ethcmn.Address `json:"to" rlp:"nil"` // nil means contract creation + Amount *big.Int `json:"value"` + Payload []byte `json:"input"` + + // signature values + V *big.Int `json:"v"` + R *big.Int `json:"r"` + S *big.Int `json:"s"` + + // hash is only used when marshaling to JSON + Hash *ethcmn.Hash `json:"hash" rlp:"-"` +} + +// encodableTxData implements the Ethereum transaction data structure. It is used +// solely as intended in Ethereum abiding by the protocol. +type encodableTxData struct { AccountNonce uint64 `json:"nonce"` Price string `json:"gasPrice"` GasLimit uint64 `json:"gas"` @@ -25,39 +46,53 @@ type EncodableTxData struct { Hash *ethcmn.Hash `json:"hash" rlp:"-"` } -func marshalAmino(td EncodableTxData) (string, error) { - bz, err := ModuleCdc.MarshalBinaryBare(td) - return string(bz), err -} - -func unmarshalAmino(td *EncodableTxData, text string) error { - return ModuleCdc.UnmarshalBinaryBare([]byte(text), td) -} - // MarshalAmino defines custom encoding scheme for TxData -func (td TxData) MarshalAmino() (string, error) { - e := EncodableTxData{ - AccountNonce: td.AccountNonce, - Price: utils.MarshalBigInt(td.Price), - GasLimit: td.GasLimit, - Recipient: td.Recipient, - Amount: utils.MarshalBigInt(td.Amount), - Payload: td.Payload, - - V: utils.MarshalBigInt(td.V), - R: utils.MarshalBigInt(td.R), - S: utils.MarshalBigInt(td.S), - - Hash: td.Hash, +func (td TxData) MarshalAmino() ([]byte, error) { + gasPrice, err := utils.MarshalBigInt(td.Price) + if err != nil { + return nil, err } - return marshalAmino(e) + amount, err := utils.MarshalBigInt(td.Amount) + if err != nil { + return nil, err + } + + v, err := utils.MarshalBigInt(td.V) + if err != nil { + return nil, err + } + + r, err := utils.MarshalBigInt(td.R) + if err != nil { + return nil, err + } + + s, err := utils.MarshalBigInt(td.S) + if err != nil { + return nil, err + } + + e := encodableTxData{ + AccountNonce: td.AccountNonce, + Price: gasPrice, + GasLimit: td.GasLimit, + Recipient: td.Recipient, + Amount: amount, + Payload: td.Payload, + V: v, + R: r, + S: s, + Hash: td.Hash, + } + + return ModuleCdc.MarshalBinaryBare(e) } // UnmarshalAmino defines custom decoding scheme for TxData -func (td *TxData) UnmarshalAmino(text string) error { - e := new(EncodableTxData) - err := unmarshalAmino(e, text) +func (td *TxData) UnmarshalAmino(data []byte) error { + var e encodableTxData + err := ModuleCdc.UnmarshalBinaryBare(data, &e) if err != nil { return err } diff --git a/x/evm/types/tx_data_test.go b/x/evm/types/tx_data_test.go new file mode 100644 index 00000000..4e938439 --- /dev/null +++ b/x/evm/types/tx_data_test.go @@ -0,0 +1,56 @@ +package types + +import ( + "math/big" + "testing" + + "github.com/stretchr/testify/require" + + ethcmn "github.com/ethereum/go-ethereum/common" +) + +func TestMarshalAndUnmarshalData(t *testing.T) { + addr := GenerateEthAddress() + hash := ethcmn.BigToHash(big.NewInt(2)) + + txData := TxData{ + AccountNonce: 2, + Price: big.NewInt(3), + GasLimit: 1, + Recipient: &addr, + Amount: big.NewInt(4), + Payload: []byte("test"), + V: big.NewInt(5), + R: big.NewInt(6), + S: big.NewInt(7), + Hash: &hash, + } + + bz, err := txData.MarshalAmino() + require.NoError(t, err) + require.NotNil(t, bz) + + var txData2 TxData + err = txData2.UnmarshalAmino(bz) + require.NoError(t, err) + + require.Equal(t, txData, txData2) +} + +func TestMsgEthereumTxAmino(t *testing.T) { + addr := GenerateEthAddress() + msg := NewMsgEthereumTx(5, &addr, big.NewInt(1), 100000, big.NewInt(3), []byte("test")) + + msg.Data.V = big.NewInt(1) + msg.Data.R = big.NewInt(2) + msg.Data.S = big.NewInt(3) + + raw, err := ModuleCdc.MarshalBinaryBare(msg) + require.NoError(t, err) + + var msg2 MsgEthereumTx + + err = ModuleCdc.UnmarshalBinaryBare(raw, &msg2) + require.NoError(t, err) + require.Equal(t, msg, msg2) +} diff --git a/x/evm/types/utils.go b/x/evm/types/utils.go index 4387d8de..344ef4d8 100644 --- a/x/evm/types/utils.go +++ b/x/evm/types/utils.go @@ -2,7 +2,11 @@ package types import ( "fmt" + "math/big" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/ethermint/crypto" ethcmn "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -86,3 +90,66 @@ func DecodeLogs(in []byte) ([]*ethtypes.Log, error) { } return logs, nil } + +// ---------------------------------------------------------------------------- +// Auxiliary + +// TxDecoder returns an sdk.TxDecoder that can decode both auth.StdTx and +// MsgEthereumTx transactions. +func TxDecoder(cdc *codec.Codec) sdk.TxDecoder { + return func(txBytes []byte) (sdk.Tx, error) { + var tx sdk.Tx + + if len(txBytes) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") + } + + // sdk.Tx is an interface. The concrete message types + // are registered by MakeTxCodec + err := cdc.UnmarshalBinaryBare(txBytes, &tx) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) + } + + return tx, nil + } +} + +// recoverEthSig recovers a signature according to the Ethereum specification and +// returns the sender or an error. +// +// Ref: Ethereum Yellow Paper (BYZANTIUM VERSION 69351d5) Appendix F +// nolint: gocritic +func recoverEthSig(R, S, Vb *big.Int, sigHash ethcmn.Hash) (ethcmn.Address, error) { + if Vb.BitLen() > 8 { + return ethcmn.Address{}, errors.New("invalid signature") + } + + V := byte(Vb.Uint64() - 27) + if !ethcrypto.ValidateSignatureValues(V, R, S, true) { + return ethcmn.Address{}, errors.New("invalid signature") + } + + // encode the signature in uncompressed format + r, s := R.Bytes(), S.Bytes() + sig := make([]byte, 65) + + copy(sig[32-len(r):32], r) + copy(sig[64-len(s):64], s) + sig[64] = V + + // recover the public key from the signature + pub, err := ethcrypto.Ecrecover(sigHash[:], sig) + if err != nil { + return ethcmn.Address{}, err + } + + if len(pub) == 0 || pub[0] != 4 { + return ethcmn.Address{}, errors.New("invalid public key") + } + + var addr ethcmn.Address + copy(addr[:], ethcrypto.Keccak256(pub[1:])[12:]) + + return addr, nil +}