From ffbb20765562a2a8cffbba7e4305654f2dc316a9 Mon Sep 17 00:00:00 2001 From: KamiD <44460798+KamiD@users.noreply.github.com> Date: Thu, 7 Jan 2021 19:55:01 +0800 Subject: [PATCH 1/7] fix panic when start a node with snapshot (#673) * fix panic when start a node with snapshot * change the return value of evm.NewKeeper to a pointer, roll back the before change * add changelog * fix importer test --- CHANGELOG.md | 1 + app/ethermint.go | 2 +- importer/importer_test.go | 8 ++++---- x/evm/genesis_test.go | 8 ++++---- x/evm/handler.go | 6 +++--- x/evm/handler_test.go | 2 +- x/evm/keeper/keeper.go | 4 ++-- x/evm/keeper/keeper_test.go | 2 +- x/evm/module.go | 12 ++++++------ 9 files changed, 23 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b1222d55..34db7f958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot * (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent ## [v0.4.0] - 2020-12-15 diff --git a/app/ethermint.go b/app/ethermint.go index 4b793e383..b9dfba57b 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -125,7 +125,7 @@ type EthermintApp struct { UpgradeKeeper upgrade.Keeper ParamsKeeper params.Keeper EvidenceKeeper evidence.Keeper - EvmKeeper evm.Keeper + EvmKeeper *evm.Keeper FaucetKeeper faucet.Keeper // the module manager diff --git a/importer/importer_test.go b/importer/importer_test.go index 27f4e2e4b..005f893de 100644 --- a/importer/importer_test.go +++ b/importer/importer_test.go @@ -99,7 +99,7 @@ func trapSignals() { } // nolint: interfacer -func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper, evmKeeper evm.Keeper) { +func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper, evmKeeper *evm.Keeper) { genBlock := ethcore.DefaultGenesisBlock() ms := cms.CacheMultiStore() ctx := sdk.NewContext(ms, abci.Header{}, false, logger) @@ -285,7 +285,7 @@ func TestImportBlocks(t *testing.T) { // reward. The total reward consists of the static block reward and rewards for // included uncles. The coinbase of each uncle block is also rewarded. func accumulateRewards( - config *ethparams.ChainConfig, evmKeeper evm.Keeper, + config *ethparams.ChainConfig, evmKeeper *evm.Keeper, header *ethtypes.Header, uncles []*ethtypes.Header, ) { @@ -318,7 +318,7 @@ func accumulateRewards( // Code is pulled from go-ethereum 1.9 because the StateDB interface does not include the // SetBalance function implementation // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/consensus/misc/dao.go#L74 -func applyDAOHardFork(evmKeeper evm.Keeper) { +func applyDAOHardFork(evmKeeper *evm.Keeper) { // Retrieve the contract to refund balances into if !evmKeeper.CommitStateDB.Exist(ethparams.DAORefundContract) { evmKeeper.CommitStateDB.CreateAccount(ethparams.DAORefundContract) @@ -339,7 +339,7 @@ func applyDAOHardFork(evmKeeper evm.Keeper) { // Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88 func applyTransaction( config *ethparams.ChainConfig, bc ethcore.ChainContext, author *ethcmn.Address, - gp *ethcore.GasPool, evmKeeper evm.Keeper, header *ethtypes.Header, + gp *ethcore.GasPool, evmKeeper *evm.Keeper, header *ethtypes.Header, tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config, ) (*ethtypes.Receipt, uint64, error) { msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number)) diff --git a/x/evm/genesis_test.go b/x/evm/genesis_test.go index 01b99f205..5d593d436 100644 --- a/x/evm/genesis_test.go +++ b/x/evm/genesis_test.go @@ -16,10 +16,10 @@ import ( func (suite *EvmTestSuite) TestExportImport() { var genState types.GenesisState suite.Require().NotPanics(func() { - genState = evm.ExportGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper) + genState = evm.ExportGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper) }) - _ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, genState) + _ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, genState) } func (suite *EvmTestSuite) TestInitGenesis() { @@ -102,13 +102,13 @@ func (suite *EvmTestSuite) TestInitGenesis() { if tc.expPanic { suite.Require().Panics( func() { - _ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, tc.genState) + _ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, tc.genState) }, ) } else { suite.Require().NotPanics( func() { - _ = evm.InitGenesis(suite.ctx, suite.app.EvmKeeper, suite.app.AccountKeeper, tc.genState) + _ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, tc.genState) }, ) } diff --git a/x/evm/handler.go b/x/evm/handler.go index 82d271899..d1347f4a1 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -13,7 +13,7 @@ import ( ) // NewHandler returns a handler for Ethermint type messages. -func NewHandler(k Keeper) sdk.Handler { +func NewHandler(k *Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { @@ -28,7 +28,7 @@ func NewHandler(k Keeper) sdk.Handler { } // handleMsgEthereumTx handles an Ethereum specific tx -func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) { +func handleMsgEthereumTx(ctx sdk.Context, k *Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) { // execute state transition res, err := k.EthereumTx(ctx, msg) if err != nil { @@ -42,7 +42,7 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s } // handleMsgEthermint handles an sdk.StdTx for an Ethereum state transition -func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk.Result, error) { +func handleMsgEthermint(ctx sdk.Context, k *Keeper, msg types.MsgEthermint) (*sdk.Result, error) { // parse the chainID from a string to a base-10 integer chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID()) if err != nil { diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 3aefc98a5..93ce59f59 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -46,7 +46,7 @@ func (suite *EvmTestSuite) SetupTest() { suite.app = app.Setup(checkTx) suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()}) suite.handler = evm.NewHandler(suite.app.EvmKeeper) - suite.querier = keeper.NewQuerier(suite.app.EvmKeeper) + suite.querier = keeper.NewQuerier(*suite.app.EvmKeeper) suite.codec = codec.New() } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 43763c51a..b61df17e1 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -44,14 +44,14 @@ type Keeper struct { // NewKeeper generates new evm module keeper func NewKeeper( cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, ak types.AccountKeeper, -) Keeper { +) *Keeper { // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) } // NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations - return Keeper{ + return &Keeper{ cdc: cdc, storeKey: storeKey, accountKeeper: ak, diff --git a/x/evm/keeper/keeper_test.go b/x/evm/keeper/keeper_test.go index df7796e0c..27ee25902 100644 --- a/x/evm/keeper/keeper_test.go +++ b/x/evm/keeper/keeper_test.go @@ -43,7 +43,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.app = app.Setup(checkTx) suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()}) - suite.querier = keeper.NewQuerier(suite.app.EvmKeeper) + suite.querier = keeper.NewQuerier(*suite.app.EvmKeeper) suite.address = ethcmn.HexToAddress(addrHex) balance := sdk.NewCoins(ethermint.NewPhotonCoin(sdk.ZeroInt())) diff --git a/x/evm/module.go b/x/evm/module.go index 34b882944..c3eea99e8 100644 --- a/x/evm/module.go +++ b/x/evm/module.go @@ -69,12 +69,12 @@ func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { // AppModule implements an application module for the evm module. type AppModule struct { AppModuleBasic - keeper Keeper + keeper *Keeper ak types.AccountKeeper } // NewAppModule creates a new AppModule Object -func NewAppModule(k Keeper, ak types.AccountKeeper) AppModule { +func NewAppModule(k *Keeper, ak types.AccountKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: k, @@ -89,7 +89,7 @@ func (AppModule) Name() string { // RegisterInvariants interface for registering invariants func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.keeper) + keeper.RegisterInvariants(ir, *am.keeper) } // Route specifies path for transactions @@ -109,7 +109,7 @@ func (am AppModule) QuerierRoute() string { // NewQuerierHandler sets up new querier handler for module func (am AppModule) NewQuerierHandler() sdk.Querier { - return keeper.NewQuerier(am.keeper) + return keeper.NewQuerier(*am.keeper) } // BeginBlock function for module at start of each block @@ -126,11 +126,11 @@ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.V func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState types.ModuleCdc.MustUnmarshalJSON(data, &genesisState) - return InitGenesis(ctx, am.keeper, am.ak, genesisState) + return InitGenesis(ctx, *am.keeper, am.ak, genesisState) } // ExportGenesis exports the genesis state to be used by daemon func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper, am.ak) + gs := ExportGenesis(ctx, *am.keeper, am.ak) return types.ModuleCdc.MustMarshalJSON(gs) } From ed313c9482e22e2deebc381936259337cde612a8 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 7 Jan 2021 18:45:32 -0300 Subject: [PATCH 2/7] stargate: proto files (#679) * stargate: proto files * third party proto files * third party proto files * add annotations * rm proto-gen-any * rm script any --- .clang-format | 116 +++++ Makefile | 80 ++-- buf.yaml | 21 +- go.mod | 4 + go.sum | 16 +- .../crypto/v1alpha1/ethsecp256k1/keys.proto | 19 + proto/ethermint/evm/v1alpha1/evm.proto | 173 ++++++++ proto/ethermint/evm/v1alpha1/genesis.proto | 45 ++ proto/ethermint/evm/v1alpha1/query.proto | 172 ++++++++ proto/ethermint/evm/v1alpha1/tx.proto | 106 +++++ proto/ethermint/types/v1alpha1/account.proto | 25 ++ scripts/protoc-swagger-gen.sh | 27 ++ scripts/protocgen.sh | 39 +- third_party/proto/cosmos_proto/cosmos.proto | 16 + third_party/proto/gogoproto/gogo.proto | 145 +++++++ .../proto/google/api/annotations.proto | 31 ++ third_party/proto/google/api/http.proto | 318 ++++++++++++++ third_party/proto/google/api/httpbody.proto | 78 ++++ third_party/proto/google/protobuf/any.proto | 161 +++++++ third_party/proto/tendermint/abci/types.proto | 407 ++++++++++++++++++ .../proto/tendermint/crypto/keys.proto | 17 + .../proto/tendermint/crypto/proof.proto | 41 ++ .../proto/tendermint/types/types.proto | 157 +++++++ 23 files changed, 2155 insertions(+), 59 deletions(-) create mode 100644 .clang-format create mode 100644 proto/ethermint/crypto/v1alpha1/ethsecp256k1/keys.proto create mode 100644 proto/ethermint/evm/v1alpha1/evm.proto create mode 100644 proto/ethermint/evm/v1alpha1/genesis.proto create mode 100644 proto/ethermint/evm/v1alpha1/query.proto create mode 100644 proto/ethermint/evm/v1alpha1/tx.proto create mode 100644 proto/ethermint/types/v1alpha1/account.proto create mode 100755 scripts/protoc-swagger-gen.sh create mode 100644 third_party/proto/cosmos_proto/cosmos.proto create mode 100644 third_party/proto/gogoproto/gogo.proto create mode 100644 third_party/proto/google/api/annotations.proto create mode 100644 third_party/proto/google/api/http.proto create mode 100644 third_party/proto/google/api/httpbody.proto create mode 100644 third_party/proto/google/protobuf/any.proto create mode 100644 third_party/proto/tendermint/abci/types.proto create mode 100644 third_party/proto/tendermint/crypto/keys.proto create mode 100644 third_party/proto/tendermint/crypto/proof.proto create mode 100644 third_party/proto/tendermint/types/types.proto diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..7f662a4fd --- /dev/null +++ b/.clang-format @@ -0,0 +1,116 @@ +--- +Language: Proto +# BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Right +RawStringFormats: + - Delimiters: + - pb + Language: TextProto + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Never +... + diff --git a/Makefile b/Makefile index fd46c766f..68b2785f2 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,10 @@ GO_MOD=GO111MODULE=on BUILDDIR ?= $(CURDIR)/build SIMAPP = ./app LEDGER_ENABLED ?= true +HTTPS_GIT := https://github.com/cosmos/ethermint.git +DOCKER := $(shell which docker) +DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf + ifeq ($(OS),Windows_NT) DETECTED_OS := windows @@ -340,33 +344,39 @@ format: ### Protobuf ### ############################################################################### -proto-all: proto-gen proto-lint proto-check-breaking +proto-all: proto-format proto-lint proto-gen proto-gen: - @./scripts/protocgen.sh + @echo "Generating Protobuf files" + $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace tendermintdev/sdk-proto-gen sh ./scripts/protocgen.sh + +proto-format: + @echo "Formatting Protobuf files" + $(DOCKER) run --rm -v $(CURDIR):/workspace \ + --workdir /workspace tendermintdev/docker-build-proto \ + find ./ -not -path "./third_party/*" -name *.proto -exec clang-format -i {} \; + +proto-swagger-gen: + @./scripts/protoc-swagger-gen.sh proto-lint: - @buf check lint --error-format=json + @$(DOCKER_BUF) check lint --error-format=json -# NOTE: should match the default repo branch proto-check-breaking: - @buf check breaking --against-input '.git#branch=development' + @$(DOCKER_BUF) check breaking --against-input $(HTTPS_GIT)#branch=development +TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.0-rc6/proto/tendermint +GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos +COSMOS_SDK_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/master +COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master -TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.33.3 -GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos -COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/master -SDK_PROTO_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/master +TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto +TM_ABCI_TYPES = third_party/proto/tendermint/abci +TM_TYPES = third_party/proto/tendermint/types -TM_KV_TYPES = third_party/proto/tendermint/libs/kv -TM_MERKLE_TYPES = third_party/proto/tendermint/crypto/merkle -TM_ABCI_TYPES = third_party/proto/tendermint/abci/types GOGO_PROTO_TYPES = third_party/proto/gogoproto -COSMOS_PROTO_TYPES = third_party/proto/cosmos-proto -SDK_PROTO_TYPES = third_party/proto/cosmos-sdk/types -AUTH_PROTO_TYPES = third_party/proto/cosmos-sdk/x/auth/types -VESTING_PROTO_TYPES = third_party/proto/cosmos-sdk/x/auth/vesting/types -SUPPLY_PROTO_TYPES = third_party/proto/cosmos-sdk/x/supply/types +COSMOS_SDK_PROTO = third_party/proto/cosmos-sdk +COSMOS_PROTO_TYPES = third_party/proto/cosmos_proto proto-update-deps: @mkdir -p $(GOGO_PROTO_TYPES) @@ -375,36 +385,22 @@ proto-update-deps: @mkdir -p $(COSMOS_PROTO_TYPES) @curl -sSL $(COSMOS_PROTO_URL)/cosmos.proto > $(COSMOS_PROTO_TYPES)/cosmos.proto +## Importing of tendermint protobuf definitions currently requires the +## use of `sed` in order to build properly with cosmos-sdk's proto file layout +## (which is the standard Buf.build FILE_LAYOUT) +## Issue link: https://github.com/tendermint/tendermint/issues/5021 @mkdir -p $(TM_ABCI_TYPES) - @curl -sSL $(TM_URL)/abci/types/types.proto > $(TM_ABCI_TYPES)/types.proto - @sed -i '' '8 s|crypto/merkle/merkle.proto|third_party/proto/tendermint/crypto/merkle/merkle.proto|g' $(TM_ABCI_TYPES)/types.proto - @sed -i '' '9 s|libs/kv/types.proto|third_party/proto/tendermint/libs/kv/types.proto|g' $(TM_ABCI_TYPES)/types.proto - - @mkdir -p $(TM_KV_TYPES) - @curl -sSL $(TM_URL)/libs/kv/types.proto > $(TM_KV_TYPES)/types.proto - - @mkdir -p $(TM_MERKLE_TYPES) - @curl -sSL $(TM_URL)/crypto/merkle/merkle.proto > $(TM_MERKLE_TYPES)/merkle.proto - - @mkdir -p $(SDK_PROTO_TYPES) - @curl -sSL $(SDK_PROTO_URL)/types/types.proto > $(SDK_PROTO_TYPES)/types.proto - - @mkdir -p $(AUTH_PROTO_TYPES) - @curl -sSL $(SDK_PROTO_URL)/x/auth/types/types.proto > $(AUTH_PROTO_TYPES)/types.proto - @sed -i '' '5 s|types/types.proto|third_party/proto/cosmos-sdk/types/types.proto|g' $(AUTH_PROTO_TYPES)/types.proto + @curl -sSL $(TM_URL)/abci/types.proto > $(TM_ABCI_TYPES)/types.proto - @mkdir -p $(VESTING_PROTO_TYPES) - curl -sSL $(SDK_PROTO_URL)/x/auth/vesting/types/types.proto > $(VESTING_PROTO_TYPES)/types.proto - @sed -i '' '5 s|types/types.proto|third_party/proto/cosmos-sdk/types/types.proto|g' $(VESTING_PROTO_TYPES)/types.proto - @sed -i '' '6 s|x/auth/types/types.proto|third_party/proto/cosmos-sdk/x/auth/types/types.proto|g' $(VESTING_PROTO_TYPES)/types.proto + @mkdir -p $(TM_TYPES) + @curl -sSL $(TM_URL)/types/types.proto > $(TM_TYPES)/types.proto - @mkdir -p $(SUPPLY_PROTO_TYPES) - curl -sSL $(SDK_PROTO_URL)/x/supply/types/types.proto > $(SUPPLY_PROTO_TYPES)/types.proto - @sed -i '' '5 s|types/types.proto|third_party/proto/cosmos-sdk/types/types.proto|g' $(SUPPLY_PROTO_TYPES)/types.proto - @sed -i '' '6 s|x/auth/types/types.proto|third_party/proto/cosmos-sdk/x/auth/types/types.proto|g' $(SUPPLY_PROTO_TYPES)/types.proto + @mkdir -p $(TM_CRYPTO_TYPES) + @curl -sSL $(TM_URL)/crypto/proof.proto > $(TM_CRYPTO_TYPES)/proof.proto + @curl -sSL $(TM_URL)/crypto/keys.proto > $(TM_CRYPTO_TYPES)/keys.proto +.PHONY: proto-all proto-gen proto-gen-any proto-swagger-gen proto-format proto-lint proto-check-breaking proto-update-deps -.PHONY: proto-all proto-gen proto-lint proto-check-breaking proto-update-deps ############################################################################### diff --git a/buf.yaml b/buf.yaml index a0b081889..72a5e46b7 100644 --- a/buf.yaml +++ b/buf.yaml @@ -1,6 +1,9 @@ build: roots: - - . + - proto + - third_party/proto + excludes: + - third_party/proto/google/protobuf lint: use: - DEFAULT @@ -9,12 +12,20 @@ lint: except: - UNARY_RPC - COMMENT_FIELD - - PACKAGE_DIRECTORY_MATCH + - SERVICE_SUFFIX + - PACKAGE_VERSION_SUFFIX + - RPC_REQUEST_STANDARD_NAME ignore: - - third_party - - codec/testdata + - tendermint + - gogoproto + - cosmos_proto + - google + - confio breaking: use: - FILE ignore: - - third_party + - tendermint + - gogoproto + - cosmos_proto + - google diff --git a/go.mod b/go.mod index 31b95a783..90cd5b10a 100644 --- a/go.mod +++ b/go.mod @@ -11,12 +11,14 @@ require ( github.com/deckarep/golang-set v1.7.1 // indirect github.com/ethereum/go-ethereum v1.9.25 github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect + github.com/golang/protobuf v1.4.3 // indirect github.com/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.4.2 github.com/mattn/go-colorable v0.1.7 // indirect github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20200123000308-a60dcd172b4c github.com/pkg/errors v0.9.1 github.com/prometheus/tsdb v0.9.1 // indirect + github.com/regen-network/cosmos-proto v0.3.0 // indirect github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cobra v1.1.1 github.com/spf13/viper v1.7.1 @@ -29,3 +31,5 @@ require ( google.golang.org/grpc v1.30.0 // indirect gopkg.in/yaml.v2 v2.4.0 ) + +replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.2-alpha.regen.4 diff --git a/go.sum b/go.sum index a31ef98e3..de8c2d444 100644 --- a/go.sum +++ b/go.sum @@ -223,11 +223,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me 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= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -242,6 +237,7 @@ github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -251,6 +247,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= @@ -381,7 +379,6 @@ github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM5 github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/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= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23 h1:FOOIBWrEkLgmlgGfMuZT83xIwfPDxEI2OHu6xUmJMFE= @@ -557,6 +554,10 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/regen-network/cosmos-proto v0.3.0 h1:24dVpPrPi0GDoPVLesf2Ug98iK5QgVscPl0ga4Eoub0= +github.com/regen-network/cosmos-proto v0.3.0/go.mod h1:zuP2jVPHab6+IIyOx3nXHFN+euFNeS3W8XQkcdd4s7A= +github.com/regen-network/protobuf v1.3.2-alpha.regen.4 h1:c9jEnU+xm6vqyrQe3M94UFWqiXxRIKKnqBOh2EACmBE= +github.com/regen-network/protobuf v1.3.2-alpha.regen.4/go.mod h1:/J8/bR1T/NXyIdQDLUaq15LjNE83nRzkyrLAMcPewig= github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= @@ -831,7 +832,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -856,6 +856,7 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd h1:hHkvGJK23seRCflePJnVa9IMv8fsuavSCWKd11kDQFs= golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -889,6 +890,7 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 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= +google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= diff --git a/proto/ethermint/crypto/v1alpha1/ethsecp256k1/keys.proto b/proto/ethermint/crypto/v1alpha1/ethsecp256k1/keys.proto new file mode 100644 index 000000000..f1247094a --- /dev/null +++ b/proto/ethermint/crypto/v1alpha1/ethsecp256k1/keys.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package ethermint.crypto.v1alpha1.ethsecp256k1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/ethermint/crypto/ethsecp256k1"; + +// PubKey defines a type alias for an ecdsa.PublicKey that implements +// Tendermint's PubKey interface. It represents the 33-byte compressed public +// key format. +message PubKey { + option (gogoproto.goproto_stringer) = false; + + bytes key = 1; +} + +// PrivKey defines a type alias for an ecdsa.PrivateKey that implements +// Tendermint's PrivateKey interface. +message PrivKey { bytes key = 1; } diff --git a/proto/ethermint/evm/v1alpha1/evm.proto b/proto/ethermint/evm/v1alpha1/evm.proto new file mode 100644 index 000000000..6850b899d --- /dev/null +++ b/proto/ethermint/evm/v1alpha1/evm.proto @@ -0,0 +1,173 @@ +syntax = "proto3"; +package ethermint.evm.v1alpha1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/ethermint/x/evm/types"; + +// Params defines the EVM module parameters +message Params { + option (gogoproto.goproto_stringer) = false; + + // evm_denom represents the token denomination used to run the EVM state + // transitions. + string evm_denom = 1 [ (gogoproto.moretags) = "yaml:\"evm_denom\""]; + // enable_create toggles state transitions that use the vm.Create function + bool enable_create = 2 [ (gogoproto.moretags) = "yaml:\"enable_create\""]; + // enable_call toggles state transitions that use the vm.Call function + bool enable_call = 3 [ (gogoproto.moretags) = "yaml:\"enable_call\""]; + // extra_eips defines the additional EIPs for the vm.Config + repeated int64 extra_eips = 4 [ + (gogoproto.customname) = "ExtraEIPs", + (gogoproto.moretags) = "yaml:\"extra_eips\"" + ]; +} + +// ChainConfig defines the Ethereum ChainConfig parameters using sdk.Int values +// instead of big.Int. +// +// NOTE 1: Since empty/uninitialized Ints (i.e with a nil big.Int value) are +// parsed to zero, we need to manually specify that negative Int values will be +// considered as nil. See getBlockValue for reference. +// +// NOTE 2: This type is not a configurable Param since the SDK does not allow +// for validation against a previous stored parameter values or the current +// block height (retrieved from context). If you want to update the config +// values, use an software upgrade procedure. +message ChainConfig { + // Homestead switch block (< 0 no fork, 0 = already homestead) + string homestead_block = 1 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"homestead_block\"", + (gogoproto.nullable) = false + ]; + // TheDAO hard-fork switch block (< 0 no fork) + string dao_fork_block = 2 [ + (gogoproto.customname) = "DAOForkBlock", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"dao_fork_block\"", + (gogoproto.nullable) = false + ]; + // Whether the nodes supports or opposes the DAO hard-fork + bool dao_fork_support = 3 [ + (gogoproto.customname) = "DAOForkSupport", + (gogoproto.moretags) = "yaml:\"dao_fork_support\"" + ]; + // EIP150 implements the Gas price changes + // (https://github.com/ethereum/EIPs/issues/150) EIP150 HF block (< 0 no fork) + string eip150_block = 4 [ + (gogoproto.customname) = "EIP150Block", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"eip150_block\"", + (gogoproto.nullable) = false + ]; + // EIP150 HF hash (needed for header only clients as only gas pricing changed) + string eip150_hash = 5 [ + (gogoproto.customname) = "EIP150Hash", + (gogoproto.moretags) = "yaml:\"byzantium_block\"" + ]; + // EIP155Block HF block + string eip155_block = 6 [ + (gogoproto.customname) = "EIP155Block", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"eip155_block\"", + (gogoproto.nullable) = false + ]; + // EIP158 HF block + string eip158_block = 7 [ + (gogoproto.customname) = "EIP158Block", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"eip158_block\"", + (gogoproto.nullable) = false + ]; + // Byzantium switch block (< 0 no fork, 0 = already on byzantium) + string byzantium_block = 8 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"byzantium_block\"", + (gogoproto.nullable) = false + ]; + // Constantinople switch block (< 0 no fork, 0 = already activated) + string constantinople_block = 9 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"constantinople_block\"", + (gogoproto.nullable) = false + ]; + // Petersburg switch block (< 0 same as Constantinople) + string petersburg_block = 10 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"petersburg_block\"", + (gogoproto.nullable) = false + ]; + // Istanbul switch block (< 0 no fork, 0 = already on istanbul) + string istanbul_block = 11 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"istanbul_block\"", + (gogoproto.nullable) = false + ]; + // Eip-2384 (bomb delay) switch block (< 0 no fork, 0 = already activated) + string muir_glacier_block = 12 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"muir_glacier_block\"", + (gogoproto.nullable) = false + ]; + // YOLO v2: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet) + string yolo_v2_block = 13 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"yolo_v2_block\"", + (gogoproto.nullable) = false + ]; + // EWASM switch block (< 0 no fork, 0 = already activated) + string ewasm_block = 14 [ + (gogoproto.customname) = "EWASMBlock", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.moretags) = "yaml:\"ewasm_block\"", + (gogoproto.nullable) = false + ]; +} + +// State represents a single Storage key value pair item. +message State { + string key = 1; + string value = 2; +} + +// TransactionLogs define the logs generated from a transaction execution +// with a given hash. It it used for import/export data as transactions are not +// persisted on blockchain state after an upgrade. +message TransactionLogs { + string hash = 1; + repeated Log logs = 2; +} + +// Log represents an protobuf compatible Ethereum Log that defines a contract +// log event. These events are generated by the LOG opcode and stored/indexed by +// the node. +message Log { + // Consensus fields: + + // address of the contract that generated the event + string address = 1; + // list of topics provided by the contract. + repeated string topics = 2; + // supplied by the contract, usually ABI-encoded + bytes data = 3; + + // Derived fields. These fields are filled in by the node + // but not secured by consensus. + + // block in which the transaction was included + uint64 block_number = 4 [ (gogoproto.jsontag) = "blockNumber" ]; + // hash of the transaction + string tx_hash = 5 [ (gogoproto.jsontag) = "transactionHash" ]; + // index of the transaction in the block + uint64 tx_index = 6 [ (gogoproto.jsontag) = "transactionIndex" ]; + // hash of the block in which the transaction was included + string block_hash = 7 [ (gogoproto.jsontag) = "blockHash" ]; + // index of the log in the block + uint64 index = 8 [ (gogoproto.jsontag) = "logIndex" ]; + + // The Removed field is true if this log was reverted due to a chain + // reorganisation. You must pay attention to this field if you receive logs + // through a filter query. + bool removed = 9; +} diff --git a/proto/ethermint/evm/v1alpha1/genesis.proto b/proto/ethermint/evm/v1alpha1/genesis.proto new file mode 100644 index 000000000..536e3be0c --- /dev/null +++ b/proto/ethermint/evm/v1alpha1/genesis.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; +package ethermint.evm.v1alpha1; + +import "gogoproto/gogo.proto"; +import "ethermint/evm/v1alpha1/evm.proto"; + +option go_package = "github.com/cosmos/ethermint/x/evm/types"; + +// GenesisState defines the evm module's genesis state. +message GenesisState { + // accounts is an array containing the ethereum genesis accounts. + repeated GenesisAccount accounts = 1 [ (gogoproto.nullable) = false ]; + // chain_config defines the Ethereum chain configuration. + ChainConfig chain_config = 2 [ + (gogoproto.moretags) = "yaml:\"chain_config\"", + (gogoproto.nullable) = false + ]; + // params defines all the paramaters of the module. + Params params = 3 [ (gogoproto.nullable) = false ]; + + repeated TransactionLogs txs_logs = 4 [ + (gogoproto.moretags) = "yaml:\"txs_logs\"", + (gogoproto.nullable) = false + ]; +} + +// GenesisAccount defines an account to be initialized in the genesis state. +// Its main difference between with Geth's GenesisAccount is that it uses a +// custom storage type and that it doesn't contain the private key field. +message GenesisAccount { + // address defines an ethereum hex formated address of an account + string address = 1; + // balance defines the available evm tokens for the account + string balance = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // code defines the hex bytes of the account code. + string code = 3; + // storage defines the set of state key values for the account. + repeated State storage = 4 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "Storage" + ]; +} \ No newline at end of file diff --git a/proto/ethermint/evm/v1alpha1/query.proto b/proto/ethermint/evm/v1alpha1/query.proto new file mode 100644 index 000000000..55dafffd3 --- /dev/null +++ b/proto/ethermint/evm/v1alpha1/query.proto @@ -0,0 +1,172 @@ +syntax = "proto3"; +package ethermint.evm.v1alpha1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "ethermint/evm/v1alpha1/evm.proto"; + +option go_package = "github.com/cosmos/ethermint/x/evm/types"; + +// Query defines the gRPC querier service. +service Query { + // Account queries an Ethereum account. + rpc Account(QueryAccountRequest) returns (QueryAccountResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/account/{address}"; + } + + // Balance queries the balance of a the EVM denomination for a single + // EthAccount. + rpc Balance(QueryBalanceRequest) returns (QueryBalanceResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/balances/{address}"; + } + + // Storage queries the balance of all coins for a single account. + rpc Storage(QueryStorageRequest) returns (QueryStorageResponse) { + option (google.api.http).get = + "/ethermint/evm/v1alpha1/storage/{address}/{key}"; + } + + // Code queries the balance of all coins for a single account. + rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/codes/{address}"; + } + + // TxLogs queries ethereum logs from a transaction. + rpc TxLogs(QueryTxLogsRequest) returns (QueryTxLogsResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/tx_logs/{hash}"; + } + + // BlockLogs queries all the ethereum logs for a given block hash. + rpc BlockLogs(QueryBlockLogsRequest) returns (QueryBlockLogsResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/block_logs/{hash}"; + } + + // BlockBloom queries the block bloom filter bytes at a given height. + rpc BlockBloom(QueryBlockBloomRequest) returns (QueryBlockBloomResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/block_bloom"; + } + + // Params queries the parameters of x/evm module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ethermint/evm/v1alpha1/params"; + } +} + +// QueryAccountRequest is the request type for the Query/Account RPC method. +message QueryAccountRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // address is the ethereum hex address to query the account for. + string address = 1; +} + +// QueryAccountResponse is the response type for the Query/Account RPC method. +message QueryAccountResponse { + // balance is the balance of the EVM denomination. + string balance = 1; + // code_hash is the code bytes from the EOA. + bytes code_hash = 2; + // nonce is the account's sequence number. + uint64 nonce = 3; +} + +// QueryBalanceRequest is the request type for the Query/Balance RPC method. +message QueryBalanceRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // address is the ethereum hex address to query the balance for. + string address = 1; +} + +// QueryBalanceResponse is the response type for the Query/Balance RPC method. +message QueryBalanceResponse { + // balance is the balance of the EVM denomination. + string balance = 1; +} + +// QueryStorageRequest is the request type for the Query/Storage RPC method. +message QueryStorageRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + /// address is the ethereum hex address to query the storage state for. + string address = 1; + + // key defines the key of the storage state + string key = 2; +} + +// QueryStorageResponse is the response type for the Query/Storage RPC +// method. +message QueryStorageResponse { + // key defines the storage state value hash associated with the given key. + string value = 1; +} + +// QueryCodeRequest is the request type for the Query/Code RPC method. +message QueryCodeRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // address is the ethereum hex address to query the code for. + string address = 1; +} + +// QueryCodeResponse is the response type for the Query/Code RPC +// method. +message QueryCodeResponse { + // code represents the code bytes from an ethereum address. + bytes code = 1; +} + +// QueryTxLogsRequest is the request type for the Query/TxLogs RPC method. +message QueryTxLogsRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // hash is the ethereum transaction hex hash to query the logs for. + string hash = 1; +} + +// QueryTxLogs is the response type for the Query/TxLogs RPC method. +message QueryTxLogsResponse { + // logs represents the ethereum logs generated from the given transaction. + repeated Log logs = 1; +} + +// QueryBlockLogsRequest is the request type for the Query/BlockLogs RPC method. +message QueryBlockLogsRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // hash is the block hash to query the logs for. + string hash = 1; +} + +// QueryTxLogs is the response type for the Query/BlockLogs RPC method. +message QueryBlockLogsResponse { + // logs represents the ethereum logs generated at the given block hash. + repeated TransactionLogs tx_logs = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryBlockBloomRequest is the request type for the Query/BlockBloom RPC +// method. +message QueryBlockBloomRequest {} + +// QueryBlockBloomResponse is the response type for the Query/BlockBloom RPC +// method. +message QueryBlockBloomResponse { + // bloom represents bloom filter for the given block hash. + bytes bloom = 1; +} + +// QueryParamsRequest defines the request type for querying x/evm parameters. +message QueryParamsRequest {} + +// QueryParamsResponse defines the response type for querying x/evm parameters. +message QueryParamsResponse { + // params define the evm module parameters. + Params params = 1 [ (gogoproto.nullable) = false ]; +} diff --git a/proto/ethermint/evm/v1alpha1/tx.proto b/proto/ethermint/evm/v1alpha1/tx.proto new file mode 100644 index 000000000..1dd184927 --- /dev/null +++ b/proto/ethermint/evm/v1alpha1/tx.proto @@ -0,0 +1,106 @@ +syntax = "proto3"; +package ethermint.evm.v1alpha1; + +import "gogoproto/gogo.proto"; +import "ethermint/evm/v1alpha1/evm.proto"; + +option go_package = "github.com/cosmos/ethermint/x/evm/types"; + +// Msg defines the evm Msg service. +service Msg { + // EthereumTx defines a method submitting Ethereum transactions. + rpc EthereumTx(MsgEthereumTx) returns (MsgEthereumTxResponse); +} + +// MsgEthereumTx encapsulates an Ethereum transaction as an SDK message. +message MsgEthereumTx { + option (gogoproto.goproto_getters) = false; + + TxData data = 1; + // caches + double size = 2 [ (gogoproto.jsontag) = "-" ]; + SigCache from = 3 [ (gogoproto.jsontag) = "-" ]; +} + +// MsgEthereumTxResponse defines the Msg/EthereumTx response type. +message MsgEthereumTxResponse { + option (gogoproto.goproto_getters) = false; + + // contract_address contains the ethereum address of the created contract (if + // any). If the state transition is an evm.Call, the contract address will be + // empty. + string contract_address = 1 [(gogoproto.moretags) = "yaml:\"contract_address\""]; + // bloom represents the bloom filter bytes + bytes bloom = 2; + // tx_logs contains the transaction hash and the proto-compatible ethereum + // logs. + TransactionLogs tx_logs = 3 [ + (gogoproto.moretags) = "yaml:\"tx_logs\"", + (gogoproto.nullable) = false + ]; + // ret defines the bytes from the execution. + bytes ret = 4; +} + +// TxData implements the Ethereum transaction data structure. It is used +// solely as intended in Ethereum abiding by the protocol. +message TxData { + option (gogoproto.goproto_getters) = false; + + // nonce corresponds to the account nonce (transaction sequence). + uint64 nonce = 1 [(gogoproto.customname) = "AccountNonce"]; + // price defines the unsigned integer value of the gas price in bytes. + string price = 2 [ + (gogoproto.jsontag) = "gasPrice", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // gas defines the gas limit defined for the transaction. + uint64 gas = 3 [(gogoproto.customname) = "GasLimit"]; + Recipient to = 4 [ + (gogoproto.customname) = "Recipient", + (gogoproto.moretags) = "rlp:\"nil\"" + ]; + // value defines the unsigned integer value of the transaction amount. + string value = 5 [ + (gogoproto.customname) = "Amount", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // input defines the data payload bytes of the transaction. + bytes input = 6 [(gogoproto.customname) = "Payload"]; + // v defines the signature value + bytes v = 7; + // r defines the signature value + bytes r = 8; + // s define the signature value + bytes s = 9; + // hash defines the tx data hash, which is only used when marshaling to JSON. + string hash = 10 [ (gogoproto.moretags) = "rlp:\"-\"" ]; +} + +// Recipient defines a protobuf-compatible wrapper for an Ethereum address +// pointer. It is required for RLP encoding. +message Recipient { + option (gogoproto.goproto_getters) = false; + + // address defines the hex-formated ethereum address of the recipient + string address = 1; +} + +// SigCache is used to cache the derived sender and contains the signer used +// to derive it. +message SigCache { + option (gogoproto.goproto_getters) = false; + + EIP155Signer signer = 1; + string address = 2; +} + +// EIP155Transaction implements Signer using the EIP155 rules. +message EIP155Signer { + option (gogoproto.goproto_getters) = false; + + bytes chain_id = 1 [(gogoproto.customname) = "chainId"]; + bytes chain_id_mul = 2 [(gogoproto.customname) = "chainIdMul"]; +} \ No newline at end of file diff --git a/proto/ethermint/types/v1alpha1/account.proto b/proto/ethermint/types/v1alpha1/account.proto new file mode 100644 index 000000000..fcdff4651 --- /dev/null +++ b/proto/ethermint/types/v1alpha1/account.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package ethermint.types.v1alpha1; + +import "cosmos/auth/v1beta1/auth.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/ethermint/types"; + +// EthAccount implements the authtypes.AccountI interface and embeds an +// authtypes.BaseAccount type. It is compatible with the auth AccountKeeper. +message EthAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.equal) = false; + + option (cosmos_proto.implements_interface) = + "github.com/cosmos/cosmos-sdk/x/auth/types.AccountI"; + + cosmos.auth.v1beta1.BaseAccount base_account = 1 [ + (gogoproto.embed) = true, + (gogoproto.moretags) = "yaml:\"base_account\"" + ]; + bytes code_hash = 2 [ (gogoproto.moretags) = "yaml:\"code_hash\"" ]; +} diff --git a/scripts/protoc-swagger-gen.sh b/scripts/protoc-swagger-gen.sh new file mode 100755 index 000000000..7a6c62534 --- /dev/null +++ b/scripts/protoc-swagger-gen.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +set -eo pipefail + +mkdir -p ./tmp-swagger-gen +proto_dirs=$(find ./proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) +for dir in $proto_dirs; do + + # generate swagger files (filter query files) + query_file=$(find "${dir}" -maxdepth 1 -name 'query.proto') + if [[ ! -z "$query_file" ]]; then + buf protoc \ + -I "proto" \ + -I "third_party/proto" \ + "$query_file" \ + --swagger_out=./tmp-swagger-gen \ + --swagger_opt=logtostderr=true --swagger_opt=fqn_for_swagger_name=true --swagger_opt=simple_operation_ids=true + fi +done + +# combine swagger files +# uses nodejs package `swagger-combine`. +# all the individual swagger files need to be configured in `config.json` for merging +swagger-combine ./client/docs/config.json -o ./client/docs/swagger-ui/swagger.yaml -f yaml --continueOnConflictingPaths true --includeDefinitions true + +# clean swagger files +rm -rf ./tmp-swagger-gen diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index 0818824a4..28e247d44 100755 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -2,10 +2,39 @@ set -eo pipefail -proto_dirs=$(find . -path ./third_party -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) +protoc_gen_gocosmos() { + if ! grep "github.com/gogo/protobuf => github.com/regen-network/protobuf" go.mod &>/dev/null ; then + echo -e "\tPlease run this command from somewhere inside the ethermint folder." + return 1 + fi + + go get github.com/regen-network/cosmos-proto/protoc-gen-gocosmos 2>/dev/null +} + +protoc_gen_gocosmos + +proto_dirs=$(find ./proto -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq) for dir in $proto_dirs; do - protoc \ - -I. \ - --gocosmos_out=plugins=interfacetype,paths=source_relative:. \ - $(find "${dir}" -name '*.proto') + buf protoc \ + -I "proto" \ + -I "third_party/proto" \ + --gocosmos_out=plugins=interfacetype+grpc,\ +Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:. \ + $(find "${dir}" -maxdepth 1 -name '*.proto') + + # command to generate gRPC gateway (*.pb.gw.go in respective modules) files + buf protoc \ + -I "proto" \ + -I "third_party/proto" \ + --grpc-gateway_out=logtostderr=true:. \ + $(find "${dir}" -maxdepth 1 -name '*.proto') + done + +# generate codec/testdata proto code +buf protoc -I "proto" -I "third_party/proto" -I "testutil/testdata" --gocosmos_out=plugins=interfacetype+grpc,\ +Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:. ./testutil/testdata/*.proto + +# move proto files to the right places +cp -r github.com/cosmos/ethermint/* ./ +rm -rf github.com diff --git a/third_party/proto/cosmos_proto/cosmos.proto b/third_party/proto/cosmos_proto/cosmos.proto new file mode 100644 index 000000000..167b17075 --- /dev/null +++ b/third_party/proto/cosmos_proto/cosmos.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package cosmos_proto; + +import "google/protobuf/descriptor.proto"; + +option go_package = "github.com/regen-network/cosmos-proto"; + +extend google.protobuf.MessageOptions { + string interface_type = 93001; + + string implements_interface = 93002; +} + +extend google.protobuf.FieldOptions { + string accepts_interface = 93001; +} diff --git a/third_party/proto/gogoproto/gogo.proto b/third_party/proto/gogoproto/gogo.proto new file mode 100644 index 000000000..49e78f99f --- /dev/null +++ b/third_party/proto/gogoproto/gogo.proto @@ -0,0 +1,145 @@ +// Protocol Buffers for Go with Gadgets +// +// Copyright (c) 2013, The GoGo Authors. All rights reserved. +// http://github.com/gogo/protobuf +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; +package gogoproto; + +import "google/protobuf/descriptor.proto"; + +option java_package = "com.google.protobuf"; +option java_outer_classname = "GoGoProtos"; +option go_package = "github.com/gogo/protobuf/gogoproto"; + +extend google.protobuf.EnumOptions { + optional bool goproto_enum_prefix = 62001; + optional bool goproto_enum_stringer = 62021; + optional bool enum_stringer = 62022; + optional string enum_customname = 62023; + optional bool enumdecl = 62024; +} + +extend google.protobuf.EnumValueOptions { + optional string enumvalue_customname = 66001; +} + +extend google.protobuf.FileOptions { + optional bool goproto_getters_all = 63001; + optional bool goproto_enum_prefix_all = 63002; + optional bool goproto_stringer_all = 63003; + optional bool verbose_equal_all = 63004; + optional bool face_all = 63005; + optional bool gostring_all = 63006; + optional bool populate_all = 63007; + optional bool stringer_all = 63008; + optional bool onlyone_all = 63009; + + optional bool equal_all = 63013; + optional bool description_all = 63014; + optional bool testgen_all = 63015; + optional bool benchgen_all = 63016; + optional bool marshaler_all = 63017; + optional bool unmarshaler_all = 63018; + optional bool stable_marshaler_all = 63019; + + optional bool sizer_all = 63020; + + optional bool goproto_enum_stringer_all = 63021; + optional bool enum_stringer_all = 63022; + + optional bool unsafe_marshaler_all = 63023; + optional bool unsafe_unmarshaler_all = 63024; + + optional bool goproto_extensions_map_all = 63025; + optional bool goproto_unrecognized_all = 63026; + optional bool gogoproto_import = 63027; + optional bool protosizer_all = 63028; + optional bool compare_all = 63029; + optional bool typedecl_all = 63030; + optional bool enumdecl_all = 63031; + + optional bool goproto_registration = 63032; + optional bool messagename_all = 63033; + + optional bool goproto_sizecache_all = 63034; + optional bool goproto_unkeyed_all = 63035; +} + +extend google.protobuf.MessageOptions { + optional bool goproto_getters = 64001; + optional bool goproto_stringer = 64003; + optional bool verbose_equal = 64004; + optional bool face = 64005; + optional bool gostring = 64006; + optional bool populate = 64007; + optional bool stringer = 67008; + optional bool onlyone = 64009; + + optional bool equal = 64013; + optional bool description = 64014; + optional bool testgen = 64015; + optional bool benchgen = 64016; + optional bool marshaler = 64017; + optional bool unmarshaler = 64018; + optional bool stable_marshaler = 64019; + + optional bool sizer = 64020; + + optional bool unsafe_marshaler = 64023; + optional bool unsafe_unmarshaler = 64024; + + optional bool goproto_extensions_map = 64025; + optional bool goproto_unrecognized = 64026; + + optional bool protosizer = 64028; + optional bool compare = 64029; + + optional bool typedecl = 64030; + + optional bool messagename = 64033; + + optional bool goproto_sizecache = 64034; + optional bool goproto_unkeyed = 64035; +} + +extend google.protobuf.FieldOptions { + optional bool nullable = 65001; + optional bool embed = 65002; + optional string customtype = 65003; + optional string customname = 65004; + optional string jsontag = 65005; + optional string moretags = 65006; + optional string casttype = 65007; + optional string castkey = 65008; + optional string castvalue = 65009; + + optional bool stdtime = 65010; + optional bool stdduration = 65011; + optional bool wktpointer = 65012; + + optional string castrepeated = 65013; +} diff --git a/third_party/proto/google/api/annotations.proto b/third_party/proto/google/api/annotations.proto new file mode 100644 index 000000000..85c361b47 --- /dev/null +++ b/third_party/proto/google/api/annotations.proto @@ -0,0 +1,31 @@ +// Copyright (c) 2015, Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +import "google/api/http.proto"; +import "google/protobuf/descriptor.proto"; + +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "AnnotationsProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +extend google.protobuf.MethodOptions { + // See `HttpRule`. + HttpRule http = 72295728; +} diff --git a/third_party/proto/google/api/http.proto b/third_party/proto/google/api/http.proto new file mode 100644 index 000000000..2bd3a19bf --- /dev/null +++ b/third_party/proto/google/api/http.proto @@ -0,0 +1,318 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.api; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; +option java_multiple_files = true; +option java_outer_classname = "HttpProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + + +// Defines the HTTP configuration for an API service. It contains a list of +// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method +// to one or more HTTP REST API methods. +message Http { + // A list of HTTP configuration rules that apply to individual API methods. + // + // **NOTE:** All service configuration rules follow "last one wins" order. + repeated HttpRule rules = 1; + + // When set to true, URL path parmeters will be fully URI-decoded except in + // cases of single segment matches in reserved expansion, where "%2F" will be + // left encoded. + // + // The default behavior is to not decode RFC 6570 reserved characters in multi + // segment matches. + bool fully_decode_reserved_expansion = 2; +} + +// `HttpRule` defines the mapping of an RPC method to one or more HTTP +// REST API methods. The mapping specifies how different portions of the RPC +// request message are mapped to URL path, URL query parameters, and +// HTTP request body. The mapping is typically specified as an +// `google.api.http` annotation on the RPC method, +// see "google/api/annotations.proto" for details. +// +// The mapping consists of a field specifying the path template and +// method kind. The path template can refer to fields in the request +// message, as in the example below which describes a REST GET +// operation on a resource collection of messages: +// +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http).get = "/v1/messages/{message_id}/{sub.subfield}"; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // mapped to the URL +// SubMessage sub = 2; // `sub.subfield` is url-mapped +// } +// message Message { +// string text = 1; // content of the resource +// } +// +// The same http annotation can alternatively be expressed inside the +// `GRPC API Configuration` YAML file. +// +// http: +// rules: +// - selector: .Messaging.GetMessage +// get: /v1/messages/{message_id}/{sub.subfield} +// +// This definition enables an automatic, bidrectional mapping of HTTP +// JSON to RPC. Example: +// +// HTTP | RPC +// -----|----- +// `GET /v1/messages/123456/foo` | `GetMessage(message_id: "123456" sub: SubMessage(subfield: "foo"))` +// +// In general, not only fields but also field paths can be referenced +// from a path pattern. Fields mapped to the path pattern cannot be +// repeated and must have a primitive (non-message) type. +// +// Any fields in the request message which are not bound by the path +// pattern automatically become (optional) HTTP query +// parameters. Assume the following definition of the request message: +// +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http).get = "/v1/messages/{message_id}"; +// } +// } +// message GetMessageRequest { +// message SubMessage { +// string subfield = 1; +// } +// string message_id = 1; // mapped to the URL +// int64 revision = 2; // becomes a parameter +// SubMessage sub = 3; // `sub.subfield` becomes a parameter +// } +// +// +// This enables a HTTP JSON to RPC mapping as below: +// +// HTTP | RPC +// -----|----- +// `GET /v1/messages/123456?revision=2&sub.subfield=foo` | `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: "foo"))` +// +// Note that fields which are mapped to HTTP parameters must have a +// primitive type or a repeated primitive type. Message types are not +// allowed. In the case of a repeated type, the parameter can be +// repeated in the URL, as in `...?param=A¶m=B`. +// +// For HTTP method kinds which allow a request body, the `body` field +// specifies the mapping. Consider a REST update method on the +// message resource collection: +// +// +// service Messaging { +// rpc UpdateMessage(UpdateMessageRequest) returns (Message) { +// option (google.api.http) = { +// put: "/v1/messages/{message_id}" +// body: "message" +// }; +// } +// } +// message UpdateMessageRequest { +// string message_id = 1; // mapped to the URL +// Message message = 2; // mapped to the body +// } +// +// +// The following HTTP JSON to RPC mapping is enabled, where the +// representation of the JSON in the request body is determined by +// protos JSON encoding: +// +// HTTP | RPC +// -----|----- +// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" message { text: "Hi!" })` +// +// The special name `*` can be used in the body mapping to define that +// every field not bound by the path template should be mapped to the +// request body. This enables the following alternative definition of +// the update method: +// +// service Messaging { +// rpc UpdateMessage(Message) returns (Message) { +// option (google.api.http) = { +// put: "/v1/messages/{message_id}" +// body: "*" +// }; +// } +// } +// message Message { +// string message_id = 1; +// string text = 2; +// } +// +// +// The following HTTP JSON to RPC mapping is enabled: +// +// HTTP | RPC +// -----|----- +// `PUT /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: "123456" text: "Hi!")` +// +// Note that when using `*` in the body mapping, it is not possible to +// have HTTP parameters, as all fields not bound by the path end in +// the body. This makes this option more rarely used in practice of +// defining REST APIs. The common usage of `*` is in custom methods +// which don't use the URL at all for transferring data. +// +// It is possible to define multiple HTTP methods for one RPC by using +// the `additional_bindings` option. Example: +// +// service Messaging { +// rpc GetMessage(GetMessageRequest) returns (Message) { +// option (google.api.http) = { +// get: "/v1/messages/{message_id}" +// additional_bindings { +// get: "/v1/users/{user_id}/messages/{message_id}" +// } +// }; +// } +// } +// message GetMessageRequest { +// string message_id = 1; +// string user_id = 2; +// } +// +// +// This enables the following two alternative HTTP JSON to RPC +// mappings: +// +// HTTP | RPC +// -----|----- +// `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` +// `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: "123456")` +// +// # Rules for HTTP mapping +// +// The rules for mapping HTTP path, query parameters, and body fields +// to the request message are as follows: +// +// 1. The `body` field specifies either `*` or a field path, or is +// omitted. If omitted, it indicates there is no HTTP request body. +// 2. Leaf fields (recursive expansion of nested messages in the +// request) can be classified into three types: +// (a) Matched in the URL template. +// (b) Covered by body (if body is `*`, everything except (a) fields; +// else everything under the body field) +// (c) All other fields. +// 3. URL query parameters found in the HTTP request are mapped to (c) fields. +// 4. Any body sent with an HTTP request can contain only (b) fields. +// +// The syntax of the path template is as follows: +// +// Template = "/" Segments [ Verb ] ; +// Segments = Segment { "/" Segment } ; +// Segment = "*" | "**" | LITERAL | Variable ; +// Variable = "{" FieldPath [ "=" Segments ] "}" ; +// FieldPath = IDENT { "." IDENT } ; +// Verb = ":" LITERAL ; +// +// The syntax `*` matches a single path segment. The syntax `**` matches zero +// or more path segments, which must be the last part of the path except the +// `Verb`. The syntax `LITERAL` matches literal text in the path. +// +// The syntax `Variable` matches part of the URL path as specified by its +// template. A variable template must not contain other variables. If a variable +// matches a single path segment, its template may be omitted, e.g. `{var}` +// is equivalent to `{var=*}`. +// +// If a variable contains exactly one path segment, such as `"{var}"` or +// `"{var=*}"`, when such a variable is expanded into a URL path, all characters +// except `[-_.~0-9a-zA-Z]` are percent-encoded. Such variables show up in the +// Discovery Document as `{var}`. +// +// If a variable contains one or more path segments, such as `"{var=foo/*}"` +// or `"{var=**}"`, when such a variable is expanded into a URL path, all +// characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. Such variables +// show up in the Discovery Document as `{+var}`. +// +// NOTE: While the single segment variable matches the semantics of +// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 +// Simple String Expansion, the multi segment variable **does not** match +// RFC 6570 Reserved Expansion. The reason is that the Reserved Expansion +// does not expand special characters like `?` and `#`, which would lead +// to invalid URLs. +// +// NOTE: the field paths in variables and in the `body` must not refer to +// repeated fields or map fields. +message HttpRule { + // Selects methods to which this rule applies. + // + // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + string selector = 1; + + // Determines the URL pattern is matched by this rules. This pattern can be + // used with any of the {get|put|post|delete|patch} methods. A custom method + // can be defined using the 'custom' field. + oneof pattern { + // Used for listing and getting information about resources. + string get = 2; + + // Used for updating a resource. + string put = 3; + + // Used for creating a resource. + string post = 4; + + // Used for deleting a resource. + string delete = 5; + + // Used for updating a resource. + string patch = 6; + + // The custom pattern is used for specifying an HTTP method that is not + // included in the `pattern` field, such as HEAD, or "*" to leave the + // HTTP method unspecified for this rule. The wild-card rule is useful + // for services that provide content to Web (HTML) clients. + CustomHttpPattern custom = 8; + } + + // The name of the request field whose value is mapped to the HTTP body, or + // `*` for mapping all fields not captured by the path pattern to the HTTP + // body. NOTE: the referred field must not be a repeated field and must be + // present at the top-level of request message type. + string body = 7; + + // Optional. The name of the response field whose value is mapped to the HTTP + // body of response. Other response fields are ignored. When + // not set, the response message will be used as HTTP body of response. + string response_body = 12; + + // Additional HTTP bindings for the selector. Nested bindings must + // not contain an `additional_bindings` field themselves (that is, + // the nesting may only be one level deep). + repeated HttpRule additional_bindings = 11; +} + +// A custom pattern is used for defining custom HTTP verb. +message CustomHttpPattern { + // The name of this custom HTTP verb. + string kind = 1; + + // The path matched by this custom verb. + string path = 2; +} diff --git a/third_party/proto/google/api/httpbody.proto b/third_party/proto/google/api/httpbody.proto new file mode 100644 index 000000000..4428515c1 --- /dev/null +++ b/third_party/proto/google/api/httpbody.proto @@ -0,0 +1,78 @@ +// Copyright 2018 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.api; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody"; +option java_multiple_files = true; +option java_outer_classname = "HttpBodyProto"; +option java_package = "com.google.api"; +option objc_class_prefix = "GAPI"; + +// Message that represents an arbitrary HTTP body. It should only be used for +// payload formats that can't be represented as JSON, such as raw binary or +// an HTML page. +// +// +// This message can be used both in streaming and non-streaming API methods in +// the request as well as the response. +// +// It can be used as a top-level request field, which is convenient if one +// wants to extract parameters from either the URL or HTTP template into the +// request fields and also want access to the raw HTTP body. +// +// Example: +// +// message GetResourceRequest { +// // A unique request id. +// string request_id = 1; +// +// // The raw HTTP body is bound to this field. +// google.api.HttpBody http_body = 2; +// } +// +// service ResourceService { +// rpc GetResource(GetResourceRequest) returns (google.api.HttpBody); +// rpc UpdateResource(google.api.HttpBody) returns +// (google.protobuf.Empty); +// } +// +// Example with streaming methods: +// +// service CaldavService { +// rpc GetCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// rpc UpdateCalendar(stream google.api.HttpBody) +// returns (stream google.api.HttpBody); +// } +// +// Use of this type only changes how the request and response bodies are +// handled, all other features will continue to work unchanged. +message HttpBody { + // The HTTP Content-Type header value specifying the content type of the body. + string content_type = 1; + + // The HTTP request/response body as raw binary. + bytes data = 2; + + // Application specific response metadata. Must be set in the first response + // for streaming APIs. + repeated google.protobuf.Any extensions = 3; +} \ No newline at end of file diff --git a/third_party/proto/google/protobuf/any.proto b/third_party/proto/google/protobuf/any.proto new file mode 100644 index 000000000..1431810ea --- /dev/null +++ b/third_party/proto/google/protobuf/any.proto @@ -0,0 +1,161 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package google.protobuf; + +import "gogoproto/gogo.proto"; + +option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "types"; +option java_package = "com.google.protobuf"; +option java_outer_classname = "AnyProto"; +option java_multiple_files = true; +option objc_class_prefix = "GPB"; + +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// Example 3: Pack and unpack a message in Python. +// +// foo = Foo(...) +// any = Any() +// any.Pack(foo) +// ... +// if any.Is(Foo.DESCRIPTOR): +// any.Unpack(foo) +// ... +// +// Example 4: Pack and unpack a message in Go +// +// foo := &pb.Foo{...} +// any, err := ptypes.MarshalAny(foo) +// ... +// foo := &pb.Foo{} +// if err := ptypes.UnmarshalAny(any, foo); err != nil { +// ... +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". +// +// +// JSON +// ==== +// The JSON representation of an `Any` value uses the regular +// representation of the deserialized, embedded message, with an +// additional field `@type` which contains the type URL. Example: +// +// package google.profile; +// message Person { +// string first_name = 1; +// string last_name = 2; +// } +// +// { +// "@type": "type.googleapis.com/google.profile.Person", +// "firstName": , +// "lastName": +// } +// +// If the embedded message type is well-known and has a custom JSON +// representation, that representation will be embedded adding a field +// `value` which holds the custom JSON in addition to the `@type` +// field. Example (for message [google.protobuf.Duration][]): +// +// { +// "@type": "type.googleapis.com/google.protobuf.Duration", +// "value": "1.212s" +// } +// +message Any { + // A URL/resource name that uniquely identifies the type of the serialized + // protocol buffer message. This string must contain at least + // one "/" character. The last segment of the URL's path must represent + // the fully qualified name of the type (as in + // `path/google.protobuf.Duration`). The name should be in a canonical form + // (e.g., leading "." is not accepted). + // + // In practice, teams usually precompile into the binary all types that they + // expect it to use in the context of Any. However, for URLs which use the + // scheme `http`, `https`, or no scheme, one can optionally set up a type + // server that maps type URLs to message definitions as follows: + // + // * If no scheme is provided, `https` is assumed. + // * An HTTP GET on the URL must yield a [google.protobuf.Type][] + // value in binary format, or produce an error. + // * Applications are allowed to cache lookup results based on the + // URL, or have them precompiled into a binary to avoid any + // lookup. Therefore, binary compatibility needs to be preserved + // on changes to types. (Use versioned type names to manage + // breaking changes.) + // + // Note: this functionality is not currently available in the official + // protobuf release, and it is not used for type URLs beginning with + // type.googleapis.com. + // + // Schemes other than `http`, `https` (or the empty scheme) might be + // used with implementation specific semantics. + // + string type_url = 1; + + // Must be a valid serialized protocol buffer of the above specified type. + bytes value = 2; + + option (gogoproto.typedecl) = false; +} + +option (gogoproto.goproto_registration) = false; diff --git a/third_party/proto/tendermint/abci/types.proto b/third_party/proto/tendermint/abci/types.proto new file mode 100644 index 000000000..2cbcabb29 --- /dev/null +++ b/third_party/proto/tendermint/abci/types.proto @@ -0,0 +1,407 @@ +syntax = "proto3"; +package tendermint.abci; + +option go_package = "github.com/tendermint/tendermint/abci/types"; + +// For more information on gogo.proto, see: +// https://github.com/gogo/protobuf/blob/master/extensions.md +import "tendermint/crypto/proof.proto"; +import "tendermint/types/types.proto"; +import "tendermint/crypto/keys.proto"; +import "tendermint/types/params.proto"; +import "google/protobuf/timestamp.proto"; +import "gogoproto/gogo.proto"; + +// This file is copied from http://github.com/tendermint/abci +// NOTE: When using custom types, mind the warnings. +// https://github.com/gogo/protobuf/blob/master/custom_types.md#warnings-and-issues + +//---------------------------------------- +// Request types + +message Request { + oneof value { + RequestEcho echo = 1; + RequestFlush flush = 2; + RequestInfo info = 3; + RequestSetOption set_option = 4; + RequestInitChain init_chain = 5; + RequestQuery query = 6; + RequestBeginBlock begin_block = 7; + RequestCheckTx check_tx = 8; + RequestDeliverTx deliver_tx = 9; + RequestEndBlock end_block = 10; + RequestCommit commit = 11; + RequestListSnapshots list_snapshots = 12; + RequestOfferSnapshot offer_snapshot = 13; + RequestLoadSnapshotChunk load_snapshot_chunk = 14; + RequestApplySnapshotChunk apply_snapshot_chunk = 15; + } +} + +message RequestEcho { + string message = 1; +} + +message RequestFlush {} + +message RequestInfo { + string version = 1; + uint64 block_version = 2; + uint64 p2p_version = 3; +} + +// nondeterministic +message RequestSetOption { + string key = 1; + string value = 2; +} + +message RequestInitChain { + 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; + int64 initial_height = 6; +} + +message RequestQuery { + bytes data = 1; + string path = 2; + int64 height = 3; + bool prove = 4; +} + +message RequestBeginBlock { + bytes hash = 1; + tendermint.types.Header header = 2 [(gogoproto.nullable) = false]; + LastCommitInfo last_commit_info = 3 [(gogoproto.nullable) = false]; + repeated Evidence byzantine_validators = 4 [(gogoproto.nullable) = false]; +} + +enum CheckTxType { + NEW = 0 [(gogoproto.enumvalue_customname) = "New"]; + RECHECK = 1 [(gogoproto.enumvalue_customname) = "Recheck"]; +} + +message RequestCheckTx { + bytes tx = 1; + CheckTxType type = 2; +} + +message RequestDeliverTx { + bytes tx = 1; +} + +message RequestEndBlock { + int64 height = 1; +} + +message RequestCommit {} + +// lists available snapshots +message RequestListSnapshots { +} + +// offers a snapshot to the application +message RequestOfferSnapshot { + Snapshot snapshot = 1; // snapshot offered by peers + bytes app_hash = 2; // light client-verified app hash for snapshot height +} + +// loads a snapshot chunk +message RequestLoadSnapshotChunk { + uint64 height = 1; + uint32 format = 2; + uint32 chunk = 3; +} + +// Applies a snapshot chunk +message RequestApplySnapshotChunk { + uint32 index = 1; + bytes chunk = 2; + string sender = 3; +} + +//---------------------------------------- +// Response types + +message Response { + oneof value { + ResponseException exception = 1; + ResponseEcho echo = 2; + ResponseFlush flush = 3; + ResponseInfo info = 4; + ResponseSetOption set_option = 5; + ResponseInitChain init_chain = 6; + ResponseQuery query = 7; + ResponseBeginBlock begin_block = 8; + ResponseCheckTx check_tx = 9; + ResponseDeliverTx deliver_tx = 10; + ResponseEndBlock end_block = 11; + ResponseCommit commit = 12; + ResponseListSnapshots list_snapshots = 13; + ResponseOfferSnapshot offer_snapshot = 14; + ResponseLoadSnapshotChunk load_snapshot_chunk = 15; + ResponseApplySnapshotChunk apply_snapshot_chunk = 16; + } +} + +// nondeterministic +message ResponseException { + string error = 1; +} + +message ResponseEcho { + string message = 1; +} + +message ResponseFlush {} + +message ResponseInfo { + string data = 1; + + string version = 2; + uint64 app_version = 3; + + int64 last_block_height = 4; + bytes last_block_app_hash = 5; +} + +// nondeterministic +message ResponseSetOption { + uint32 code = 1; + // bytes data = 2; + string log = 3; + string info = 4; +} + +message ResponseInitChain { + ConsensusParams consensus_params = 1; + repeated ValidatorUpdate validators = 2 [(gogoproto.nullable) = false]; + bytes app_hash = 3; +} + +message ResponseQuery { + uint32 code = 1; + // bytes data = 2; // use "value" instead. + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 index = 5; + bytes key = 6; + bytes value = 7; + tendermint.crypto.ProofOps proof_ops = 8; + int64 height = 9; + string codespace = 10; +} + +message ResponseBeginBlock { + repeated Event events = 1 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; +} + +message ResponseCheckTx { + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5 [json_name = "gas_wanted"]; + int64 gas_used = 6 [json_name = "gas_used"]; + repeated Event events = 7 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; + string codespace = 8; +} + +message ResponseDeliverTx { + uint32 code = 1; + bytes data = 2; + string log = 3; // nondeterministic + string info = 4; // nondeterministic + int64 gas_wanted = 5 [json_name = "gas_wanted"]; + int64 gas_used = 6 [json_name = "gas_used"]; + repeated Event events = 7 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; + string codespace = 8; +} + +message ResponseEndBlock { + repeated ValidatorUpdate validator_updates = 1 + [(gogoproto.nullable) = false]; + ConsensusParams consensus_param_updates = 2; + repeated Event events = 3 + [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; +} + +message ResponseCommit { + // reserve 1 + bytes data = 2; + int64 retain_height = 3; +} + +message ResponseListSnapshots { + repeated Snapshot snapshots = 1; +} + +message ResponseOfferSnapshot { + Result result = 1; + + enum Result { + UNKNOWN = 0; // Unknown result, abort all snapshot restoration + ACCEPT = 1; // Snapshot accepted, apply chunks + ABORT = 2; // Abort all snapshot restoration + REJECT = 3; // Reject this specific snapshot, try others + REJECT_FORMAT = 4; // Reject all snapshots of this format, try others + REJECT_SENDER = 5; // Reject all snapshots from the sender(s), try others + } +} + +message ResponseLoadSnapshotChunk { + bytes chunk = 1; +} + +message ResponseApplySnapshotChunk { + Result result = 1; + repeated uint32 refetch_chunks = 2; // Chunks to refetch and reapply + repeated string reject_senders = 3; // Chunk senders to reject and ban + + enum Result { + UNKNOWN = 0; // Unknown result, abort all snapshot restoration + ACCEPT = 1; // Chunk successfully accepted + ABORT = 2; // Abort all snapshot restoration + RETRY = 3; // Retry chunk (combine with refetch and reject) + RETRY_SNAPSHOT = 4; // Retry snapshot (combine with refetch and reject) + REJECT_SNAPSHOT = 5; // Reject this snapshot, try others + } +} + +//---------------------------------------- +// Misc. + +// ConsensusParams contains all consensus-relevant parameters +// that can be adjusted by the abci app +message ConsensusParams { + BlockParams block = 1; + tendermint.types.EvidenceParams evidence = 2; + tendermint.types.ValidatorParams validator = 3; + tendermint.types.VersionParams version = 4; +} + +// BlockParams contains limits on the block size. +message BlockParams { + // Note: must be greater than 0 + int64 max_bytes = 1; + // Note: must be greater or equal to -1 + int64 max_gas = 2; +} + +message LastCommitInfo { + int32 round = 1; + repeated VoteInfo votes = 2 [(gogoproto.nullable) = false]; +} + +// Event allows application developers to attach additional information to +// ResponseBeginBlock, ResponseEndBlock, ResponseCheckTx and ResponseDeliverTx. +// Later, transactions may be queried using these events. +message Event { + string type = 1; + repeated EventAttribute attributes = 2 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "attributes,omitempty" + ]; +} + +// EventAttribute is a single key-value pair, associated with an event. +message EventAttribute { + bytes key = 1; + bytes value = 2; + bool index = 3; // nondeterministic +} + +// TxResult contains results of executing the transaction. +// +// One usage is indexing transaction results. +message TxResult { + int64 height = 1; + uint32 index = 2; + bytes tx = 3; + ResponseDeliverTx result = 4 [(gogoproto.nullable) = false]; +} + +//---------------------------------------- +// Blockchain Types + +// Validator +message Validator { + bytes address = 1; // The first 20 bytes of SHA256(public key) + // PubKey pub_key = 2 [(gogoproto.nullable)=false]; + int64 power = 3; // The voting power +} + +// ValidatorUpdate +message ValidatorUpdate { + tendermint.crypto.PublicKey pub_key = 1 [(gogoproto.nullable) = false]; + int64 power = 2; +} + +// VoteInfo +message VoteInfo { + Validator validator = 1 [(gogoproto.nullable) = false]; + bool signed_last_block = 2; +} + +enum EvidenceType { + UNKNOWN = 0; + DUPLICATE_VOTE = 1; + LIGHT_CLIENT_ATTACK = 2; +} + +message Evidence { + EvidenceType type = 1; + // The offending validator + Validator validator = 2 [(gogoproto.nullable) = false]; + // The height when the offense occurred + int64 height = 3; + // The corresponding time where the offense occurred + google.protobuf.Timestamp time = 4 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true + ]; + // Total voting power of the validator set in case the ABCI application does + // not store historical validators. + // https://github.com/tendermint/tendermint/issues/4581 + int64 total_voting_power = 5; +} + +//---------------------------------------- +// State Sync Types + +message Snapshot { + uint64 height = 1; // The height at which the snapshot was taken + uint32 format = 2; // The application-specific snapshot format + uint32 chunks = 3; // Number of chunks in the snapshot + bytes hash = 4; // Arbitrary snapshot hash, equal only if identical + bytes metadata = 5; // Arbitrary application metadata +} + +//---------------------------------------- +// Service Definition + +service ABCIApplication { + rpc Echo(RequestEcho) returns (ResponseEcho); + rpc Flush(RequestFlush) returns (ResponseFlush); + rpc Info(RequestInfo) returns (ResponseInfo); + rpc SetOption(RequestSetOption) returns (ResponseSetOption); + rpc DeliverTx(RequestDeliverTx) returns (ResponseDeliverTx); + rpc CheckTx(RequestCheckTx) returns (ResponseCheckTx); + rpc Query(RequestQuery) returns (ResponseQuery); + rpc Commit(RequestCommit) returns (ResponseCommit); + rpc InitChain(RequestInitChain) returns (ResponseInitChain); + rpc BeginBlock(RequestBeginBlock) returns (ResponseBeginBlock); + rpc EndBlock(RequestEndBlock) returns (ResponseEndBlock); + rpc ListSnapshots(RequestListSnapshots) returns (ResponseListSnapshots); + rpc OfferSnapshot(RequestOfferSnapshot) returns (ResponseOfferSnapshot); + rpc LoadSnapshotChunk(RequestLoadSnapshotChunk) returns (ResponseLoadSnapshotChunk); + rpc ApplySnapshotChunk(RequestApplySnapshotChunk) returns (ResponseApplySnapshotChunk); +} diff --git a/third_party/proto/tendermint/crypto/keys.proto b/third_party/proto/tendermint/crypto/keys.proto new file mode 100644 index 000000000..16fd7adf3 --- /dev/null +++ b/third_party/proto/tendermint/crypto/keys.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package tendermint.crypto; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto"; + +import "gogoproto/gogo.proto"; + +// PublicKey defines the keys available for use with Tendermint Validators +message PublicKey { + option (gogoproto.compare) = true; + option (gogoproto.equal) = true; + + oneof sum { + bytes ed25519 = 1; + bytes secp256k1 = 2; + } +} diff --git a/third_party/proto/tendermint/crypto/proof.proto b/third_party/proto/tendermint/crypto/proof.proto new file mode 100644 index 000000000..975df7685 --- /dev/null +++ b/third_party/proto/tendermint/crypto/proof.proto @@ -0,0 +1,41 @@ +syntax = "proto3"; +package tendermint.crypto; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/crypto"; + +import "gogoproto/gogo.proto"; + +message Proof { + int64 total = 1; + int64 index = 2; + bytes leaf_hash = 3; + repeated bytes aunts = 4; +} + +message ValueOp { + // Encoded in ProofOp.Key. + bytes key = 1; + + // To encode in ProofOp.Data + Proof proof = 2; +} + +message DominoOp { + string key = 1; + string input = 2; + string output = 3; +} + +// ProofOp defines an operation used for calculating Merkle root +// The data could be arbitrary format, providing nessecary data +// for example neighbouring node hash +message ProofOp { + string type = 1; + bytes key = 2; + bytes data = 3; +} + +// ProofOps is Merkle proof defined by the list of ProofOps +message ProofOps { + repeated ProofOp ops = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/tendermint/types/types.proto b/third_party/proto/tendermint/types/types.proto new file mode 100644 index 000000000..7f7ea74ca --- /dev/null +++ b/third_party/proto/tendermint/types/types.proto @@ -0,0 +1,157 @@ +syntax = "proto3"; +package tendermint.types; + +option go_package = "github.com/tendermint/tendermint/proto/tendermint/types"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/timestamp.proto"; +import "tendermint/crypto/proof.proto"; +import "tendermint/version/types.proto"; +import "tendermint/types/validator.proto"; + +// BlockIdFlag indicates which BlcokID the signature is for +enum BlockIDFlag { + option (gogoproto.goproto_enum_stringer) = true; + option (gogoproto.goproto_enum_prefix) = false; + + BLOCK_ID_FLAG_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "BlockIDFlagUnknown"]; + BLOCK_ID_FLAG_ABSENT = 1 [(gogoproto.enumvalue_customname) = "BlockIDFlagAbsent"]; + BLOCK_ID_FLAG_COMMIT = 2 [(gogoproto.enumvalue_customname) = "BlockIDFlagCommit"]; + BLOCK_ID_FLAG_NIL = 3 [(gogoproto.enumvalue_customname) = "BlockIDFlagNil"]; +} + +// SignedMsgType is a type of signed message in the consensus. +enum SignedMsgType { + option (gogoproto.goproto_enum_stringer) = true; + option (gogoproto.goproto_enum_prefix) = false; + + SIGNED_MSG_TYPE_UNKNOWN = 0 [(gogoproto.enumvalue_customname) = "UnknownType"]; + // Votes + SIGNED_MSG_TYPE_PREVOTE = 1 [(gogoproto.enumvalue_customname) = "PrevoteType"]; + SIGNED_MSG_TYPE_PRECOMMIT = 2 [(gogoproto.enumvalue_customname) = "PrecommitType"]; + + // Proposals + SIGNED_MSG_TYPE_PROPOSAL = 32 [(gogoproto.enumvalue_customname) = "ProposalType"]; +} + +// PartsetHeader +message PartSetHeader { + uint32 total = 1; + bytes hash = 2; +} + +message Part { + uint32 index = 1; + bytes bytes = 2; + tendermint.crypto.Proof proof = 3 [(gogoproto.nullable) = false]; +} + +// BlockID +message BlockID { + bytes hash = 1; + PartSetHeader part_set_header = 2 [(gogoproto.nullable) = false]; +} + +// -------------------------------- + +// Header defines the structure of a Tendermint block header. +message Header { + // basic block info + tendermint.version.Consensus version = 1 [(gogoproto.nullable) = false]; + string chain_id = 2 [(gogoproto.customname) = "ChainID"]; + int64 height = 3; + google.protobuf.Timestamp time = 4 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + + // prev block info + BlockID last_block_id = 5 [(gogoproto.nullable) = false]; + + // hashes of block data + bytes last_commit_hash = 6; // commit from validators from the last block + bytes data_hash = 7; // transactions + + // hashes from the app output from the prev block + bytes validators_hash = 8; // validators for the current block + bytes next_validators_hash = 9; // validators for the next block + bytes consensus_hash = 10; // consensus params for current block + bytes app_hash = 11; // state after txs from the previous block + bytes last_results_hash = 12; // root hash of all results from the txs from the previous block + + // consensus info + bytes evidence_hash = 13; // evidence included in the block + bytes proposer_address = 14; // original proposer of the block +} + +// Data contains the set of transactions included in the block +message Data { + // Txs that will be applied by state @ block.Height+1. + // NOTE: not all txs here are valid. We're just agreeing on the order first. + // This means that block.AppHash does not include these txs. + repeated bytes txs = 1; +} + +// Vote represents a prevote, precommit, or commit vote from validators for +// consensus. +message Vote { + SignedMsgType type = 1; + int64 height = 2; + int32 round = 3; + BlockID block_id = 4 + [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; // zero if vote is nil. + google.protobuf.Timestamp timestamp = 5 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes validator_address = 6; + int32 validator_index = 7; + bytes signature = 8; +} + +// Commit contains the evidence that a block was committed by a set of validators. +message Commit { + int64 height = 1; + int32 round = 2; + BlockID block_id = 3 [(gogoproto.nullable) = false, (gogoproto.customname) = "BlockID"]; + repeated CommitSig signatures = 4 [(gogoproto.nullable) = false]; +} + +// CommitSig is a part of the Vote included in a Commit. +message CommitSig { + BlockIDFlag block_id_flag = 1; + bytes validator_address = 2; + google.protobuf.Timestamp timestamp = 3 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes signature = 4; +} + +message Proposal { + SignedMsgType type = 1; + int64 height = 2; + int32 round = 3; + int32 pol_round = 4; + BlockID block_id = 5 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; + google.protobuf.Timestamp timestamp = 6 + [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + bytes signature = 7; +} + +message SignedHeader { + Header header = 1; + Commit commit = 2; +} + +message LightBlock { + SignedHeader signed_header = 1; + tendermint.types.ValidatorSet validator_set = 2; +} + +message BlockMeta { + BlockID block_id = 1 [(gogoproto.customname) = "BlockID", (gogoproto.nullable) = false]; + int64 block_size = 2; + Header header = 3 [(gogoproto.nullable) = false]; + int64 num_txs = 4; +} + +// TxProof represents a Merkle proof of the presence of a transaction in the Merkle tree. +message TxProof { + bytes root_hash = 1; + bytes data = 2; + tendermint.crypto.Proof proof = 3; +} From 153478eb691aec668558a811a837bf3587784127 Mon Sep 17 00:00:00 2001 From: Pierre <974741468@qq.com> Date: Fri, 8 Jan 2021 20:28:25 +0800 Subject: [PATCH 3/7] evm: roll back CommitStateDB after failing to execute handler (#677) * Roll back CommitStateDB after failing to execute handler in evm module * add function CopyCommitStateDB * add comment * add comment * Add ut about the dirty data generated by CommitStateDB * format code --- x/evm/handler.go | 40 +++++++++++++-- x/evm/handler_test.go | 110 +++++++++++++++++++++++++++++++++++++++++ x/evm/types/statedb.go | 66 +++++++++++++------------ 3 files changed, 182 insertions(+), 34 deletions(-) diff --git a/x/evm/handler.go b/x/evm/handler.go index d1347f4a1..e4e25f70e 100644 --- a/x/evm/handler.go +++ b/x/evm/handler.go @@ -14,16 +14,50 @@ import ( // NewHandler returns a handler for Ethermint type messages. func NewHandler(k *Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + return func(ctx sdk.Context, msg sdk.Msg) (result *sdk.Result, err error) { + snapshotStateDB := k.CommitStateDB.Copy() + + // The "recover" code here is used to solve the problem of dirty data + // in CommitStateDB due to insufficient gas. + + // The following is a detailed description: + // If the gas is insufficient during the execution of the "handler", + // panic will be thrown from the function "ConsumeGas" and finally + // caught by the function "runTx" from Cosmos. The function "runTx" + // will think that the execution of Msg has failed and the modified + // data in the Store will not take effect. + + // Stacktraceļ¼šrunTx->runMsgs->handler->...->gaskv.Store.Set->ConsumeGas + + // The problem is that when the modified data in the Store does not take + // effect, the data in the modified CommitStateDB is not rolled back, + // they take effect, and dirty data is generated. + // Therefore, the code here specifically deals with this situation. + // See https://github.com/cosmos/ethermint/issues/668 for more information. + defer func() { + if r := recover(); r != nil { + // We first used "k.CommitStateDB = snapshotStateDB" to roll back + // CommitStateDB, but this can only change the CommitStateDB in the + // current Keeper object, but the Keeper object will be destroyed + // soon, it is not a global variable, so the content pointed to by + // the CommitStateDB pointer can be modified to take effect. + types.CopyCommitStateDB(snapshotStateDB, k.CommitStateDB) + panic(r) + } + }() ctx = ctx.WithEventManager(sdk.NewEventManager()) switch msg := msg.(type) { case types.MsgEthereumTx: - return handleMsgEthereumTx(ctx, k, msg) + result, err = handleMsgEthereumTx(ctx, k, msg) case types.MsgEthermint: - return handleMsgEthermint(ctx, k, msg) + result, err = handleMsgEthermint(ctx, k, msg) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) } + if err != nil { + types.CopyCommitStateDB(snapshotStateDB, k.CommitStateDB) + } + return result, err } } diff --git a/x/evm/handler_test.go b/x/evm/handler_test.go index 93ce59f59..3a67e0888 100644 --- a/x/evm/handler_test.go +++ b/x/evm/handler_test.go @@ -2,6 +2,7 @@ package evm_test import ( "crypto/ecdsa" + "encoding/json" "fmt" "math/big" "strings" @@ -415,3 +416,112 @@ func (suite *EvmTestSuite) TestSendTransaction() { suite.Require().NoError(err) suite.Require().NotNil(result) } + +func (suite *EvmTestSuite) TestOutOfGasWhenDeployContract() { + // Test contract: + //http://remix.ethereum.org/#optimize=false&evmVersion=istanbul&version=soljson-v0.5.15+commit.6a57276f.js + //2_Owner.sol + // + //pragma solidity >=0.4.22 <0.7.0; + // + ///** + // * @title Owner + // * @dev Set & change owner + // */ + //contract Owner { + // + // address private owner; + // + // // event for EVM logging + // event OwnerSet(address indexed oldOwner, address indexed newOwner); + // + // // modifier to check if caller is owner + // modifier isOwner() { + // // If the first argument of 'require' evaluates to 'false', execution terminates and all + // // changes to the state and to Ether balances are reverted. + // // This used to consume all gas in old EVM versions, but not anymore. + // // It is often a good idea to use 'require' to check if functions are called correctly. + // // As a second argument, you can also provide an explanation about what went wrong. + // require(msg.sender == owner, "Caller is not owner"); + // _; + //} + // + // /** + // * @dev Set contract deployer as owner + // */ + // constructor() public { + // owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor + // emit OwnerSet(address(0), owner); + //} + // + // /** + // * @dev Change owner + // * @param newOwner address of new owner + // */ + // function changeOwner(address newOwner) public isOwner { + // emit OwnerSet(owner, newOwner); + // owner = newOwner; + //} + // + // /** + // * @dev Return owner address + // * @return address of owner + // */ + // function getOwner() external view returns (address) { + // return owner; + //} + //} + + // Deploy contract - Owner.sol + gasLimit := uint64(1) + suite.ctx = suite.ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + gasPrice := big.NewInt(10000) + + priv, err := ethsecp256k1.GenerateKey() + suite.Require().NoError(err, "failed to create key") + + bytecode := common.FromHex("0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a36102c4806100dc6000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063893d20e814610058578063a6f9dae1146100a2575b600080fd5b6100606100e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e4600480360360208110156100b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061010f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820f397f2733a89198bc7fed0764083694c5b828791f39ebcbc9e414bccef14b48064736f6c63430005100032") + tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode) + tx.Sign(big.NewInt(3), priv.ToECDSA()) + suite.Require().NoError(err) + + snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) + suite.Require().Nil(err) + + defer func() { + if r := recover(); r != nil { + currentCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) + suite.Require().Nil(err) + suite.Require().Equal(snapshotCommitStateDBJson, currentCommitStateDBJson) + } else { + suite.Require().Fail("panic did not happen") + } + }() + + suite.handler(suite.ctx, tx) + suite.Require().Fail("panic did not happen") +} + +func (suite *EvmTestSuite) TestErrorWhenDeployContract() { + gasLimit := uint64(1000000) + gasPrice := big.NewInt(10000) + + priv, err := ethsecp256k1.GenerateKey() + suite.Require().NoError(err, "failed to create key") + + bytecode := common.FromHex("0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424") + + tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode) + tx.Sign(big.NewInt(3), priv.ToECDSA()) + suite.Require().NoError(err) + + snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) + suite.Require().Nil(err) + + _, sdkErr := suite.handler(suite.ctx, tx) + suite.Require().NotNil(sdkErr) + + currentCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB) + suite.Require().Nil(err) + suite.Require().Equal(snapshotCommitStateDBJson, currentCommitStateDBJson) +} diff --git a/x/evm/types/statedb.go b/x/evm/types/statedb.go index 2c6de2fe3..24ccdc46c 100644 --- a/x/evm/types/statedb.go +++ b/x/evm/types/statedb.go @@ -760,59 +760,63 @@ func (csdb *CommitStateDB) CreateAccount(addr ethcmn.Address) { // // NOTE: Snapshots of the copied state cannot be applied to the copy. func (csdb *CommitStateDB) Copy() *CommitStateDB { - csdb.lock.Lock() - defer csdb.lock.Unlock() // copy all the basic fields, initialize the memory ones - state := &CommitStateDB{ - ctx: csdb.ctx, - storeKey: csdb.storeKey, - paramSpace: csdb.paramSpace, - accountKeeper: csdb.accountKeeper, - stateObjects: []stateEntry{}, - addressToObjectIndex: make(map[ethcmn.Address]int), - stateObjectsDirty: make(map[ethcmn.Address]struct{}), - refund: csdb.refund, - logSize: csdb.logSize, - preimages: make([]preimageEntry, len(csdb.preimages)), - hashToPreimageIndex: make(map[ethcmn.Hash]int, len(csdb.hashToPreimageIndex)), - journal: newJournal(), - } + state := &CommitStateDB{} + CopyCommitStateDB(csdb, state) + + return state +} + +func CopyCommitStateDB(from, to *CommitStateDB) { + from.lock.Lock() + defer from.lock.Unlock() + + to.ctx = from.ctx + to.storeKey = from.storeKey + to.paramSpace = from.paramSpace + to.accountKeeper = from.accountKeeper + to.stateObjects = []stateEntry{} + to.addressToObjectIndex = make(map[ethcmn.Address]int) + to.stateObjectsDirty = make(map[ethcmn.Address]struct{}) + to.refund = from.refund + to.logSize = from.logSize + to.preimages = make([]preimageEntry, len(from.preimages)) + to.hashToPreimageIndex = make(map[ethcmn.Hash]int, len(from.hashToPreimageIndex)) + to.journal = newJournal() // copy the dirty states, logs, and preimages - for _, dirty := range csdb.journal.dirties { + for _, dirty := range from.journal.dirties { // There is a case where an object is in the journal but not in the // stateObjects: OOG after touch on ripeMD prior to Byzantium. Thus, we // need to check for nil. // // Ref: https://github.com/ethereum/go-ethereum/pull/16485#issuecomment-380438527 - if idx, exist := csdb.addressToObjectIndex[dirty.address]; exist { - state.stateObjects = append(state.stateObjects, stateEntry{ + if idx, exist := from.addressToObjectIndex[dirty.address]; exist { + to.stateObjects = append(to.stateObjects, stateEntry{ address: dirty.address, - stateObject: csdb.stateObjects[idx].stateObject.deepCopy(state), + stateObject: from.stateObjects[idx].stateObject.deepCopy(to), }) - state.addressToObjectIndex[dirty.address] = len(state.stateObjects) - 1 - state.stateObjectsDirty[dirty.address] = struct{}{} + to.addressToObjectIndex[dirty.address] = len(to.stateObjects) - 1 + to.stateObjectsDirty[dirty.address] = struct{}{} } } // Above, we don't copy the actual journal. This means that if the copy is // copied, the loop above will be a no-op, since the copy's journal is empty. // Thus, here we iterate over stateObjects, to enable copies of copies. - for addr := range csdb.stateObjectsDirty { - if idx, exist := state.addressToObjectIndex[addr]; !exist { - state.setStateObject(csdb.stateObjects[idx].stateObject.deepCopy(state)) - state.stateObjectsDirty[addr] = struct{}{} + for addr := range from.stateObjectsDirty { + if idx, exist := to.addressToObjectIndex[addr]; !exist { + to.setStateObject(from.stateObjects[idx].stateObject.deepCopy(to)) + to.stateObjectsDirty[addr] = struct{}{} } } // copy pre-images - for i, preimageEntry := range csdb.preimages { - state.preimages[i] = preimageEntry - state.hashToPreimageIndex[preimageEntry.hash] = i + for i, preimageEntry := range from.preimages { + to.preimages[i] = preimageEntry + to.hashToPreimageIndex[preimageEntry.hash] = i } - - return state } // ForEachStorage iterates over each storage items, all invoke the provided From 4a619b1e1b3124039d0ff9fde75d4e5d36013434 Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Fri, 8 Jan 2021 10:25:02 -0300 Subject: [PATCH 4/7] faucet: remove module (#678) * changelog v0.4.0 * faucet: remove module * changelog * codecov --- CHANGELOG.md | 5 +- app/ethermint.go | 11 +- codecov.yml | 1 - docs/guides/join_network.md | 108 ++++++++------- docs/quickstart/run_node.md | 2 +- docs/quickstart/testnet.md | 25 ---- init.sh | 8 -- scripts/contract-test.sh | 5 +- tests-solidity/init-test-node.sh | 8 -- x/faucet/alias.go | 24 ---- x/faucet/client/cli/query.go | 53 -------- x/faucet/client/cli/tx.go | 71 ---------- x/faucet/client/rest/tx.go | 83 ------------ x/faucet/genesis.go | 35 ----- x/faucet/handler.go | 43 ------ x/faucet/keeper/keeper.go | 209 ----------------------------- x/faucet/keeper/querier.go | 34 ----- x/faucet/module.go | 137 ------------------- x/faucet/types/codec.go | 17 --- x/faucet/types/errors.go | 10 -- x/faucet/types/events.go | 11 -- x/faucet/types/expected_keepers.go | 20 --- x/faucet/types/genesis.go | 45 ------- x/faucet/types/key.go | 23 ---- x/faucet/types/msgs.go | 52 ------- 25 files changed, 66 insertions(+), 974 deletions(-) delete mode 100644 x/faucet/alias.go delete mode 100644 x/faucet/client/cli/query.go delete mode 100644 x/faucet/client/cli/tx.go delete mode 100644 x/faucet/client/rest/tx.go delete mode 100644 x/faucet/genesis.go delete mode 100644 x/faucet/handler.go delete mode 100644 x/faucet/keeper/keeper.go delete mode 100644 x/faucet/keeper/querier.go delete mode 100644 x/faucet/module.go delete mode 100644 x/faucet/types/codec.go delete mode 100644 x/faucet/types/errors.go delete mode 100644 x/faucet/types/events.go delete mode 100644 x/faucet/types/expected_keepers.go delete mode 100644 x/faucet/types/genesis.go delete mode 100644 x/faucet/types/key.go delete mode 100644 x/faucet/types/msgs.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 34db7f958..eefabf285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,12 +39,13 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (faucet) [\#678](https://github.com/cosmos/ethermint/pull/678) Faucet module has been removed in favor of client libraries such as [`@cosmjs/faucet`](https://github.com/cosmos/cosmjs/tree/master/packages/faucet). * (evm) [\#670](https://github.com/cosmos/ethermint/pull/670) Migrate types to the ones defined by the protobuf messages, which are required for the stargate release. ### Bug Fixes -* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot -* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent +* (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent. +* (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot. ## [v0.4.0] - 2020-12-15 diff --git a/app/ethermint.go b/app/ethermint.go index b9dfba57b..78616432e 100644 --- a/app/ethermint.go +++ b/app/ethermint.go @@ -30,7 +30,6 @@ import ( ethermintcodec "github.com/cosmos/ethermint/codec" ethermint "github.com/cosmos/ethermint/types" "github.com/cosmos/ethermint/x/evm" - "github.com/cosmos/ethermint/x/faucet" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" @@ -74,7 +73,6 @@ var ( evidence.AppModuleBasic{}, upgrade.AppModuleBasic{}, evm.AppModuleBasic{}, - faucet.AppModuleBasic{}, ) // module account permissions @@ -85,7 +83,6 @@ var ( staking.BondedPoolName: {supply.Burner, supply.Staking}, staking.NotBondedPoolName: {supply.Burner, supply.Staking}, gov.ModuleName: {supply.Burner}, - faucet.ModuleName: {supply.Minter}, } // module accounts that are allowed to receive tokens @@ -126,7 +123,6 @@ type EthermintApp struct { ParamsKeeper params.Keeper EvidenceKeeper evidence.Keeper EvmKeeper *evm.Keeper - FaucetKeeper faucet.Keeper // the module manager mm *module.Manager @@ -157,7 +153,7 @@ func NewEthermintApp( bam.MainStoreKey, auth.StoreKey, staking.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, gov.StoreKey, params.StoreKey, upgrade.StoreKey, evidence.StoreKey, - evm.StoreKey, faucet.StoreKey, + evm.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(params.TStoreKey) @@ -215,9 +211,6 @@ func NewEthermintApp( app.EvmKeeper = evm.NewKeeper( app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper, ) - app.FaucetKeeper = faucet.NewKeeper( - app.cdc, keys[faucet.StoreKey], app.SupplyKeeper, - ) // create evidence keeper with router evidenceKeeper := evidence.NewKeeper( @@ -261,7 +254,6 @@ func NewEthermintApp( staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), evidence.NewAppModule(app.EvidenceKeeper), evm.NewAppModule(app.EvmKeeper, app.AccountKeeper), - faucet.NewAppModule(app.FaucetKeeper), ) // During begin block slashing happens after distr.BeginBlocker so that @@ -281,7 +273,6 @@ func NewEthermintApp( auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName, evm.ModuleName, crisis.ModuleName, genutil.ModuleName, evidence.ModuleName, - faucet.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) diff --git a/codecov.yml b/codecov.yml index e754fadc8..fad64951d 100644 --- a/codecov.yml +++ b/codecov.yml @@ -58,7 +58,6 @@ ignore: - "docs" - "*.md" - "cmd" - - "x/faucet" - "**/*.pb.go" - "types/*.pb.go" - "tests/*" diff --git a/docs/guides/join_network.md b/docs/guides/join_network.md index 77c6c1bed..12ede0378 100644 --- a/docs/guides/join_network.md +++ b/docs/guides/join_network.md @@ -2,67 +2,79 @@ order: 5 --> - # Joining Chainsafe's Public Testnet -This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io). +This document outlines the steps to join the public testnet hosted by [Chainsafe](https://chainsafe.io). -## Steps: -1. Install the Ethermint binaries (ethermintd & ethermint cli): -``` -git clone https://github.com/cosmos/ethermint -cd ethermint -make install -``` +## Steps -2. Create an Ethermint account: -``` -ethermintcli keys add -``` +1. Install the Ethermint binaries (ethermintd & ethermint cli) -3. Copy genesis file: -Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json + ```bash + git clone https://github.com/cosmos/ethermint + cd ethermint + make install + ``` -4. Add peers: -Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following; -``` -"7678d52de4a724e468e503a7743664d12a78b5b0@18.204.206.179:26656,c62fadc76b7fa1ab25669b64fdc00c8d8d422bd0@3.86.104.251:26656,5fa7d4550b57298b059d1dd8af01829482e7d097@54.210.246.165:26656" -``` +2. Create an Ethermint account -5. Validate genesis and start the Ethermint network: -``` -ethermintd validate-genesis -``` -``` -ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace -``` -(we recommend running the command in the background for convenience) + ```bash + ethermintcli keys add + ``` -6. Start the RPC server: -``` -ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id etherminttestnet-777 --trace -``` -where `$KEY` is the key name that was used in step 2. -(we recommend running the command in the background for convenience) +3. Copy genesis file -7. Request funds from the faucet: -You will need to know the Ethereum hex address, and it can be found with the following command: + Follow this [link](https://gist.github.com/araskachoi/43f86f3edff23729b817e8b0bb86295a) and copy it over to the directory ~/.ethermintd/config/genesis.json -``` -curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 -``` -Using the output of the above command, you will then send the command with your valid Ethereum address: -``` -curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000 -``` +4. Add peers + + Edit the file located in ~/.ethermintd/config/config.toml and edit line 350 (persistent_peers) to the following + + ```toml + "7678d52de4a724e468e503a7743664d12a78b5b0@18.204.206.179:26656,c62fadc76b7fa1ab25669b64fdc00c8d8d422bd0@3.86.104.251:26656,5fa7d4550b57298b059d1dd8af01829482e7d097@54.210.246.165:26656" + ``` + +5. Validate genesis and start the Ethermint network + + ```bash + ethermintd validate-genesis + + ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" --trace + ``` + + (we recommend running the command in the background for convenience) + +6. Start the RPC server + + ```bash + ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id etherminttestnet-777 --trace + ``` + + where `$KEY` is the key name that was used in step 2. + (we recommend running the command in the background for convenience) + +7. Request funds from the faucet + + You will need to know the Ethereum hex address, and it can be found with the following command: + + ```bash + curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}' -H "Content-Type: application/json" http://localhost:8545 + ``` + + Using the output of the above command, you will then send the command with your valid Ethereum address + + ```bash + curl --header "Content-Type: application/json" --request POST --data '{"address":"0xYourEthereumHexAddress"}' 3.95.21.91:3000 + ``` ## Public Testnet Node RPC Endpoints -Node0: `54.210.246.165:8545` -Node1: `3.86.104.251:8545` -Node2: `18.204.206.179:8545` +- **Node0**: `54.210.246.165:8545` +- **Node1**: `3.86.104.251:8545` +- **Node2**: `18.204.206.179:8545` example: -``` + +```bash curl -X POST --data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' -H "Content-Type: application/json" 54.210.246.165:8545 -``` \ No newline at end of file +``` diff --git a/docs/quickstart/run_node.md b/docs/quickstart/run_node.md index 1561ef000..ca9284987 100644 --- a/docs/quickstart/run_node.md +++ b/docs/quickstart/run_node.md @@ -12,7 +12,7 @@ Run a local node and start the REST and JSON-RPC clients {synopsis} ## Automated deployment -Run the local node with faucet enabled: +Run the local node ::: warning The script below will remove any pre-existing binaries installed. Use the manual deploy if you want diff --git a/docs/quickstart/testnet.md b/docs/quickstart/testnet.md index 98ca23de8..1719e609b 100644 --- a/docs/quickstart/testnet.md +++ b/docs/quickstart/testnet.md @@ -311,31 +311,6 @@ For more information on seeds and peers, you can the Tendermint [P2P documentati The final step is to [start the nodes](./run_node.md#start-node). Once enough voting power (+2/3) from the genesis validators is up-and-running, the testnet will start producing blocks. -## Testnet faucet - -Once the ethermint daemon is up and running, you can request tokens to your address using the `faucet` module: - -```bash -# query your initial balance -ethermintcli q bank balances $(ethermintcli keys show -a) - -# send a tx to request tokens to your account address -ethermintcli tx faucet request 100aphoton --from - -# query your balance after the request -ethermintcli q bank balances $(ethermintcli keys show -a) -``` - -You can also check to total amount funded by the faucet and the total supply of the chain via: - -```bash -# total amount funded by the faucet -ethermintcli q faucet funded - -# total supply -ethermintcli q supply total -``` - ## Next {hide} Learn about how to setup a [validator](./validator-setup.md) node on Ethermint {hide} diff --git a/init.sh b/init.sh index 46acda794..65067c73c 100755 --- a/init.sh +++ b/init.sh @@ -29,9 +29,6 @@ cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["crisis"]["constant_f cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json -# Enable faucet -cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json - # increase block time (?) cat $HOME/.ethermintd/config/genesis.json | jq '.consensus_params["block"]["time_iota_ms"]="30000"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json @@ -56,11 +53,6 @@ ethermintd gentx --name $KEY --amount=1000000000000000000aphoton --keyring-backe # Collect genesis tx ethermintd collect-gentxs -echo -e '\n\ntestnet faucet enabled' -echo -e 'to transfer tokens to your account address use:' -echo -e "ethermintcli tx faucet request 100aphoton --from $KEY\n" - - # Run this to ensure everything worked and that the genesis file is setup correctly ethermintd validate-genesis diff --git a/scripts/contract-test.sh b/scripts/contract-test.sh index 554fed6ac..359bc5823 100644 --- a/scripts/contract-test.sh +++ b/scripts/contract-test.sh @@ -31,9 +31,6 @@ cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["crisis"]["constant_f cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["gov"]["deposit_params"]["min_deposit"][0]["denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="aphoton"' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json -# Enable faucet -cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json - # Allocate genesis accounts (cosmos formatted addresses) $PWD/build/ethermintd add-genesis-account "$("$PWD"/build/ethermintcli keys show "$KEY$i" -a)" 100000000000000000000aphoton @@ -51,7 +48,7 @@ $PWD/build/ethermintd start --pruning=nothing --rpc.unsafe --log_level "main:inf sleep 1 -# Start the rest server with unlocked faucet key in background and log to file +# Start the rest server with unlocked key in background and log to file $PWD/build/ethermintcli rest-server --laddr "tcp://localhost:8545" --unlock-key $KEY --chain-id $CHAINID --trace > ethermintcli.log & solcjs --abi $PWD/tests-solidity/suites/basic/contracts/Counter.sol --bin -o $PWD/tests-solidity/suites/basic/counter diff --git a/tests-solidity/init-test-node.sh b/tests-solidity/init-test-node.sh index 867081aeb..fd642d91e 100755 --- a/tests-solidity/init-test-node.sh +++ b/tests-solidity/init-test-node.sh @@ -42,14 +42,6 @@ ethermintd gentx --name $VAL_KEY --keyring-backend test # Collect genesis tx ethermintd collect-gentxs -# Enable faucet -cat $HOME/.ethermintd/config/genesis.json | jq '.app_state["faucet"]["enable_faucet"]=true' > $HOME/.ethermintd/config/tmp_genesis.json && mv $HOME/.ethermintd/config/tmp_genesis.json $HOME/.ethermintd/config/genesis.json - -echo -e '\n\ntestnet faucet enabled' -echo -e 'to transfer tokens to your account address use:' -echo -e "ethermintcli tx faucet request 100aphoton --from $VAL_KEY\n" - - # Run this to ensure everything worked and that the genesis file is setup correctly ethermintd validate-genesis diff --git a/x/faucet/alias.go b/x/faucet/alias.go deleted file mode 100644 index f280118ed..000000000 --- a/x/faucet/alias.go +++ /dev/null @@ -1,24 +0,0 @@ -package faucet - -import ( - "github.com/cosmos/ethermint/x/faucet/keeper" - "github.com/cosmos/ethermint/x/faucet/types" -) - -const ( - ModuleName = types.ModuleName - RouterKey = types.RouterKey - StoreKey = types.StoreKey - QuerierRoute = types.QuerierRoute -) - -var ( - NewKeeper = keeper.NewKeeper - NewQuerier = keeper.NewQuerier - ModuleCdc = types.ModuleCdc - RegisterCodec = types.RegisterCodec -) - -type ( - Keeper = keeper.Keeper -) diff --git a/x/faucet/client/cli/query.go b/x/faucet/client/cli/query.go deleted file mode 100644 index 65725ecb3..000000000 --- a/x/faucet/client/cli/query.go +++ /dev/null @@ -1,53 +0,0 @@ -package cli - -import ( - "fmt" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - - "github.com/cosmos/ethermint/x/faucet/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GetQueryCmd defines evm module queries through the cli -func GetQueryCmd(cdc *codec.Codec) *cobra.Command { - faucetQueryCmd := &cobra.Command{ - Use: types.ModuleName, - Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - faucetQueryCmd.AddCommand(flags.GetCommands( - GetCmdFunded(cdc), - )...) - return faucetQueryCmd -} - -// GetCmdFunded queries the total amount funded by the faucet. -func GetCmdFunded(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "funded", - Short: "Gets storage for an account at a given key", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := context.NewCLIContext().WithCodec(cdc) - - res, height, err := clientCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryFunded)) - if err != nil { - return err - } - - var out sdk.Coins - cdc.MustUnmarshalJSON(res, &out) - clientCtx = clientCtx.WithHeight(height) - return clientCtx.PrintOutput(out) - }, - } -} diff --git a/x/faucet/client/cli/tx.go b/x/faucet/client/cli/tx.go deleted file mode 100644 index d33820053..000000000 --- a/x/faucet/client/cli/tx.go +++ /dev/null @@ -1,71 +0,0 @@ -package cli - -import ( - "bufio" - - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// GetTxCmd return faucet sub-command for tx -func GetTxCmd(cdc *codec.Codec) *cobra.Command { - faucetTxCmd := &cobra.Command{ - Use: types.ModuleName, - Short: "faucet transaction subcommands", - DisableFlagParsing: true, - SuggestionsMinimumDistance: 2, - RunE: client.ValidateCmd, - } - - faucetTxCmd.AddCommand(flags.PostCommands( - GetCmdRequest(cdc), - )...) - - return faucetTxCmd -} - -// GetCmdRequest is the CLI command to fund an address with the requested coins -func GetCmdRequest(cdc *codec.Codec) *cobra.Command { - return &cobra.Command{ - Use: "request [amount] [other-recipient (optional)]", - Short: "request an address with the requested coins", - Args: cobra.RangeArgs(1, 2), - RunE: func(cmd *cobra.Command, args []string) error { - inBuf := bufio.NewReader(cmd.InOrStdin()) - clientCtx := context.NewCLIContext().WithCodec(cdc) - txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc)) - - amount, err := sdk.ParseCoins(args[0]) - if err != nil { - return err - } - - var recipient sdk.AccAddress - if len(args) == 1 { - recipient = clientCtx.GetFromAddress() - } else { - recipient, err = sdk.AccAddressFromBech32(args[1]) - } - - if err != nil { - return err - } - - msg := types.NewMsgFund(amount, clientCtx.GetFromAddress(), recipient) - if err := msg.ValidateBasic(); err != nil { - return err - } - - return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg}) - }, - } -} diff --git a/x/faucet/client/rest/tx.go b/x/faucet/client/rest/tx.go deleted file mode 100644 index dd634694a..000000000 --- a/x/faucet/client/rest/tx.go +++ /dev/null @@ -1,83 +0,0 @@ -package rest - -import ( - "fmt" - "net/http" - - "github.com/gorilla/mux" - - "github.com/cosmos/cosmos-sdk/client/context" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/rest" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// RegisterRoutes register REST endpoints for the faucet module -func RegisterRoutes(clientCtx context.CLIContext, r *mux.Router) { - r.HandleFunc(fmt.Sprintf("/%s/request", types.ModuleName), requestHandler(clientCtx)).Methods("POST") - r.HandleFunc(fmt.Sprintf("/%s/funded", types.ModuleName), fundedHandlerFn(clientCtx)).Methods("GET") -} - -// PostRequestBody defines fund request's body. -type PostRequestBody struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - Amount sdk.Coins `json:"amount" yaml:"amount"` - Recipient string `json:"receipient" yaml:"receipient"` -} - -func requestHandler(clientCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - var req PostRequestBody - if !rest.ReadRESTReq(w, r, clientCtx.Codec, &req) { - rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse request") - return - } - - baseReq := req.BaseReq.Sanitize() - if !baseReq.ValidateBasic(w) { - return - } - - sender, err := sdk.AccAddressFromBech32(baseReq.From) - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - var recipient sdk.AccAddress - if req.Recipient == "" { - recipient = sender - } else { - recipient, err = sdk.AccAddressFromBech32(req.Recipient) - } - - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - msg := types.NewMsgFund(req.Amount, sender, recipient) - err = msg.ValidateBasic() - if err != nil { - rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) - return - } - - authclient.WriteGenerateStdTxResponse(w, clientCtx, baseReq, []sdk.Msg{msg}) - } -} - -func fundedHandlerFn(clientCtx context.CLIContext) http.HandlerFunc { - return func(w http.ResponseWriter, _ *http.Request) { - res, height, err := clientCtx.Query(fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryFunded)) - if err != nil { - rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) - return - } - - clientCtx = clientCtx.WithHeight(height) - rest.PostProcessResponse(w, clientCtx, res) - } -} diff --git a/x/faucet/genesis.go b/x/faucet/genesis.go deleted file mode 100644 index 6e3f7888e..000000000 --- a/x/faucet/genesis.go +++ /dev/null @@ -1,35 +0,0 @@ -package faucet - -import ( - "fmt" - - "github.com/cosmos/ethermint/x/faucet/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - - abci "github.com/tendermint/tendermint/abci/types" -) - -// InitGenesis initializes genesis state based on exported genesis -func InitGenesis(ctx sdk.Context, k Keeper, data types.GenesisState) []abci.ValidatorUpdate { - if acc := k.GetFaucetAccount(ctx); acc == nil { - panic(fmt.Sprintf("%s module account has not been set", ModuleName)) - } - - k.SetEnabled(ctx, data.EnableFaucet) - k.SetTimout(ctx, data.Timeout) - k.SetCap(ctx, data.FaucetCap) - k.SetMaxPerRequest(ctx, data.MaxAmountPerRequest) - - return []abci.ValidatorUpdate{} -} - -// ExportGenesis exports genesis state -func ExportGenesis(ctx sdk.Context, k Keeper) types.GenesisState { - return types.GenesisState{ - EnableFaucet: k.IsEnabled(ctx), - Timeout: k.GetTimeout(ctx), - FaucetCap: k.GetCap(ctx), - MaxAmountPerRequest: k.GetMaxPerRequest(ctx), - } -} diff --git a/x/faucet/handler.go b/x/faucet/handler.go deleted file mode 100644 index 9124d7043..000000000 --- a/x/faucet/handler.go +++ /dev/null @@ -1,43 +0,0 @@ -package faucet - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// NewHandler returns a handler for faucet messages. -func NewHandler(keeper Keeper) sdk.Handler { - return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { - ctx = ctx.WithEventManager(sdk.NewEventManager()) - switch msg := msg.(type) { - case types.MsgFund: - return handleMsgFund(ctx, keeper, msg) - default: - return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg) - } - } -} - -// handleMsgFund handles a message to fund an address -func handleMsgFund(ctx sdk.Context, keeper Keeper, msg types.MsgFund) (*sdk.Result, error) { - err := keeper.Fund(ctx, msg.Amount, msg.Recipient) - if err != nil { - return nil, err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - sdk.EventTypeMessage, - sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), - sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()), - sdk.NewAttribute(types.AttributeRecipient, msg.Recipient.String()), - ), - ) - - return &sdk.Result{ - Events: ctx.EventManager().Events(), - }, nil -} diff --git a/x/faucet/keeper/keeper.go b/x/faucet/keeper/keeper.go deleted file mode 100644 index 80a4a087a..000000000 --- a/x/faucet/keeper/keeper.go +++ /dev/null @@ -1,209 +0,0 @@ -package keeper - -import ( - "errors" - "fmt" - "time" - - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" - - "github.com/cosmos/ethermint/x/faucet/types" -) - -// Keeper defines the faucet Keeper. -type Keeper struct { - cdc *codec.Codec - storeKey sdk.StoreKey - supplyKeeper types.SupplyKeeper - - // History of users and their funding timeouts. They are reset if the app is reinitialized. - timeouts map[string]time.Time -} - -// NewKeeper creates a new faucet Keeper instance. -func NewKeeper( - cdc *codec.Codec, storeKey sdk.StoreKey, supplyKeeper types.SupplyKeeper, -) Keeper { - return Keeper{ - cdc: cdc, - storeKey: storeKey, - supplyKeeper: supplyKeeper, - timeouts: make(map[string]time.Time), - } -} - -// Logger returns a module-specific logger. -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) -} - -// GetFaucetAccount returns the faucet ModuleAccount -func (k Keeper) GetFaucetAccount(ctx sdk.Context) supplyexported.ModuleAccountI { - return k.supplyKeeper.GetModuleAccount(ctx, types.ModuleName) -} - -// Fund checks for timeout and max thresholds and then mints coins and transfers -// coins to the recipient. -func (k Keeper) Fund(ctx sdk.Context, amount sdk.Coins, recipient sdk.AccAddress) error { - if !k.IsEnabled(ctx) { - return errors.New("faucet is not enabled. Restart the application and set faucet's 'enable_faucet' genesis field to true") - } - - if err := k.rateLimit(ctx, recipient.String()); err != nil { - return err - } - - totalRequested := sdk.ZeroInt() - for _, coin := range amount { - totalRequested = totalRequested.Add(coin.Amount) - } - - maxPerReq := k.GetMaxPerRequest(ctx) - if totalRequested.GT(maxPerReq) { - return fmt.Errorf("canot fund more than %s per request. requested %s", maxPerReq, totalRequested) - } - - funded := k.GetFunded(ctx) - totalFunded := sdk.ZeroInt() - for _, coin := range funded { - totalFunded = totalFunded.Add(coin.Amount) - } - - cap := k.GetCap(ctx) - - if totalFunded.Add(totalRequested).GT(cap) { - return fmt.Errorf("maximum cap of %s reached. Cannot continue funding", cap) - } - - if err := k.supplyKeeper.MintCoins(ctx, types.ModuleName, amount); err != nil { - return err - } - - if err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, amount); err != nil { - return err - } - - k.SetFunded(ctx, funded.Add(amount...)) - - k.Logger(ctx).Info(fmt.Sprintf("funded %s to %s", amount, recipient)) - return nil -} - -func (k Keeper) GetTimeout(ctx sdk.Context) time.Duration { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.TimeoutKey) - if len(bz) == 0 { - return time.Duration(0) - } - - var timeout time.Duration - k.cdc.MustUnmarshalBinaryBare(bz, &timeout) - - return timeout -} - -func (k Keeper) SetTimout(ctx sdk.Context, timeout time.Duration) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(timeout) - store.Set(types.TimeoutKey, bz) -} - -func (k Keeper) IsEnabled(ctx sdk.Context) bool { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.EnableFaucetKey) - if len(bz) == 0 { - return false - } - - var enabled bool - k.cdc.MustUnmarshalBinaryBare(bz, &enabled) - return enabled -} - -func (k Keeper) SetEnabled(ctx sdk.Context, enabled bool) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(enabled) - store.Set(types.EnableFaucetKey, bz) -} - -func (k Keeper) GetCap(ctx sdk.Context) sdk.Int { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.CapKey) - if len(bz) == 0 { - return sdk.ZeroInt() - } - - var cap sdk.Int - k.cdc.MustUnmarshalBinaryBare(bz, &cap) - - return cap -} - -func (k Keeper) SetCap(ctx sdk.Context, cap sdk.Int) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(cap) - store.Set(types.CapKey, bz) -} - -func (k Keeper) GetMaxPerRequest(ctx sdk.Context) sdk.Int { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.MaxPerRequestKey) - if len(bz) == 0 { - return sdk.ZeroInt() - } - - var maxPerReq sdk.Int - k.cdc.MustUnmarshalBinaryBare(bz, &maxPerReq) - - return maxPerReq -} - -func (k Keeper) SetMaxPerRequest(ctx sdk.Context, maxPerReq sdk.Int) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(maxPerReq) - store.Set(types.MaxPerRequestKey, bz) -} - -func (k Keeper) GetFunded(ctx sdk.Context) sdk.Coins { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.FundedKey) - if len(bz) == 0 { - return nil - } - - var funded sdk.Coins - k.cdc.MustUnmarshalBinaryBare(bz, &funded) - - return funded -} - -func (k Keeper) SetFunded(ctx sdk.Context, funded sdk.Coins) { - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshalBinaryBare(funded) - store.Set(types.FundedKey, bz) -} - -func (k Keeper) rateLimit(ctx sdk.Context, address string) error { - // first time requester, can send request - lastRequest, ok := k.timeouts[address] - if !ok { - k.timeouts[address] = time.Now().UTC() - return nil - } - - defaultTimeout := k.GetTimeout(ctx) - sinceLastRequest := time.Since(lastRequest) - - if defaultTimeout > sinceLastRequest { - wait := defaultTimeout - sinceLastRequest - return fmt.Errorf("%s has requested funds within the last %s, wait %s before trying again", address, defaultTimeout.String(), wait.String()) - } - - // user able to send funds since they have waited for period - k.timeouts[address] = time.Now().UTC() - return nil -} diff --git a/x/faucet/keeper/querier.go b/x/faucet/keeper/querier.go deleted file mode 100644 index f63a928c9..000000000 --- a/x/faucet/keeper/querier.go +++ /dev/null @@ -1,34 +0,0 @@ -package keeper - -import ( - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/ethermint/x/faucet/types" - - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// NewQuerier is the module level router for state queries -func NewQuerier(k Keeper) sdk.Querier { - return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) { - switch path[0] { - case types.QueryFunded: - return queryFunded(ctx, req, k) - default: - return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query endpoint") - } - } -} - -func queryFunded(ctx sdk.Context, _ abci.RequestQuery, k Keeper) ([]byte, error) { - funded := k.GetFunded(ctx) - - bz, err := codec.MarshalJSONIndent(k.cdc, funded) - if err != nil { - return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) - } - - return bz, nil -} diff --git a/x/faucet/module.go b/x/faucet/module.go deleted file mode 100644 index a770610a7..000000000 --- a/x/faucet/module.go +++ /dev/null @@ -1,137 +0,0 @@ -package faucet - -import ( - "encoding/json" - "fmt" - - "github.com/gorilla/mux" - "github.com/spf13/cobra" - - abci "github.com/tendermint/tendermint/abci/types" - - "github.com/cosmos/cosmos-sdk/client/context" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - - "github.com/cosmos/ethermint/x/faucet/client/cli" - "github.com/cosmos/ethermint/x/faucet/client/rest" - "github.com/cosmos/ethermint/x/faucet/types" -) - -// type check to ensure the interface is properly implemented -var ( - _ module.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} -) - -// AppModuleBasic defines the basic application module used by the faucet module. -type AppModuleBasic struct{} - -// Name returns the faucet module's name. -func (AppModuleBasic) Name() string { - return types.ModuleName -} - -// RegisterCodec registers the faucet module's types for the given codec. -func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { - RegisterCodec(cdc) -} - -// DefaultGenesis returns default genesis state as raw bytes for the faucet -// module. -func (AppModuleBasic) DefaultGenesis() json.RawMessage { - return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState()) -} - -// ValidateGenesis performs genesis state validation for the faucet module. -func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error { - var genesisState types.GenesisState - if err := types.ModuleCdc.UnmarshalJSON(bz, &genesisState); err != nil { - return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) - } - - return genesisState.Validate() -} - -// RegisterRESTRoutes registers the REST routes for the faucet module. -func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) { - rest.RegisterRoutes(ctx, rtr) -} - -// GetTxCmd returns the root tx command for the faucet module. -func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetTxCmd(cdc) -} - -// GetQueryCmd returns no root query command for the faucet module. -func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { - return cli.GetQueryCmd(cdc) -} - -type AppModule struct { - AppModuleBasic - keeper Keeper -} - -// NewAppModule creates a new AppModule Object -func NewAppModule(k Keeper) AppModule { - return AppModule{ - AppModuleBasic: AppModuleBasic{}, - keeper: k, - } -} - -// Name returns the faucet module's name. -func (AppModule) Name() string { - return ModuleName -} - -// RegisterInvariants registers the faucet module invariants. -func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} - -// Route returns the message routing key for the faucet module. -func (AppModule) Route() string { - return RouterKey -} - -// NewHandler returns an sdk.Handler for the faucet module. -func (am AppModule) NewHandler() sdk.Handler { - return NewHandler(am.keeper) -} - -// QuerierRoute returns the faucet module's querier route name. -func (AppModule) QuerierRoute() string { - return QuerierRoute -} - -// NewQuerierHandler returns the faucet module sdk.Querier. -func (am AppModule) NewQuerierHandler() sdk.Querier { - return NewQuerier(am.keeper) -} - -// InitGenesis performs genesis initialization for the faucet module. It returns -// no validator updates. -func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate { - var genesisState types.GenesisState - types.ModuleCdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) - return []abci.ValidatorUpdate{} -} - -// ExportGenesis returns the exported genesis state as raw bytes for the faucet -// module. -func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage { - gs := ExportGenesis(ctx, am.keeper) - return types.ModuleCdc.MustMarshalJSON(gs) -} - -// BeginBlock returns the begin blocker for the faucet module. -func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { -} - -// EndBlock returns the end blocker for the faucet module. It returns no validator -// updates. -func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} diff --git a/x/faucet/types/codec.go b/x/faucet/types/codec.go deleted file mode 100644 index 0378955bd..000000000 --- a/x/faucet/types/codec.go +++ /dev/null @@ -1,17 +0,0 @@ -package types - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// ModuleCdc is the codec for the module -var ModuleCdc = codec.New() - -func init() { - RegisterCodec(ModuleCdc) -} - -// RegisterCodec registers concrete types on the Amino codec -func RegisterCodec(cdc *codec.Codec) { - cdc.RegisterConcrete(MsgFund{}, "ethermint/MsgFund", nil) -} diff --git a/x/faucet/types/errors.go b/x/faucet/types/errors.go deleted file mode 100644 index ec36514a3..000000000 --- a/x/faucet/types/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -import ( - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -var ( - // ErrWithdrawTooOften withdraw too often - ErrWithdrawTooOften = sdkerrors.Register(ModuleName, 2, "each address can withdraw only once") -) diff --git a/x/faucet/types/events.go b/x/faucet/types/events.go deleted file mode 100644 index f43e62a5e..000000000 --- a/x/faucet/types/events.go +++ /dev/null @@ -1,11 +0,0 @@ -package types - -// Faucet module events -const ( - AttributeRecipient string = "recipient" -) - -// Supported endpoints -const ( - QueryFunded = "funded" -) diff --git a/x/faucet/types/expected_keepers.go b/x/faucet/types/expected_keepers.go deleted file mode 100644 index 17fb55096..000000000 --- a/x/faucet/types/expected_keepers.go +++ /dev/null @@ -1,20 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" -) - -// SupplyKeeper is required for mining coin -type SupplyKeeper interface { - MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - SendCoinsFromModuleToAccount( - ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins, - ) error - GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI -} - -// StakingKeeper is required for getting Denom -type StakingKeeper interface { - BondDenom(ctx sdk.Context) string -} diff --git a/x/faucet/types/genesis.go b/x/faucet/types/genesis.go deleted file mode 100644 index 6721482e9..000000000 --- a/x/faucet/types/genesis.go +++ /dev/null @@ -1,45 +0,0 @@ -package types - -import ( - "fmt" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GenesisState defines the application's genesis state. It contains all the -// information required and accounts to initialize the blockchain. -type GenesisState struct { - // enable faucet funding - EnableFaucet bool `json:"enable_faucet" yaml:"enable_faucet"` - // addresses can send requests every duration - Timeout time.Duration `json:"timeout" yaml:"timeout"` - // max total amount to be funded by the faucet - FaucetCap sdk.Int `json:"faucet_cap" yaml:"faucet_cap"` - // max amount per request (i.e sum of all requested coin amounts). - MaxAmountPerRequest sdk.Int `json:"max_amount_per_request" yaml:"max_amount_per_request"` -} - -// Validate performs a basic validation of the GenesisState fields. -func (gs GenesisState) Validate() error { - if gs.Timeout < 0 { - return fmt.Errorf("timeout cannot be negative: %s", gs.Timeout) - } - if gs.FaucetCap.IsNegative() { - return fmt.Errorf("faucet cap cannot be negative: %d", gs.FaucetCap) - } - if gs.MaxAmountPerRequest.IsNegative() { - return fmt.Errorf("max amount per request cannot be negative: %d", gs.MaxAmountPerRequest) - } - return nil -} - -// DefaultGenesisState sets default evm genesis config -func DefaultGenesisState() GenesisState { - return GenesisState{ - EnableFaucet: false, - Timeout: 20 * time.Minute, - FaucetCap: sdk.NewInt(1000000000), - MaxAmountPerRequest: sdk.NewInt(1000), - } -} diff --git a/x/faucet/types/key.go b/x/faucet/types/key.go deleted file mode 100644 index 6b1adc75d..000000000 --- a/x/faucet/types/key.go +++ /dev/null @@ -1,23 +0,0 @@ -package types - -const ( - // ModuleName is the name of the module - ModuleName = "faucet" - - // StoreKey to be used when creating the KVStore - StoreKey = ModuleName - - // RouterKey uses module name for tx routing - RouterKey = ModuleName - - // QuerierRoute uses module name for query routing - QuerierRoute = ModuleName -) - -var ( - EnableFaucetKey = []byte{0x01} - TimeoutKey = []byte{0x02} - CapKey = []byte{0x03} - MaxPerRequestKey = []byte{0x04} - FundedKey = []byte{0x05} -) diff --git a/x/faucet/types/msgs.go b/x/faucet/types/msgs.go deleted file mode 100644 index 04f914155..000000000 --- a/x/faucet/types/msgs.go +++ /dev/null @@ -1,52 +0,0 @@ -package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// MsgFund funds a recipient address -type MsgFund struct { - Amount sdk.Coins `json:"amount" yaml:"amount"` - Sender sdk.AccAddress `json:"sender" yaml:"sender"` - Recipient sdk.AccAddress `json:"receipient" yaml:"receipient"` -} - -// NewMsgFund is a constructor function for NewMsgFund -func NewMsgFund(amount sdk.Coins, sender, recipient sdk.AccAddress) MsgFund { - return MsgFund{ - Amount: amount, - Sender: sender, - Recipient: recipient, - } -} - -// Route should return the name of the module -func (msg MsgFund) Route() string { return RouterKey } - -// Type should return the action -func (msg MsgFund) Type() string { return "fund" } - -// ValidateBasic runs stateless checks on the message -func (msg MsgFund) ValidateBasic() error { - if !msg.Amount.IsValid() { - return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String()) - } - if msg.Sender.Empty() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "sender %s", msg.Sender.String()) - } - if msg.Recipient.Empty() { - return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "recipient %s", msg.Recipient.String()) - } - return nil -} - -// GetSignBytes encodes the message for signing -func (msg MsgFund) GetSignBytes() []byte { - return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) -} - -// GetSigners defines whose signature is required -func (msg MsgFund) GetSigners() []sdk.AccAddress { - return []sdk.AccAddress{msg.Sender} -} From d7bdbd7488644f0aaeee5cdcdc119c863f199f72 Mon Sep 17 00:00:00 2001 From: Daniel Choi <13338103+araskachoi@users.noreply.github.com> Date: Fri, 8 Jan 2021 17:44:50 -0800 Subject: [PATCH 5/7] Fix nonce issue for replay attack (#692) * fix nonce issue for replay attack * fix lint * add to changelog --- CHANGELOG.md | 2 ++ app/ante/eth.go | 2 +- rpc/namespaces/eth/api.go | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eefabf285..263afeda2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (evm) [\#687](https://github.com/cosmos/ethermint/issues/687) Fix nonce check to explicitly check for the correct nonce, rather than a simple 'greater than' comparison. +* (api) [\#687](https://github.com/cosmos/ethermint/issues/687) Returns error for a transaction with an incorrect nonce. * (evm) [\#674](https://github.com/cosmos/ethermint/issues/674) Reset all cache after account data has been committed in `EndBlock` to make sure every node state consistent. * (evm) [\#672](https://github.com/cosmos/ethermint/issues/672) Fix panic of `wrong Block.Header.AppHash` when restart a node with snapshot. diff --git a/app/ante/eth.go b/app/ante/eth.go index 6f4f6a1e6..b367f0bb9 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -257,7 +257,7 @@ func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim // if multiple transactions are submitted in succession with increasing nonces, // all will be rejected except the first, since the first needs to be included in a block // before the sequence increments - if msgEthTx.Data.AccountNonce < seq { + if msgEthTx.Data.AccountNonce != seq { return ctx, sdkerrors.Wrapf( sdkerrors.ErrInvalidSequence, "invalid nonce; got %d, expected %d", msgEthTx.Data.AccountNonce, seq, diff --git a/rpc/namespaces/eth/api.go b/rpc/namespaces/eth/api.go index fb7ff5d54..69baf413c 100644 --- a/rpc/namespaces/eth/api.go +++ b/rpc/namespaces/eth/api.go @@ -1000,16 +1000,16 @@ func (api *PublicEthereumAPI) generateFromArgs(args rpctypes.SendTxArgs) (*evmty gasPrice = big.NewInt(ethermint.DefaultGasPrice) } - if args.Nonce == nil { - // get the nonce from the account retriever and the pending transactions - nonce, err = api.accountNonce(api.clientCtx, args.From, true) - } else { - nonce = (uint64)(*args.Nonce) - } - + // get the nonce from the account retriever and the pending transactions + nonce, err = api.accountNonce(api.clientCtx, args.From, true) if err != nil { return nil, err } + if args.Nonce != nil { + if nonce != (uint64)(*args.Nonce) { + return nil, fmt.Errorf(fmt.Sprintf("invalid nonce; got %d, expected %d", (uint64)(*args.Nonce), nonce)) + } + } if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { return nil, errors.New("both 'data' and 'input' are set and not equal. Please use 'input' to pass transaction call data") From 52d6d7148208911123155d853e1433e5b827c54a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Jan 2021 08:19:49 -0300 Subject: [PATCH 6/7] build(deps): bump gaurav-nelson/github-action-markdown-link-check (#696) Bumps [gaurav-nelson/github-action-markdown-link-check](https://github.com/gaurav-nelson/github-action-markdown-link-check) from 1.0.11 to 1.0.12. - [Release notes](https://github.com/gaurav-nelson/github-action-markdown-link-check/releases) - [Commits](https://github.com/gaurav-nelson/github-action-markdown-link-check/compare/1.0.11...0fe4911067fa322422f325b002d2038ba5602170) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/linkchecker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linkchecker.yml b/.github/workflows/linkchecker.yml index ec7b48d7a..44c94b1a3 100644 --- a/.github/workflows/linkchecker.yml +++ b/.github/workflows/linkchecker.yml @@ -7,6 +7,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@development - - uses: gaurav-nelson/github-action-markdown-link-check@1.0.11 + - uses: gaurav-nelson/github-action-markdown-link-check@1.0.12 with: folder-path: "docs" From 9ecd264ae0e8c6ace10abe3bc45ab8d3c29dc10f Mon Sep 17 00:00:00 2001 From: Pierre <974741468@qq.com> Date: Mon, 11 Jan 2021 21:31:30 +0800 Subject: [PATCH 7/7] Add API for compatible query of two types of transactions (#683) * Add API for compatible query of two types of transactions * format code * optimize code * optimize code * format code * optimize code * add error handling Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- rpc/config.go | 8 ++-- x/evm/client/rest/rest.go | 98 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 x/evm/client/rest/rest.go diff --git a/rpc/config.go b/rpc/config.go index 12125449e..f3fc92051 100644 --- a/rpc/config.go +++ b/rpc/config.go @@ -6,21 +6,19 @@ import ( "os" "strings" - "github.com/spf13/viper" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" - authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" - "github.com/cosmos/ethermint/app" "github.com/cosmos/ethermint/crypto/ethsecp256k1" "github.com/cosmos/ethermint/crypto/hd" "github.com/cosmos/ethermint/rpc/websockets" + evmrest "github.com/cosmos/ethermint/x/evm/client/rest" "github.com/ethereum/go-ethereum/rpc" + "github.com/spf13/viper" ) const ( @@ -75,7 +73,7 @@ func RegisterRoutes(rs *lcd.RestServer) { // Register all other Cosmos routes client.RegisterRoutes(rs.CliCtx, rs.Mux) - authrest.RegisterTxRoutes(rs.CliCtx, rs.Mux) + evmrest.RegisterRoutes(rs.CliCtx, rs.Mux) app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) // start websockets server diff --git a/x/evm/client/rest/rest.go b/x/evm/client/rest/rest.go new file mode 100644 index 000000000..7658faa96 --- /dev/null +++ b/x/evm/client/rest/rest.go @@ -0,0 +1,98 @@ +package rest + +import ( + "encoding/hex" + "encoding/json" + "net/http" + "strings" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/types/rest" + authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + rpctypes "github.com/cosmos/ethermint/rpc/types" + "github.com/ethereum/go-ethereum/common" + "github.com/gorilla/mux" +) + +// RegisterRoutes - Central function to define routes that get registered by the main application +func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { + r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/txs", authrest.QueryTxsRequestHandlerFn(cliCtx)).Methods("GET") // default from auth + r.HandleFunc("/txs", authrest.BroadcastTxRequest(cliCtx)).Methods("POST") // default from auth + r.HandleFunc("/txs/encode", authrest.EncodeTxRequestHandlerFn(cliCtx)).Methods("POST") // default from auth + r.HandleFunc("/txs/decode", authrest.DecodeTxRequestHandlerFn(cliCtx)).Methods("POST") // default from auth +} + +func QueryTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + hashHexStr := vars["hash"] + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + ethHashPrefix := "0x" + if strings.HasPrefix(hashHexStr, ethHashPrefix) { + // eth Tx + ethHashPrefixLength := len(ethHashPrefix) + output, err := getEthTransactionByHash(cliCtx, hashHexStr[ethHashPrefixLength:]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + rest.PostProcessResponseBare(w, cliCtx, output) + return + } + + output, err := utils.QueryTx(cliCtx, hashHexStr) + if err != nil { + if strings.Contains(err.Error(), hashHexStr) { + rest.WriteErrorResponse(w, http.StatusNotFound, err.Error()) + return + } + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + rest.PostProcessResponseBare(w, cliCtx, output) + } + +} + +// GetTransactionByHash returns the transaction identified by hash. +func getEthTransactionByHash(cliCtx context.CLIContext, hashHex string) ([]byte, error) { + hash, err := hex.DecodeString(hashHex) + if err != nil { + return nil, err + } + node, err := cliCtx.GetNode() + if err != nil { + return nil, err + } + tx, err := node.Tx(hash, false) + if err != nil { + return nil, err + } + + // Can either cache or just leave this out if not necessary + block, err := node.Block(&tx.Height) + if err != nil { + return nil, err + } + + blockHash := common.BytesToHash(block.Block.Header.Hash()) + + ethTx, err := rpctypes.RawTxToEthTx(cliCtx, tx.Tx) + if err != nil { + return nil, err + } + + height := uint64(tx.Height) + res, err := rpctypes.NewTransaction(ethTx, common.BytesToHash(tx.Tx.Hash()), blockHash, height, uint64(tx.Index)) + if err != nil { + return nil, err + } + return json.Marshal(res) +}