From df3c2572115dfaef7b1584c4e7dc7bce50bde755 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Wed, 27 Jul 2022 18:09:23 +0300 Subject: [PATCH 01/27] x/tracking module added which is a split version of x/gastracker without reward features --- app/ante.go | 9 +- app/app.go | 51 +- docs/proto/proto-docs.md | 233 +++++ e2e/testing/chain.go | 8 +- go.mod | 1 + go.sum | 5 +- proto/archway/tracking/v1/genesis.proto | 23 + proto/archway/tracking/v1/query.proto | 55 ++ proto/archway/tracking/v1/tracking.proto | 65 ++ x/tracking/abci.go | 19 + x/tracking/ante/tracking.go | 33 + x/tracking/client/cli/query.go | 77 ++ x/tracking/keeper/common_test.go | 46 + x/tracking/keeper/gas_processor.go | 87 ++ x/tracking/keeper/genesis.go | 22 + x/tracking/keeper/grpc_query.go | 63 ++ x/tracking/keeper/keeper.go | 63 ++ x/tracking/keeper/params.go | 24 + x/tracking/keeper/state.go | 48 + x/tracking/keeper/state_contract_op.go | 173 ++++ x/tracking/keeper/state_test.go | 238 +++++ x/tracking/keeper/state_tx_info.go | 177 ++++ x/tracking/module.go | 171 ++++ x/tracking/types/codec.go | 26 + x/tracking/types/genesis.go | 55 ++ x/tracking/types/genesis.pb.go | 453 +++++++++ x/tracking/types/keys.go | 52 + x/tracking/types/params.go | 67 ++ x/tracking/types/query.go | 9 + x/tracking/types/query.pb.go | 1120 ++++++++++++++++++++++ x/tracking/types/query.pb.gw.go | 210 ++++ x/tracking/types/tracking.go | 43 + x/tracking/types/tracking.pb.go | 960 +++++++++++++++++++ 33 files changed, 4675 insertions(+), 11 deletions(-) create mode 100644 proto/archway/tracking/v1/genesis.proto create mode 100644 proto/archway/tracking/v1/query.proto create mode 100644 proto/archway/tracking/v1/tracking.proto create mode 100644 x/tracking/abci.go create mode 100644 x/tracking/ante/tracking.go create mode 100644 x/tracking/client/cli/query.go create mode 100644 x/tracking/keeper/common_test.go create mode 100644 x/tracking/keeper/gas_processor.go create mode 100644 x/tracking/keeper/genesis.go create mode 100644 x/tracking/keeper/grpc_query.go create mode 100644 x/tracking/keeper/keeper.go create mode 100644 x/tracking/keeper/params.go create mode 100644 x/tracking/keeper/state.go create mode 100644 x/tracking/keeper/state_contract_op.go create mode 100644 x/tracking/keeper/state_test.go create mode 100644 x/tracking/keeper/state_tx_info.go create mode 100644 x/tracking/module.go create mode 100644 x/tracking/types/codec.go create mode 100644 x/tracking/types/genesis.go create mode 100644 x/tracking/types/genesis.pb.go create mode 100644 x/tracking/types/keys.go create mode 100644 x/tracking/types/params.go create mode 100644 x/tracking/types/query.go create mode 100644 x/tracking/types/query.pb.go create mode 100644 x/tracking/types/query.pb.gw.go create mode 100644 x/tracking/types/tracking.go create mode 100644 x/tracking/types/tracking.pb.go diff --git a/app/ante.go b/app/ante.go index 52c87f67..64c90dc8 100644 --- a/app/ante.go +++ b/app/ante.go @@ -11,7 +11,8 @@ import ( wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" - gastrackerante "github.com/archway-network/archway/x/gastracker/ante" + trackingAnte "github.com/archway-network/archway/x/tracking/ante" + trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC @@ -24,7 +25,7 @@ type HandlerOptions struct { TXCounterStoreKey sdk.StoreKey - GasTrackingKeeper gastrackerante.GasTrackingKeeper + TrackingKeeper trackingKeeper.Keeper } func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { @@ -60,7 +61,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), // custom archway fee deduction, which splits fees between gastracker and auths fee collector - gastrackerante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.GasTrackingKeeper), + //gastrackerante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.GasTrackingKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), @@ -68,7 +69,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewAnteDecorator(options.IBCChannelkeeper), - gastrackerante.NewTxGasTrackingDecorator(options.GasTrackingKeeper), + trackingAnte.NewTxGasTrackingDecorator(options.TrackingKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/app/app.go b/app/app.go index b919f272..4de5b5b5 100644 --- a/app/app.go +++ b/app/app.go @@ -2,6 +2,9 @@ package app import ( "fmt" + "github.com/archway-network/archway/x/tracking" + trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" + trackingTypes "github.com/archway-network/archway/x/tracking/types" "io" "net/http" "os" @@ -202,6 +205,7 @@ var ( vesting.AppModuleBasic{}, wasm.AppModuleBasic{}, gastrackermodule.AppModuleBasic{}, + tracking.AppModuleBasic{}, ) // module account permissions @@ -256,6 +260,7 @@ type ArchwayApp struct { AuthzKeeper authzkeeper.Keeper WASMKeeper wasm.Keeper GasTrackingKeeper gastrackerkeeper.Keeper + TrackingKeeper trackingKeeper.Keeper ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper @@ -301,6 +306,7 @@ func NewArchwayApp( govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, wasm.StoreKey, gastracker.StoreKey, + trackingTypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -459,6 +465,13 @@ func NewArchwayApp( defaultGasRegister, ) + app.TrackingKeeper = trackingKeeper.NewKeeper( + appCodec, + keys[trackingTypes.StoreKey], + defaultGasRegister, + app.getSubspace(trackingTypes.ModuleName), + ) + wasmDir := filepath.Join(homePath, "wasm") wasmConfig, err := wasm.ReadWasmConfig(appOpts) if err != nil { @@ -511,7 +524,7 @@ func NewArchwayApp( ) // Setting gas recorder here to avoid cyclic loop - trackingWasmVm.SetGasRecorder(app.GasTrackingKeeper) + trackingWasmVm.SetGasRecorder(app.TrackingKeeper) // The gov proposal types can be individually enabled if len(enabledProposals) != 0 { @@ -562,6 +575,7 @@ func NewArchwayApp( params.NewAppModule(app.ParamsKeeper), transferModule, gastrackermodule.NewAppModule(app.appCodec, app.GasTrackingKeeper, app.BankKeeper), + tracking.NewAppModule(app.appCodec, app.TrackingKeeper), crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), // always be last to make sure that it checks for all invariants and not only part of them ) @@ -590,7 +604,37 @@ func NewArchwayApp( // additional non simd modules ibchost.ModuleName, ibctransfertypes.ModuleName, + // wasm + wasm.ModuleName, + // wasm gas tracking + trackingTypes.ModuleName, + ) + + app.mm.SetOrderEndBlockers( + // we have to specify all modules here (Cosmos's order is taken as a reference) + crisistypes.ModuleName, + govtypes.ModuleName, + stakingtypes.ModuleName, + ibctransfertypes.ModuleName, + ibchost.ModuleName, + feegrant.ModuleName, + authz.ModuleName, + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + minttypes.ModuleName, + genutiltypes.ModuleName, + evidencetypes.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + // wasm wasm.ModuleName, + // wasm gas tracking + gastracker.ModuleName, + trackingTypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -623,6 +667,8 @@ func NewArchwayApp( ibctransfertypes.ModuleName, // wasm after ibc transfer wasm.ModuleName, + // wasm gas tracking + trackingTypes.ModuleName, ) // Uncomment if you want to set a custom migration order here. @@ -676,7 +722,7 @@ func NewArchwayApp( IBCChannelkeeper: app.IBCKeeper.ChannelKeeper, WasmConfig: &wasmConfig, TXCounterStoreKey: keys[wasm.StoreKey], - GasTrackingKeeper: app.GasTrackingKeeper, + TrackingKeeper: app.TrackingKeeper, }, ) if err != nil { @@ -839,6 +885,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(wasm.ModuleName) paramsKeeper.Subspace(gastracker.DefaultParamSpace) + paramsKeeper.Subspace(trackingTypes.ModuleName) return paramsKeeper } diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index 4a13f161..f746dd55 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -33,6 +33,25 @@ - [Msg](#archway.gastracker.v1.Msg) +- [archway/tracking/v1/tracking.proto](#archway/tracking/v1/tracking.proto) + - [ContractOperationInfo](#archway.tracking.v1.ContractOperationInfo) + - [Params](#archway.tracking.v1.Params) + - [TxInfo](#archway.tracking.v1.TxInfo) + + - [ContractOperation](#archway.tracking.v1.ContractOperation) + +- [archway/tracking/v1/genesis.proto](#archway/tracking/v1/genesis.proto) + - [GenesisState](#archway.tracking.v1.GenesisState) + +- [archway/tracking/v1/query.proto](#archway/tracking/v1/query.proto) + - [QueryBlockGasTrackingRequest](#archway.tracking.v1.QueryBlockGasTrackingRequest) + - [QueryBlockGasTrackingResponse](#archway.tracking.v1.QueryBlockGasTrackingResponse) + - [QueryParamsRequest](#archway.tracking.v1.QueryParamsRequest) + - [QueryParamsResponse](#archway.tracking.v1.QueryParamsResponse) + - [TxTracking](#archway.tracking.v1.TxTracking) + + - [Query](#archway.tracking.v1.Query) + - [Scalar Value Types](#scalar-value-types) @@ -381,6 +400,220 @@ Msg defines the gastracker msg service + +

Top

+ +## archway/tracking/v1/tracking.proto + + + + + +### ContractOperationInfo +ContractOperationInfo keeps a single contract operation gas consumption data. +Object is being created by the IngestGasRecord call from the wasmd. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `id` | [uint64](#uint64) | | id defines the unique operation ID. | +| `tx_id` | [uint64](#uint64) | | tx_id defines a transaction ID operation relates to (TxInfo.id). | +| `contract_address` | [string](#string) | | contract_address defines the contract address operation relates to. | +| `operation_type` | [ContractOperation](#archway.tracking.v1.ContractOperation) | | operation_type defines the gas consumption type. | +| `vm_gas` | [uint64](#uint64) | | vm_gas is the gas consumption reported by the WASM VM. Value is adjusted by this module (CalculateUpdatedGas func). | +| `sdk_gas` | [uint64](#uint64) | | sdk_gas is the gas consumption reported by the SDK gas meter and the WASM GasRegister (cost of Execute/Query/etc). Value is adjusted by this module (CalculateUpdatedGas func). | + + + + + + + + +### Params +Params defines the module parameters. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `gas_tracking_enabled` | [bool](#bool) | | gas_tracking_enabled flag indicates whether gas tracking is enabled (TXs and ContractOperations creation). | + + + + + + + + +### TxInfo +TxInfo keeps a transaction gas tracking data. +Object is being created at the module EndBlocker. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `id` | [uint64](#uint64) | | id defines the unique transaction ID. | +| `height` | [int64](#int64) | | height defines the block height of the transaction. | +| `total_gas` | [uint64](#uint64) | | total_gas defines total gas consumption by the transaction. It is the sum of gas consumed by all contract operations (VM + SDK gas). | + + + + + + + + + + +### ContractOperation +ContractOperation denotes which operation consumed gas. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| CONTRACT_OPERATION_UNSPECIFIED | 0 | Invalid or unknown operation | +| CONTRACT_OPERATION_INSTANTIATION | 1 | Instantiate operation | +| CONTRACT_OPERATION_EXECUTION | 2 | Execute operation | +| CONTRACT_OPERATION_QUERY | 3 | Query | +| CONTRACT_OPERATION_MIGRATE | 4 | Migrate operation | +| CONTRACT_OPERATION_IBC | 5 | IBC operations | +| CONTRACT_OPERATION_SUDO | 6 | Sudo operation | +| CONTRACT_OPERATION_REPLY | 7 | Reply callback operation | + + + + + + + + + + + +

Top

+ +## archway/tracking/v1/genesis.proto + + + + + +### GenesisState +GenesisState defines the initial state of the tracking module. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#archway.tracking.v1.Params) | | params defines all the module parameters. | +| `tx_infos` | [TxInfo](#archway.tracking.v1.TxInfo) | repeated | tx_infos defines a list of all the tracked transactions. | +| `contract_op_infos` | [ContractOperationInfo](#archway.tracking.v1.ContractOperationInfo) | repeated | contract_op_infos defines a list of all the tracked contract operations. | + + + + + + + + + + + + + + + + +

Top

+ +## archway/tracking/v1/query.proto + + + + + +### QueryBlockGasTrackingRequest +QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. + + + + + + + + +### QueryBlockGasTrackingResponse +QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `txs` | [TxTracking](#archway.tracking.v1.TxTracking) | repeated | | + + + + + + + + +### QueryParamsRequest +QueryParamsRequest is the request for Query.Params. + + + + + + + + +### QueryParamsResponse +QueryParamsResponse is the response for Query.Params. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#archway.tracking.v1.Params) | | | + + + + + + + + +### TxTracking +TxTracking is the tracking information for a transaction used by the Query.BlockGasTracking query. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `info` | [TxInfo](#archway.tracking.v1.TxInfo) | | info defines the transaction details. | +| `contract_operations` | [ContractOperationInfo](#archway.tracking.v1.ContractOperationInfo) | repeated | contract_operations defines contract operations consumed by the transaction. | + + + + + + + + + + + + + + +### Query +Query service for the tracking module. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Params` | [QueryParamsRequest](#archway.tracking.v1.QueryParamsRequest) | [QueryParamsResponse](#archway.tracking.v1.QueryParamsResponse) | Params returns module parameters. | GET|/archway/tracking/v1/params| +| `BlockGasTracking` | [QueryBlockGasTrackingRequest](#archway.tracking.v1.QueryBlockGasTrackingRequest) | [QueryBlockGasTrackingResponse](#archway.tracking.v1.QueryBlockGasTrackingResponse) | BlockGasTracking returns block gas tracking for the latest block | GET|/archway/tracking/v1/block_gas_tracking| + + + + + ## Scalar Value Types | .proto Type | Notes | C++ | Java | Python | Go | C# | PHP | Ruby | diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 730ab65f..1e4a7c7a 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -60,8 +60,9 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { // Create an app and a default genesis state encCfg := app.MakeEncodingConfig() + // Pick your poison here =) //logger := log.TestingLogger() - logger := log.TestingLogger() + logger := log.NewNopLogger() archApp := app.NewArchwayApp( logger, @@ -248,6 +249,11 @@ func (chain *TestChain) GetUnbondingTime() time.Duration { return chain.app.StakingKeeper.UnbondingTime(chain.GetContext()) } +// GetApp returns the application. +func (chain *TestChain) GetApp() *app.ArchwayApp { + return chain.app +} + // NextBlock starts a new block with options time shift. func (chain *TestChain) NextBlock(skipTime time.Duration) { chain.endBlock() diff --git a/go.mod b/go.mod index a0ec9d91..234cf8aa 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/tendermint/tm-db v0.6.7 google.golang.org/genproto v0.0.0-20220317150908-0efb43f6373e google.golang.org/grpc v1.45.0 + sigs.k8s.io/yaml v1.2.0 ) require ( diff --git a/go.sum b/go.sum index aa54574d..5cf8f243 100644 --- a/go.sum +++ b/go.sum @@ -77,7 +77,6 @@ github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220719123407-a0448ffb23f6 h1:aNPZ+lxg github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220719123407-a0448ffb23f6/go.mod h1:qCTzr8cQYwoYdA9AT4azEVbiYGjULS1nrUgw6YScXks= github.com/CosmWasm/tinyjson v0.9.0 h1:sPjgikATp5W0vD/v/Qz99uQ6G/lh/SuK0Wfskqua4Co= github.com/CosmWasm/tinyjson v0.9.0/go.mod h1:5+7QnSKrkIWnpIdhUT2t2EYzXnII3/3MlM0oDsBSbc8= -github.com/CosmWasm/wasmvm v1.0.0-beta10/go.mod h1:y+yd9piV8KlrB7ISRZz1sDwH4UVm4Q9rEX9501dBNog= github.com/CosmWasm/wasmvm v1.0.0-rc.0 h1:YI0ytwQZewPhSNxlqsrZ3/bVKTYXmrR1bfVapleCXWk= github.com/CosmWasm/wasmvm v1.0.0-rc.0/go.mod h1:ei0xpvomwSdONsxDuONzV7bL1jSET1M8brEx0FCXc+A= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -291,12 +290,10 @@ github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= -github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= -github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -1290,7 +1287,6 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1571,5 +1567,6 @@ rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/proto/archway/tracking/v1/genesis.proto b/proto/archway/tracking/v1/genesis.proto new file mode 100644 index 00000000..d7edd7c0 --- /dev/null +++ b/proto/archway/tracking/v1/genesis.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; +package archway.tracking.v1; + +option go_package = "github.com/archway-network/archway/x/tracking/types"; + +import "gogoproto/gogo.proto"; +import "archway/tracking/v1/tracking.proto"; + +// GenesisState defines the initial state of the tracking module. +message GenesisState { + // params defines all the module parameters. + Params params = 1 [ + (gogoproto.nullable) = false] + ; + // tx_infos defines a list of all the tracked transactions. + repeated TxInfo tx_infos = 2 [ + (gogoproto.nullable) = false + ]; + // contract_op_infos defines a list of all the tracked contract operations. + repeated ContractOperationInfo contract_op_infos = 3 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/tracking/v1/query.proto b/proto/archway/tracking/v1/query.proto new file mode 100644 index 00000000..572f248e --- /dev/null +++ b/proto/archway/tracking/v1/query.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; +package archway.tracking.v1; + +option go_package = "github.com/archway-network/archway/x/tracking/types"; + +import "gogoproto/gogo.proto"; +import "archway/tracking/v1/tracking.proto"; +import "google/api/annotations.proto"; + +// Query service for the tracking module. +service Query { + // Params returns module parameters. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/archway/tracking/v1/params"; + } + + // BlockGasTracking returns block gas tracking for the latest block + rpc BlockGasTracking(QueryBlockGasTrackingRequest) returns (QueryBlockGasTrackingResponse) { + option (google.api.http).get = "/archway/tracking/v1/block_gas_tracking"; + } +} + +// QueryParamsRequest is the request for Query.Params. +message QueryParamsRequest {} + +// QueryParamsResponse is the response for Query.Params. +message QueryParamsResponse { + archway.tracking.v1.Params params = 1 [ + (gogoproto.nullable) = false + ]; +} + +// QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. +message QueryBlockGasTrackingRequest {} + +// QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. +message QueryBlockGasTrackingResponse { + repeated TxTracking txs = 1 [ + (gogoproto.nullable) = false + ]; +} + +// TxTracking is the tracking information for a transaction used by the Query.BlockGasTracking query. +message TxTracking { + option (gogoproto.goproto_stringer) = false; + + // info defines the transaction details. + TxInfo info = 1 [ + (gogoproto.nullable) = false + ]; + // contract_operations defines contract operations consumed by the transaction. + repeated ContractOperationInfo contract_operations = 2 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/tracking/v1/tracking.proto b/proto/archway/tracking/v1/tracking.proto new file mode 100644 index 00000000..6f4aa78d --- /dev/null +++ b/proto/archway/tracking/v1/tracking.proto @@ -0,0 +1,65 @@ +syntax = "proto3"; +package archway.tracking.v1; + +option go_package = "github.com/archway-network/archway/x/tracking/types"; + +import "gogoproto/gogo.proto"; + +// Params defines the module parameters. +message Params { + option (gogoproto.goproto_stringer) = false; + + // gas_tracking_enabled flag indicates whether gas tracking is enabled (TXs and ContractOperations creation). + bool gas_tracking_enabled = 1; +} + +// ContractOperation denotes which operation consumed gas. +enum ContractOperation { + CONTRACT_OPERATION_UNSPECIFIED = 0; // Invalid or unknown operation + CONTRACT_OPERATION_INSTANTIATION = 1; // Instantiate operation + CONTRACT_OPERATION_EXECUTION = 2; // Execute operation + CONTRACT_OPERATION_QUERY = 3; // Query + CONTRACT_OPERATION_MIGRATE = 4; // Migrate operation + CONTRACT_OPERATION_IBC = 5; // IBC operations + CONTRACT_OPERATION_SUDO = 6; // Sudo operation + CONTRACT_OPERATION_REPLY = 7; // Reply callback operation +} + +// TxInfo keeps a transaction gas tracking data. +// Object is being created at the module EndBlocker. +message TxInfo { + option (gogoproto.goproto_stringer) = false; + + // id defines the unique transaction ID. + uint64 id = 1; + // height defines the block height of the transaction. + int64 height = 2; + // total_gas defines total gas consumption by the transaction. + // It is the sum of gas consumed by all contract operations (VM + SDK gas). + uint64 total_gas = 3; +} + +// ContractOperationInfo keeps a single contract operation gas consumption data. +// Object is being created by the IngestGasRecord call from the wasmd. +message ContractOperationInfo { + option (gogoproto.goproto_stringer) = false; + + // id defines the unique operation ID. + uint64 id = 1; + // tx_id defines a transaction ID operation relates to (TxInfo.id). + uint64 tx_id = 2; + // contract_address defines the contract address operation relates to. + string contract_address = 3; + // operation_type defines the gas consumption type. + ContractOperation operation_type = 4; + // vm_gas is the gas consumption reported by the WASM VM. + // Value is adjusted by this module (CalculateUpdatedGas func). + uint64 vm_gas = 5 [ + (gogoproto.moretags) = "yaml:\"vm_gas\"" + ]; + // sdk_gas is the gas consumption reported by the SDK gas meter and the WASM GasRegister (cost of Execute/Query/etc). + // Value is adjusted by this module (CalculateUpdatedGas func). + uint64 sdk_gas = 6 [ + (gogoproto.moretags) = "yaml:\"sdk_gas\"" + ]; +} \ No newline at end of file diff --git a/x/tracking/abci.go b/x/tracking/abci.go new file mode 100644 index 00000000..344f904f --- /dev/null +++ b/x/tracking/abci.go @@ -0,0 +1,19 @@ +package tracking + +import ( + "github.com/archway-network/archway/x/tracking/keeper" + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" + "time" +) + +// EndBlocker modifies tracked transactions using tracked contract operations. +func EndBlocker(ctx sdk.Context, k keeper.Keeper) []abci.ValidatorUpdate { + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker) + + k.FinalizeBlockTxTracking(ctx) + + return []abci.ValidatorUpdate{} +} diff --git a/x/tracking/ante/tracking.go b/x/tracking/ante/tracking.go new file mode 100644 index 00000000..231ddf53 --- /dev/null +++ b/x/tracking/ante/tracking.go @@ -0,0 +1,33 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.AnteDecorator = TxGasTrackingDecorator{} + +// TrackingKeeperExpected defines the expected interface of the TrackingKeeper. +type TrackingKeeperExpected interface { + TrackNewTx(ctx sdk.Context) +} + +// TxGasTrackingDecorator is an Ante decorator that starts the gas tracking for a new transaction. +type TxGasTrackingDecorator struct { + keeper TrackingKeeperExpected +} + +// AnteHandle implements the AnteDecorator interface. +func (d TxGasTrackingDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + if ctx.BlockHeight() <= 1 { + return next(ctx, tx, simulate) + } + + d.keeper.TrackNewTx(ctx) + + return next(ctx, tx, simulate) +} + +// NewTxGasTrackingDecorator returns a new TxGasTrackingDecorator instance. +func NewTxGasTrackingDecorator(keeper TrackingKeeperExpected) TxGasTrackingDecorator { + return TxGasTrackingDecorator{keeper: keeper} +} diff --git a/x/tracking/client/cli/query.go b/x/tracking/client/cli/query.go new file mode 100644 index 00000000..8312c0aa --- /dev/null +++ b/x/tracking/client/cli/query.go @@ -0,0 +1,77 @@ +package cli + +import ( + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" +) + +// GetQueryCmd builds query command group for the module. +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the tracking module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + cmd.AddCommand( + getQueryParamsCmd(), + getQueryBlockGasTrackingCmd(), + ) + + return cmd +} + +func getQueryParamsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Args: cobra.NoArgs, + Short: "Query the current tracking parameters", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func getQueryBlockGasTrackingCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "block-gas-tracking", + Args: cobra.NoArgs, + Short: "Query gas tracking data for the current block height", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.BlockGasTracking(cmd.Context(), &types.QueryBlockGasTrackingRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/tracking/keeper/common_test.go b/x/tracking/keeper/common_test.go new file mode 100644 index 00000000..6211dd3b --- /dev/null +++ b/x/tracking/keeper/common_test.go @@ -0,0 +1,46 @@ +package keeper_test + +import ( + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/x/tracking/types" + "github.com/stretchr/testify/suite" + "testing" +) + +type KeeperTestSuite struct { + suite.Suite + + chain *e2eTesting.TestChain +} + +func (s *KeeperTestSuite) SetupTest() { + s.chain = e2eTesting.NewTestChain(s.T(), 1) +} + +func TestTrackingKeeper(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} + +func ContractOperationToWASM(opType types.ContractOperation) uint64 { + switch opType { + case types.ContractOperation_CONTRACT_OPERATION_INSTANTIATION: + return wasmTypes.ContractOperationInstantiate + case types.ContractOperation_CONTRACT_OPERATION_EXECUTION: + return wasmTypes.ContractOperationExecute + case types.ContractOperation_CONTRACT_OPERATION_QUERY: + return wasmTypes.ContractOperationQuery + case types.ContractOperation_CONTRACT_OPERATION_MIGRATE: + return wasmTypes.ContractOperationMigrate + case types.ContractOperation_CONTRACT_OPERATION_IBC: + return wasmTypes.ContractOperationIbcPacketReceive + case types.ContractOperation_CONTRACT_OPERATION_SUDO: + return wasmTypes.ContractOperationSudo + case types.ContractOperation_CONTRACT_OPERATION_REPLY: + return wasmTypes.ContractOperationReply + case types.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED: + fallthrough + default: + return wasmTypes.ContractOperationUnknown + } +} diff --git a/x/tracking/keeper/gas_processor.go b/x/tracking/keeper/gas_processor.go new file mode 100644 index 00000000..f8eb02a9 --- /dev/null +++ b/x/tracking/keeper/gas_processor.go @@ -0,0 +1,87 @@ +package keeper + +import ( + "fmt" + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/archway-network/archway/x/tracking/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ wasmTypes.ContractGasProcessor = &Keeper{} + +// IngestGasRecord implements the wasmTypes.ContractGasProcessor interface. +// It is called by the wasmd to track contract gas records. +func (k Keeper) IngestGasRecord(ctx sdk.Context, records []wasmTypes.ContractGasRecord) error { + // Skip ingesting if not enabled + if !k.GasTrackingEnabled(ctx) { + return nil + } + + // Ingest operation for every record + for _, record := range records { + contractAddr, err := sdk.AccAddressFromBech32(record.ContractAddress) + if err != nil { + return fmt.Errorf("parsing contract address: %w", err) + } + + var opType types.ContractOperation + switch record.OperationId { + case wasmTypes.ContractOperationQuery: + opType = types.ContractOperation_CONTRACT_OPERATION_QUERY + case wasmTypes.ContractOperationInstantiate: + opType = types.ContractOperation_CONTRACT_OPERATION_INSTANTIATION + case wasmTypes.ContractOperationExecute: + opType = types.ContractOperation_CONTRACT_OPERATION_EXECUTION + case wasmTypes.ContractOperationMigrate: + opType = types.ContractOperation_CONTRACT_OPERATION_MIGRATE + case wasmTypes.ContractOperationSudo: + opType = types.ContractOperation_CONTRACT_OPERATION_SUDO + case wasmTypes.ContractOperationReply: + opType = types.ContractOperation_CONTRACT_OPERATION_REPLY + case wasmTypes.ContractOperationIbcPacketTimeout: + fallthrough + case wasmTypes.ContractOperationIbcPacketAck: + fallthrough + case wasmTypes.ContractOperationIbcPacketReceive: + fallthrough + case wasmTypes.ContractOperationIbcChannelClose: + fallthrough + case wasmTypes.ContractOperationIbcChannelOpen: + fallthrough + case wasmTypes.ContractOperationIbcChannelConnect: + opType = types.ContractOperation_CONTRACT_OPERATION_IBC + default: + opType = types.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED + } + + k.TrackNewContractOperation( + ctx, + contractAddr, + opType, + k.WasmGasRegister.FromWasmVMGas(record.OriginalGas.VMGas), + record.OriginalGas.SDKGas, + ) + } + + return nil +} + +// GetGasCalculationFn implements the wasmTypes.ContractGasProcessor interface. +// It is called by the wasmd to get the gas consumption adjustment function for a contract. +// This is a no-op function since we don't change gas values atm. +func (k Keeper) GetGasCalculationFn(ctx sdk.Context, contractAddrBz string) (func(operationId uint64, gasInfo wasmTypes.GasConsumptionInfo) wasmTypes.GasConsumptionInfo, error) { + return func(operationId uint64, gasConsumptionInfo wasmTypes.GasConsumptionInfo) wasmTypes.GasConsumptionInfo { + return gasConsumptionInfo + }, nil +} + +// CalculateUpdatedGas implements the wasmTypes.ContractGasProcessor interface. +// It is called by the wasmd to modify a gas consumption record. +func (k Keeper) CalculateUpdatedGas(ctx sdk.Context, record wasmTypes.ContractGasRecord) (wasmTypes.GasConsumptionInfo, error) { + gasCalcFn, err := k.GetGasCalculationFn(ctx, record.ContractAddress) + if err != nil { + return wasmTypes.GasConsumptionInfo{}, err + } + + return gasCalcFn(record.OperationId, record.OriginalGas), nil +} diff --git a/x/tracking/keeper/genesis.go b/x/tracking/keeper/genesis.go new file mode 100644 index 00000000..98ee2a2c --- /dev/null +++ b/x/tracking/keeper/genesis.go @@ -0,0 +1,22 @@ +package keeper + +import ( + "github.com/archway-network/archway/x/tracking/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ExportGenesis exports the module genesis for the current block. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + return types.NewGenesisState( + k.GetParams(ctx), + k.state.TxInfoState(ctx).Export(), + k.state.ContractOpInfoState(ctx).Export(), + ) +} + +// InitGenesis initializes the module genesis state. +func (k Keeper) InitGenesis(ctx sdk.Context, state *types.GenesisState) { + k.SetParams(ctx, state.Params) + k.state.TxInfoState(ctx).Import(state.TxInfos) + k.state.ContractOpInfoState(ctx).Import(state.ContractOpInfos) +} diff --git a/x/tracking/keeper/grpc_query.go b/x/tracking/keeper/grpc_query.go new file mode 100644 index 00000000..ec99da72 --- /dev/null +++ b/x/tracking/keeper/grpc_query.go @@ -0,0 +1,63 @@ +package keeper + +import ( + "context" + "github.com/archway-network/archway/x/tracking/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var _ types.QueryServer = &QueryServer{} + +// QueryServer implements the module gRPC query service. +type QueryServer struct { + keeper Keeper +} + +// NewQueryServer creates a new gRPC query server. +func NewQueryServer(keeper Keeper) *QueryServer { + return &QueryServer{ + keeper: keeper, + } +} + +// Params implements the types.QueryServer interface. +func (s *QueryServer) Params(c context.Context, request *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + return &types.QueryParamsResponse{ + Params: s.keeper.GetParams(ctx), + }, nil +} + +// BlockGasTracking implements the types.QueryServer interface. +func (s *QueryServer) BlockGasTracking(c context.Context, request *types.QueryBlockGasTrackingRequest) (*types.QueryBlockGasTrackingResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + txState := s.keeper.state.TxInfoState(ctx) + contractOpState := s.keeper.state.ContractOpInfoState(ctx) + + var response types.QueryBlockGasTrackingResponse + + txInfos := txState.GetTxInfosByBlock(ctx.BlockHeight()) + response.Txs = make([]types.TxTracking, 0, len(txInfos)) + for _, txInfo := range txInfos { + response.Txs = append( + response.Txs, + types.TxTracking{ + Info: txInfo, + ContractOperations: contractOpState.GetContractOpInfoByTxID(txInfo.Id), + }, + ) + } + + return &response, nil +} diff --git a/x/tracking/keeper/keeper.go b/x/tracking/keeper/keeper.go new file mode 100644 index 00000000..0ba179e7 --- /dev/null +++ b/x/tracking/keeper/keeper.go @@ -0,0 +1,63 @@ +package keeper + +import ( + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/tendermint/tendermint/libs/log" +) + +// Keeper provides module state operations. +type Keeper struct { + WasmGasRegister wasmKeeper.GasRegister + + cdc codec.Codec + paramStore paramTypes.Subspace + state State +} + +// NewKeeper creates a new Keeper instance. +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, gasRegister wasmKeeper.GasRegister, ps paramTypes.Subspace) Keeper { + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + cdc: cdc, + WasmGasRegister: gasRegister, + paramStore: ps, + state: NewState(cdc, key), + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", "x/"+types.ModuleName) +} + +// TrackNewTx creates a new transaction tracking info with a unique ID that is used to link new contract operations to. +// TxInfo object itself is created later during the EndBlocker. +func (k Keeper) TrackNewTx(ctx sdk.Context) { + k.state.TxInfoState(ctx).CreateEmptyTxInfo() +} + +// TrackNewContractOperation creates a new contract operation tracking entry with a unique ID using the current transaction ID. +func (k Keeper) TrackNewContractOperation(ctx sdk.Context, contractAddr sdk.AccAddress, opType types.ContractOperation, vmGasConsumed, sdkGasConsumed uint64) { + curTxID := k.state.TxInfoState(ctx).GetCurrentTxID() + k.state.ContractOpInfoState(ctx).CreateContractOpInfo(curTxID, contractAddr, opType, vmGasConsumed, sdkGasConsumed) +} + +// FinalizeBlockTxTracking updates block transactions total gas consumed value using tracked contract operations. +func (k Keeper) FinalizeBlockTxTracking(ctx sdk.Context) { + txState := k.state.TxInfoState(ctx) + contractOpState := k.state.ContractOpInfoState(ctx) + + for _, txInfo := range txState.GetTxInfosByBlock(ctx.BlockHeight()) { + for _, contractOp := range contractOpState.GetContractOpInfoByTxID(txInfo.Id) { + txInfo.TotalGas += contractOp.VmGas + contractOp.SdkGas + } + txState.SetTxInfo(txInfo) + } +} diff --git a/x/tracking/keeper/params.go b/x/tracking/keeper/params.go new file mode 100644 index 00000000..de7a8688 --- /dev/null +++ b/x/tracking/keeper/params.go @@ -0,0 +1,24 @@ +package keeper + +import ( + "github.com/archway-network/archway/x/tracking/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GasTrackingEnabled return gas tracking enabled param flag. +func (k Keeper) GasTrackingEnabled(ctx sdk.Context) (res bool) { + k.paramStore.Get(ctx, types.GasTrackingEnabledParamKey, &res) + return +} + +// GetParams return all module parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams( + k.GasTrackingEnabled(ctx), + ) +} + +// SetParams sets all module parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramStore.SetParamSet(ctx, ¶ms) +} diff --git a/x/tracking/keeper/state.go b/x/tracking/keeper/state.go new file mode 100644 index 00000000..e3802480 --- /dev/null +++ b/x/tracking/keeper/state.go @@ -0,0 +1,48 @@ +package keeper + +import ( + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// State is a wrapper around the module storage state. +type State struct { + key sdk.StoreKey + cdc codec.Codec +} + +// NewState creates a new State instance. +func NewState(cdc codec.Codec, key sdk.StoreKey) State { + return State{ + key: key, + cdc: cdc, + } +} + +// TxInfoState returns types.TxInfo repository. +func (s State) TxInfoState(ctx sdk.Context) TxInfoState { + baseStore := ctx.KVStore(s.key) + return TxInfoState{ + stateStore: prefix.NewStore(baseStore, types.TxInfoStatePrefix), + cdc: s.cdc, + ctx: ctx, + } +} + +// ContractOpInfoState returns types.ContractOperationInfo repository. +func (s State) ContractOpInfoState(ctx sdk.Context) ContractOpInfoState { + baseStore := ctx.KVStore(s.key) + return ContractOpInfoState{ + stateStore: prefix.NewStore(baseStore, types.ContractOpInfoStatePrefix), + cdc: s.cdc, + ctx: ctx, + } +} + +// GetState returns the module storage state. +// Only for testing purposes. +func (k Keeper) GetState() State { + return k.state +} diff --git a/x/tracking/keeper/state_contract_op.go b/x/tracking/keeper/state_contract_op.go new file mode 100644 index 00000000..2eaa03e0 --- /dev/null +++ b/x/tracking/keeper/state_contract_op.go @@ -0,0 +1,173 @@ +package keeper + +import ( + "fmt" + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ContractOpInfoState provides access to the types.ContractOperationInfo objects storage operations. +type ContractOpInfoState struct { + stateStore storeTypes.KVStore + cdc codec.Codec + ctx sdk.Context +} + +// CreateContractOpInfo creates a new types.ContractOperationInfo object with unique ID. +func (s ContractOpInfoState) CreateContractOpInfo(txID uint64, contractAddr sdk.AccAddress, opType types.ContractOperation, vmGas, sdkGas uint64) types.ContractOperationInfo { + obj := types.ContractOperationInfo{ + Id: s.getNextID(), + TxId: txID, + ContractAddress: contractAddr.String(), + OperationType: opType, + VmGas: vmGas, + SdkGas: sdkGas, + } + + s.setContractOpInfo(&obj) + s.setTxIndex(obj.TxId, obj.Id) + s.setLastID(obj.Id) + + return obj +} + +// GetContractOpInfo returns a types.ContractOperationInfo object by ID. +func (s ContractOpInfoState) GetContractOpInfo(id uint64) (types.ContractOperationInfo, bool) { + obj := s.getContractOpInfo(id) + if obj == nil { + return types.ContractOperationInfo{}, false + } + + return *obj, true +} + +// GetContractOpInfoByTxID returns a list of types.ContractOperationInfo objects by tx ID. +func (s ContractOpInfoState) GetContractOpInfoByTxID(txID uint64) (objs []types.ContractOperationInfo) { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoTxIndexPrefix) + + iterator := sdk.KVStorePrefixIterator(store, s.buildTxIndexPrefix(txID)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + _, id := s.parseTxIndexKey(iterator.Key()) + + obj, found := s.GetContractOpInfo(id) + if !found { + panic(fmt.Errorf("invalid ContractOpInfo tx index state: id (%d): not found", id)) + } + objs = append(objs, obj) + } + + return +} + +// Import initializes state from the module genesis data. +func (s ContractOpInfoState) Import(objs []types.ContractOperationInfo) { + lastID := uint64(0) + for _, obj := range objs { + s.setContractOpInfo(&obj) + s.setTxIndex(obj.TxId, obj.Id) + if obj.Id > lastID { + lastID = obj.Id + } + } + s.setLastID(lastID) +} + +// Export returns the module genesis data for the state. +func (s ContractOpInfoState) Export() (objs []types.ContractOperationInfo) { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var obj types.ContractOperationInfo + s.cdc.MustUnmarshal(iterator.Value(), &obj) + objs = append(objs, obj) + } + + return +} + +// setLastID sets the last types.ContractOperationInfo unique ID. +func (s ContractOpInfoState) setLastID(id uint64) { + s.stateStore.Set( + types.ContractOpInfoIDKey, + sdk.Uint64ToBigEndian(id), + ) +} + +// getNextID returns the next types.ContractOperationInfo unique ID. +func (s ContractOpInfoState) getNextID() uint64 { + lastIDBz := s.stateStore.Get(types.ContractOpInfoIDKey) + lastID := sdk.BigEndianToUint64(lastIDBz) // returns 0 if nil + + return lastID + 1 +} + +// buildTxInfoKey returns the key used to store a types.ContractOperationInfo object. +func (s ContractOpInfoState) buildContractOpInfoKey(id uint64) []byte { + return sdk.Uint64ToBigEndian(id) +} + +// setContractOpInfo sets a types.ContractOperationInfo object. +func (s ContractOpInfoState) setContractOpInfo(obj *types.ContractOperationInfo) { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoPrefix) + store.Set( + s.buildContractOpInfoKey(obj.Id), + s.cdc.MustMarshal(obj), + ) +} + +// getContractOpInfo returns a types.ContractOperationInfo object by ID. +func (s ContractOpInfoState) getContractOpInfo(id uint64) *types.ContractOperationInfo { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoPrefix) + + bz := store.Get(s.buildContractOpInfoKey(id)) + if bz == nil { + return nil + } + + var obj types.ContractOperationInfo + s.cdc.MustUnmarshal(bz, &obj) + + return &obj +} + +// buildTxIndexPrefix returns the key prefix used to maintain types.ContractOperationInfo tx index. +func (s ContractOpInfoState) buildTxIndexPrefix(txID uint64) []byte { + return sdk.Uint64ToBigEndian(txID) +} + +// buildTxIndexKey returns the key used to maintain types.ContractOperationInfo tx index. +func (s ContractOpInfoState) buildTxIndexKey(txID, id uint64) []byte { + return append( + s.buildTxIndexPrefix(txID), + sdk.Uint64ToBigEndian(id)..., + ) +} + +// parseTxIndexKey parses the types.ContractOperationInfo tx index key. +func (s ContractOpInfoState) parseTxIndexKey(key []byte) (txID, id uint64) { + if len(key) != 16 { + panic(fmt.Errorf("invalid ContractOpInfo TxInfo index key length: %d", len(key))) + } + + txID = sdk.BigEndianToUint64(key[:8]) + id = sdk.BigEndianToUint64(key[8:]) + + return +} + +// setTxIndex adds the types.ContractOperationInfo tx index entry. +func (s ContractOpInfoState) setTxIndex(txID, id uint64) { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoTxIndexPrefix) + store.Set( + s.buildTxIndexKey(txID, id), + []byte{}, + ) +} diff --git a/x/tracking/keeper/state_test.go b/x/tracking/keeper/state_test.go new file mode 100644 index 00000000..e3e28e87 --- /dev/null +++ b/x/tracking/keeper/state_test.go @@ -0,0 +1,238 @@ +package keeper_test + +import ( + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/archway-network/archway/x/tracking/types" +) + +// TestStates tests TxInfo and ContractOperationInfo state storages. +// Test append multiple objects for different blocks to make sure there are no namespace +// collisions (prefixed store keys) and state indexes work as expected. +func (s *KeeperTestSuite) TestStates() { + type testData struct { + Tx types.TxInfo + Ops []types.ContractOperationInfo + } + + chain := s.chain + ctx, keeper := chain.GetContext(), chain.GetApp().TrackingKeeper + + // Fixtures + startBlock := ctx.BlockHeight() + testDataExpected := []testData{ + // Block 1, Tx 1: 3 ops + { + Tx: types.TxInfo{ + Id: 1, + Height: startBlock + 1, + TotalGas: 450, + }, + Ops: []types.ContractOperationInfo{ + { + Id: 1, + TxId: 1, + ContractAddress: chain.GetAccount(0).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_EXECUTION, + VmGas: 100, // here and below: converted to SDK gas + SdkGas: 200, + }, + { + Id: 2, + TxId: 1, + ContractAddress: chain.GetAccount(1).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_QUERY, + VmGas: 50, + SdkGas: 100, + }, + }, + }, + // Block 1, Tx 2: 3 ops (2 from the same contract) + { + Tx: types.TxInfo{ + Id: 2, + Height: startBlock + 1, + TotalGas: 2600, + }, + Ops: []types.ContractOperationInfo{ + { + Id: 3, + TxId: 2, + ContractAddress: chain.GetAccount(2).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_INSTANTIATION, + VmGas: 500, + SdkGas: 1000, + }, + { + Id: 4, + TxId: 2, + ContractAddress: chain.GetAccount(3).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_EXECUTION, + VmGas: 250, + SdkGas: 300, + }, + { + Id: 5, + TxId: 2, + ContractAddress: chain.GetAccount(3).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_EXECUTION, + VmGas: 250, + SdkGas: 300, + }, + }, + }, + // Block 2, Tx 1: 3 ops from 2 contracts (mixed) + { + Tx: types.TxInfo{ + Id: 3, + Height: startBlock + 2, + TotalGas: 725, + }, + Ops: []types.ContractOperationInfo{ + { + Id: 6, + TxId: 3, + ContractAddress: chain.GetAccount(0).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_EXECUTION, + VmGas: 50, + SdkGas: 25, + }, + { + Id: 7, + TxId: 3, + ContractAddress: chain.GetAccount(1).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_IBC, + VmGas: 100, + SdkGas: 50, + }, + { + Id: 8, + TxId: 3, + ContractAddress: chain.GetAccount(0).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_REPLY, + VmGas: 200, + SdkGas: 300, + }, + }, + }, + // Block 2, Tx 2: 2 ops from 2 contracts + { + Tx: types.TxInfo{ + Id: 4, + Height: startBlock + 2, + TotalGas: 2100, + }, + Ops: []types.ContractOperationInfo{ + { + Id: 9, + TxId: 4, + ContractAddress: chain.GetAccount(0).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_MIGRATE, + VmGas: 100, + SdkGas: 500, + }, + { + Id: 10, + TxId: 4, + ContractAddress: chain.GetAccount(1).Address.String(), + OperationType: types.ContractOperation_CONTRACT_OPERATION_SUDO, + VmGas: 500, + SdkGas: 1000, + }, + }, + }, + } + + // Upload fixtures + block := int64(0) + for _, data := range testDataExpected { + // Switch to next block + if data.Tx.Height != block { + chain.NextBlock(0) // that updates TxInfo objs via EndBlocker + ctx = chain.GetContext() + block = ctx.BlockHeight() + } + + // Start tracking a new Tx (emulate Ante handler) + keeper.TrackNewTx(ctx) + + // Ingest contract operations + records := make([]wasmTypes.ContractGasRecord, 0, len(data.Ops)) + for _, op := range data.Ops { + records = append( + records, + wasmTypes.ContractGasRecord{ + OperationId: ContractOperationToWASM(op.OperationType), + ContractAddress: op.ContractAddress, + OriginalGas: wasmTypes.GasConsumptionInfo{ + VMGas: keeper.WasmGasRegister.ToWasmVMGas(op.VmGas), + SDKGas: op.SdkGas, + }, + }, + ) + } + s.Require().NoError(keeper.IngestGasRecord(ctx, records)) + } + keeper.FinalizeBlockTxTracking(ctx) + + // Check that the states are as expected + s.Run("Check objects one by one", func() { + opState := keeper.GetState().ContractOpInfoState(ctx) + txState := keeper.GetState().TxInfoState(ctx) + + for _, data := range testDataExpected { + // Check ContractOperations + for _, op := range data.Ops { + opInfo, found := opState.GetContractOpInfo(op.Id) + s.Require().True(found, "ContractOpInfo (%d): not found", op.Id) + s.Assert().Equal(op, opInfo, "ContractOpInfo (%d): wrong value", op.Id) + } + + // Check TxInfo + txInfo, found := txState.GetTxInfo(data.Tx.Id) + s.Require().True(found, "TxInfo (%d): not found", data.Tx.Id) + s.Assert().Equal(data.Tx, txInfo, "TxInfo (%d): wrong value", data.Tx.Id) + } + }) + + // Check TxInfos search via block index + s.Run("Check TxInfo block index", func() { + txState := keeper.GetState().TxInfoState(ctx) + + // 1st block + { + height := testDataExpected[0].Tx.Height + txInfosExpected := []types.TxInfo{ + testDataExpected[0].Tx, + testDataExpected[1].Tx, + } + + txInfosReceived := txState.GetTxInfosByBlock(height) + s.Assert().ElementsMatch(txInfosExpected, txInfosReceived, "TxInfosByBlock (%d): wrong value", height) + } + + // 2nd block + { + height := testDataExpected[2].Tx.Height + txInfosExpected := []types.TxInfo{ + testDataExpected[2].Tx, + testDataExpected[3].Tx, + } + + txInfosReceived := txState.GetTxInfosByBlock(height) + s.Assert().ElementsMatch(txInfosExpected, txInfosReceived, "TxInfosByBlock (%d): wrong value", height) + } + }) + + // Check ContractOpInfos search via tx index + s.Run("Check ContractOpInfo tx index", func() { + opsState := keeper.GetState().ContractOpInfoState(ctx) + + for _, data := range testDataExpected { + txID := data.Tx.Id + opsExpected := data.Ops + + opsReceived := opsState.GetContractOpInfoByTxID(txID) + s.Assert().ElementsMatch(opsExpected, opsReceived, "ContractOpInfoByTxID (%d): wrong value", txID) + } + }) +} diff --git a/x/tracking/keeper/state_tx_info.go b/x/tracking/keeper/state_tx_info.go new file mode 100644 index 00000000..65268edf --- /dev/null +++ b/x/tracking/keeper/state_tx_info.go @@ -0,0 +1,177 @@ +package keeper + +import ( + "fmt" + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TxInfoState provides access to the types.TxInfo objects storage operations. +type TxInfoState struct { + stateStore storeTypes.KVStore + cdc codec.Codec + ctx sdk.Context +} + +// GetCurrentTxID returns the latest types.TxInfo unique ID. +func (s TxInfoState) GetCurrentTxID() uint64 { + lastIDBz := s.stateStore.Get(types.TxInfoIDKey) + lastID := sdk.BigEndianToUint64(lastIDBz) // returns 0 if nil + + return lastID +} + +// CreateEmptyTxInfo creates a new types.TxInfo object with unique ID. +func (s TxInfoState) CreateEmptyTxInfo() types.TxInfo { + obj := types.TxInfo{ + Id: s.nextID(), + Height: s.ctx.BlockHeight(), + } + + s.SetTxInfo(obj) + s.setBlockIndex(s.ctx.BlockHeight(), obj.Id) + s.setLastID(obj.Id) + + return obj +} + +// SetTxInfo sets a types.TxInfo object overwriting and existing one. +func (s TxInfoState) SetTxInfo(obj types.TxInfo) { + store := prefix.NewStore(s.stateStore, types.TxInfoPrefix) + store.Set( + s.buildTxInfoKey(obj.Id), + s.cdc.MustMarshal(&obj), + ) +} + +// GetTxInfo returns a types.TxInfo object by ID. +func (s TxInfoState) GetTxInfo(id uint64) (types.TxInfo, bool) { + obj := s.getTxInfo(id) + if obj == nil { + return types.TxInfo{}, false + } + + return *obj, true +} + +// GetTxInfosByBlock returns a list of types.TxInfo objects by block height. +func (s TxInfoState) GetTxInfosByBlock(height int64) (objs []types.TxInfo) { + store := prefix.NewStore(s.stateStore, types.TxInfoBlockIndexPrefix) + + iterator := sdk.KVStorePrefixIterator(store, s.buildBlockIndexPrefix(height)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + _, id := s.parseBlockIndexKey(iterator.Key()) + + obj, found := s.GetTxInfo(id) + if !found { + panic(fmt.Errorf("invalid TxInfo block index state: id (%d): not found", id)) + } + objs = append(objs, obj) + } + + return +} + +// Import initializes state from the module genesis data. +func (s TxInfoState) Import(objs []types.TxInfo) { + lastID := uint64(0) + for _, obj := range objs { + s.SetTxInfo(obj) + s.setBlockIndex(obj.Height, obj.Id) + if obj.Id > lastID { + lastID = obj.Id + } + } + s.setLastID(lastID) +} + +// Export returns the module genesis data for the state. +func (s TxInfoState) Export() (objs []types.TxInfo) { + store := prefix.NewStore(s.stateStore, types.TxInfoPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var obj types.TxInfo + s.cdc.MustUnmarshal(iterator.Value(), &obj) + objs = append(objs, obj) + } + + return +} + +// setLastID sets the last types.TxInfo unique ID. +func (s TxInfoState) setLastID(id uint64) { + s.stateStore.Set( + types.TxInfoIDKey, + sdk.Uint64ToBigEndian(id), + ) +} + +// nextID returns the next types.TxInfo unique ID. +func (s TxInfoState) nextID() uint64 { + lastIDBz := s.stateStore.Get(types.TxInfoIDKey) + lastID := sdk.BigEndianToUint64(lastIDBz) // returns 0 if nil + + return lastID + 1 +} + +// buildTxInfoKey returns the key used to store a types.TxInfo object. +func (s TxInfoState) buildTxInfoKey(id uint64) []byte { + return sdk.Uint64ToBigEndian(id) +} + +// getTxInfo returns a types.TxInfo object by ID. +func (s TxInfoState) getTxInfo(id uint64) *types.TxInfo { + store := prefix.NewStore(s.stateStore, types.TxInfoPrefix) + + bz := store.Get(s.buildTxInfoKey(id)) + if bz == nil { + return nil + } + + var obj types.TxInfo + s.cdc.MustUnmarshal(bz, &obj) + + return &obj +} + +// buildBlockIndexPrefix returns the key prefix used to maintain types.TxInfo block index. +func (s TxInfoState) buildBlockIndexPrefix(height int64) []byte { + return sdk.Uint64ToBigEndian(uint64(height)) +} + +// buildBlockIndexKey returns the key used to maintain types.TxInfo block index. +func (s TxInfoState) buildBlockIndexKey(height int64, id uint64) []byte { + return append( + s.buildBlockIndexPrefix(height), + sdk.Uint64ToBigEndian(id)..., + ) +} + +// parseBlockIndexKey parses the types.TxInfo block index key. +func (s TxInfoState) parseBlockIndexKey(key []byte) (height int64, id uint64) { + if len(key) != 16 { + panic(fmt.Errorf("invalid TxInfo block index key length: %d", len(key))) + } + + height = int64(sdk.BigEndianToUint64(key[:8])) + id = sdk.BigEndianToUint64(key[8:]) + + return +} + +// setBlockIndex adds the types.TxInfo block index entry. +func (s TxInfoState) setBlockIndex(height int64, id uint64) { + store := prefix.NewStore(s.stateStore, types.TxInfoBlockIndexPrefix) + store.Set( + s.buildBlockIndexKey(height, id), + []byte{}, + ) +} diff --git a/x/tracking/module.go b/x/tracking/module.go new file mode 100644 index 00000000..7958389d --- /dev/null +++ b/x/tracking/module.go @@ -0,0 +1,171 @@ +// Package tracking defines a module that tracks WASM contracts gas usage per transaction. +package tracking + +import ( + "context" + "encoding/json" + "fmt" + "github.com/archway-network/archway/x/tracking/client/cli" + "github.com/archway-network/archway/x/tracking/keeper" + "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codecTypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simTypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + "math/rand" +) + +var ( + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModule = AppModule{} +) + +// AppModuleBasic defines the basic application module for this module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// Name returns the module's name. +func (a AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the module's types on the given LegacyAmino codec. +func (a AppModuleBasic) RegisterLegacyAminoCodec(amino *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(amino) +} + +// RegisterInterfaces registers the module's interface types. +func (a AppModuleBasic) RegisterInterfaces(registry codecTypes.InterfaceRegistry) {} + +// DefaultGenesis returns default genesis state as raw bytes for the module. +func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the module. +func (a AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var state types.GenesisState + if err := cdc.UnmarshalJSON(bz, &state); err != nil { + return fmt.Errorf("failed to unmarshal x/%s genesis state: %w", types.ModuleName, err) + } + + return state.Validate() +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, serveMux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(clientCtx)); err != nil { + panic(fmt.Errorf("registering query handler for x/%s: %w", types.ModuleName, err)) + } +} + +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} + +// GetTxCmd returns the root tx command for the module. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return nil +} + +// GetQueryCmd returns no root query command for the module. +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// AppModule implements an application module for this module. +type AppModule struct { + AppModuleBasic + + cdc codec.Codec + keeper keeper.Keeper +} + +// NewAppModule creates a new AppModule object. +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: keeper, + } +} + +// RegisterInvariants registers the module invariants. +func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// Route returns the message routing key for the module. +// Deprecated. +func (AppModule) Route() sdk.Route { return sdk.Route{} } + +// QuerierRoute returns the module's querier route name. +func (a AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// LegacyQuerierHandler returns the staking module sdk.Querier. +func (a AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers the module services. +func (a AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServer(a.keeper)) +} + +// InitGenesis performs genesis initialization for the module. It returns no validator updates. +func (a AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(bz, &genesisState) + + a.keeper.InitGenesis(ctx, &genesisState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the module. +func (a AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + state := a.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(state) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (a AppModule) ConsensusVersion() uint64 { + return 1 +} + +// BeginBlock returns the begin blocker for the module. +func (a AppModule) BeginBlock(context sdk.Context, block abci.RequestBeginBlock) {} + +// EndBlock returns the end blocker for the module. It returns no validator updates. +func (a AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return EndBlocker(ctx, a.keeper) +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the module. +func (a AppModule) GenerateGenesisState(input *module.SimulationState) {} + +// ProposalContents doesn't return any content functions for governance proposals. +func (a AppModule) ProposalContents(_ module.SimulationState) []simTypes.WeightedProposalContent { + return []simTypes.WeightedProposalContent{} +} + +// RandomizedParams creates randomized param changes for the simulator. +func (a AppModule) RandomizedParams(r *rand.Rand) []simTypes.ParamChange { + return []simTypes.ParamChange{} +} + +// RegisterStoreDecoder registers a decoder for the module's types. +func (a AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { + +} + +// WeightedOperations returns all the module operations with their respective weights. +func (a AppModule) WeightedOperations(_ module.SimulationState) []simTypes.WeightedOperation { + return []simTypes.WeightedOperation{} +} diff --git a/x/tracking/types/codec.go b/x/tracking/types/codec.go new file mode 100644 index 00000000..5a8505bd --- /dev/null +++ b/x/tracking/types/codec.go @@ -0,0 +1,26 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptoCodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// RegisterLegacyAminoCodec registers the necessary interfaces and concrete types on the provided LegacyAmino codec. +// These types are used for Amino JSON serialization. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} + +// RegisterInterfaces registers interfaces types with the interface registry. +func RegisterInterfaces(registry types.InterfaceRegistry) {} + +var ( + ModuleCdc = codec.NewAminoCodec(amino) + amino = codec.NewLegacyAmino() +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptoCodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) +} diff --git a/x/tracking/types/genesis.go b/x/tracking/types/genesis.go new file mode 100644 index 00000000..e9a085a7 --- /dev/null +++ b/x/tracking/types/genesis.go @@ -0,0 +1,55 @@ +package types + +import "fmt" + +// NewGenesisState creates a new GenesisState object. +func NewGenesisState(params Params, txInfos []TxInfo, contractOpInfos []ContractOperationInfo) *GenesisState { + return &GenesisState{ + Params: params, + TxInfos: txInfos, + ContractOpInfos: contractOpInfos, + } +} + +// DefaultGenesisState returns a default genesis state. +func DefaultGenesisState() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + TxInfos: []TxInfo{}, + ContractOpInfos: []ContractOperationInfo{}, + } +} + +// Validate performs genesis state validation. +func (m GenesisState) Validate() error { + if err := m.Params.Validate(); err != nil { + return fmt.Errorf("params: %w", err) + } + + txIDSet := make(map[uint64]struct{}) + for i, txInfo := range m.TxInfos { + if err := txInfo.Validate(); err != nil { + return fmt.Errorf("txInfos [%d]: %w", i, err) + } + if _, ok := txIDSet[txInfo.Id]; ok { + return fmt.Errorf("txInfos [%d]: duplicated ID: %d", i, txInfo.Id) + } + txIDSet[txInfo.Id] = struct{}{} + } + + opIDSet := make(map[uint64]struct{}) + for i, opInfo := range m.ContractOpInfos { + if err := opInfo.Validate(); err != nil { + return fmt.Errorf("contractOpInfos [%d]: %w", i, err) + } + if _, ok := opIDSet[opInfo.Id]; ok { + return fmt.Errorf("contractOpInfos [%d]: duplicated ID: %d", i, opInfo.Id) + } + if _, ok := txIDSet[opInfo.TxId]; !ok { + return fmt.Errorf("contractOpInfos [%d]: txId (%d): not found", i, opInfo.TxId) + } + opIDSet[opInfo.Id] = struct{}{} + } + + return nil +} diff --git a/x/tracking/types/genesis.pb.go b/x/tracking/types/genesis.pb.go new file mode 100644 index 00000000..2a8af993 --- /dev/null +++ b/x/tracking/types/genesis.pb.go @@ -0,0 +1,453 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/tracking/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the initial state of the tracking module. +type GenesisState struct { + // params defines all the module parameters. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // tx_infos defines a list of all the tracked transactions. + TxInfos []TxInfo `protobuf:"bytes,2,rep,name=tx_infos,json=txInfos,proto3" json:"tx_infos"` + // contract_op_infos defines a list of all the tracked contract operations. + ContractOpInfos []ContractOperationInfo `protobuf:"bytes,3,rep,name=contract_op_infos,json=contractOpInfos,proto3" json:"contract_op_infos"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_3734e87d4a484a58, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetTxInfos() []TxInfo { + if m != nil { + return m.TxInfos + } + return nil +} + +func (m *GenesisState) GetContractOpInfos() []ContractOperationInfo { + if m != nil { + return m.ContractOpInfos + } + return nil +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "archway.tracking.v1.GenesisState") +} + +func init() { proto.RegisterFile("archway/tracking/v1/genesis.proto", fileDescriptor_3734e87d4a484a58) } + +var fileDescriptor_3734e87d4a484a58 = []byte{ + // 278 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4c, 0x2c, 0x4a, 0xce, + 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x29, 0x4a, 0x4c, 0xce, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x33, 0xd4, + 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x86, + 0x2a, 0xd1, 0x83, 0x29, 0xd1, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xeb, + 0x83, 0x58, 0x10, 0xa5, 0x52, 0x4a, 0xd8, 0x4c, 0x83, 0x6b, 0x03, 0xab, 0x51, 0x7a, 0xca, 0xc8, + 0xc5, 0xe3, 0x0e, 0xb1, 0x20, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x92, 0x8b, 0xad, 0x20, 0xb1, + 0x28, 0x31, 0xb7, 0x58, 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x5a, 0x0f, 0x8b, 0x85, 0x7a, + 0x01, 0x60, 0x25, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x41, 0x35, 0x08, 0xd9, 0x70, 0x71, + 0x94, 0x54, 0xc4, 0x67, 0xe6, 0xa5, 0xe5, 0x17, 0x4b, 0x30, 0x29, 0x30, 0xe3, 0xd4, 0x1c, 0x52, + 0xe1, 0x99, 0x97, 0x96, 0x0f, 0xd5, 0xcc, 0x5e, 0x02, 0xe6, 0x15, 0x0b, 0xc5, 0x70, 0x09, 0x26, + 0xe7, 0xe7, 0x81, 0xd4, 0x95, 0xc4, 0xe7, 0x17, 0x40, 0x8d, 0x61, 0x06, 0x1b, 0xa3, 0x85, 0xd5, + 0x18, 0x67, 0xa8, 0x6a, 0xff, 0x82, 0xd4, 0xa2, 0xc4, 0x92, 0xcc, 0xfc, 0x3c, 0x24, 0x53, 0xf9, + 0x93, 0xe1, 0x92, 0x60, 0xd3, 0x9d, 0x7c, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, + 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, + 0x21, 0xca, 0x38, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x6a, 0x8d, + 0x6e, 0x5e, 0x6a, 0x49, 0x79, 0x7e, 0x51, 0x36, 0x8c, 0xaf, 0x5f, 0x81, 0x08, 0xc2, 0x92, 0xca, + 0x82, 0xd4, 0xe2, 0x24, 0x36, 0x70, 0xe8, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x15, 0x76, + 0x2d, 0x8e, 0xb1, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractOpInfos) > 0 { + for iNdEx := len(m.ContractOpInfos) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractOpInfos[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.TxInfos) > 0 { + for iNdEx := len(m.TxInfos) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TxInfos[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.TxInfos) > 0 { + for _, e := range m.TxInfos { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ContractOpInfos) > 0 { + for _, e := range m.ContractOpInfos { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxInfos", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxInfos = append(m.TxInfos, TxInfo{}) + if err := m.TxInfos[len(m.TxInfos)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractOpInfos", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractOpInfos = append(m.ContractOpInfos, ContractOperationInfo{}) + if err := m.ContractOpInfos[len(m.ContractOpInfos)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tracking/types/keys.go b/x/tracking/types/keys.go new file mode 100644 index 00000000..18a6b6a8 --- /dev/null +++ b/x/tracking/types/keys.go @@ -0,0 +1,52 @@ +package types + +const ( + // ModuleName is the module name. + ModuleName = "tracking" + // StoreKey is the module KV storage prefix key. + StoreKey = ModuleName + // QuerierRoute is the querier route for the module. + QuerierRoute = ModuleName +) + +// TxInfo prefixed store state keys. +var ( + // TxInfoStatePrefix defines the state global prefix. + TxInfoStatePrefix = []byte{0x00} + + // TxInfoIDKey defines the key for storing last unique TxInfo's ID. + // Key: TxInfoStatePrefix | TxInfoIDKey + // Value: uint64 + TxInfoIDKey = []byte{0x00} + + // TxInfoPrefix defines the prefix for storing TxInfo objects. + // Key: TxInfoStatePrefix | TxInfoPrefix | {ID} + // Value: TxInfo + TxInfoPrefix = []byte{0x01} + + // TxInfoBlockIndexPrefix defines the prefix for storing TxInfo's block index. + // Key: TxInfoStatePrefix | TxInfoBlockIndexPrefix | {Height} | {ID} + // Value: None + TxInfoBlockIndexPrefix = []byte{0x02} +) + +// ContractOperationInfo prefixed store state keys. +var ( + // ContractOpInfoStatePrefix defines the state global prefix. + ContractOpInfoStatePrefix = []byte{0x01} + + // ContractOpInfoIDKey defines the key for storing last unique ContractOperationInfo's ID. + // Key: ContractOpInfoStatePrefix | ContractOpInfoIDKey + // Value: uint64 + ContractOpInfoIDKey = []byte{0x00} + + // ContractOpInfoPrefix defines the prefix for storing ContractOperationInfo objects. + // Key: ContractOpInfoStatePrefix | ContractOpInfoPrefix | {ID} + // Value: ContractOperationInfo + ContractOpInfoPrefix = []byte{0x01} + + // ContractOpInfoTxIndexPrefix defines the prefix for storing ContractOperationInfo's TxInfo index. + // Key: ContractOpInfoStatePrefix | ContractOpInfoTxIndexPrefix | {TxInfoID} | {ID} + // Value: None + ContractOpInfoTxIndexPrefix = []byte{0x02} +) diff --git a/x/tracking/types/params.go b/x/tracking/types/params.go new file mode 100644 index 00000000..7c1796f4 --- /dev/null +++ b/x/tracking/types/params.go @@ -0,0 +1,67 @@ +package types + +import ( + "fmt" + paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" + "sigs.k8s.io/yaml" +) + +var ( + GasTrackingEnabledParamKey = []byte("GasTrackingEnabled") +) + +var _ paramTypes.ParamSet = (*Params)(nil) + +// ParamKeyTable creates a new params table. +func ParamKeyTable() paramTypes.KeyTable { + return paramTypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance. +func NewParams(gasTrackingEnabled bool) Params { + return Params{ + GasTrackingEnabled: gasTrackingEnabled, + } +} + +// DefaultParams returns a default set of parameters. +func DefaultParams() Params { + return NewParams(true) +} + +// ParamSetPairs Implements the paramTypes.ParamSet interface. +func (m *Params) ParamSetPairs() paramTypes.ParamSetPairs { + return paramTypes.ParamSetPairs{ + paramTypes.NewParamSetPair(GasTrackingEnabledParamKey, &m.GasTrackingEnabled, validateGasTrackingEnabled), + } +} + +// Validate perform object fields validation. +func (m Params) Validate() error { + if err := validateGasTrackingEnabled(m.GasTrackingEnabled); err != nil { + return err + } + + return nil +} + +// String implements the fmt.Stringer interface. +func (m Params) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} + +func validateGasTrackingEnabled(v interface{}) (retErr error) { + defer func() { + if retErr != nil { + retErr = fmt.Errorf("gasTrackingEnabled param: %w", retErr) + } + }() + + v, ok := v.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", v) + } + + return +} diff --git a/x/tracking/types/query.go b/x/tracking/types/query.go new file mode 100644 index 00000000..b8926b19 --- /dev/null +++ b/x/tracking/types/query.go @@ -0,0 +1,9 @@ +package types + +import "sigs.k8s.io/yaml" + +// String implements the fmt.Stringer interface. +func (m TxTracking) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} diff --git a/x/tracking/types/query.pb.go b/x/tracking/types/query.pb.go new file mode 100644 index 00000000..b533020d --- /dev/null +++ b/x/tracking/types/query.pb.go @@ -0,0 +1,1120 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/tracking/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request for Query.Params. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_65deeabf437120fa, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response for Query.Params. +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_65deeabf437120fa, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. +type QueryBlockGasTrackingRequest struct { +} + +func (m *QueryBlockGasTrackingRequest) Reset() { *m = QueryBlockGasTrackingRequest{} } +func (m *QueryBlockGasTrackingRequest) String() string { return proto.CompactTextString(m) } +func (*QueryBlockGasTrackingRequest) ProtoMessage() {} +func (*QueryBlockGasTrackingRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_65deeabf437120fa, []int{2} +} +func (m *QueryBlockGasTrackingRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBlockGasTrackingRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBlockGasTrackingRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryBlockGasTrackingRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBlockGasTrackingRequest.Merge(m, src) +} +func (m *QueryBlockGasTrackingRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryBlockGasTrackingRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBlockGasTrackingRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBlockGasTrackingRequest proto.InternalMessageInfo + +// QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. +type QueryBlockGasTrackingResponse struct { + Txs []TxTracking `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs"` +} + +func (m *QueryBlockGasTrackingResponse) Reset() { *m = QueryBlockGasTrackingResponse{} } +func (m *QueryBlockGasTrackingResponse) String() string { return proto.CompactTextString(m) } +func (*QueryBlockGasTrackingResponse) ProtoMessage() {} +func (*QueryBlockGasTrackingResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_65deeabf437120fa, []int{3} +} +func (m *QueryBlockGasTrackingResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBlockGasTrackingResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBlockGasTrackingResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryBlockGasTrackingResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBlockGasTrackingResponse.Merge(m, src) +} +func (m *QueryBlockGasTrackingResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryBlockGasTrackingResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBlockGasTrackingResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBlockGasTrackingResponse proto.InternalMessageInfo + +func (m *QueryBlockGasTrackingResponse) GetTxs() []TxTracking { + if m != nil { + return m.Txs + } + return nil +} + +// TxTracking is the tracking information for a transaction used by the Query.BlockGasTracking query. +type TxTracking struct { + // info defines the transaction details. + Info TxInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` + // contract_operations defines contract operations consumed by the transaction. + ContractOperations []ContractOperationInfo `protobuf:"bytes,2,rep,name=contract_operations,json=contractOperations,proto3" json:"contract_operations"` +} + +func (m *TxTracking) Reset() { *m = TxTracking{} } +func (*TxTracking) ProtoMessage() {} +func (*TxTracking) Descriptor() ([]byte, []int) { + return fileDescriptor_65deeabf437120fa, []int{4} +} +func (m *TxTracking) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxTracking) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxTracking.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxTracking) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxTracking.Merge(m, src) +} +func (m *TxTracking) XXX_Size() int { + return m.Size() +} +func (m *TxTracking) XXX_DiscardUnknown() { + xxx_messageInfo_TxTracking.DiscardUnknown(m) +} + +var xxx_messageInfo_TxTracking proto.InternalMessageInfo + +func (m *TxTracking) GetInfo() TxInfo { + if m != nil { + return m.Info + } + return TxInfo{} +} + +func (m *TxTracking) GetContractOperations() []ContractOperationInfo { + if m != nil { + return m.ContractOperations + } + return nil +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "archway.tracking.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "archway.tracking.v1.QueryParamsResponse") + proto.RegisterType((*QueryBlockGasTrackingRequest)(nil), "archway.tracking.v1.QueryBlockGasTrackingRequest") + proto.RegisterType((*QueryBlockGasTrackingResponse)(nil), "archway.tracking.v1.QueryBlockGasTrackingResponse") + proto.RegisterType((*TxTracking)(nil), "archway.tracking.v1.TxTracking") +} + +func init() { proto.RegisterFile("archway/tracking/v1/query.proto", fileDescriptor_65deeabf437120fa) } + +var fileDescriptor_65deeabf437120fa = []byte{ + // 443 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0xf7, 0xa5, 0x21, 0xc3, 0x75, 0x41, 0x97, 0x0e, 0x95, 0xdb, 0xda, 0xc8, 0x0c, 0x0d, 0x48, + 0xf8, 0x14, 0x57, 0x08, 0xc1, 0x18, 0x06, 0xc4, 0x80, 0x28, 0x55, 0x06, 0xc4, 0x12, 0x5d, 0xac, + 0xab, 0x6b, 0xa5, 0xbd, 0xe7, 0xfa, 0x2e, 0xad, 0xb3, 0x21, 0x3e, 0x01, 0x12, 0x0b, 0x23, 0x33, + 0x62, 0xe7, 0x2b, 0x64, 0x8c, 0xc4, 0xc2, 0x84, 0x50, 0xc2, 0x07, 0x41, 0xbe, 0x3b, 0x27, 0x10, + 0x1c, 0x10, 0x9b, 0xf5, 0x7e, 0x7f, 0xfd, 0x9e, 0x8d, 0x7d, 0x96, 0xc7, 0x67, 0xd7, 0x6c, 0x42, + 0x55, 0xce, 0xe2, 0x51, 0x2a, 0x12, 0x7a, 0xd5, 0xa5, 0x97, 0x63, 0x9e, 0x4f, 0xc2, 0x2c, 0x07, + 0x05, 0xa4, 0x6d, 0x09, 0x61, 0x45, 0x08, 0xaf, 0xba, 0xee, 0x4e, 0x02, 0x09, 0x68, 0x9c, 0x96, + 0x4f, 0x86, 0xea, 0x06, 0x75, 0x5e, 0x4b, 0x99, 0xe1, 0xec, 0x27, 0x00, 0xc9, 0x39, 0xa7, 0x2c, + 0x4b, 0x29, 0x13, 0x02, 0x14, 0x53, 0x29, 0x08, 0x69, 0xd0, 0x60, 0x07, 0x93, 0x17, 0x65, 0xf6, + 0x31, 0xcb, 0xd9, 0x85, 0x3c, 0xe1, 0x97, 0x63, 0x2e, 0x55, 0x70, 0x8c, 0xdb, 0xbf, 0x4d, 0x65, + 0x06, 0x42, 0x72, 0xf2, 0x10, 0xb7, 0x32, 0x3d, 0xd9, 0x45, 0xb7, 0x50, 0x67, 0x3b, 0xda, 0x0b, + 0x6b, 0xaa, 0x86, 0x46, 0xd4, 0x6b, 0x4e, 0xbf, 0xf9, 0xce, 0x89, 0x15, 0x04, 0x1e, 0xde, 0xd7, + 0x8e, 0xbd, 0x73, 0x88, 0x47, 0x4f, 0x98, 0xec, 0x5b, 0x41, 0x95, 0xf8, 0x12, 0x1f, 0x6c, 0xc0, + 0x6d, 0xf6, 0x03, 0xbc, 0xa5, 0x8a, 0x32, 0x78, 0xab, 0xb3, 0x1d, 0xf9, 0xb5, 0xc1, 0xfd, 0xa2, + 0x52, 0xd9, 0xf0, 0x52, 0x11, 0x7c, 0x42, 0x18, 0xaf, 0x10, 0x72, 0x1f, 0x37, 0x53, 0x71, 0x0a, + 0x7f, 0x7d, 0x83, 0x7e, 0xf1, 0x54, 0x9c, 0x82, 0x35, 0xd1, 0x74, 0xc2, 0x70, 0x3b, 0x06, 0x51, + 0x92, 0xd4, 0x00, 0x32, 0x9e, 0x9b, 0x25, 0xee, 0x36, 0x74, 0x9d, 0xbb, 0xb5, 0x2e, 0x8f, 0x2d, + 0xff, 0x79, 0x45, 0xff, 0xc5, 0x94, 0xc4, 0xeb, 0xa0, 0x7c, 0xd4, 0x7c, 0xff, 0xc1, 0x77, 0xa2, + 0xcf, 0x0d, 0x7c, 0x43, 0x6f, 0x82, 0xbc, 0x46, 0xb8, 0x65, 0x76, 0x49, 0x0e, 0x6b, 0x03, 0xfe, + 0x3c, 0x9c, 0xdb, 0xf9, 0x37, 0xd1, 0xec, 0x33, 0xb8, 0xfd, 0xe6, 0xcb, 0x8f, 0x77, 0x8d, 0x03, + 0xb2, 0x47, 0xeb, 0xbe, 0x21, 0x73, 0x35, 0xf2, 0x11, 0xe1, 0x9b, 0xeb, 0x17, 0x21, 0xdd, 0xcd, + 0x19, 0x1b, 0xae, 0xeb, 0x46, 0xff, 0x23, 0xb1, 0x05, 0xa9, 0x2e, 0x78, 0x87, 0x1c, 0xd6, 0x16, + 0x1c, 0x96, 0xb2, 0x41, 0xc2, 0xe4, 0xa0, 0x9a, 0xf6, 0x9e, 0x4d, 0xe7, 0x1e, 0x9a, 0xcd, 0x3d, + 0xf4, 0x7d, 0xee, 0xa1, 0xb7, 0x0b, 0xcf, 0x99, 0x2d, 0x3c, 0xe7, 0xeb, 0xc2, 0x73, 0x5e, 0x1d, + 0x25, 0xa9, 0x3a, 0x1b, 0x0f, 0xc3, 0x18, 0x2e, 0x2a, 0xb3, 0x7b, 0x82, 0xab, 0x6b, 0xc8, 0x47, + 0x4b, 0xf3, 0x62, 0x65, 0xaf, 0x26, 0x19, 0x97, 0xc3, 0x96, 0xfe, 0x41, 0x8e, 0x7e, 0x06, 0x00, + 0x00, 0xff, 0xff, 0xaf, 0x9d, 0x18, 0x90, 0xb0, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params returns module parameters. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // BlockGasTracking returns block gas tracking for the latest block + BlockGasTracking(ctx context.Context, in *QueryBlockGasTrackingRequest, opts ...grpc.CallOption) (*QueryBlockGasTrackingResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/archway.tracking.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) BlockGasTracking(ctx context.Context, in *QueryBlockGasTrackingRequest, opts ...grpc.CallOption) (*QueryBlockGasTrackingResponse, error) { + out := new(QueryBlockGasTrackingResponse) + err := c.cc.Invoke(ctx, "/archway.tracking.v1.Query/BlockGasTracking", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params returns module parameters. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // BlockGasTracking returns block gas tracking for the latest block + BlockGasTracking(context.Context, *QueryBlockGasTrackingRequest) (*QueryBlockGasTrackingResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) BlockGasTracking(ctx context.Context, req *QueryBlockGasTrackingRequest) (*QueryBlockGasTrackingResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BlockGasTracking not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.tracking.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_BlockGasTracking_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryBlockGasTrackingRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).BlockGasTracking(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.tracking.v1.Query/BlockGasTracking", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).BlockGasTracking(ctx, req.(*QueryBlockGasTrackingRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "archway.tracking.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "BlockGasTracking", + Handler: _Query_BlockGasTracking_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "archway/tracking/v1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryBlockGasTrackingRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryBlockGasTrackingRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBlockGasTrackingRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryBlockGasTrackingResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryBlockGasTrackingResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBlockGasTrackingResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Txs) > 0 { + for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Txs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *TxTracking) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxTracking) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxTracking) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractOperations) > 0 { + for iNdEx := len(m.ContractOperations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractOperations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryBlockGasTrackingRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryBlockGasTrackingResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Txs) > 0 { + for _, e := range m.Txs { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *TxTracking) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Info.Size() + n += 1 + l + sovQuery(uint64(l)) + if len(m.ContractOperations) > 0 { + for _, e := range m.ContractOperations { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryBlockGasTrackingRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryBlockGasTrackingRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBlockGasTrackingRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryBlockGasTrackingResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryBlockGasTrackingResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBlockGasTrackingResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Txs = append(m.Txs, TxTracking{}) + if err := m.Txs[len(m.Txs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TxTracking) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxTracking: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxTracking: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractOperations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractOperations = append(m.ContractOperations, ContractOperationInfo{}) + if err := m.ContractOperations[len(m.ContractOperations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tracking/types/query.pb.gw.go b/x/tracking/types/query.pb.gw.go new file mode 100644 index 00000000..3960c775 --- /dev/null +++ b/x/tracking/types/query.pb.gw.go @@ -0,0 +1,210 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: archway/tracking/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_BlockGasTracking_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBlockGasTrackingRequest + var metadata runtime.ServerMetadata + + msg, err := client.BlockGasTracking(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_BlockGasTracking_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBlockGasTrackingRequest + var metadata runtime.ServerMetadata + + msg, err := server.BlockGasTracking(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_BlockGasTracking_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_BlockGasTracking_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BlockGasTracking_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_BlockGasTracking_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_BlockGasTracking_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BlockGasTracking_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "tracking", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_BlockGasTracking_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "tracking", "v1", "block_gas_tracking"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_BlockGasTracking_0 = runtime.ForwardResponseMessage +) diff --git a/x/tracking/types/tracking.go b/x/tracking/types/tracking.go new file mode 100644 index 00000000..3335f578 --- /dev/null +++ b/x/tracking/types/tracking.go @@ -0,0 +1,43 @@ +package types + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + "sigs.k8s.io/yaml" +) + +// String implements the fmt.Stringer interface. +func (m TxInfo) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} + +// Validate performs object fields validation. +func (m TxInfo) Validate() error { + if m.Id == 0 { + return fmt.Errorf("id: must be GT 0") + } + + return nil +} + +// String implements the fmt.Stringer interface. +func (m ContractOperationInfo) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} + +// Validate performs object fields validation. +func (m ContractOperationInfo) Validate() error { + if m.Id == 0 { + return fmt.Errorf("id: must be GT 0") + } + if m.TxId == 0 { + return fmt.Errorf("txId: must be GT 0") + } + if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { + return fmt.Errorf("contractAddress: %s", err.Error()) + } + + return nil +} diff --git a/x/tracking/types/tracking.pb.go b/x/tracking/types/tracking.pb.go new file mode 100644 index 00000000..2bb36d45 --- /dev/null +++ b/x/tracking/types/tracking.pb.go @@ -0,0 +1,960 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/tracking/v1/tracking.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ContractOperation denotes which operation consumed gas. +type ContractOperation int32 + +const ( + ContractOperation_CONTRACT_OPERATION_UNSPECIFIED ContractOperation = 0 + ContractOperation_CONTRACT_OPERATION_INSTANTIATION ContractOperation = 1 + ContractOperation_CONTRACT_OPERATION_EXECUTION ContractOperation = 2 + ContractOperation_CONTRACT_OPERATION_QUERY ContractOperation = 3 + ContractOperation_CONTRACT_OPERATION_MIGRATE ContractOperation = 4 + ContractOperation_CONTRACT_OPERATION_IBC ContractOperation = 5 + ContractOperation_CONTRACT_OPERATION_SUDO ContractOperation = 6 + ContractOperation_CONTRACT_OPERATION_REPLY ContractOperation = 7 +) + +var ContractOperation_name = map[int32]string{ + 0: "CONTRACT_OPERATION_UNSPECIFIED", + 1: "CONTRACT_OPERATION_INSTANTIATION", + 2: "CONTRACT_OPERATION_EXECUTION", + 3: "CONTRACT_OPERATION_QUERY", + 4: "CONTRACT_OPERATION_MIGRATE", + 5: "CONTRACT_OPERATION_IBC", + 6: "CONTRACT_OPERATION_SUDO", + 7: "CONTRACT_OPERATION_REPLY", +} + +var ContractOperation_value = map[string]int32{ + "CONTRACT_OPERATION_UNSPECIFIED": 0, + "CONTRACT_OPERATION_INSTANTIATION": 1, + "CONTRACT_OPERATION_EXECUTION": 2, + "CONTRACT_OPERATION_QUERY": 3, + "CONTRACT_OPERATION_MIGRATE": 4, + "CONTRACT_OPERATION_IBC": 5, + "CONTRACT_OPERATION_SUDO": 6, + "CONTRACT_OPERATION_REPLY": 7, +} + +func (x ContractOperation) String() string { + return proto.EnumName(ContractOperation_name, int32(x)) +} + +func (ContractOperation) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_43be6db97c4ee6cb, []int{0} +} + +// Params defines the module parameters. +type Params struct { + // gas_tracking_enabled flag indicates whether gas tracking is enabled (TXs and ContractOperations creation). + GasTrackingEnabled bool `protobuf:"varint,1,opt,name=gas_tracking_enabled,json=gasTrackingEnabled,proto3" json:"gas_tracking_enabled,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_43be6db97c4ee6cb, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetGasTrackingEnabled() bool { + if m != nil { + return m.GasTrackingEnabled + } + return false +} + +// TxInfo keeps a transaction gas tracking data. +// Object is being created at the module EndBlocker. +type TxInfo struct { + // id defines the unique transaction ID. + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // height defines the block height of the transaction. + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + // total_gas defines total gas consumption by the transaction. + // It is the sum of gas consumed by all contract operations (VM + SDK gas). + TotalGas uint64 `protobuf:"varint,3,opt,name=total_gas,json=totalGas,proto3" json:"total_gas,omitempty"` +} + +func (m *TxInfo) Reset() { *m = TxInfo{} } +func (*TxInfo) ProtoMessage() {} +func (*TxInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_43be6db97c4ee6cb, []int{1} +} +func (m *TxInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxInfo.Merge(m, src) +} +func (m *TxInfo) XXX_Size() int { + return m.Size() +} +func (m *TxInfo) XXX_DiscardUnknown() { + xxx_messageInfo_TxInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_TxInfo proto.InternalMessageInfo + +func (m *TxInfo) GetId() uint64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *TxInfo) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *TxInfo) GetTotalGas() uint64 { + if m != nil { + return m.TotalGas + } + return 0 +} + +// ContractOperationInfo keeps a single contract operation gas consumption data. +// Object is being created by the IngestGasRecord call from the wasmd. +type ContractOperationInfo struct { + // id defines the unique operation ID. + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + // tx_id defines a transaction ID operation relates to (TxInfo.id). + TxId uint64 `protobuf:"varint,2,opt,name=tx_id,json=txId,proto3" json:"tx_id,omitempty"` + // contract_address defines the contract address operation relates to. + ContractAddress string `protobuf:"bytes,3,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // operation_type defines the gas consumption type. + OperationType ContractOperation `protobuf:"varint,4,opt,name=operation_type,json=operationType,proto3,enum=archway.tracking.v1.ContractOperation" json:"operation_type,omitempty"` + // vm_gas is the gas consumption reported by the WASM VM. + // Value is adjusted by this module (CalculateUpdatedGas func). + VmGas uint64 `protobuf:"varint,5,opt,name=vm_gas,json=vmGas,proto3" json:"vm_gas,omitempty" yaml:"vm_gas"` + // sdk_gas is the gas consumption reported by the SDK gas meter and the WASM GasRegister (cost of Execute/Query/etc). + // Value is adjusted by this module (CalculateUpdatedGas func). + SdkGas uint64 `protobuf:"varint,6,opt,name=sdk_gas,json=sdkGas,proto3" json:"sdk_gas,omitempty" yaml:"sdk_gas"` +} + +func (m *ContractOperationInfo) Reset() { *m = ContractOperationInfo{} } +func (*ContractOperationInfo) ProtoMessage() {} +func (*ContractOperationInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_43be6db97c4ee6cb, []int{2} +} +func (m *ContractOperationInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractOperationInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractOperationInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContractOperationInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractOperationInfo.Merge(m, src) +} +func (m *ContractOperationInfo) XXX_Size() int { + return m.Size() +} +func (m *ContractOperationInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ContractOperationInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractOperationInfo proto.InternalMessageInfo + +func (m *ContractOperationInfo) GetId() uint64 { + if m != nil { + return m.Id + } + return 0 +} + +func (m *ContractOperationInfo) GetTxId() uint64 { + if m != nil { + return m.TxId + } + return 0 +} + +func (m *ContractOperationInfo) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *ContractOperationInfo) GetOperationType() ContractOperation { + if m != nil { + return m.OperationType + } + return ContractOperation_CONTRACT_OPERATION_UNSPECIFIED +} + +func (m *ContractOperationInfo) GetVmGas() uint64 { + if m != nil { + return m.VmGas + } + return 0 +} + +func (m *ContractOperationInfo) GetSdkGas() uint64 { + if m != nil { + return m.SdkGas + } + return 0 +} + +func init() { + proto.RegisterEnum("archway.tracking.v1.ContractOperation", ContractOperation_name, ContractOperation_value) + proto.RegisterType((*Params)(nil), "archway.tracking.v1.Params") + proto.RegisterType((*TxInfo)(nil), "archway.tracking.v1.TxInfo") + proto.RegisterType((*ContractOperationInfo)(nil), "archway.tracking.v1.ContractOperationInfo") +} + +func init() { + proto.RegisterFile("archway/tracking/v1/tracking.proto", fileDescriptor_43be6db97c4ee6cb) +} + +var fileDescriptor_43be6db97c4ee6cb = []byte{ + // 531 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0x4f, 0x6e, 0xda, 0x40, + 0x18, 0xc5, 0xb1, 0x63, 0x9c, 0xe4, 0x93, 0x42, 0x9d, 0x49, 0x9a, 0x22, 0x12, 0x19, 0x64, 0x55, + 0x15, 0x6d, 0x55, 0x68, 0x9a, 0x5d, 0x56, 0x05, 0xc7, 0x45, 0x96, 0xca, 0x9f, 0x0e, 0x46, 0x6a, + 0xba, 0xb1, 0x06, 0xec, 0x1a, 0x0b, 0xf0, 0x20, 0x7b, 0x4a, 0xe0, 0x16, 0x95, 0xda, 0x45, 0x97, + 0x3d, 0x4e, 0x97, 0x59, 0x76, 0x15, 0x55, 0x70, 0x83, 0x9c, 0xa0, 0x62, 0x6c, 0xe8, 0x22, 0xee, + 0x6e, 0xe6, 0xbd, 0xdf, 0xe7, 0xf7, 0x3c, 0xa3, 0x01, 0x8d, 0x84, 0x83, 0xe1, 0x0d, 0x59, 0x54, + 0x59, 0x48, 0x06, 0x23, 0x3f, 0xf0, 0xaa, 0xb3, 0xf3, 0xed, 0xba, 0x32, 0x0d, 0x29, 0xa3, 0xe8, + 0x28, 0x61, 0x2a, 0x5b, 0x7d, 0x76, 0x5e, 0x38, 0xf6, 0xa8, 0x47, 0xb9, 0x5f, 0x5d, 0xaf, 0x62, + 0x54, 0x7b, 0x0b, 0x72, 0x87, 0x84, 0x64, 0x12, 0xa1, 0xd7, 0x70, 0xec, 0x91, 0xc8, 0xde, 0x8c, + 0xd8, 0x6e, 0x40, 0xfa, 0x63, 0xd7, 0xc9, 0x0b, 0x25, 0xa1, 0xbc, 0x87, 0x91, 0x47, 0x22, 0x2b, + 0xb1, 0x8c, 0xd8, 0xb9, 0x94, 0x7e, 0xfc, 0x2c, 0x66, 0xb4, 0x2e, 0xc8, 0xd6, 0xdc, 0x0c, 0x3e, + 0x53, 0x94, 0x03, 0xd1, 0x8f, 0x79, 0x09, 0x8b, 0xbe, 0x83, 0x4e, 0x40, 0x1e, 0xba, 0xbe, 0x37, + 0x64, 0x79, 0xb1, 0x24, 0x94, 0x77, 0x70, 0xb2, 0x43, 0xa7, 0xb0, 0xcf, 0x28, 0x23, 0x63, 0xdb, + 0x23, 0x51, 0x7e, 0x87, 0xe3, 0x7b, 0x5c, 0x68, 0x90, 0x28, 0xf9, 0xe8, 0x37, 0x11, 0x1e, 0xeb, + 0x34, 0x58, 0x97, 0x61, 0xed, 0xa9, 0x1b, 0x12, 0xe6, 0xd3, 0x20, 0x35, 0xe4, 0x08, 0xb2, 0x6c, + 0x6e, 0xfb, 0x0e, 0xcf, 0x90, 0xb0, 0xc4, 0xe6, 0xa6, 0x83, 0x9e, 0x83, 0x32, 0x48, 0xa6, 0x6d, + 0xe2, 0x38, 0xa1, 0x1b, 0xc5, 0x41, 0xfb, 0xf8, 0xd1, 0x46, 0xaf, 0xc5, 0x32, 0x6a, 0x42, 0x8e, + 0x6e, 0x02, 0x6c, 0xb6, 0x98, 0xba, 0x79, 0xa9, 0x24, 0x94, 0x73, 0x6f, 0x9e, 0x55, 0x52, 0x0e, + 0xb1, 0xf2, 0xa0, 0x13, 0x3e, 0xd8, 0x4e, 0x5b, 0x8b, 0xa9, 0x8b, 0xca, 0x20, 0xcf, 0x26, 0xfc, + 0xc7, 0xb2, 0xeb, 0x3e, 0xf5, 0xc3, 0xfb, 0xbb, 0xe2, 0xc1, 0x82, 0x4c, 0xc6, 0x97, 0x5a, 0xac, + 0x6b, 0x38, 0x3b, 0x9b, 0x34, 0x48, 0x84, 0x5e, 0xc2, 0x6e, 0xe4, 0x8c, 0x38, 0x2a, 0x73, 0x14, + 0xdd, 0xdf, 0x15, 0x73, 0x31, 0x9a, 0x18, 0x1a, 0x96, 0x23, 0x67, 0xb4, 0x3d, 0x95, 0x17, 0xdf, + 0x45, 0x38, 0x7c, 0xd0, 0x00, 0x69, 0xa0, 0xea, 0xed, 0x96, 0x85, 0x6b, 0xba, 0x65, 0xb7, 0x3b, + 0x06, 0xae, 0x59, 0x66, 0xbb, 0x65, 0xf7, 0x5a, 0xdd, 0x8e, 0xa1, 0x9b, 0xef, 0x4c, 0xe3, 0x4a, + 0xc9, 0xa0, 0xa7, 0x50, 0x4a, 0x61, 0xcc, 0x56, 0xd7, 0xaa, 0xb5, 0x2c, 0x93, 0xef, 0x14, 0x01, + 0x95, 0xe0, 0x2c, 0x85, 0x32, 0x3e, 0x1a, 0x7a, 0x8f, 0x13, 0x22, 0x3a, 0x83, 0x7c, 0x0a, 0xf1, + 0xa1, 0x67, 0xe0, 0x6b, 0x65, 0x07, 0xa9, 0x50, 0x48, 0x71, 0x9b, 0x66, 0x03, 0xd7, 0x2c, 0x43, + 0x91, 0x50, 0x01, 0x4e, 0xd2, 0x5a, 0xd4, 0x75, 0x25, 0x8b, 0x4e, 0xe1, 0x49, 0x8a, 0xd7, 0xed, + 0x5d, 0xb5, 0x15, 0xf9, 0x3f, 0xb1, 0xd8, 0xe8, 0xbc, 0xbf, 0x56, 0x76, 0xeb, 0xcd, 0x5f, 0x4b, + 0x55, 0xb8, 0x5d, 0xaa, 0xc2, 0x9f, 0xa5, 0x2a, 0x7c, 0x5d, 0xa9, 0x99, 0xdb, 0x95, 0x9a, 0xf9, + 0xbd, 0x52, 0x33, 0x9f, 0x2e, 0x3c, 0x9f, 0x0d, 0xbf, 0xf4, 0x2b, 0x03, 0x3a, 0xa9, 0x26, 0xd7, + 0xf9, 0x2a, 0x70, 0xd9, 0x0d, 0x0d, 0x47, 0x9b, 0x7d, 0x75, 0xfe, 0xef, 0x25, 0xad, 0xaf, 0x3f, + 0xea, 0xcb, 0xfc, 0x65, 0x5c, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x0c, 0x2c, 0xc0, 0x6a, + 0x03, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.GasTrackingEnabled { + i-- + if m.GasTrackingEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TxInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TotalGas != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.TotalGas)) + i-- + dAtA[i] = 0x18 + } + if m.Height != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x10 + } + if m.Id != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ContractOperationInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractOperationInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractOperationInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.SdkGas != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.SdkGas)) + i-- + dAtA[i] = 0x30 + } + if m.VmGas != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.VmGas)) + i-- + dAtA[i] = 0x28 + } + if m.OperationType != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.OperationType)) + i-- + dAtA[i] = 0x20 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTracking(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0x1a + } + if m.TxId != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.TxId)) + i-- + dAtA[i] = 0x10 + } + if m.Id != 0 { + i = encodeVarintTracking(dAtA, i, uint64(m.Id)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintTracking(dAtA []byte, offset int, v uint64) int { + offset -= sovTracking(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GasTrackingEnabled { + n += 2 + } + return n +} + +func (m *TxInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovTracking(uint64(m.Id)) + } + if m.Height != 0 { + n += 1 + sovTracking(uint64(m.Height)) + } + if m.TotalGas != 0 { + n += 1 + sovTracking(uint64(m.TotalGas)) + } + return n +} + +func (m *ContractOperationInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Id != 0 { + n += 1 + sovTracking(uint64(m.Id)) + } + if m.TxId != 0 { + n += 1 + sovTracking(uint64(m.TxId)) + } + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTracking(uint64(l)) + } + if m.OperationType != 0 { + n += 1 + sovTracking(uint64(m.OperationType)) + } + if m.VmGas != 0 { + n += 1 + sovTracking(uint64(m.VmGas)) + } + if m.SdkGas != 0 { + n += 1 + sovTracking(uint64(m.SdkGas)) + } + return n +} + +func sovTracking(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTracking(x uint64) (n int) { + return sovTracking(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasTrackingEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.GasTrackingEnabled = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTracking(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTracking + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TxInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalGas", wireType) + } + m.TotalGas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalGas |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTracking(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTracking + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractOperationInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractOperationInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractOperationInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Id", wireType) + } + m.Id = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Id |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxId", wireType) + } + m.TxId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTracking + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTracking + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OperationType", wireType) + } + m.OperationType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OperationType |= ContractOperation(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VmGas", wireType) + } + m.VmGas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VmGas |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SdkGas", wireType) + } + m.SdkGas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SdkGas |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTracking(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTracking + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTracking(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTracking + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTracking + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTracking + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTracking + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTracking + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTracking + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTracking = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTracking = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTracking = fmt.Errorf("proto: unexpected end of group") +) From 57ba42bcb05a4b04d9012dbfed9b659fc9dcac47 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Wed, 27 Jul 2022 21:38:47 +0300 Subject: [PATCH 02/27] Gas consumption tests added --- e2e/common_voter_test.go | 1 - e2e/gastracking_test.go | 62 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 e2e/gastracking_test.go diff --git a/e2e/common_voter_test.go b/e2e/common_voter_test.go index f917b703..5882681c 100644 --- a/e2e/common_voter_test.go +++ b/e2e/common_voter_test.go @@ -71,7 +71,6 @@ func (s *E2ETestSuite) VoterNewVoting(chain *e2eTesting.TestChain, contractAddr } _, res, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) - s.Require().NoError(err) txRes := chain.ParseSDKResultData(res) s.Require().Len(txRes.Data, 1) diff --git a/e2e/gastracking_test.go b/e2e/gastracking_test.go new file mode 100644 index 00000000..8f60fab6 --- /dev/null +++ b/e2e/gastracking_test.go @@ -0,0 +1,62 @@ +package e2e + +import ( + voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + trackingTypes "github.com/archway-network/archway/x/tracking/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "time" +) + +// TestGasTracking_TxGasConsumption tries to check gas consumption by contract execution, but +// since we can't (or I don't know how) check the real gas consumption by WASM only, it is kind of useless. +func (s *E2ETestSuite) TestGasTracking_TxGasConsumption() { + chain := s.chainA + + acc := chain.GetAccount(0) + contractAddr := s.VoterUploadAndInstantiate(chain, acc) + + // Send Tx manually to get Tx results + var txGasUsed uint64 + { + req := voterTypes.MsgExecute{ + NewVoting: &voterTypes.NewVotingRequest{ + Name: "Test", + VoteOptions: []string{"Yes", "No"}, + Duration: uint64(time.Minute), + }, + } + reqBz, err := req.MarshalJSON() + s.Require().NoError(err) + + msg := wasmdTypes.MsgExecuteContract{ + Sender: acc.Address.String(), + Contract: contractAddr.String(), + Msg: reqBz, + Funds: sdk.NewCoins(sdk.Coin{ + Denom: sdk.DefaultBondDenom, + Amount: sdk.NewIntFromUint64(DefNewVotingCostAmt), + }), + } + + gasInfo, _, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) + txGasUsed = gasInfo.GasUsed + } + + // Get gas tracking data + var trackedGas uint64 + { + ctx := chain.GetContext() + + txInfos := chain.GetApp().TrackingKeeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(ctx.BlockHeight() - 1) + s.Require().Len(txInfos, 1) + + contractOps := chain.GetApp().TrackingKeeper.GetState().ContractOpInfoState(ctx).GetContractOpInfoByTxID(txInfos[0].Id) + s.Require().Len(contractOps, 1) + s.Equal(trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, contractOps[0].OperationType) + + trackedGas = txInfos[0].TotalGas + } + + s.Assert().Less(trackedGas, txGasUsed) +} From ac15fdda4b844b07037182576034a3c79ed05a7e Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Thu, 28 Jul 2022 00:00:27 +0300 Subject: [PATCH 03/27] x/tracking refactoring; x/rewards added (WIP) --- docs/proto/proto-docs.md | 378 ++++++- proto/archway/rewards/v1beta1/genesis.proto | 29 + proto/archway/rewards/v1beta1/query.proto | 44 + proto/archway/rewards/v1beta1/rewards.proto | 35 + proto/archway/rewards/v1beta1/tx.proto | 29 + .../tracking/{v1 => v1beta1}/genesis.proto | 4 +- .../tracking/{v1 => v1beta1}/query.proto | 22 +- .../tracking/{v1 => v1beta1}/tracking.proto | 34 +- x/rewards/keeper/grpc_query.go | 60 ++ x/rewards/keeper/keeper.go | 73 ++ x/rewards/keeper/msg_server.go | 48 + x/rewards/keeper/params.go | 38 + x/rewards/keeper/state.go | 32 + x/rewards/keeper/state_metadata.go | 95 ++ x/rewards/types/codec.go | 26 + x/rewards/types/errors.go | 10 + x/rewards/types/genesis.go | 50 + x/rewards/types/genesis.pb.go | 619 ++++++++++++ x/rewards/types/keys.go | 23 + x/rewards/types/msg.go | 66 ++ x/rewards/types/params.go | 118 +++ x/rewards/types/query.pb.go | 926 ++++++++++++++++++ x/rewards/types/query.pb.gw.go | 228 +++++ x/rewards/types/rewards.go | 25 + x/rewards/types/rewards.pb.go | 638 ++++++++++++ x/rewards/types/tx.pb.go | 641 ++++++++++++ x/tracking/keeper/grpc_query.go | 21 +- x/tracking/keeper/keeper.go | 22 + x/tracking/types/genesis.pb.go | 50 +- x/tracking/types/params.go | 3 +- x/tracking/types/query.pb.go | 353 +------ x/tracking/types/query.pb.gw.go | 2 +- x/tracking/types/tracking.go | 6 + x/tracking/types/tracking.pb.go | 524 +++++++++- 34 files changed, 4796 insertions(+), 476 deletions(-) create mode 100644 proto/archway/rewards/v1beta1/genesis.proto create mode 100644 proto/archway/rewards/v1beta1/query.proto create mode 100644 proto/archway/rewards/v1beta1/rewards.proto create mode 100644 proto/archway/rewards/v1beta1/tx.proto rename proto/archway/tracking/{v1 => v1beta1}/genesis.proto (88%) rename proto/archway/tracking/{v1 => v1beta1}/query.proto (65%) rename proto/archway/tracking/{v1 => v1beta1}/tracking.proto (74%) create mode 100644 x/rewards/keeper/grpc_query.go create mode 100644 x/rewards/keeper/keeper.go create mode 100644 x/rewards/keeper/msg_server.go create mode 100644 x/rewards/keeper/params.go create mode 100644 x/rewards/keeper/state.go create mode 100644 x/rewards/keeper/state_metadata.go create mode 100644 x/rewards/types/codec.go create mode 100644 x/rewards/types/errors.go create mode 100644 x/rewards/types/genesis.go create mode 100644 x/rewards/types/genesis.pb.go create mode 100644 x/rewards/types/keys.go create mode 100644 x/rewards/types/msg.go create mode 100644 x/rewards/types/params.go create mode 100644 x/rewards/types/query.pb.go create mode 100644 x/rewards/types/query.pb.gw.go create mode 100644 x/rewards/types/rewards.go create mode 100644 x/rewards/types/rewards.pb.go create mode 100644 x/rewards/types/tx.pb.go diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index f746dd55..143a6a54 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -33,24 +33,47 @@ - [Msg](#archway.gastracker.v1.Msg) -- [archway/tracking/v1/tracking.proto](#archway/tracking/v1/tracking.proto) - - [ContractOperationInfo](#archway.tracking.v1.ContractOperationInfo) - - [Params](#archway.tracking.v1.Params) - - [TxInfo](#archway.tracking.v1.TxInfo) +- [archway/rewards/v1beta1/rewards.proto](#archway/rewards/v1beta1/rewards.proto) + - [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) + - [Params](#archway.rewards.v1beta1.Params) - - [ContractOperation](#archway.tracking.v1.ContractOperation) +- [archway/rewards/v1beta1/genesis.proto](#archway/rewards/v1beta1/genesis.proto) + - [GenesisContractMetadata](#archway.rewards.v1beta1.GenesisContractMetadata) + - [GenesisState](#archway.rewards.v1beta1.GenesisState) -- [archway/tracking/v1/genesis.proto](#archway/tracking/v1/genesis.proto) - - [GenesisState](#archway.tracking.v1.GenesisState) +- [archway/rewards/v1beta1/query.proto](#archway/rewards/v1beta1/query.proto) + - [QueryContractMetadataRequest](#archway.rewards.v1beta1.QueryContractMetadataRequest) + - [QueryContractMetadataResponse](#archway.rewards.v1beta1.QueryContractMetadataResponse) + - [QueryParamsRequest](#archway.rewards.v1beta1.QueryParamsRequest) + - [QueryParamsResponse](#archway.rewards.v1beta1.QueryParamsResponse) -- [archway/tracking/v1/query.proto](#archway/tracking/v1/query.proto) - - [QueryBlockGasTrackingRequest](#archway.tracking.v1.QueryBlockGasTrackingRequest) - - [QueryBlockGasTrackingResponse](#archway.tracking.v1.QueryBlockGasTrackingResponse) - - [QueryParamsRequest](#archway.tracking.v1.QueryParamsRequest) - - [QueryParamsResponse](#archway.tracking.v1.QueryParamsResponse) - - [TxTracking](#archway.tracking.v1.TxTracking) + - [Query](#archway.rewards.v1beta1.Query) - - [Query](#archway.tracking.v1.Query) +- [archway/rewards/v1beta1/tx.proto](#archway/rewards/v1beta1/tx.proto) + - [MsgSetContractMetadata](#archway.rewards.v1beta1.MsgSetContractMetadata) + - [MsgSetContractMetadataResponse](#archway.rewards.v1beta1.MsgSetContractMetadataResponse) + + - [Msg](#archway.rewards.v1beta1.Msg) + +- [archway/tracking/v1beta1/tracking.proto](#archway/tracking/v1beta1/tracking.proto) + - [BlockTracking](#archway.tracking.v1beta1.BlockTracking) + - [ContractOperationInfo](#archway.tracking.v1beta1.ContractOperationInfo) + - [Params](#archway.tracking.v1beta1.Params) + - [TxInfo](#archway.tracking.v1beta1.TxInfo) + - [TxTracking](#archway.tracking.v1beta1.TxTracking) + + - [ContractOperation](#archway.tracking.v1beta1.ContractOperation) + +- [archway/tracking/v1beta1/genesis.proto](#archway/tracking/v1beta1/genesis.proto) + - [GenesisState](#archway.tracking.v1beta1.GenesisState) + +- [archway/tracking/v1beta1/query.proto](#archway/tracking/v1beta1/query.proto) + - [QueryBlockGasTrackingRequest](#archway.tracking.v1beta1.QueryBlockGasTrackingRequest) + - [QueryBlockGasTrackingResponse](#archway.tracking.v1beta1.QueryBlockGasTrackingResponse) + - [QueryParamsRequest](#archway.tracking.v1beta1.QueryParamsRequest) + - [QueryParamsResponse](#archway.tracking.v1beta1.QueryParamsResponse) + + - [Query](#archway.tracking.v1beta1.Query) - [Scalar Value Types](#scalar-value-types) @@ -400,14 +423,261 @@ Msg defines the gastracker msg service - + +

Top

+ +## archway/rewards/v1beta1/rewards.proto + + + + + +### ContractMetadata +ContractMetadata defines the contract rewards distribution options. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `owner_address` | [string](#string) | | owner_address is the contract owner address that can modify contract reward options (bech32 encoded). | +| `rewards_address` | [string](#string) | | rewards_address is an address to distribute rewards to (bech32 encoded). | + + + + + + + + +### Params +Params defines the module parameters. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `rewards_enabled` | [bool](#bool) | | rewards_enabled flag indicates whether rewards calculation and distribution is enabled. | +| `inflation_rewards_ratio` | [string](#string) | | | +| `tx_fee_rebate_ratio` | [string](#string) | | | + + + + + + + + + + + + + + + + +

Top

+ +## archway/rewards/v1beta1/genesis.proto + + + + + +### GenesisContractMetadata +GenesisContractMetadata is used init ContractMetadata state via module genesis. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `contract_address` | [string](#string) | | contract_address defines the contract address. | +| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata defines the contract metadata. | + + + + + + + + +### GenesisState +GenesisState defines the initial state of the tracking module. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#archway.rewards.v1beta1.Params) | | params defines all the module parameters. | +| `contracts_metadata` | [GenesisContractMetadata](#archway.rewards.v1beta1.GenesisContractMetadata) | repeated | contracts_metadata defines a list of all contracts metadata. | + + + + + + + + + + + + + + + + +

Top

+ +## archway/rewards/v1beta1/query.proto + + + + + +### QueryContractMetadataRequest +QueryContractMetadataRequest is the request for Query.ContractMetadata. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `contract_address` | [string](#string) | | contract_address is the contract address (bech32 encoded). | + + + + + + + + +### QueryContractMetadataResponse +QueryContractMetadataResponse is the response for Query.ContractMetadata. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | | + + + + + + + + +### QueryParamsRequest +QueryParamsRequest is the request for Query.Params. + + + + + + + + +### QueryParamsResponse +QueryParamsResponse is the response for Query.Params. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `params` | [Params](#archway.rewards.v1beta1.Params) | | | + + + + + + + + + + + + + + +### Query +Query service for the tracking module. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `Params` | [QueryParamsRequest](#archway.rewards.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#archway.rewards.v1beta1.QueryParamsResponse) | Params returns module parameters. | GET|/archway/rewards/v1/params| +| `ContractMetadata` | [QueryContractMetadataRequest](#archway.rewards.v1beta1.QueryContractMetadataRequest) | [QueryContractMetadataResponse](#archway.rewards.v1beta1.QueryContractMetadataResponse) | ContractMetadata returns the contract rewards parameters (metadata). | GET|/archway/rewards/v1/contract_metadata| + + + + + +

Top

-## archway/tracking/v1/tracking.proto +## archway/rewards/v1beta1/tx.proto + + + + + +### MsgSetContractMetadata +MsgSetContractMetadata is the request for Msg.SetContractMetadata. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sender_address` | [string](#string) | | sender_address is the msg sender address (bech32 encoded). | +| `contract_address` | [string](#string) | | contract_address is the target contract address (bech32 encoded). | +| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata is the contract metadata to set / update. | + + + + + - +### MsgSetContractMetadataResponse +MsgSetContractMetadataResponse is the response for Msg.SetContractMetadata. + + + + + + + + + + + + + + +### Msg +Msg defines the module messaging service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `SetContractMetadata` | [MsgSetContractMetadata](#archway.rewards.v1beta1.MsgSetContractMetadata) | [MsgSetContractMetadataResponse](#archway.rewards.v1beta1.MsgSetContractMetadataResponse) | SetContractMetadata creates or updates an existing contract metadata. Method is authorized to the contract owner (admin if no metadata exists). | | + + + + + + +

Top

+ +## archway/tracking/v1beta1/tracking.proto + + + + + +### BlockTracking +BlockTracking is the tracking information for a block. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `txs` | [TxTracking](#archway.tracking.v1beta1.TxTracking) | repeated | txs defines the list of transactions tracked in the block. | + + + + + + + ### ContractOperationInfo ContractOperationInfo keeps a single contract operation gas consumption data. @@ -419,7 +689,7 @@ Object is being created by the IngestGasRecord call from the wasmd. | `id` | [uint64](#uint64) | | id defines the unique operation ID. | | `tx_id` | [uint64](#uint64) | | tx_id defines a transaction ID operation relates to (TxInfo.id). | | `contract_address` | [string](#string) | | contract_address defines the contract address operation relates to. | -| `operation_type` | [ContractOperation](#archway.tracking.v1.ContractOperation) | | operation_type defines the gas consumption type. | +| `operation_type` | [ContractOperation](#archway.tracking.v1beta1.ContractOperation) | | operation_type defines the gas consumption type. | | `vm_gas` | [uint64](#uint64) | | vm_gas is the gas consumption reported by the WASM VM. Value is adjusted by this module (CalculateUpdatedGas func). | | `sdk_gas` | [uint64](#uint64) | | sdk_gas is the gas consumption reported by the SDK gas meter and the WASM GasRegister (cost of Execute/Query/etc). Value is adjusted by this module (CalculateUpdatedGas func). | @@ -428,7 +698,7 @@ Object is being created by the IngestGasRecord call from the wasmd. - + ### Params Params defines the module parameters. @@ -443,7 +713,7 @@ Params defines the module parameters. - + ### TxInfo TxInfo keeps a transaction gas tracking data. @@ -460,10 +730,26 @@ Object is being created at the module EndBlocker. + + + +### TxTracking +TxTracking is the tracking information for a single transaction. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `info` | [TxInfo](#archway.tracking.v1beta1.TxInfo) | | info defines the transaction details. | +| `contract_operations` | [ContractOperationInfo](#archway.tracking.v1beta1.ContractOperationInfo) | repeated | contract_operations defines the list of contract operations consumed by the transaction. | + + + + + - + ### ContractOperation ContractOperation denotes which operation consumed gas. @@ -488,14 +774,14 @@ ContractOperation denotes which operation consumed gas. - +

Top

-## archway/tracking/v1/genesis.proto +## archway/tracking/v1beta1/genesis.proto - + ### GenesisState GenesisState defines the initial state of the tracking module. @@ -503,9 +789,9 @@ GenesisState defines the initial state of the tracking module. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `params` | [Params](#archway.tracking.v1.Params) | | params defines all the module parameters. | -| `tx_infos` | [TxInfo](#archway.tracking.v1.TxInfo) | repeated | tx_infos defines a list of all the tracked transactions. | -| `contract_op_infos` | [ContractOperationInfo](#archway.tracking.v1.ContractOperationInfo) | repeated | contract_op_infos defines a list of all the tracked contract operations. | +| `params` | [Params](#archway.tracking.v1beta1.Params) | | params defines all the module parameters. | +| `tx_infos` | [TxInfo](#archway.tracking.v1beta1.TxInfo) | repeated | tx_infos defines a list of all the tracked transactions. | +| `contract_op_infos` | [ContractOperationInfo](#archway.tracking.v1beta1.ContractOperationInfo) | repeated | contract_op_infos defines a list of all the tracked contract operations. | @@ -521,14 +807,14 @@ GenesisState defines the initial state of the tracking module. - +

Top

-## archway/tracking/v1/query.proto +## archway/tracking/v1beta1/query.proto - + ### QueryBlockGasTrackingRequest QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. @@ -538,7 +824,7 @@ QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. - + ### QueryBlockGasTrackingResponse QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. @@ -546,14 +832,14 @@ QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `txs` | [TxTracking](#archway.tracking.v1.TxTracking) | repeated | | +| `block` | [BlockTracking](#archway.tracking.v1beta1.BlockTracking) | | | - + ### QueryParamsRequest QueryParamsRequest is the request for Query.Params. @@ -563,7 +849,7 @@ QueryParamsRequest is the request for Query.Params. - + ### QueryParamsResponse QueryParamsResponse is the response for Query.Params. @@ -571,23 +857,7 @@ QueryParamsResponse is the response for Query.Params. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `params` | [Params](#archway.tracking.v1.Params) | | | - - - - - - - - -### TxTracking -TxTracking is the tracking information for a transaction used by the Query.BlockGasTracking query. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `info` | [TxInfo](#archway.tracking.v1.TxInfo) | | info defines the transaction details. | -| `contract_operations` | [ContractOperationInfo](#archway.tracking.v1.ContractOperationInfo) | repeated | contract_operations defines contract operations consumed by the transaction. | +| `params` | [Params](#archway.tracking.v1beta1.Params) | | | @@ -600,15 +870,15 @@ TxTracking is the tracking information for a transaction used by the Query.Block - + ### Query Query service for the tracking module. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `Params` | [QueryParamsRequest](#archway.tracking.v1.QueryParamsRequest) | [QueryParamsResponse](#archway.tracking.v1.QueryParamsResponse) | Params returns module parameters. | GET|/archway/tracking/v1/params| -| `BlockGasTracking` | [QueryBlockGasTrackingRequest](#archway.tracking.v1.QueryBlockGasTrackingRequest) | [QueryBlockGasTrackingResponse](#archway.tracking.v1.QueryBlockGasTrackingResponse) | BlockGasTracking returns block gas tracking for the latest block | GET|/archway/tracking/v1/block_gas_tracking| +| `Params` | [QueryParamsRequest](#archway.tracking.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#archway.tracking.v1beta1.QueryParamsResponse) | Params returns module parameters. | GET|/archway/tracking/v1/params| +| `BlockGasTracking` | [QueryBlockGasTrackingRequest](#archway.tracking.v1beta1.QueryBlockGasTrackingRequest) | [QueryBlockGasTrackingResponse](#archway.tracking.v1beta1.QueryBlockGasTrackingResponse) | BlockGasTracking returns block gas tracking for the latest block | GET|/archway/tracking/v1/block_gas_tracking| diff --git a/proto/archway/rewards/v1beta1/genesis.proto b/proto/archway/rewards/v1beta1/genesis.proto new file mode 100644 index 00000000..a3b63989 --- /dev/null +++ b/proto/archway/rewards/v1beta1/genesis.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +package archway.rewards.v1beta1; + +option go_package = "github.com/archway-network/archway/x/rewards/types"; + +import "gogoproto/gogo.proto"; +import "archway/rewards/v1beta1/rewards.proto"; + +// GenesisState defines the initial state of the tracking module. +message GenesisState { + // params defines all the module parameters. + Params params = 1 [ + (gogoproto.nullable) = false + ]; + // contracts_metadata defines a list of all contracts metadata. + repeated GenesisContractMetadata contracts_metadata = 2 [ + (gogoproto.nullable) = false + ]; +} + +// GenesisContractMetadata is used init ContractMetadata state via module genesis. +message GenesisContractMetadata { + // contract_address defines the contract address. + string contract_address = 1; + // metadata defines the contract metadata. + ContractMetadata metadata = 2 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/rewards/v1beta1/query.proto b/proto/archway/rewards/v1beta1/query.proto new file mode 100644 index 00000000..52d0ef15 --- /dev/null +++ b/proto/archway/rewards/v1beta1/query.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; +package archway.rewards.v1beta1; + +option go_package = "github.com/archway-network/archway/x/rewards/types"; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "archway/rewards/v1beta1/rewards.proto"; + +// Query service for the tracking module. +service Query { + // Params returns module parameters. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/archway/rewards/v1/params"; + } + + // ContractMetadata returns the contract rewards parameters (metadata). + rpc ContractMetadata(QueryContractMetadataRequest) returns (QueryContractMetadataResponse) { + option (google.api.http).get = "/archway/rewards/v1/contract_metadata"; + } +} + +// QueryParamsRequest is the request for Query.Params. +message QueryParamsRequest {} + +// QueryParamsResponse is the response for Query.Params. +message QueryParamsResponse { + Params params = 1 [ + (gogoproto.nullable) = false + ]; +} + +// QueryContractMetadataRequest is the request for Query.ContractMetadata. +message QueryContractMetadataRequest { + // contract_address is the contract address (bech32 encoded). + string contract_address = 1; +} + +// QueryContractMetadataResponse is the response for Query.ContractMetadata. +message QueryContractMetadataResponse { + ContractMetadata metadata = 1 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/rewards/v1beta1/rewards.proto b/proto/archway/rewards/v1beta1/rewards.proto new file mode 100644 index 00000000..b07462ea --- /dev/null +++ b/proto/archway/rewards/v1beta1/rewards.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; +package archway.rewards.v1beta1; + +option go_package = "github.com/archway-network/archway/x/rewards/types"; + +import "gogoproto/gogo.proto"; + +// Params defines the module parameters. +message Params { + option (gogoproto.goproto_stringer) = false; + + // rewards_enabled flag indicates whether rewards calculation and distribution is enabled. + bool rewards_enabled = 1; + + string inflation_rewards_ratio = 2 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + string tx_fee_rebate_ratio = 3 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; +} + +// ContractMetadata defines the contract rewards distribution options. +message ContractMetadata { + option (gogoproto.goproto_stringer) = false; + + // owner_address is the contract owner address that can modify contract reward options (bech32 encoded). + string owner_address = 1; + + // rewards_address is an address to distribute rewards to (bech32 encoded). + string rewards_address = 2; +} diff --git a/proto/archway/rewards/v1beta1/tx.proto b/proto/archway/rewards/v1beta1/tx.proto new file mode 100644 index 00000000..f1405154 --- /dev/null +++ b/proto/archway/rewards/v1beta1/tx.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +package archway.rewards.v1beta1; + +option go_package = "github.com/archway-network/archway/x/rewards/types"; + +import "gogoproto/gogo.proto"; +import "archway/rewards/v1beta1/rewards.proto"; + +// Msg defines the module messaging service. +service Msg { + // SetContractMetadata creates or updates an existing contract metadata. + // Method is authorized to the contract owner (admin if no metadata exists). + rpc SetContractMetadata(MsgSetContractMetadata) returns (MsgSetContractMetadataResponse); +} + +// MsgSetContractMetadata is the request for Msg.SetContractMetadata. +message MsgSetContractMetadata { + // sender_address is the msg sender address (bech32 encoded). + string sender_address = 1; + // contract_address is the target contract address (bech32 encoded). + string contract_address = 2; + // metadata is the contract metadata to set / update. + ContractMetadata metadata = 3 [ + (gogoproto.nullable) = false + ]; +} + +// MsgSetContractMetadataResponse is the response for Msg.SetContractMetadata. +message MsgSetContractMetadataResponse {} diff --git a/proto/archway/tracking/v1/genesis.proto b/proto/archway/tracking/v1beta1/genesis.proto similarity index 88% rename from proto/archway/tracking/v1/genesis.proto rename to proto/archway/tracking/v1beta1/genesis.proto index d7edd7c0..ba7aeccb 100644 --- a/proto/archway/tracking/v1/genesis.proto +++ b/proto/archway/tracking/v1beta1/genesis.proto @@ -1,10 +1,10 @@ syntax = "proto3"; -package archway.tracking.v1; +package archway.tracking.v1beta1; option go_package = "github.com/archway-network/archway/x/tracking/types"; import "gogoproto/gogo.proto"; -import "archway/tracking/v1/tracking.proto"; +import "archway/tracking/v1beta1/tracking.proto"; // GenesisState defines the initial state of the tracking module. message GenesisState { diff --git a/proto/archway/tracking/v1/query.proto b/proto/archway/tracking/v1beta1/query.proto similarity index 65% rename from proto/archway/tracking/v1/query.proto rename to proto/archway/tracking/v1beta1/query.proto index 572f248e..5011afca 100644 --- a/proto/archway/tracking/v1/query.proto +++ b/proto/archway/tracking/v1beta1/query.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package archway.tracking.v1; +package archway.tracking.v1beta1; option go_package = "github.com/archway-network/archway/x/tracking/types"; import "gogoproto/gogo.proto"; -import "archway/tracking/v1/tracking.proto"; import "google/api/annotations.proto"; +import "archway/tracking/v1beta1/tracking.proto"; // Query service for the tracking module. service Query { @@ -25,7 +25,7 @@ message QueryParamsRequest {} // QueryParamsResponse is the response for Query.Params. message QueryParamsResponse { - archway.tracking.v1.Params params = 1 [ + Params params = 1 [ (gogoproto.nullable) = false ]; } @@ -35,21 +35,7 @@ message QueryBlockGasTrackingRequest {} // QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. message QueryBlockGasTrackingResponse { - repeated TxTracking txs = 1 [ - (gogoproto.nullable) = false - ]; -} - -// TxTracking is the tracking information for a transaction used by the Query.BlockGasTracking query. -message TxTracking { - option (gogoproto.goproto_stringer) = false; - - // info defines the transaction details. - TxInfo info = 1 [ - (gogoproto.nullable) = false - ]; - // contract_operations defines contract operations consumed by the transaction. - repeated ContractOperationInfo contract_operations = 2 [ + BlockTracking block = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/archway/tracking/v1/tracking.proto b/proto/archway/tracking/v1beta1/tracking.proto similarity index 74% rename from proto/archway/tracking/v1/tracking.proto rename to proto/archway/tracking/v1beta1/tracking.proto index 6f4aa78d..33edd0dd 100644 --- a/proto/archway/tracking/v1/tracking.proto +++ b/proto/archway/tracking/v1beta1/tracking.proto @@ -1,5 +1,5 @@ syntax = "proto3"; -package archway.tracking.v1; +package archway.tracking.v1beta1; option go_package = "github.com/archway-network/archway/x/tracking/types"; @@ -54,12 +54,32 @@ message ContractOperationInfo { ContractOperation operation_type = 4; // vm_gas is the gas consumption reported by the WASM VM. // Value is adjusted by this module (CalculateUpdatedGas func). - uint64 vm_gas = 5 [ - (gogoproto.moretags) = "yaml:\"vm_gas\"" - ]; + uint64 vm_gas = 5; // sdk_gas is the gas consumption reported by the SDK gas meter and the WASM GasRegister (cost of Execute/Query/etc). // Value is adjusted by this module (CalculateUpdatedGas func). - uint64 sdk_gas = 6 [ - (gogoproto.moretags) = "yaml:\"sdk_gas\"" + uint64 sdk_gas = 6; +} + +// BlockTracking is the tracking information for a block. +message BlockTracking { + option (gogoproto.goproto_stringer) = false; + + // txs defines the list of transactions tracked in the block. + repeated TxTracking txs = 1 [ + (gogoproto.nullable) = false + ]; +} + +// TxTracking is the tracking information for a single transaction. +message TxTracking { + option (gogoproto.goproto_stringer) = false; + + // info defines the transaction details. + TxInfo info = 1 [ + (gogoproto.nullable) = false + ]; + // contract_operations defines the list of contract operations consumed by the transaction. + repeated ContractOperationInfo contract_operations = 2 [ + (gogoproto.nullable) = false ]; -} \ No newline at end of file +} diff --git a/x/rewards/keeper/grpc_query.go b/x/rewards/keeper/grpc_query.go new file mode 100644 index 00000000..3a0c6d81 --- /dev/null +++ b/x/rewards/keeper/grpc_query.go @@ -0,0 +1,60 @@ +package keeper + +import ( + "context" + "github.com/archway-network/archway/x/rewards/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var _ types.QueryServer = &QueryServer{} + +// QueryServer implements the module gRPC query service. +type QueryServer struct { + keeper Keeper +} + +// NewQueryServer creates a new gRPC query server. +func NewQueryServer(keeper Keeper) *QueryServer { + return &QueryServer{ + keeper: keeper, + } +} + +// Params implements the types.QueryServer interface. +func (s *QueryServer) Params(c context.Context, request *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + return &types.QueryParamsResponse{ + Params: s.keeper.GetParams(ctx), + }, nil +} + +// ContractMetadata implements the types.QueryServer interface. +func (s *QueryServer) ContractMetadata(c context.Context, request *types.QueryContractMetadataRequest) (*types.QueryContractMetadataResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + contractAddr, err := sdk.AccAddressFromBech32(request.ContractAddress) + if err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid contract address") + } + + ctx := sdk.UnwrapSDKContext(c) + metaState := s.keeper.state.ContractMetadataState(ctx) + + meta, found := metaState.GetContractMetadata(contractAddr) + if !found { + return nil, status.Errorf(codes.NotFound, "metadata for the contract: not found") + } + + return &types.QueryContractMetadataResponse{ + Metadata: meta, + }, nil +} diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go new file mode 100644 index 00000000..09539730 --- /dev/null +++ b/x/rewards/keeper/keeper.go @@ -0,0 +1,73 @@ +package keeper + +import ( + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/archway-network/archway/x/rewards/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/tendermint/tendermint/libs/log" +) + +// ContractInfoReaderExpected defines the interface for the wasmd module dependency. +type ContractInfoReaderExpected interface { + GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmTypes.ContractInfo +} + +// Keeper provides module state operations. +type Keeper struct { + cdc codec.Codec + paramStore paramTypes.Subspace + state State + contractInfoView ContractInfoReaderExpected +} + +// NewKeeper creates a new Keeper instance. +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInfoReaderExpected, ps paramTypes.Subspace) Keeper { + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(types.ParamKeyTable()) + } + + return Keeper{ + cdc: cdc, + paramStore: ps, + state: NewState(cdc, key), + contractInfoView: contractInfoReader, + } +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", "x/"+types.ModuleName) +} + +// SetContractMetadata creates or updates the contract metadata verifying the ownership: +// * Meta could be created by the contract admin (if set); +// * Meta could be modified by the contract owner; +func (k Keeper) SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sdk.AccAddress, requestedMeta types.ContractMetadata) error { + state := k.state.ContractMetadataState(ctx) + + // Check if the contract exists + contractInfo := k.contractInfoView.GetContractInfo(ctx, contractAddr) + if contractInfo == nil { + return types.ErrContractNotFound + } + + // Check ownership + existingMeta, found := state.GetContractMetadata(contractAddr) + if found { + if existingMeta.OwnerAddress != senderAddr.String() { + return sdkErrors.Wrap(types.ErrUnauthorized, "metadata can only be changed by the contract owner") + } + } else { + if contractInfo.Admin != senderAddr.String() { + return sdkErrors.Wrap(types.ErrUnauthorized, "metadata can only be created by the contract admin") + } + } + + // Set + state.SetContractMetadata(contractAddr, requestedMeta) + + return nil +} diff --git a/x/rewards/keeper/msg_server.go b/x/rewards/keeper/msg_server.go new file mode 100644 index 00000000..58279594 --- /dev/null +++ b/x/rewards/keeper/msg_server.go @@ -0,0 +1,48 @@ +package keeper + +import ( + "context" + "github.com/archway-network/archway/x/rewards/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var _ types.MsgServer = (*MsgServer)(nil) + +// MsgServer implements the module gRPC messaging service. +type MsgServer struct { + keeper Keeper +} + +// NewMsgServer creates a new gRPC messaging server. +func NewMsgServer(keeper Keeper) *MsgServer { + return &MsgServer{ + keeper: keeper, + } +} + +// SetContractMetadata implements the types.MsgServer interface. +func (s MsgServer) SetContractMetadata(c context.Context, request *types.MsgSetContractMetadata) (*types.MsgSetContractMetadataResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + senderAddr, err := sdk.AccAddressFromBech32(request.SenderAddress) + if err != nil { + return nil, err // returning error "as is" since this should not happen due to the earlier ValidateBasic call + } + + contractAddr, err := sdk.AccAddressFromBech32(request.ContractAddress) + if err != nil { + return nil, err // returning error "as is" since this should not happen due to the earlier ValidateBasic call + } + + if err := s.keeper.SetContractMetadata(ctx, senderAddr, contractAddr, request.Metadata); err != nil { + return nil, err + } + + return &types.MsgSetContractMetadataResponse{}, nil +} diff --git a/x/rewards/keeper/params.go b/x/rewards/keeper/params.go new file mode 100644 index 00000000..efad253f --- /dev/null +++ b/x/rewards/keeper/params.go @@ -0,0 +1,38 @@ +package keeper + +import ( + "github.com/archway-network/archway/x/rewards/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// RewardsEnabled return rewards calculation and distribution enabled param flag. +func (k Keeper) RewardsEnabled(ctx sdk.Context) (res bool) { + k.paramStore.Get(ctx, types.RewardsEnabledParamKey, &res) + return +} + +// InflationRewardsRatio return inflation rewards params ratio. +func (k Keeper) InflationRewardsRatio(ctx sdk.Context) (res sdk.Dec) { + k.paramStore.Get(ctx, types.InflationRewardsRatioParamKey, &res) + return +} + +// TxFeeRebateRatio return tx fee rebate rewards params ratio. +func (k Keeper) TxFeeRebateRatio(ctx sdk.Context) (res sdk.Dec) { + k.paramStore.Get(ctx, types.TxFeeRebateRatioParamKey, &res) + return +} + +// GetParams return all module parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams( + k.RewardsEnabled(ctx), + k.InflationRewardsRatio(ctx), + k.TxFeeRebateRatio(ctx), + ) +} + +// SetParams sets all module parameters. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramStore.SetParamSet(ctx, ¶ms) +} diff --git a/x/rewards/keeper/state.go b/x/rewards/keeper/state.go new file mode 100644 index 00000000..932f29e2 --- /dev/null +++ b/x/rewards/keeper/state.go @@ -0,0 +1,32 @@ +package keeper + +import ( + "github.com/archway-network/archway/x/rewards/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// State is a wrapper around the module storage state. +type State struct { + key sdk.StoreKey + cdc codec.Codec +} + +// NewState creates a new State instance. +func NewState(cdc codec.Codec, key sdk.StoreKey) State { + return State{ + key: key, + cdc: cdc, + } +} + +// ContractMetadataState returns types.ContractMetadata repository. +func (s State) ContractMetadataState(ctx sdk.Context) ContractMetadataState { + baseStore := ctx.KVStore(s.key) + return ContractMetadataState{ + stateStore: prefix.NewStore(baseStore, types.ContractMetadataStatePrefix), + cdc: s.cdc, + ctx: ctx, + } +} diff --git a/x/rewards/keeper/state_metadata.go b/x/rewards/keeper/state_metadata.go new file mode 100644 index 00000000..5067942d --- /dev/null +++ b/x/rewards/keeper/state_metadata.go @@ -0,0 +1,95 @@ +package keeper + +import ( + "fmt" + "github.com/archway-network/archway/x/rewards/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ContractMetadataState provides access to the types.ContractMetadata objects storage operations. +type ContractMetadataState struct { + stateStore storeTypes.KVStore + cdc codec.Codec + ctx sdk.Context +} + +// SetContractMetadata creates or modifies a types.ContractMetadata object. +func (s ContractMetadataState) SetContractMetadata(contractAddr sdk.AccAddress, meta types.ContractMetadata) { + store := prefix.NewStore(s.stateStore, types.ContractMetadataPrefix) + store.Set( + s.buildContractMetadataKey(contractAddr), + s.cdc.MustMarshal(&meta), + ) +} + +// GetContractMetadata returns a types.ContractMetadata object by contract address. +func (s ContractMetadataState) GetContractMetadata(contractAddr sdk.AccAddress) (types.ContractMetadata, bool) { + obj := s.getContractMetadata(contractAddr) + if obj == nil { + return types.ContractMetadata{}, false + } + + return *obj, true +} + +// Import initializes state from the module genesis data. +func (s ContractMetadataState) Import(objs []types.GenesisContractMetadata) { + for _, obj := range objs { + s.SetContractMetadata(obj.MustGetContractAddress(), obj.Metadata) + } +} + +// Export returns the module genesis data for the state. +func (s ContractMetadataState) Export() (objs []types.GenesisContractMetadata) { + store := prefix.NewStore(s.stateStore, types.ContractMetadataPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + contractAddr := s.parseContractMetadataKey(iterator.Key()) + + var obj types.ContractMetadata + s.cdc.MustUnmarshal(iterator.Value(), &obj) + + objs = append(objs, types.GenesisContractMetadata{ + ContractAddress: contractAddr.String(), + Metadata: obj, + }) + } + + return +} + +// buildContractMetadataKey returns the key used to store a types.ContractMetadata object. +func (s ContractMetadataState) buildContractMetadataKey(contractAddr sdk.AccAddress) []byte { + return contractAddr.Bytes() +} + +// parseContractMetadataKey parses and validates types.ContractMetadata storage key. +func (s ContractMetadataState) parseContractMetadataKey(key []byte) sdk.AccAddress { + addr := sdk.AccAddress(key) + if err := sdk.VerifyAddressFormat(addr); err != nil { + panic(fmt.Errorf("invalid contract address key: %w", err)) + } + + return addr +} + +// getContractMetadata returns a types.ContractMetadata object by contract address. +func (s ContractMetadataState) getContractMetadata(contractAddr sdk.AccAddress) *types.ContractMetadata { + store := prefix.NewStore(s.stateStore, types.ContractMetadataPrefix) + + bz := store.Get(s.buildContractMetadataKey(contractAddr)) + if bz == nil { + return nil + } + + var obj types.ContractMetadata + s.cdc.MustUnmarshal(bz, &obj) + + return &obj +} diff --git a/x/rewards/types/codec.go b/x/rewards/types/codec.go new file mode 100644 index 00000000..5a8505bd --- /dev/null +++ b/x/rewards/types/codec.go @@ -0,0 +1,26 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + cryptoCodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// RegisterLegacyAminoCodec registers the necessary interfaces and concrete types on the provided LegacyAmino codec. +// These types are used for Amino JSON serialization. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} + +// RegisterInterfaces registers interfaces types with the interface registry. +func RegisterInterfaces(registry types.InterfaceRegistry) {} + +var ( + ModuleCdc = codec.NewAminoCodec(amino) + amino = codec.NewLegacyAmino() +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptoCodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) +} diff --git a/x/rewards/types/errors.go b/x/rewards/types/errors.go new file mode 100644 index 00000000..a407a6b6 --- /dev/null +++ b/x/rewards/types/errors.go @@ -0,0 +1,10 @@ +package types + +import sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + +var ( + DefaultCodespace = ModuleName + ErrInternal = sdkErrors.Register(DefaultCodespace, 0, "internal error") // smth went wrong + ErrContractNotFound = sdkErrors.Register(DefaultCodespace, 1, "contract not found") // contract info not found + ErrUnauthorized = sdkErrors.Register(DefaultCodespace, 2, "unauthorized operation") // contract ownership issue +) diff --git a/x/rewards/types/genesis.go b/x/rewards/types/genesis.go new file mode 100644 index 00000000..8e08b458 --- /dev/null +++ b/x/rewards/types/genesis.go @@ -0,0 +1,50 @@ +package types + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Validate perform object fields validation. +func (m GenesisState) Validate() error { + if err := m.Params.Validate(); err != nil { + return fmt.Errorf("params: %w", err) + } + + contractAddrSet := make(map[string]struct{}) + for i, meta := range m.ContractsMetadata { + if err := meta.Validate(); err != nil { + return fmt.Errorf("contractsMetadata [%d]: %w", i, err) + } + + if _, ok := contractAddrSet[meta.ContractAddress]; ok { + return fmt.Errorf("contractsMetadata [%d]: duplicated contract address: %s", i, meta.ContractAddress) + } + contractAddrSet[meta.ContractAddress] = struct{}{} + } + + return nil +} + +// Validate perform object fields validation. +func (m GenesisContractMetadata) Validate() error { + if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { + return fmt.Errorf("contractAddress: %w", err) + } + if err := m.Metadata.Validate(); err != nil { + return fmt.Errorf("metadata: %w", err) + } + + return nil +} + +// MustGetContractAddress returns the contract address parsed. +// Contract: panics of error. +func (m GenesisContractMetadata) MustGetContractAddress() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(m.ContractAddress) + if err != nil { + panic(fmt.Errorf("invalid contract address: %w", err)) + } + + return addr +} diff --git a/x/rewards/types/genesis.pb.go b/x/rewards/types/genesis.pb.go new file mode 100644 index 00000000..97a469c5 --- /dev/null +++ b/x/rewards/types/genesis.pb.go @@ -0,0 +1,619 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/rewards/v1beta1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the initial state of the tracking module. +type GenesisState struct { + // params defines all the module parameters. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // contracts_metadata defines a list of all contracts metadata. + ContractsMetadata []GenesisContractMetadata `protobuf:"bytes,2,rep,name=contracts_metadata,json=contractsMetadata,proto3" json:"contracts_metadata"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_cdced50517b403fe, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetContractsMetadata() []GenesisContractMetadata { + if m != nil { + return m.ContractsMetadata + } + return nil +} + +// GenesisContractMetadata is used init ContractMetadata state via module genesis. +type GenesisContractMetadata struct { + // contract_address defines the contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // metadata defines the contract metadata. + Metadata ContractMetadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata"` +} + +func (m *GenesisContractMetadata) Reset() { *m = GenesisContractMetadata{} } +func (m *GenesisContractMetadata) String() string { return proto.CompactTextString(m) } +func (*GenesisContractMetadata) ProtoMessage() {} +func (*GenesisContractMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_cdced50517b403fe, []int{1} +} +func (m *GenesisContractMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisContractMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisContractMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisContractMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisContractMetadata.Merge(m, src) +} +func (m *GenesisContractMetadata) XXX_Size() int { + return m.Size() +} +func (m *GenesisContractMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisContractMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisContractMetadata proto.InternalMessageInfo + +func (m *GenesisContractMetadata) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *GenesisContractMetadata) GetMetadata() ContractMetadata { + if m != nil { + return m.Metadata + } + return ContractMetadata{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "archway.rewards.v1beta1.GenesisState") + proto.RegisterType((*GenesisContractMetadata)(nil), "archway.rewards.v1beta1.GenesisContractMetadata") +} + +func init() { + proto.RegisterFile("archway/rewards/v1beta1/genesis.proto", fileDescriptor_cdced50517b403fe) +} + +var fileDescriptor_cdced50517b403fe = []byte{ + // 303 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4d, 0x2c, 0x4a, 0xce, + 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x4a, 0x2d, 0x4f, 0x2c, 0x4a, 0x29, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, + 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, + 0xc9, 0x17, 0x12, 0x87, 0x2a, 0xd3, 0x83, 0x2a, 0xd3, 0x83, 0x2a, 0x93, 0x12, 0x49, 0xcf, 0x4f, + 0xcf, 0x07, 0xab, 0xd1, 0x07, 0xb1, 0x20, 0xca, 0xa5, 0x70, 0x9a, 0x0a, 0xd3, 0x0e, 0x56, 0xa6, + 0xb4, 0x85, 0x91, 0x8b, 0xc7, 0x1d, 0x62, 0x4f, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x90, 0x2d, 0x17, + 0x5b, 0x41, 0x62, 0x51, 0x62, 0x6e, 0xb1, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0xbc, 0x1e, + 0x0e, 0x7b, 0xf5, 0x02, 0xc0, 0xca, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0x6a, 0x12, + 0x4a, 0xe5, 0x12, 0x4a, 0xce, 0xcf, 0x2b, 0x29, 0x4a, 0x4c, 0x2e, 0x29, 0x8e, 0xcf, 0x4d, 0x2d, + 0x49, 0x4c, 0x49, 0x2c, 0x49, 0x94, 0x60, 0x52, 0x60, 0xd6, 0xe0, 0x36, 0x32, 0xc0, 0x69, 0x14, + 0xd4, 0x05, 0xce, 0x50, 0x9d, 0xbe, 0x50, 0x7d, 0x50, 0xb3, 0x05, 0xe1, 0x26, 0xc2, 0x24, 0x94, + 0x26, 0x32, 0x72, 0x89, 0xe3, 0xd0, 0x24, 0xa4, 0xc9, 0x25, 0x00, 0xd3, 0x10, 0x9f, 0x98, 0x92, + 0x52, 0x94, 0x5a, 0x0c, 0xf1, 0x0b, 0x67, 0x10, 0x3f, 0x4c, 0xdc, 0x11, 0x22, 0x2c, 0xe4, 0xcd, + 0xc5, 0x81, 0xe4, 0x46, 0x90, 0x77, 0x35, 0x71, 0xba, 0x11, 0x87, 0xe3, 0xe0, 0x06, 0x38, 0xf9, + 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, + 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x51, 0x7a, 0x66, 0x49, 0x46, + 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xd4, 0x78, 0xdd, 0xbc, 0xd4, 0x92, 0xf2, 0xfc, 0xa2, + 0x6c, 0x18, 0x5f, 0xbf, 0x02, 0x1e, 0x51, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0xf8, + 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x70, 0x6f, 0x45, 0x36, 0x1e, 0x02, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractsMetadata) > 0 { + for iNdEx := len(m.ContractsMetadata) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractsMetadata[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *GenesisContractMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisContractMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.ContractsMetadata) > 0 { + for _, e := range m.ContractsMetadata { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *GenesisContractMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractsMetadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractsMetadata = append(m.ContractsMetadata, GenesisContractMetadata{}) + if err := m.ContractsMetadata[len(m.ContractsMetadata)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GenesisContractMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisContractMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisContractMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/rewards/types/keys.go b/x/rewards/types/keys.go new file mode 100644 index 00000000..4fb90241 --- /dev/null +++ b/x/rewards/types/keys.go @@ -0,0 +1,23 @@ +package types + +const ( + // ModuleName is the module name. + ModuleName = "rewards" + // StoreKey is the module KV storage prefix key. + StoreKey = ModuleName + // QuerierRoute is the querier route for the module. + QuerierRoute = ModuleName + // RouterKey is the msg router key for the module. + RouterKey = ModuleName +) + +// ContractMetadata prefixed store state keys. +var ( + // ContractMetadataStatePrefix defines the state global prefix. + ContractMetadataStatePrefix = []byte{0x00} + + // ContractMetadataPrefix defines the prefix for storing ContractMetadata objects. + // Key: ContractMetadataStatePrefix | ContractMetadataPrefix | {contractAddress} + // Value: ContractMetadata + ContractMetadataPrefix = []byte{0x01} +) diff --git a/x/rewards/types/msg.go b/x/rewards/types/msg.go new file mode 100644 index 00000000..63ad3687 --- /dev/null +++ b/x/rewards/types/msg.go @@ -0,0 +1,66 @@ +package types + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + TypeMsgSetContractMetadata = "set-contract-metadata" +) + +var ( + _ sdk.Msg = &MsgSetContractMetadata{} +) + +// NewMsgSetContractMetadata creates a new MsgSetContractMetadata instance. +func NewMsgSetContractMetadata(senderAddr, contractAddr, ownerAddr, rewardsAddr sdk.AccAddress) *MsgSetContractMetadata { + return &MsgSetContractMetadata{ + SenderAddress: senderAddr.String(), + ContractAddress: contractAddr.String(), + Metadata: ContractMetadata{ + OwnerAddress: ownerAddr.String(), + RewardsAddress: rewardsAddr.String(), + }, + } +} + +// Route implements the sdk.Msg interface. +func (m MsgSetContractMetadata) Route() string { return RouterKey } + +// Type implements the sdk.Msg interface. +func (m MsgSetContractMetadata) Type() string { return TypeMsgSetContractMetadata } + +// GetSigners implements the sdk.Msg interface. +func (m MsgSetContractMetadata) GetSigners() []sdk.AccAddress { + senderAddr, err := sdk.AccAddressFromBech32(m.SenderAddress) + if err != nil { + panic(fmt.Errorf("parsing sender address: %w", err)) + } + + return []sdk.AccAddress{senderAddr} +} + +// GetSignBytes implements the sdk.Msg interface. +func (m MsgSetContractMetadata) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&m) + return sdk.MustSortJSON(bz) +} + +// ValidateBasic implements the sdk.Msg interface. +func (m MsgSetContractMetadata) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(m.SenderAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid sender address") + } + + if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid contract address") + } + + if err := m.Metadata.Validate(); err != nil { + return err + } + + return nil +} diff --git a/x/rewards/types/params.go b/x/rewards/types/params.go new file mode 100644 index 00000000..37eb27d9 --- /dev/null +++ b/x/rewards/types/params.go @@ -0,0 +1,118 @@ +package types + +import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" + paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var ( + RewardsEnabledParamKey = []byte("RewardsEnabled") + InflationRewardsRatioParamKey = []byte("InflationRewardsRatio") + TxFeeRebateRatioParamKey = []byte("TxFeeRebateRatio") +) + +var _ paramTypes.ParamSet = (*Params)(nil) + +// ParamKeyTable creates a new params table. +func ParamKeyTable() paramTypes.KeyTable { + return paramTypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance. +func NewParams(rewardsEnabled bool, inflationRewardsRatio, txFeeRebateRatio sdk.Dec) Params { + return Params{ + RewardsEnabled: rewardsEnabled, + InflationRewardsRatio: inflationRewardsRatio, + TxFeeRebateRatio: txFeeRebateRatio, + } +} + +// DefaultParams returns a default set of parameters. +func DefaultParams() Params { + defInflationRatio := sdk.MustNewDecFromStr("0.20") // 20% + defTxFeeRebateRatio := sdk.MustNewDecFromStr("0.50") // 50% + + return NewParams(true, defInflationRatio, defTxFeeRebateRatio) +} + +// ParamSetPairs Implements the paramTypes.ParamSet interface. +func (m *Params) ParamSetPairs() paramTypes.ParamSetPairs { + return paramTypes.ParamSetPairs{ + paramTypes.NewParamSetPair(RewardsEnabledParamKey, &m.RewardsEnabled, validateRewardsEnabled), + paramTypes.NewParamSetPair(InflationRewardsRatioParamKey, &m.InflationRewardsRatio, validateInflationRewardsRatio), + paramTypes.NewParamSetPair(TxFeeRebateRatioParamKey, &m.TxFeeRebateRatio, validateTxFeeRebateRatio), + } +} + +// Validate perform object fields validation. +func (m Params) Validate() error { + if err := validateRewardsEnabled(m.RewardsEnabled); err != nil { + return err + } + if err := validateInflationRewardsRatio(m.InflationRewardsRatio); err != nil { + return err + } + if err := validateTxFeeRebateRatio(m.TxFeeRebateRatio); err != nil { + return err + } + + return nil +} + +func validateRewardsEnabled(v interface{}) (retErr error) { + defer func() { + if retErr != nil { + retErr = fmt.Errorf("rewardsEnabled param: %w", retErr) + } + }() + + v, ok := v.(bool) + if !ok { + return fmt.Errorf("invalid parameter type: %T", v) + } + + return +} + +func validateInflationRewardsRatio(v interface{}) (retErr error) { + defer func() { + if retErr != nil { + retErr = fmt.Errorf("inflationRewardsRatio param: %w", retErr) + } + }() + + p, ok := v.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", v) + } + + return validateRatio(p) +} + +func validateTxFeeRebateRatio(v interface{}) (retErr error) { + defer func() { + if retErr != nil { + retErr = fmt.Errorf("txFeeRebateRatio param: %w", retErr) + } + }() + + p, ok := v.(sdk.Dec) + if !ok { + return fmt.Errorf("invalid parameter type: %T", v) + } + + return validateRatio(p) +} + +// validateRatio is a generic ratio coefficient validator. +func validateRatio(v sdk.Dec) error { + if v.IsNegative() { + return fmt.Errorf("must be GTE 0.0") + } + if v.GT(sdk.OneDec()) { + return fmt.Errorf("must be LTE 1.0") + } + + return nil +} diff --git a/x/rewards/types/query.pb.go b/x/rewards/types/query.pb.go new file mode 100644 index 00000000..7a629f0f --- /dev/null +++ b/x/rewards/types/query.pb.go @@ -0,0 +1,926 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/rewards/v1beta1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is the request for Query.Params. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response for Query.Params. +type QueryParamsResponse struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// QueryContractMetadataRequest is the request for Query.ContractMetadata. +type QueryContractMetadataRequest struct { + // contract_address is the contract address (bech32 encoded). + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` +} + +func (m *QueryContractMetadataRequest) Reset() { *m = QueryContractMetadataRequest{} } +func (m *QueryContractMetadataRequest) String() string { return proto.CompactTextString(m) } +func (*QueryContractMetadataRequest) ProtoMessage() {} +func (*QueryContractMetadataRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{2} +} +func (m *QueryContractMetadataRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractMetadataRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractMetadataRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryContractMetadataRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractMetadataRequest.Merge(m, src) +} +func (m *QueryContractMetadataRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryContractMetadataRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractMetadataRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractMetadataRequest proto.InternalMessageInfo + +func (m *QueryContractMetadataRequest) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +// QueryContractMetadataResponse is the response for Query.ContractMetadata. +type QueryContractMetadataResponse struct { + Metadata ContractMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata"` +} + +func (m *QueryContractMetadataResponse) Reset() { *m = QueryContractMetadataResponse{} } +func (m *QueryContractMetadataResponse) String() string { return proto.CompactTextString(m) } +func (*QueryContractMetadataResponse) ProtoMessage() {} +func (*QueryContractMetadataResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{3} +} +func (m *QueryContractMetadataResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractMetadataResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryContractMetadataResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractMetadataResponse.Merge(m, src) +} +func (m *QueryContractMetadataResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryContractMetadataResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractMetadataResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractMetadataResponse proto.InternalMessageInfo + +func (m *QueryContractMetadataResponse) GetMetadata() ContractMetadata { + if m != nil { + return m.Metadata + } + return ContractMetadata{} +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "archway.rewards.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "archway.rewards.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryContractMetadataRequest)(nil), "archway.rewards.v1beta1.QueryContractMetadataRequest") + proto.RegisterType((*QueryContractMetadataResponse)(nil), "archway.rewards.v1beta1.QueryContractMetadataResponse") +} + +func init() { + proto.RegisterFile("archway/rewards/v1beta1/query.proto", fileDescriptor_078e0e66cc6cb70d) +} + +var fileDescriptor_078e0e66cc6cb70d = []byte{ + // 397 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x31, 0x4b, 0xf3, 0x40, + 0x1c, 0xc6, 0x93, 0xf2, 0xbe, 0x45, 0xcf, 0xc1, 0x72, 0x16, 0x94, 0x50, 0x53, 0x89, 0x14, 0x2d, + 0xda, 0x1c, 0xad, 0xe8, 0xe6, 0x60, 0x9d, 0x44, 0x05, 0x2d, 0x4e, 0x2e, 0x72, 0x4d, 0x8e, 0xb4, + 0xd8, 0xe6, 0xd2, 0xbb, 0xab, 0xb5, 0xab, 0x8b, 0xab, 0xe0, 0x17, 0xf1, 0x43, 0x38, 0x74, 0x2c, + 0xb8, 0x38, 0x89, 0xb4, 0x7e, 0x10, 0x69, 0xee, 0x12, 0xb0, 0x35, 0xa2, 0x5b, 0x78, 0xee, 0xf9, + 0x3f, 0xcf, 0x2f, 0xff, 0x3b, 0xb0, 0x8e, 0x99, 0xd3, 0xe8, 0xe1, 0x3e, 0x62, 0xa4, 0x87, 0x99, + 0xcb, 0xd1, 0x4d, 0xb9, 0x4e, 0x04, 0x2e, 0xa3, 0x4e, 0x97, 0xb0, 0xbe, 0x1d, 0x30, 0x2a, 0x28, + 0x5c, 0x56, 0x26, 0x5b, 0x99, 0x6c, 0x65, 0x32, 0xb2, 0x1e, 0xf5, 0x68, 0xe8, 0x41, 0x93, 0x2f, + 0x69, 0x37, 0x72, 0x1e, 0xa5, 0x5e, 0x8b, 0x20, 0x1c, 0x34, 0x11, 0xf6, 0x7d, 0x2a, 0xb0, 0x68, + 0x52, 0x9f, 0xab, 0xd3, 0x42, 0x52, 0x63, 0x14, 0x1e, 0xda, 0xac, 0x2c, 0x80, 0xe7, 0x13, 0x84, + 0x33, 0xcc, 0x70, 0x9b, 0xd7, 0x48, 0xa7, 0x4b, 0xb8, 0xb0, 0x2e, 0xc0, 0xd2, 0x17, 0x95, 0x07, + 0xd4, 0xe7, 0x04, 0xee, 0x83, 0x74, 0x10, 0x2a, 0x2b, 0xfa, 0x9a, 0xbe, 0xb9, 0x50, 0xc9, 0xdb, + 0x09, 0xc4, 0xb6, 0x1c, 0xac, 0xfe, 0x1b, 0xbc, 0xe5, 0xb5, 0x9a, 0x1a, 0xb2, 0x8e, 0x40, 0x2e, + 0x4c, 0x3d, 0xa4, 0xbe, 0x60, 0xd8, 0x11, 0xa7, 0x44, 0x60, 0x17, 0x0b, 0xac, 0x5a, 0x61, 0x11, + 0x64, 0x1c, 0x75, 0x74, 0x85, 0x5d, 0x97, 0x11, 0x2e, 0x8b, 0xe6, 0x6b, 0x8b, 0x91, 0x7e, 0x20, + 0x65, 0xab, 0x05, 0x56, 0x13, 0xa2, 0x14, 0xea, 0x31, 0x98, 0x6b, 0x2b, 0x4d, 0xc1, 0x16, 0x13, + 0x61, 0xa7, 0x43, 0x14, 0x76, 0x1c, 0x50, 0x79, 0x4e, 0x81, 0xff, 0x61, 0x1d, 0xbc, 0xd7, 0x41, + 0x5a, 0xfe, 0x1b, 0xdc, 0x4a, 0xcc, 0x9b, 0x5d, 0xa8, 0xb1, 0xfd, 0x3b, 0xb3, 0x84, 0xb7, 0xac, + 0xbb, 0x97, 0x8f, 0xc7, 0x54, 0x0e, 0x1a, 0x68, 0xf6, 0x12, 0x91, 0x5c, 0x26, 0x7c, 0xd2, 0x41, + 0x66, 0x1a, 0x1c, 0xee, 0xfe, 0x5c, 0x93, 0xb0, 0x78, 0x63, 0xef, 0xaf, 0x63, 0x8a, 0xb3, 0x14, + 0x72, 0x6e, 0xc0, 0xc2, 0x77, 0x9c, 0xf1, 0x55, 0x46, 0x6b, 0xac, 0x9e, 0x0c, 0x46, 0xa6, 0x3e, + 0x1c, 0x99, 0xfa, 0xfb, 0xc8, 0xd4, 0x1f, 0xc6, 0xa6, 0x36, 0x1c, 0x9b, 0xda, 0xeb, 0xd8, 0xd4, + 0x2e, 0x2b, 0x5e, 0x53, 0x34, 0xba, 0x75, 0xdb, 0xa1, 0xed, 0x28, 0xaa, 0xe4, 0x13, 0xd1, 0xa3, + 0xec, 0x3a, 0x8e, 0xbe, 0x8d, 0xc3, 0x45, 0x3f, 0x20, 0xbc, 0x9e, 0x0e, 0x1f, 0xf0, 0xce, 0x67, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xa0, 0xb7, 0x95, 0x59, 0x5b, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Params returns module parameters. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // ContractMetadata returns the contract rewards parameters (metadata). + ContractMetadata(ctx context.Context, in *QueryContractMetadataRequest, opts ...grpc.CallOption) (*QueryContractMetadataResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/archway.rewards.v1beta1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ContractMetadata(ctx context.Context, in *QueryContractMetadataRequest, opts ...grpc.CallOption) (*QueryContractMetadataResponse, error) { + out := new(QueryContractMetadataResponse) + err := c.cc.Invoke(ctx, "/archway.rewards.v1beta1.Query/ContractMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Params returns module parameters. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // ContractMetadata returns the contract rewards parameters (metadata). + ContractMetadata(context.Context, *QueryContractMetadataRequest) (*QueryContractMetadataResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) ContractMetadata(ctx context.Context, req *QueryContractMetadataRequest) (*QueryContractMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContractMetadata not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.rewards.v1beta1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ContractMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryContractMetadataRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ContractMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.rewards.v1beta1.Query/ContractMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ContractMetadata(ctx, req.(*QueryContractMetadataRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "archway.rewards.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "ContractMetadata", + Handler: _Query_ContractMetadata_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "archway/rewards/v1beta1/query.proto", +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryContractMetadataRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryContractMetadataRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractMetadataRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryContractMetadataResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryContractMetadataResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryContractMetadataRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryContractMetadataResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Metadata.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractMetadataRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryContractMetadataRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractMetadataRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractMetadataResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryContractMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/rewards/types/query.pb.gw.go b/x/rewards/types/query.pb.gw.go new file mode 100644 index 00000000..737de3e1 --- /dev/null +++ b/x/rewards/types/query.pb.gw.go @@ -0,0 +1,228 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: archway/rewards/v1beta1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_ContractMetadata_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_ContractMetadata_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractMetadataRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractMetadata_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ContractMetadata(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ContractMetadata_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractMetadataRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractMetadata_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ContractMetadata(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ContractMetadata_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ContractMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractMetadata_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ContractMetadata_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ContractMetadata_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_ContractMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "contract_metadata"}, "", runtime.AssumeColonVerbOpt(true))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_ContractMetadata_0 = runtime.ForwardResponseMessage +) diff --git a/x/rewards/types/rewards.go b/x/rewards/types/rewards.go new file mode 100644 index 00000000..8f0c49a8 --- /dev/null +++ b/x/rewards/types/rewards.go @@ -0,0 +1,25 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + "sigs.k8s.io/yaml" +) + +// Validate performs object fields validation. +func (m ContractMetadata) Validate() error { + if _, err := sdk.AccAddressFromBech32(m.OwnerAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid owner address") + } + if _, err := sdk.AccAddressFromBech32(m.RewardsAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid rewards address") + } + + return nil +} + +// String implements the fmt.Stringer interface. +func (m ContractMetadata) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} diff --git a/x/rewards/types/rewards.pb.go b/x/rewards/types/rewards.pb.go new file mode 100644 index 00000000..d68ead5a --- /dev/null +++ b/x/rewards/types/rewards.pb.go @@ -0,0 +1,638 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/rewards/v1beta1/rewards.proto + +package types + +import ( + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the module parameters. +type Params struct { + // rewards_enabled flag indicates whether rewards calculation and distribution is enabled. + RewardsEnabled bool `protobuf:"varint,1,opt,name=rewards_enabled,json=rewardsEnabled,proto3" json:"rewards_enabled,omitempty"` + InflationRewardsRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=inflation_rewards_ratio,json=inflationRewardsRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation_rewards_ratio"` + TxFeeRebateRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=tx_fee_rebate_ratio,json=txFeeRebateRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"tx_fee_rebate_ratio"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_50f478faffe74434, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetRewardsEnabled() bool { + if m != nil { + return m.RewardsEnabled + } + return false +} + +// ContractMetadata defines the contract rewards distribution options. +type ContractMetadata struct { + // owner_address is the contract owner address that can modify contract reward options (bech32 encoded). + OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` + // rewards_address is an address to distribute rewards to (bech32 encoded). + RewardsAddress string `protobuf:"bytes,2,opt,name=rewards_address,json=rewardsAddress,proto3" json:"rewards_address,omitempty"` +} + +func (m *ContractMetadata) Reset() { *m = ContractMetadata{} } +func (*ContractMetadata) ProtoMessage() {} +func (*ContractMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_50f478faffe74434, []int{1} +} +func (m *ContractMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContractMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractMetadata.Merge(m, src) +} +func (m *ContractMetadata) XXX_Size() int { + return m.Size() +} +func (m *ContractMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_ContractMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractMetadata proto.InternalMessageInfo + +func (m *ContractMetadata) GetOwnerAddress() string { + if m != nil { + return m.OwnerAddress + } + return "" +} + +func (m *ContractMetadata) GetRewardsAddress() string { + if m != nil { + return m.RewardsAddress + } + return "" +} + +func init() { + proto.RegisterType((*Params)(nil), "archway.rewards.v1beta1.Params") + proto.RegisterType((*ContractMetadata)(nil), "archway.rewards.v1beta1.ContractMetadata") +} + +func init() { + proto.RegisterFile("archway/rewards/v1beta1/rewards.proto", fileDescriptor_50f478faffe74434) +} + +var fileDescriptor_50f478faffe74434 = []byte{ + // 344 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0xcf, 0x4e, 0xc2, 0x40, + 0x10, 0xc6, 0xbb, 0x6a, 0x88, 0x6c, 0xfc, 0x43, 0xaa, 0x06, 0xe2, 0xa1, 0x10, 0x8c, 0xca, 0x85, + 0x36, 0xe8, 0xcd, 0x9b, 0xf8, 0xe7, 0xa4, 0x89, 0xe9, 0xd1, 0xc4, 0x34, 0xd3, 0x76, 0x0a, 0x04, + 0xe8, 0x92, 0xdd, 0xd5, 0xc2, 0x5b, 0x78, 0xf4, 0xe8, 0xe3, 0x70, 0xe4, 0x68, 0x3c, 0x10, 0x03, + 0xef, 0x61, 0x0c, 0xdb, 0x6d, 0xc3, 0xd9, 0xd3, 0xee, 0xf7, 0xe5, 0x37, 0xdf, 0x64, 0x66, 0xe8, + 0x29, 0xf0, 0xa0, 0x9b, 0xc0, 0xc4, 0xe1, 0x98, 0x00, 0x0f, 0x85, 0xf3, 0xd6, 0xf2, 0x51, 0x42, + 0x2b, 0xd3, 0xf6, 0x88, 0x33, 0xc9, 0xcc, 0xb2, 0xc6, 0xec, 0xcc, 0xd6, 0xd8, 0xf1, 0x61, 0x87, + 0x75, 0x98, 0x62, 0x9c, 0xd5, 0x2f, 0xc5, 0xeb, 0xbf, 0x84, 0x16, 0x9e, 0x80, 0xc3, 0x50, 0x98, + 0xe7, 0x74, 0x5f, 0xd7, 0x78, 0x18, 0x83, 0x3f, 0xc0, 0xb0, 0x42, 0x6a, 0xa4, 0xb1, 0xed, 0xee, + 0x69, 0xfb, 0x2e, 0x75, 0xcd, 0x88, 0x96, 0x7b, 0x71, 0x34, 0x00, 0xd9, 0x63, 0xb1, 0x97, 0x95, + 0xf0, 0x95, 0xac, 0x6c, 0xd4, 0x48, 0xa3, 0xd8, 0xb6, 0xa7, 0xf3, 0xaa, 0xf1, 0x3d, 0xaf, 0x9e, + 0x75, 0x7a, 0xb2, 0xfb, 0xea, 0xdb, 0x01, 0x1b, 0x3a, 0x01, 0x13, 0x43, 0x26, 0xf4, 0xd3, 0x14, + 0x61, 0xdf, 0x91, 0x93, 0x11, 0x0a, 0xfb, 0x16, 0x03, 0xf7, 0x28, 0x8f, 0x73, 0xd3, 0x34, 0x77, + 0x25, 0xcc, 0x17, 0x7a, 0x20, 0xc7, 0x5e, 0x84, 0xe8, 0x71, 0xf4, 0x41, 0xa2, 0xee, 0xb1, 0xf9, + 0xaf, 0x1e, 0x25, 0x39, 0xbe, 0x47, 0x74, 0x55, 0x90, 0x8a, 0xbf, 0xda, 0xfa, 0xf8, 0xac, 0x1a, + 0xf5, 0x88, 0x96, 0x6e, 0x58, 0x2c, 0x39, 0x04, 0xf2, 0x11, 0x25, 0x84, 0x20, 0xc1, 0x3c, 0xa1, + 0xbb, 0x2c, 0x89, 0x91, 0x7b, 0x10, 0x86, 0x1c, 0x85, 0x50, 0x7b, 0x28, 0xba, 0x3b, 0xca, 0xbc, + 0x4e, 0xbd, 0xf5, 0x75, 0x65, 0x98, 0x9a, 0x3e, 0x5f, 0x97, 0x06, 0xd3, 0x3e, 0xed, 0x87, 0xe9, + 0xc2, 0x22, 0xb3, 0x85, 0x45, 0x7e, 0x16, 0x16, 0x79, 0x5f, 0x5a, 0xc6, 0x6c, 0x69, 0x19, 0x5f, + 0x4b, 0xcb, 0x78, 0xbe, 0x58, 0x9b, 0x40, 0x1f, 0xaf, 0x19, 0xa3, 0x4c, 0x18, 0xef, 0x67, 0xda, + 0x19, 0xe7, 0x57, 0x57, 0x13, 0xf9, 0x05, 0x75, 0xbd, 0xcb, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x95, 0x22, 0x66, 0x3b, 0x15, 0x02, 0x00, 0x00, +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.TxFeeRebateRatio.Size() + i -= size + if _, err := m.TxFeeRebateRatio.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + { + size := m.InflationRewardsRatio.Size() + i -= size + if _, err := m.InflationRewardsRatio.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.RewardsEnabled { + i-- + if m.RewardsEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ContractMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RewardsAddress) > 0 { + i -= len(m.RewardsAddress) + copy(dAtA[i:], m.RewardsAddress) + i = encodeVarintRewards(dAtA, i, uint64(len(m.RewardsAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.OwnerAddress) > 0 { + i -= len(m.OwnerAddress) + copy(dAtA[i:], m.OwnerAddress) + i = encodeVarintRewards(dAtA, i, uint64(len(m.OwnerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintRewards(dAtA []byte, offset int, v uint64) int { + offset -= sovRewards(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.RewardsEnabled { + n += 2 + } + l = m.InflationRewardsRatio.Size() + n += 1 + l + sovRewards(uint64(l)) + l = m.TxFeeRebateRatio.Size() + n += 1 + l + sovRewards(uint64(l)) + return n +} + +func (m *ContractMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OwnerAddress) + if l > 0 { + n += 1 + l + sovRewards(uint64(l)) + } + l = len(m.RewardsAddress) + if l > 0 { + n += 1 + l + sovRewards(uint64(l)) + } + return n +} + +func sovRewards(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRewards(x uint64) (n int) { + return sovRewards(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardsEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.RewardsEnabled = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationRewardsRatio", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationRewardsRatio.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxFeeRebateRatio", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TxFeeRebateRatio.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OwnerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardsAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardsAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipRewards(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRewards + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRewards + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowRewards + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthRewards + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupRewards + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthRewards + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthRewards = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowRewards = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupRewards = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/rewards/types/tx.pb.go b/x/rewards/types/tx.pb.go new file mode 100644 index 00000000..23589020 --- /dev/null +++ b/x/rewards/types/tx.pb.go @@ -0,0 +1,641 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/rewards/v1beta1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSetContractMetadata is the request for Msg.SetContractMetadata. +type MsgSetContractMetadata struct { + // sender_address is the msg sender address (bech32 encoded). + SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` + // contract_address is the target contract address (bech32 encoded). + ContractAddress string `protobuf:"bytes,2,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // metadata is the contract metadata to set / update. + Metadata ContractMetadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata"` +} + +func (m *MsgSetContractMetadata) Reset() { *m = MsgSetContractMetadata{} } +func (m *MsgSetContractMetadata) String() string { return proto.CompactTextString(m) } +func (*MsgSetContractMetadata) ProtoMessage() {} +func (*MsgSetContractMetadata) Descriptor() ([]byte, []int) { + return fileDescriptor_cda0f3b1281e62e0, []int{0} +} +func (m *MsgSetContractMetadata) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetContractMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetContractMetadata.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetContractMetadata) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetContractMetadata.Merge(m, src) +} +func (m *MsgSetContractMetadata) XXX_Size() int { + return m.Size() +} +func (m *MsgSetContractMetadata) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetContractMetadata.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetContractMetadata proto.InternalMessageInfo + +func (m *MsgSetContractMetadata) GetSenderAddress() string { + if m != nil { + return m.SenderAddress + } + return "" +} + +func (m *MsgSetContractMetadata) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *MsgSetContractMetadata) GetMetadata() ContractMetadata { + if m != nil { + return m.Metadata + } + return ContractMetadata{} +} + +// MsgSetContractMetadataResponse is the response for Msg.SetContractMetadata. +type MsgSetContractMetadataResponse struct { +} + +func (m *MsgSetContractMetadataResponse) Reset() { *m = MsgSetContractMetadataResponse{} } +func (m *MsgSetContractMetadataResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSetContractMetadataResponse) ProtoMessage() {} +func (*MsgSetContractMetadataResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_cda0f3b1281e62e0, []int{1} +} +func (m *MsgSetContractMetadataResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSetContractMetadataResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSetContractMetadataResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSetContractMetadataResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSetContractMetadataResponse.Merge(m, src) +} +func (m *MsgSetContractMetadataResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSetContractMetadataResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSetContractMetadataResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSetContractMetadataResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgSetContractMetadata)(nil), "archway.rewards.v1beta1.MsgSetContractMetadata") + proto.RegisterType((*MsgSetContractMetadataResponse)(nil), "archway.rewards.v1beta1.MsgSetContractMetadataResponse") +} + +func init() { proto.RegisterFile("archway/rewards/v1beta1/tx.proto", fileDescriptor_cda0f3b1281e62e0) } + +var fileDescriptor_cda0f3b1281e62e0 = []byte{ + // 303 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0x2c, 0x4a, 0xce, + 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x4a, 0x2d, 0x4f, 0x2c, 0x4a, 0x29, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, + 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x87, 0xaa, + 0xd0, 0x83, 0xaa, 0xd0, 0x83, 0xaa, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, 0xd1, 0x07, + 0xb1, 0x20, 0xca, 0xa5, 0x54, 0x71, 0x19, 0x08, 0xd3, 0x0e, 0x56, 0xa6, 0xb4, 0x9d, 0x91, 0x4b, + 0xcc, 0xb7, 0x38, 0x3d, 0x38, 0xb5, 0xc4, 0x39, 0x3f, 0xaf, 0xa4, 0x28, 0x31, 0xb9, 0xc4, 0x37, + 0xb5, 0x24, 0x31, 0x25, 0xb1, 0x24, 0x51, 0x48, 0x95, 0x8b, 0xaf, 0x38, 0x35, 0x2f, 0x25, 0xb5, + 0x28, 0x3e, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x58, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x88, + 0x17, 0x22, 0xea, 0x08, 0x11, 0x14, 0xd2, 0xe4, 0x12, 0x48, 0x86, 0x6a, 0x85, 0x2b, 0x64, 0x02, + 0x2b, 0xe4, 0x87, 0x89, 0xc3, 0x94, 0x7a, 0x73, 0x71, 0xe4, 0x42, 0x4d, 0x97, 0x60, 0x56, 0x60, + 0xd4, 0xe0, 0x36, 0xd2, 0xd4, 0xc3, 0xe1, 0x2b, 0x3d, 0x74, 0xe7, 0x38, 0xb1, 0x9c, 0xb8, 0x27, + 0xcf, 0x10, 0x04, 0x37, 0x40, 0x49, 0x81, 0x4b, 0x0e, 0xbb, 0xc3, 0x83, 0x52, 0x8b, 0x0b, 0xf2, + 0xf3, 0x8a, 0x53, 0x8d, 0xda, 0x18, 0xb9, 0x98, 0x7d, 0x8b, 0xd3, 0x85, 0xea, 0xb9, 0x84, 0xb1, + 0xf9, 0x4f, 0x1f, 0xa7, 0xdd, 0xd8, 0xcd, 0x95, 0x32, 0x27, 0x51, 0x03, 0xcc, 0x21, 0x4e, 0x3e, + 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, + 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x94, 0x9e, 0x59, 0x92, 0x51, + 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0x35, 0x5c, 0x37, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, + 0x1b, 0xc6, 0xd7, 0xaf, 0x80, 0x47, 0x61, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x38, 0xe6, + 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x07, 0x6d, 0x7d, 0xff, 0x33, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // SetContractMetadata creates or updates an existing contract metadata. + // Method is authorized to the contract owner (admin if no metadata exists). + SetContractMetadata(ctx context.Context, in *MsgSetContractMetadata, opts ...grpc.CallOption) (*MsgSetContractMetadataResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) SetContractMetadata(ctx context.Context, in *MsgSetContractMetadata, opts ...grpc.CallOption) (*MsgSetContractMetadataResponse, error) { + out := new(MsgSetContractMetadataResponse) + err := c.cc.Invoke(ctx, "/archway.rewards.v1beta1.Msg/SetContractMetadata", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // SetContractMetadata creates or updates an existing contract metadata. + // Method is authorized to the contract owner (admin if no metadata exists). + SetContractMetadata(context.Context, *MsgSetContractMetadata) (*MsgSetContractMetadataResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) SetContractMetadata(ctx context.Context, req *MsgSetContractMetadata) (*MsgSetContractMetadataResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetContractMetadata not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_SetContractMetadata_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSetContractMetadata) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SetContractMetadata(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.rewards.v1beta1.Msg/SetContractMetadata", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SetContractMetadata(ctx, req.(*MsgSetContractMetadata)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "archway.rewards.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SetContractMetadata", + Handler: _Msg_SetContractMetadata_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "archway/rewards/v1beta1/tx.proto", +} + +func (m *MsgSetContractMetadata) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetContractMetadata) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.SenderAddress) > 0 { + i -= len(m.SenderAddress) + copy(dAtA[i:], m.SenderAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.SenderAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSetContractMetadataResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSetContractMetadataResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSetContractMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSetContractMetadata) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SenderAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgSetContractMetadataResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSetContractMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetContractMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetContractMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SenderAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SenderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSetContractMetadataResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSetContractMetadataResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSetContractMetadataResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/tracking/keeper/grpc_query.go b/x/tracking/keeper/grpc_query.go index ec99da72..02168b8a 100644 --- a/x/tracking/keeper/grpc_query.go +++ b/x/tracking/keeper/grpc_query.go @@ -42,22 +42,9 @@ func (s *QueryServer) BlockGasTracking(c context.Context, request *types.QueryBl } ctx := sdk.UnwrapSDKContext(c) - txState := s.keeper.state.TxInfoState(ctx) - contractOpState := s.keeper.state.ContractOpInfoState(ctx) - - var response types.QueryBlockGasTrackingResponse - - txInfos := txState.GetTxInfosByBlock(ctx.BlockHeight()) - response.Txs = make([]types.TxTracking, 0, len(txInfos)) - for _, txInfo := range txInfos { - response.Txs = append( - response.Txs, - types.TxTracking{ - Info: txInfo, - ContractOperations: contractOpState.GetContractOpInfoByTxID(txInfo.Id), - }, - ) - } + blockInfo := s.keeper.GetBlockTrackingInfo(ctx, ctx.BlockHeight()) - return &response, nil + return &types.QueryBlockGasTrackingResponse{ + Block: blockInfo, + }, nil } diff --git a/x/tracking/keeper/keeper.go b/x/tracking/keeper/keeper.go index 0ba179e7..62f83470 100644 --- a/x/tracking/keeper/keeper.go +++ b/x/tracking/keeper/keeper.go @@ -61,3 +61,25 @@ func (k Keeper) FinalizeBlockTxTracking(ctx sdk.Context) { txState.SetTxInfo(txInfo) } } + +// GetBlockTrackingInfo returns block gas tracking info containing all transactions and contract operations. +func (k Keeper) GetBlockTrackingInfo(ctx sdk.Context, height int64) types.BlockTracking { + txState := k.state.TxInfoState(ctx) + contractOpState := k.state.ContractOpInfoState(ctx) + + var resp types.BlockTracking + + txInfos := txState.GetTxInfosByBlock(height) + resp.Txs = make([]types.TxTracking, 0, len(txInfos)) + for _, txInfo := range txInfos { + contractOps := contractOpState.GetContractOpInfoByTxID(txInfo.Id) + resp.Txs = append( + resp.Txs, types.TxTracking{ + Info: txInfo, + ContractOperations: contractOps, + }, + ) + } + + return resp +} diff --git a/x/tracking/types/genesis.pb.go b/x/tracking/types/genesis.pb.go index 2a8af993..9e93964e 100644 --- a/x/tracking/types/genesis.pb.go +++ b/x/tracking/types/genesis.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: archway/tracking/v1/genesis.proto +// source: archway/tracking/v1beta1/genesis.proto package types @@ -37,7 +37,7 @@ func (m *GenesisState) Reset() { *m = GenesisState{} } func (m *GenesisState) String() string { return proto.CompactTextString(m) } func (*GenesisState) ProtoMessage() {} func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_3734e87d4a484a58, []int{0} + return fileDescriptor_40f994a880eb2f25, []int{0} } func (m *GenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -88,31 +88,33 @@ func (m *GenesisState) GetContractOpInfos() []ContractOperationInfo { } func init() { - proto.RegisterType((*GenesisState)(nil), "archway.tracking.v1.GenesisState") + proto.RegisterType((*GenesisState)(nil), "archway.tracking.v1beta1.GenesisState") } -func init() { proto.RegisterFile("archway/tracking/v1/genesis.proto", fileDescriptor_3734e87d4a484a58) } +func init() { + proto.RegisterFile("archway/tracking/v1beta1/genesis.proto", fileDescriptor_40f994a880eb2f25) +} -var fileDescriptor_3734e87d4a484a58 = []byte{ - // 278 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4c, 0x2c, 0x4a, 0xce, - 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x29, 0x4a, 0x4c, 0xce, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x33, 0xd4, - 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x86, - 0x2a, 0xd1, 0x83, 0x29, 0xd1, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xcb, 0xeb, - 0x83, 0x58, 0x10, 0xa5, 0x52, 0x4a, 0xd8, 0x4c, 0x83, 0x6b, 0x03, 0xab, 0x51, 0x7a, 0xca, 0xc8, - 0xc5, 0xe3, 0x0e, 0xb1, 0x20, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x92, 0x8b, 0xad, 0x20, 0xb1, - 0x28, 0x31, 0xb7, 0x58, 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x5a, 0x0f, 0x8b, 0x85, 0x7a, - 0x01, 0x60, 0x25, 0x4e, 0x2c, 0x27, 0xee, 0xc9, 0x33, 0x04, 0x41, 0x35, 0x08, 0xd9, 0x70, 0x71, - 0x94, 0x54, 0xc4, 0x67, 0xe6, 0xa5, 0xe5, 0x17, 0x4b, 0x30, 0x29, 0x30, 0xe3, 0xd4, 0x1c, 0x52, - 0xe1, 0x99, 0x97, 0x96, 0x0f, 0xd5, 0xcc, 0x5e, 0x02, 0xe6, 0x15, 0x0b, 0xc5, 0x70, 0x09, 0x26, - 0xe7, 0xe7, 0x81, 0xd4, 0x95, 0xc4, 0xe7, 0x17, 0x40, 0x8d, 0x61, 0x06, 0x1b, 0xa3, 0x85, 0xd5, - 0x18, 0x67, 0xa8, 0x6a, 0xff, 0x82, 0xd4, 0xa2, 0xc4, 0x92, 0xcc, 0xfc, 0x3c, 0x24, 0x53, 0xf9, - 0x93, 0xe1, 0x92, 0x60, 0xd3, 0x9d, 0x7c, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, - 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, - 0x21, 0xca, 0x38, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x6a, 0x8d, - 0x6e, 0x5e, 0x6a, 0x49, 0x79, 0x7e, 0x51, 0x36, 0x8c, 0xaf, 0x5f, 0x81, 0x08, 0xc2, 0x92, 0xca, - 0x82, 0xd4, 0xe2, 0x24, 0x36, 0x70, 0xe8, 0x19, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x15, 0x76, - 0x2d, 0x8e, 0xb1, 0x01, 0x00, 0x00, +var fileDescriptor_40f994a880eb2f25 = []byte{ + // 283 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4b, 0x2c, 0x4a, 0xce, + 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x29, 0x4a, 0x4c, 0xce, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x33, 0x4c, + 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0x92, 0x80, 0xaa, 0xd3, 0x83, 0xa9, 0xd3, 0x83, 0xaa, 0x93, 0x12, 0x49, 0xcf, + 0x4f, 0xcf, 0x07, 0x2b, 0xd2, 0x07, 0xb1, 0x20, 0xea, 0xa5, 0xd4, 0x71, 0x9a, 0x0b, 0x37, 0x00, + 0xac, 0x50, 0xe9, 0x0b, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xaa, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, + 0x3b, 0x2e, 0xb6, 0x82, 0xc4, 0xa2, 0xc4, 0xdc, 0x62, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, + 0x05, 0x3d, 0x5c, 0x56, 0xeb, 0x05, 0x80, 0xd5, 0x39, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, + 0xd5, 0x25, 0xe4, 0xc8, 0xc5, 0x51, 0x52, 0x11, 0x9f, 0x99, 0x97, 0x96, 0x5f, 0x2c, 0xc1, 0xa4, + 0xc0, 0x8c, 0xdf, 0x84, 0x90, 0x0a, 0xcf, 0xbc, 0xb4, 0x7c, 0xa8, 0x09, 0xec, 0x25, 0x60, 0x5e, + 0xb1, 0x50, 0x22, 0x97, 0x60, 0x72, 0x7e, 0x1e, 0x48, 0x71, 0x49, 0x7c, 0x7e, 0x01, 0xd4, 0x2c, + 0x66, 0xb0, 0x59, 0xfa, 0xb8, 0xcd, 0x72, 0x86, 0x6a, 0xf1, 0x2f, 0x48, 0x2d, 0x4a, 0x2c, 0xc9, + 0xcc, 0xcf, 0x43, 0x32, 0x9a, 0x3f, 0x19, 0x2e, 0x09, 0xb6, 0xc2, 0xc9, 0xf7, 0xc4, 0x23, 0x39, + 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, + 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x8c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, + 0xf3, 0x73, 0xf5, 0xa1, 0x76, 0xe9, 0xe6, 0xa5, 0x96, 0x94, 0xe7, 0x17, 0x65, 0xc3, 0xf8, 0xfa, + 0x15, 0x88, 0x60, 0x2d, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, 0x07, 0xa6, 0x31, 0x20, 0x00, + 0x00, 0xff, 0xff, 0x84, 0xcc, 0x33, 0x99, 0xcf, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/tracking/types/params.go b/x/tracking/types/params.go index 7c1796f4..fd64f133 100644 --- a/x/tracking/types/params.go +++ b/x/tracking/types/params.go @@ -58,8 +58,7 @@ func validateGasTrackingEnabled(v interface{}) (retErr error) { } }() - v, ok := v.(bool) - if !ok { + if _, ok := v.(bool); !ok { return fmt.Errorf("invalid parameter type: %T", v) } diff --git a/x/tracking/types/query.pb.go b/x/tracking/types/query.pb.go index b533020d..4bae19ba 100644 --- a/x/tracking/types/query.pb.go +++ b/x/tracking/types/query.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: archway/tracking/v1/query.proto +// source: archway/tracking/v1beta1/query.proto package types @@ -37,7 +37,7 @@ func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } func (*QueryParamsRequest) ProtoMessage() {} func (*QueryParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65deeabf437120fa, []int{0} + return fileDescriptor_f4819b1e6d461893, []int{0} } func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -75,7 +75,7 @@ func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } func (*QueryParamsResponse) ProtoMessage() {} func (*QueryParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65deeabf437120fa, []int{1} + return fileDescriptor_f4819b1e6d461893, []int{1} } func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -119,7 +119,7 @@ func (m *QueryBlockGasTrackingRequest) Reset() { *m = QueryBlockGasTrack func (m *QueryBlockGasTrackingRequest) String() string { return proto.CompactTextString(m) } func (*QueryBlockGasTrackingRequest) ProtoMessage() {} func (*QueryBlockGasTrackingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_65deeabf437120fa, []int{2} + return fileDescriptor_f4819b1e6d461893, []int{2} } func (m *QueryBlockGasTrackingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -150,14 +150,14 @@ var xxx_messageInfo_QueryBlockGasTrackingRequest proto.InternalMessageInfo // QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. type QueryBlockGasTrackingResponse struct { - Txs []TxTracking `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs"` + Block BlockTracking `protobuf:"bytes,1,opt,name=block,proto3" json:"block"` } func (m *QueryBlockGasTrackingResponse) Reset() { *m = QueryBlockGasTrackingResponse{} } func (m *QueryBlockGasTrackingResponse) String() string { return proto.CompactTextString(m) } func (*QueryBlockGasTrackingResponse) ProtoMessage() {} func (*QueryBlockGasTrackingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_65deeabf437120fa, []int{3} + return fileDescriptor_f4819b1e6d461893, []int{3} } func (m *QueryBlockGasTrackingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -186,107 +186,50 @@ func (m *QueryBlockGasTrackingResponse) XXX_DiscardUnknown() { var xxx_messageInfo_QueryBlockGasTrackingResponse proto.InternalMessageInfo -func (m *QueryBlockGasTrackingResponse) GetTxs() []TxTracking { +func (m *QueryBlockGasTrackingResponse) GetBlock() BlockTracking { if m != nil { - return m.Txs + return m.Block } - return nil -} - -// TxTracking is the tracking information for a transaction used by the Query.BlockGasTracking query. -type TxTracking struct { - // info defines the transaction details. - Info TxInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` - // contract_operations defines contract operations consumed by the transaction. - ContractOperations []ContractOperationInfo `protobuf:"bytes,2,rep,name=contract_operations,json=contractOperations,proto3" json:"contract_operations"` -} - -func (m *TxTracking) Reset() { *m = TxTracking{} } -func (*TxTracking) ProtoMessage() {} -func (*TxTracking) Descriptor() ([]byte, []int) { - return fileDescriptor_65deeabf437120fa, []int{4} -} -func (m *TxTracking) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *TxTracking) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_TxTracking.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *TxTracking) XXX_Merge(src proto.Message) { - xxx_messageInfo_TxTracking.Merge(m, src) -} -func (m *TxTracking) XXX_Size() int { - return m.Size() -} -func (m *TxTracking) XXX_DiscardUnknown() { - xxx_messageInfo_TxTracking.DiscardUnknown(m) -} - -var xxx_messageInfo_TxTracking proto.InternalMessageInfo - -func (m *TxTracking) GetInfo() TxInfo { - if m != nil { - return m.Info - } - return TxInfo{} -} - -func (m *TxTracking) GetContractOperations() []ContractOperationInfo { - if m != nil { - return m.ContractOperations - } - return nil + return BlockTracking{} } func init() { - proto.RegisterType((*QueryParamsRequest)(nil), "archway.tracking.v1.QueryParamsRequest") - proto.RegisterType((*QueryParamsResponse)(nil), "archway.tracking.v1.QueryParamsResponse") - proto.RegisterType((*QueryBlockGasTrackingRequest)(nil), "archway.tracking.v1.QueryBlockGasTrackingRequest") - proto.RegisterType((*QueryBlockGasTrackingResponse)(nil), "archway.tracking.v1.QueryBlockGasTrackingResponse") - proto.RegisterType((*TxTracking)(nil), "archway.tracking.v1.TxTracking") + proto.RegisterType((*QueryParamsRequest)(nil), "archway.tracking.v1beta1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "archway.tracking.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryBlockGasTrackingRequest)(nil), "archway.tracking.v1beta1.QueryBlockGasTrackingRequest") + proto.RegisterType((*QueryBlockGasTrackingResponse)(nil), "archway.tracking.v1beta1.QueryBlockGasTrackingResponse") } -func init() { proto.RegisterFile("archway/tracking/v1/query.proto", fileDescriptor_65deeabf437120fa) } - -var fileDescriptor_65deeabf437120fa = []byte{ - // 443 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x3f, 0x6f, 0xd3, 0x40, - 0x14, 0xf7, 0xa5, 0x21, 0xc3, 0x75, 0x41, 0x97, 0x0e, 0x95, 0xdb, 0xda, 0xc8, 0x0c, 0x0d, 0x48, - 0xf8, 0x14, 0x57, 0x08, 0xc1, 0x18, 0x06, 0xc4, 0x80, 0x28, 0x55, 0x06, 0xc4, 0x12, 0x5d, 0xac, - 0xab, 0x6b, 0xa5, 0xbd, 0xe7, 0xfa, 0x2e, 0xad, 0xb3, 0x21, 0x3e, 0x01, 0x12, 0x0b, 0x23, 0x33, - 0x62, 0xe7, 0x2b, 0x64, 0x8c, 0xc4, 0xc2, 0x84, 0x50, 0xc2, 0x07, 0x41, 0xbe, 0x3b, 0x27, 0x10, - 0x1c, 0x10, 0x9b, 0xf5, 0x7e, 0x7f, 0xfd, 0x9e, 0x8d, 0x7d, 0x96, 0xc7, 0x67, 0xd7, 0x6c, 0x42, - 0x55, 0xce, 0xe2, 0x51, 0x2a, 0x12, 0x7a, 0xd5, 0xa5, 0x97, 0x63, 0x9e, 0x4f, 0xc2, 0x2c, 0x07, - 0x05, 0xa4, 0x6d, 0x09, 0x61, 0x45, 0x08, 0xaf, 0xba, 0xee, 0x4e, 0x02, 0x09, 0x68, 0x9c, 0x96, - 0x4f, 0x86, 0xea, 0x06, 0x75, 0x5e, 0x4b, 0x99, 0xe1, 0xec, 0x27, 0x00, 0xc9, 0x39, 0xa7, 0x2c, - 0x4b, 0x29, 0x13, 0x02, 0x14, 0x53, 0x29, 0x08, 0x69, 0xd0, 0x60, 0x07, 0x93, 0x17, 0x65, 0xf6, - 0x31, 0xcb, 0xd9, 0x85, 0x3c, 0xe1, 0x97, 0x63, 0x2e, 0x55, 0x70, 0x8c, 0xdb, 0xbf, 0x4d, 0x65, - 0x06, 0x42, 0x72, 0xf2, 0x10, 0xb7, 0x32, 0x3d, 0xd9, 0x45, 0xb7, 0x50, 0x67, 0x3b, 0xda, 0x0b, - 0x6b, 0xaa, 0x86, 0x46, 0xd4, 0x6b, 0x4e, 0xbf, 0xf9, 0xce, 0x89, 0x15, 0x04, 0x1e, 0xde, 0xd7, - 0x8e, 0xbd, 0x73, 0x88, 0x47, 0x4f, 0x98, 0xec, 0x5b, 0x41, 0x95, 0xf8, 0x12, 0x1f, 0x6c, 0xc0, - 0x6d, 0xf6, 0x03, 0xbc, 0xa5, 0x8a, 0x32, 0x78, 0xab, 0xb3, 0x1d, 0xf9, 0xb5, 0xc1, 0xfd, 0xa2, - 0x52, 0xd9, 0xf0, 0x52, 0x11, 0x7c, 0x42, 0x18, 0xaf, 0x10, 0x72, 0x1f, 0x37, 0x53, 0x71, 0x0a, - 0x7f, 0x7d, 0x83, 0x7e, 0xf1, 0x54, 0x9c, 0x82, 0x35, 0xd1, 0x74, 0xc2, 0x70, 0x3b, 0x06, 0x51, - 0x92, 0xd4, 0x00, 0x32, 0x9e, 0x9b, 0x25, 0xee, 0x36, 0x74, 0x9d, 0xbb, 0xb5, 0x2e, 0x8f, 0x2d, - 0xff, 0x79, 0x45, 0xff, 0xc5, 0x94, 0xc4, 0xeb, 0xa0, 0x7c, 0xd4, 0x7c, 0xff, 0xc1, 0x77, 0xa2, - 0xcf, 0x0d, 0x7c, 0x43, 0x6f, 0x82, 0xbc, 0x46, 0xb8, 0x65, 0x76, 0x49, 0x0e, 0x6b, 0x03, 0xfe, - 0x3c, 0x9c, 0xdb, 0xf9, 0x37, 0xd1, 0xec, 0x33, 0xb8, 0xfd, 0xe6, 0xcb, 0x8f, 0x77, 0x8d, 0x03, - 0xb2, 0x47, 0xeb, 0xbe, 0x21, 0x73, 0x35, 0xf2, 0x11, 0xe1, 0x9b, 0xeb, 0x17, 0x21, 0xdd, 0xcd, - 0x19, 0x1b, 0xae, 0xeb, 0x46, 0xff, 0x23, 0xb1, 0x05, 0xa9, 0x2e, 0x78, 0x87, 0x1c, 0xd6, 0x16, - 0x1c, 0x96, 0xb2, 0x41, 0xc2, 0xe4, 0xa0, 0x9a, 0xf6, 0x9e, 0x4d, 0xe7, 0x1e, 0x9a, 0xcd, 0x3d, - 0xf4, 0x7d, 0xee, 0xa1, 0xb7, 0x0b, 0xcf, 0x99, 0x2d, 0x3c, 0xe7, 0xeb, 0xc2, 0x73, 0x5e, 0x1d, - 0x25, 0xa9, 0x3a, 0x1b, 0x0f, 0xc3, 0x18, 0x2e, 0x2a, 0xb3, 0x7b, 0x82, 0xab, 0x6b, 0xc8, 0x47, - 0x4b, 0xf3, 0x62, 0x65, 0xaf, 0x26, 0x19, 0x97, 0xc3, 0x96, 0xfe, 0x41, 0x8e, 0x7e, 0x06, 0x00, - 0x00, 0xff, 0xff, 0xaf, 0x9d, 0x18, 0x90, 0xb0, 0x03, 0x00, 0x00, +func init() { + proto.RegisterFile("archway/tracking/v1beta1/query.proto", fileDescriptor_f4819b1e6d461893) +} + +var fileDescriptor_f4819b1e6d461893 = []byte{ + // 377 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x49, 0x2c, 0x4a, 0xce, + 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x29, 0x4a, 0x4c, 0xce, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x33, 0x4c, + 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, + 0x17, 0x92, 0x80, 0xaa, 0xd2, 0x83, 0xa9, 0xd2, 0x83, 0xaa, 0x92, 0x12, 0x49, 0xcf, 0x4f, 0xcf, + 0x07, 0x2b, 0xd2, 0x07, 0xb1, 0x20, 0xea, 0xa5, 0x64, 0xd2, 0xf3, 0xf3, 0xd3, 0x73, 0x52, 0xf5, + 0x13, 0x0b, 0x32, 0xf5, 0x13, 0xf3, 0xf2, 0xf2, 0x4b, 0x12, 0x4b, 0x32, 0xf3, 0xf3, 0x8a, 0xa1, + 0xb2, 0xea, 0x38, 0xed, 0x84, 0x1b, 0x0f, 0x56, 0xa8, 0x24, 0xc2, 0x25, 0x14, 0x08, 0x72, 0x45, + 0x40, 0x62, 0x51, 0x62, 0x6e, 0x71, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x52, 0x28, 0x97, + 0x30, 0x8a, 0x68, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x90, 0x1d, 0x17, 0x5b, 0x01, 0x58, 0x44, + 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x41, 0x0f, 0x97, 0xa3, 0xf5, 0x20, 0x3a, 0x9d, 0x58, + 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0xea, 0x52, 0x92, 0xe3, 0x92, 0x01, 0x1b, 0xeb, 0x94, 0x93, + 0x9f, 0x9c, 0xed, 0x9e, 0x58, 0x1c, 0x02, 0xd5, 0x05, 0xb3, 0x36, 0x85, 0x4b, 0x16, 0x87, 0x3c, + 0xd4, 0x01, 0xce, 0x5c, 0xac, 0x49, 0x20, 0x39, 0xa8, 0xfd, 0xea, 0xb8, 0xed, 0x07, 0x1b, 0x01, + 0xd3, 0x0f, 0x75, 0x06, 0x44, 0xaf, 0xd1, 0x69, 0x26, 0x2e, 0x56, 0xb0, 0x35, 0x42, 0x5d, 0x8c, + 0x5c, 0x6c, 0x10, 0x87, 0x0a, 0xe9, 0xe0, 0x36, 0x0a, 0x33, 0x7c, 0xa4, 0x74, 0x89, 0x54, 0x0d, + 0x71, 0xb6, 0x92, 0x72, 0xd3, 0xe5, 0x27, 0x93, 0x99, 0x64, 0x85, 0xa4, 0xf5, 0xb1, 0x44, 0x8b, + 0x3e, 0x24, 0x70, 0x84, 0xb6, 0x30, 0x72, 0x09, 0xa0, 0x7b, 0x5c, 0xc8, 0x8c, 0x80, 0x45, 0x38, + 0x42, 0x52, 0xca, 0x9c, 0x64, 0x7d, 0x50, 0xa7, 0xea, 0x83, 0x9d, 0xaa, 0x29, 0xa4, 0x8e, 0xd5, + 0xa9, 0xe0, 0x00, 0x8c, 0x4f, 0x4f, 0x2c, 0x8e, 0x87, 0x89, 0x3a, 0xf9, 0x9e, 0x78, 0x24, 0xc7, + 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, + 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x71, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, + 0x7e, 0x2e, 0xcc, 0x30, 0xdd, 0xbc, 0xd4, 0x92, 0xf2, 0xfc, 0xa2, 0x6c, 0xb8, 0xe1, 0x15, 0x08, + 0xe3, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xc9, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, + 0xff, 0x5b, 0xae, 0x35, 0x10, 0x35, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -317,7 +260,7 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { out := new(QueryParamsResponse) - err := c.cc.Invoke(ctx, "/archway.tracking.v1.Query/Params", in, out, opts...) + err := c.cc.Invoke(ctx, "/archway.tracking.v1beta1.Query/Params", in, out, opts...) if err != nil { return nil, err } @@ -326,7 +269,7 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . func (c *queryClient) BlockGasTracking(ctx context.Context, in *QueryBlockGasTrackingRequest, opts ...grpc.CallOption) (*QueryBlockGasTrackingResponse, error) { out := new(QueryBlockGasTrackingResponse) - err := c.cc.Invoke(ctx, "/archway.tracking.v1.Query/BlockGasTracking", in, out, opts...) + err := c.cc.Invoke(ctx, "/archway.tracking.v1beta1.Query/BlockGasTracking", in, out, opts...) if err != nil { return nil, err } @@ -366,7 +309,7 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/archway.tracking.v1.Query/Params", + FullMethod: "/archway.tracking.v1beta1.Query/Params", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) @@ -384,7 +327,7 @@ func _Query_BlockGasTracking_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/archway.tracking.v1.Query/BlockGasTracking", + FullMethod: "/archway.tracking.v1beta1.Query/BlockGasTracking", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).BlockGasTracking(ctx, req.(*QueryBlockGasTrackingRequest)) @@ -393,7 +336,7 @@ func _Query_BlockGasTracking_Handler(srv interface{}, ctx context.Context, dec f } var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "archway.tracking.v1.Query", + ServiceName: "archway.tracking.v1beta1.Query", HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ { @@ -406,7 +349,7 @@ var _Query_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "archway/tracking/v1/query.proto", + Metadata: "archway/tracking/v1beta1/query.proto", } func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { @@ -508,59 +451,8 @@ func (m *QueryBlockGasTrackingResponse) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l - if len(m.Txs) > 0 { - for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Txs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - -func (m *TxTracking) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *TxTracking) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *TxTracking) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.ContractOperations) > 0 { - for iNdEx := len(m.ContractOperations) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.ContractOperations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - } - } { - size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + size, err := m.Block.MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -618,29 +510,8 @@ func (m *QueryBlockGasTrackingResponse) Size() (n int) { } var l int _ = l - if len(m.Txs) > 0 { - for _, e := range m.Txs { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } - return n -} - -func (m *TxTracking) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Info.Size() + l = m.Block.Size() n += 1 + l + sovQuery(uint64(l)) - if len(m.ContractOperations) > 0 { - for _, e := range m.ContractOperations { - l = e.Size() - n += 1 + l + sovQuery(uint64(l)) - } - } return n } @@ -864,124 +735,7 @@ func (m *QueryBlockGasTrackingResponse) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Txs = append(m.Txs, TxTracking{}) - if err := m.Txs[len(m.Txs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *TxTracking) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TxTracking: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TxTracking: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractOperations", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Block", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1008,8 +762,7 @@ func (m *TxTracking) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ContractOperations = append(m.ContractOperations, ContractOperationInfo{}) - if err := m.ContractOperations[len(m.ContractOperations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/tracking/types/query.pb.gw.go b/x/tracking/types/query.pb.gw.go index 3960c775..73332f0a 100644 --- a/x/tracking/types/query.pb.gw.go +++ b/x/tracking/types/query.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: archway/tracking/v1/query.proto +// source: archway/tracking/v1beta1/query.proto /* Package types is a reverse proxy. diff --git a/x/tracking/types/tracking.go b/x/tracking/types/tracking.go index 3335f578..97bf2559 100644 --- a/x/tracking/types/tracking.go +++ b/x/tracking/types/tracking.go @@ -41,3 +41,9 @@ func (m ContractOperationInfo) Validate() error { return nil } + +// String implements the fmt.Stringer interface. +func (m BlockTracking) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} diff --git a/x/tracking/types/tracking.pb.go b/x/tracking/types/tracking.pb.go index 2bb36d45..19f254f0 100644 --- a/x/tracking/types/tracking.pb.go +++ b/x/tracking/types/tracking.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: archway/tracking/v1/tracking.proto +// source: archway/tracking/v1beta1/tracking.proto package types @@ -64,7 +64,7 @@ func (x ContractOperation) String() string { } func (ContractOperation) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_43be6db97c4ee6cb, []int{0} + return fileDescriptor_792f9386dd247ede, []int{0} } // Params defines the module parameters. @@ -76,7 +76,7 @@ type Params struct { func (m *Params) Reset() { *m = Params{} } func (*Params) ProtoMessage() {} func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_43be6db97c4ee6cb, []int{0} + return fileDescriptor_792f9386dd247ede, []int{0} } func (m *Params) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -127,7 +127,7 @@ type TxInfo struct { func (m *TxInfo) Reset() { *m = TxInfo{} } func (*TxInfo) ProtoMessage() {} func (*TxInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_43be6db97c4ee6cb, []int{1} + return fileDescriptor_792f9386dd247ede, []int{1} } func (m *TxInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -187,19 +187,19 @@ type ContractOperationInfo struct { // contract_address defines the contract address operation relates to. ContractAddress string `protobuf:"bytes,3,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` // operation_type defines the gas consumption type. - OperationType ContractOperation `protobuf:"varint,4,opt,name=operation_type,json=operationType,proto3,enum=archway.tracking.v1.ContractOperation" json:"operation_type,omitempty"` + OperationType ContractOperation `protobuf:"varint,4,opt,name=operation_type,json=operationType,proto3,enum=archway.tracking.v1beta1.ContractOperation" json:"operation_type,omitempty"` // vm_gas is the gas consumption reported by the WASM VM. // Value is adjusted by this module (CalculateUpdatedGas func). - VmGas uint64 `protobuf:"varint,5,opt,name=vm_gas,json=vmGas,proto3" json:"vm_gas,omitempty" yaml:"vm_gas"` + VmGas uint64 `protobuf:"varint,5,opt,name=vm_gas,json=vmGas,proto3" json:"vm_gas,omitempty"` // sdk_gas is the gas consumption reported by the SDK gas meter and the WASM GasRegister (cost of Execute/Query/etc). // Value is adjusted by this module (CalculateUpdatedGas func). - SdkGas uint64 `protobuf:"varint,6,opt,name=sdk_gas,json=sdkGas,proto3" json:"sdk_gas,omitempty" yaml:"sdk_gas"` + SdkGas uint64 `protobuf:"varint,6,opt,name=sdk_gas,json=sdkGas,proto3" json:"sdk_gas,omitempty"` } func (m *ContractOperationInfo) Reset() { *m = ContractOperationInfo{} } func (*ContractOperationInfo) ProtoMessage() {} func (*ContractOperationInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_43be6db97c4ee6cb, []int{2} + return fileDescriptor_792f9386dd247ede, []int{2} } func (m *ContractOperationInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -270,53 +270,158 @@ func (m *ContractOperationInfo) GetSdkGas() uint64 { return 0 } +// BlockTracking is the tracking information for a block. +type BlockTracking struct { + // txs defines the list of transactions tracked in the block. + Txs []TxTracking `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs"` +} + +func (m *BlockTracking) Reset() { *m = BlockTracking{} } +func (*BlockTracking) ProtoMessage() {} +func (*BlockTracking) Descriptor() ([]byte, []int) { + return fileDescriptor_792f9386dd247ede, []int{3} +} +func (m *BlockTracking) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockTracking) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockTracking.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockTracking) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockTracking.Merge(m, src) +} +func (m *BlockTracking) XXX_Size() int { + return m.Size() +} +func (m *BlockTracking) XXX_DiscardUnknown() { + xxx_messageInfo_BlockTracking.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockTracking proto.InternalMessageInfo + +func (m *BlockTracking) GetTxs() []TxTracking { + if m != nil { + return m.Txs + } + return nil +} + +// TxTracking is the tracking information for a single transaction. +type TxTracking struct { + // info defines the transaction details. + Info TxInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info"` + // contract_operations defines the list of contract operations consumed by the transaction. + ContractOperations []ContractOperationInfo `protobuf:"bytes,2,rep,name=contract_operations,json=contractOperations,proto3" json:"contract_operations"` +} + +func (m *TxTracking) Reset() { *m = TxTracking{} } +func (*TxTracking) ProtoMessage() {} +func (*TxTracking) Descriptor() ([]byte, []int) { + return fileDescriptor_792f9386dd247ede, []int{4} +} +func (m *TxTracking) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxTracking) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxTracking.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxTracking) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxTracking.Merge(m, src) +} +func (m *TxTracking) XXX_Size() int { + return m.Size() +} +func (m *TxTracking) XXX_DiscardUnknown() { + xxx_messageInfo_TxTracking.DiscardUnknown(m) +} + +var xxx_messageInfo_TxTracking proto.InternalMessageInfo + +func (m *TxTracking) GetInfo() TxInfo { + if m != nil { + return m.Info + } + return TxInfo{} +} + +func (m *TxTracking) GetContractOperations() []ContractOperationInfo { + if m != nil { + return m.ContractOperations + } + return nil +} + func init() { - proto.RegisterEnum("archway.tracking.v1.ContractOperation", ContractOperation_name, ContractOperation_value) - proto.RegisterType((*Params)(nil), "archway.tracking.v1.Params") - proto.RegisterType((*TxInfo)(nil), "archway.tracking.v1.TxInfo") - proto.RegisterType((*ContractOperationInfo)(nil), "archway.tracking.v1.ContractOperationInfo") + proto.RegisterEnum("archway.tracking.v1beta1.ContractOperation", ContractOperation_name, ContractOperation_value) + proto.RegisterType((*Params)(nil), "archway.tracking.v1beta1.Params") + proto.RegisterType((*TxInfo)(nil), "archway.tracking.v1beta1.TxInfo") + proto.RegisterType((*ContractOperationInfo)(nil), "archway.tracking.v1beta1.ContractOperationInfo") + proto.RegisterType((*BlockTracking)(nil), "archway.tracking.v1beta1.BlockTracking") + proto.RegisterType((*TxTracking)(nil), "archway.tracking.v1beta1.TxTracking") } func init() { - proto.RegisterFile("archway/tracking/v1/tracking.proto", fileDescriptor_43be6db97c4ee6cb) -} - -var fileDescriptor_43be6db97c4ee6cb = []byte{ - // 531 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0x4f, 0x6e, 0xda, 0x40, - 0x18, 0xc5, 0xb1, 0x63, 0x9c, 0xe4, 0x93, 0x42, 0x9d, 0x49, 0x9a, 0x22, 0x12, 0x19, 0x64, 0x55, - 0x15, 0x6d, 0x55, 0x68, 0x9a, 0x5d, 0x56, 0x05, 0xc7, 0x45, 0x96, 0xca, 0x9f, 0x0e, 0x46, 0x6a, - 0xba, 0xb1, 0x06, 0xec, 0x1a, 0x0b, 0xf0, 0x20, 0x7b, 0x4a, 0xe0, 0x16, 0x95, 0xda, 0x45, 0x97, - 0x3d, 0x4e, 0x97, 0x59, 0x76, 0x15, 0x55, 0x70, 0x83, 0x9c, 0xa0, 0x62, 0x6c, 0xe8, 0x22, 0xee, - 0x6e, 0xe6, 0xbd, 0xdf, 0xe7, 0xf7, 0x3c, 0xa3, 0x01, 0x8d, 0x84, 0x83, 0xe1, 0x0d, 0x59, 0x54, - 0x59, 0x48, 0x06, 0x23, 0x3f, 0xf0, 0xaa, 0xb3, 0xf3, 0xed, 0xba, 0x32, 0x0d, 0x29, 0xa3, 0xe8, - 0x28, 0x61, 0x2a, 0x5b, 0x7d, 0x76, 0x5e, 0x38, 0xf6, 0xa8, 0x47, 0xb9, 0x5f, 0x5d, 0xaf, 0x62, - 0x54, 0x7b, 0x0b, 0x72, 0x87, 0x84, 0x64, 0x12, 0xa1, 0xd7, 0x70, 0xec, 0x91, 0xc8, 0xde, 0x8c, - 0xd8, 0x6e, 0x40, 0xfa, 0x63, 0xd7, 0xc9, 0x0b, 0x25, 0xa1, 0xbc, 0x87, 0x91, 0x47, 0x22, 0x2b, - 0xb1, 0x8c, 0xd8, 0xb9, 0x94, 0x7e, 0xfc, 0x2c, 0x66, 0xb4, 0x2e, 0xc8, 0xd6, 0xdc, 0x0c, 0x3e, - 0x53, 0x94, 0x03, 0xd1, 0x8f, 0x79, 0x09, 0x8b, 0xbe, 0x83, 0x4e, 0x40, 0x1e, 0xba, 0xbe, 0x37, - 0x64, 0x79, 0xb1, 0x24, 0x94, 0x77, 0x70, 0xb2, 0x43, 0xa7, 0xb0, 0xcf, 0x28, 0x23, 0x63, 0xdb, - 0x23, 0x51, 0x7e, 0x87, 0xe3, 0x7b, 0x5c, 0x68, 0x90, 0x28, 0xf9, 0xe8, 0x37, 0x11, 0x1e, 0xeb, - 0x34, 0x58, 0x97, 0x61, 0xed, 0xa9, 0x1b, 0x12, 0xe6, 0xd3, 0x20, 0x35, 0xe4, 0x08, 0xb2, 0x6c, - 0x6e, 0xfb, 0x0e, 0xcf, 0x90, 0xb0, 0xc4, 0xe6, 0xa6, 0x83, 0x9e, 0x83, 0x32, 0x48, 0xa6, 0x6d, - 0xe2, 0x38, 0xa1, 0x1b, 0xc5, 0x41, 0xfb, 0xf8, 0xd1, 0x46, 0xaf, 0xc5, 0x32, 0x6a, 0x42, 0x8e, - 0x6e, 0x02, 0x6c, 0xb6, 0x98, 0xba, 0x79, 0xa9, 0x24, 0x94, 0x73, 0x6f, 0x9e, 0x55, 0x52, 0x0e, - 0xb1, 0xf2, 0xa0, 0x13, 0x3e, 0xd8, 0x4e, 0x5b, 0x8b, 0xa9, 0x8b, 0xca, 0x20, 0xcf, 0x26, 0xfc, - 0xc7, 0xb2, 0xeb, 0x3e, 0xf5, 0xc3, 0xfb, 0xbb, 0xe2, 0xc1, 0x82, 0x4c, 0xc6, 0x97, 0x5a, 0xac, - 0x6b, 0x38, 0x3b, 0x9b, 0x34, 0x48, 0x84, 0x5e, 0xc2, 0x6e, 0xe4, 0x8c, 0x38, 0x2a, 0x73, 0x14, - 0xdd, 0xdf, 0x15, 0x73, 0x31, 0x9a, 0x18, 0x1a, 0x96, 0x23, 0x67, 0xb4, 0x3d, 0x95, 0x17, 0xdf, - 0x45, 0x38, 0x7c, 0xd0, 0x00, 0x69, 0xa0, 0xea, 0xed, 0x96, 0x85, 0x6b, 0xba, 0x65, 0xb7, 0x3b, - 0x06, 0xae, 0x59, 0x66, 0xbb, 0x65, 0xf7, 0x5a, 0xdd, 0x8e, 0xa1, 0x9b, 0xef, 0x4c, 0xe3, 0x4a, - 0xc9, 0xa0, 0xa7, 0x50, 0x4a, 0x61, 0xcc, 0x56, 0xd7, 0xaa, 0xb5, 0x2c, 0x93, 0xef, 0x14, 0x01, - 0x95, 0xe0, 0x2c, 0x85, 0x32, 0x3e, 0x1a, 0x7a, 0x8f, 0x13, 0x22, 0x3a, 0x83, 0x7c, 0x0a, 0xf1, - 0xa1, 0x67, 0xe0, 0x6b, 0x65, 0x07, 0xa9, 0x50, 0x48, 0x71, 0x9b, 0x66, 0x03, 0xd7, 0x2c, 0x43, - 0x91, 0x50, 0x01, 0x4e, 0xd2, 0x5a, 0xd4, 0x75, 0x25, 0x8b, 0x4e, 0xe1, 0x49, 0x8a, 0xd7, 0xed, - 0x5d, 0xb5, 0x15, 0xf9, 0x3f, 0xb1, 0xd8, 0xe8, 0xbc, 0xbf, 0x56, 0x76, 0xeb, 0xcd, 0x5f, 0x4b, - 0x55, 0xb8, 0x5d, 0xaa, 0xc2, 0x9f, 0xa5, 0x2a, 0x7c, 0x5d, 0xa9, 0x99, 0xdb, 0x95, 0x9a, 0xf9, - 0xbd, 0x52, 0x33, 0x9f, 0x2e, 0x3c, 0x9f, 0x0d, 0xbf, 0xf4, 0x2b, 0x03, 0x3a, 0xa9, 0x26, 0xd7, - 0xf9, 0x2a, 0x70, 0xd9, 0x0d, 0x0d, 0x47, 0x9b, 0x7d, 0x75, 0xfe, 0xef, 0x25, 0xad, 0xaf, 0x3f, - 0xea, 0xcb, 0xfc, 0x65, 0x5c, 0xfc, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x0c, 0x2c, 0xc0, 0x6a, - 0x03, 0x00, 0x00, + proto.RegisterFile("archway/tracking/v1beta1/tracking.proto", fileDescriptor_792f9386dd247ede) +} + +var fileDescriptor_792f9386dd247ede = []byte{ + // 600 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcd, 0x4e, 0xdb, 0x40, + 0x18, 0x8c, 0x13, 0xc7, 0xc0, 0x87, 0xa0, 0xee, 0xf2, 0x67, 0x01, 0x32, 0x16, 0x42, 0x6a, 0xda, + 0xaa, 0x49, 0x81, 0x1b, 0xea, 0xa1, 0x49, 0x70, 0x91, 0xa5, 0x92, 0xa4, 0x1b, 0x47, 0x2a, 0xbd, + 0x58, 0x9b, 0xd8, 0x38, 0x56, 0x88, 0x37, 0xf2, 0x6e, 0xc1, 0xbc, 0x45, 0x0f, 0x3d, 0xf4, 0xd8, + 0xa7, 0xe8, 0x33, 0x70, 0xe4, 0xd8, 0x53, 0x55, 0xc1, 0x13, 0xf4, 0x0d, 0xaa, 0x6c, 0xec, 0x50, + 0x15, 0x53, 0xa9, 0xb7, 0xec, 0x7c, 0x33, 0xf3, 0xcd, 0x4e, 0xac, 0x85, 0x27, 0x24, 0xea, 0xf5, + 0x2f, 0xc8, 0x65, 0x85, 0x47, 0xa4, 0x37, 0x08, 0x42, 0xbf, 0x72, 0xbe, 0xdb, 0xf5, 0x38, 0xd9, + 0x9d, 0x02, 0xe5, 0x51, 0x44, 0x39, 0x45, 0x5a, 0x42, 0x2c, 0x4f, 0xf1, 0x84, 0xb8, 0xbe, 0xec, + 0x53, 0x9f, 0x0a, 0x52, 0x65, 0xfc, 0x6b, 0xc2, 0xdf, 0x7e, 0x0d, 0x4a, 0x8b, 0x44, 0x64, 0xc8, + 0xd0, 0x4b, 0x58, 0xf6, 0x09, 0x73, 0x52, 0x9d, 0xe3, 0x85, 0xa4, 0x7b, 0xe6, 0xb9, 0x9a, 0x64, + 0x48, 0xa5, 0x59, 0x8c, 0x7c, 0xc2, 0xec, 0x64, 0x64, 0x4e, 0x26, 0x07, 0xf2, 0x97, 0xaf, 0x5b, + 0xb9, 0xed, 0x36, 0x28, 0x76, 0x6c, 0x85, 0xa7, 0x14, 0x2d, 0x42, 0x3e, 0x98, 0xf0, 0x65, 0x9c, + 0x0f, 0x5c, 0xb4, 0x0a, 0x4a, 0xdf, 0x0b, 0xfc, 0x3e, 0xd7, 0xf2, 0x86, 0x54, 0x2a, 0xe0, 0xe4, + 0x84, 0x36, 0x60, 0x8e, 0x53, 0x4e, 0xce, 0x1c, 0x9f, 0x30, 0xad, 0x20, 0xe8, 0xb3, 0x02, 0x38, + 0x22, 0x2c, 0x31, 0xfd, 0x25, 0xc1, 0x4a, 0x9d, 0x86, 0xe3, 0x30, 0xbc, 0x39, 0xf2, 0x22, 0xc2, + 0x03, 0x1a, 0x66, 0x2e, 0x59, 0x82, 0x22, 0x8f, 0x9d, 0xc0, 0x15, 0x3b, 0x64, 0x2c, 0xf3, 0xd8, + 0x72, 0xd1, 0x53, 0x50, 0x7b, 0x89, 0xda, 0x21, 0xae, 0x1b, 0x79, 0x6c, 0xb2, 0x68, 0x0e, 0x3f, + 0x4a, 0xf1, 0xea, 0x04, 0x46, 0x18, 0x16, 0x69, 0xba, 0xc0, 0xe1, 0x97, 0x23, 0x4f, 0x93, 0x0d, + 0xa9, 0xb4, 0xb8, 0xf7, 0xbc, 0xfc, 0x50, 0x93, 0xe5, 0x7b, 0xc1, 0xf0, 0xc2, 0xd4, 0xc2, 0xbe, + 0x1c, 0x79, 0x68, 0x05, 0x94, 0xf3, 0xa1, 0xb8, 0x5d, 0x51, 0x84, 0x2a, 0x9e, 0x0f, 0x8f, 0x08, + 0x43, 0x6b, 0x30, 0xc3, 0xdc, 0x81, 0xc0, 0x15, 0x81, 0x2b, 0xcc, 0x1d, 0xdc, 0xdd, 0xb9, 0x0d, + 0x0b, 0xb5, 0x33, 0xda, 0x1b, 0xa4, 0x35, 0xa3, 0x57, 0x50, 0xe0, 0x31, 0xd3, 0x24, 0xa3, 0x50, + 0x9a, 0xdf, 0xdb, 0x79, 0x38, 0x8f, 0x1d, 0xa7, 0x92, 0x9a, 0x7c, 0xf5, 0x63, 0x2b, 0x87, 0xc7, + 0xb2, 0xc4, 0xf4, 0x9b, 0x04, 0x70, 0x37, 0x47, 0x07, 0x20, 0x07, 0xe1, 0x29, 0x15, 0xfd, 0xcd, + 0xef, 0x19, 0xff, 0xf2, 0x1c, 0xb7, 0x9d, 0xf8, 0x09, 0x0d, 0x3a, 0x85, 0xa5, 0x69, 0xa9, 0xd3, + 0xfb, 0x32, 0x2d, 0x2f, 0xe2, 0x55, 0xfe, 0xa3, 0xae, 0x3f, 0x9c, 0x51, 0xef, 0xef, 0x61, 0x12, + 0xfc, 0xd9, 0xe7, 0x3c, 0x3c, 0xbe, 0xa7, 0x44, 0xdb, 0xa0, 0xd7, 0x9b, 0x0d, 0x1b, 0x57, 0xeb, + 0xb6, 0xd3, 0x6c, 0x99, 0xb8, 0x6a, 0x5b, 0xcd, 0x86, 0xd3, 0x69, 0xb4, 0x5b, 0x66, 0xdd, 0x7a, + 0x63, 0x99, 0x87, 0x6a, 0x0e, 0xed, 0x80, 0x91, 0xc1, 0xb1, 0x1a, 0x6d, 0xbb, 0xda, 0xb0, 0x2d, + 0x71, 0x52, 0x25, 0x64, 0xc0, 0x66, 0x06, 0xcb, 0x7c, 0x6f, 0xd6, 0x3b, 0x82, 0x91, 0x47, 0x9b, + 0xa0, 0x65, 0x30, 0xde, 0x75, 0x4c, 0x7c, 0xa2, 0x16, 0x90, 0x0e, 0xeb, 0x19, 0xd3, 0x63, 0xeb, + 0x08, 0x57, 0x6d, 0x53, 0x95, 0xd1, 0x3a, 0xac, 0x66, 0xa5, 0xa8, 0xd5, 0xd5, 0x22, 0xda, 0x80, + 0xb5, 0x8c, 0x59, 0xbb, 0x73, 0xd8, 0x54, 0x95, 0x07, 0xd6, 0x62, 0xb3, 0xf5, 0xf6, 0x44, 0x9d, + 0xa9, 0x1d, 0x5f, 0xdd, 0xe8, 0xd2, 0xf5, 0x8d, 0x2e, 0xfd, 0xbc, 0xd1, 0xa5, 0x4f, 0xb7, 0x7a, + 0xee, 0xfa, 0x56, 0xcf, 0x7d, 0xbf, 0xd5, 0x73, 0x1f, 0xf6, 0xfd, 0x80, 0xf7, 0x3f, 0x76, 0xcb, + 0x3d, 0x3a, 0xac, 0x24, 0xff, 0xc5, 0x8b, 0xd0, 0xe3, 0x17, 0x34, 0x1a, 0xa4, 0xe7, 0x4a, 0x7c, + 0xf7, 0x7e, 0x8c, 0x3f, 0x75, 0xd6, 0x55, 0xc4, 0x2b, 0xb0, 0xff, 0x3b, 0x00, 0x00, 0xff, 0xff, + 0xb2, 0x14, 0x6e, 0x82, 0x60, 0x04, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -445,6 +550,90 @@ func (m *ContractOperationInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *BlockTracking) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockTracking) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockTracking) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Txs) > 0 { + for iNdEx := len(m.Txs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Txs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTracking(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *TxTracking) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxTracking) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxTracking) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractOperations) > 0 { + for iNdEx := len(m.ContractOperations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractOperations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTracking(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Info.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTracking(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintTracking(dAtA []byte, offset int, v uint64) int { offset -= sovTracking(v) base := offset @@ -514,6 +703,38 @@ func (m *ContractOperationInfo) Size() (n int) { return n } +func (m *BlockTracking) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Txs) > 0 { + for _, e := range m.Txs { + l = e.Size() + n += 1 + l + sovTracking(uint64(l)) + } + } + return n +} + +func (m *TxTracking) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Info.Size() + n += 1 + l + sovTracking(uint64(l)) + if len(m.ContractOperations) > 0 { + for _, e := range m.ContractOperations { + l = e.Size() + n += 1 + l + sovTracking(uint64(l)) + } + } + return n +} + func sovTracking(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -874,6 +1095,207 @@ func (m *ContractOperationInfo) Unmarshal(dAtA []byte) error { } return nil } +func (m *BlockTracking) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockTracking: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockTracking: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Txs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTracking + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTracking + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Txs = append(m.Txs, TxTracking{}) + if err := m.Txs[len(m.Txs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTracking(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTracking + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TxTracking) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxTracking: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxTracking: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTracking + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTracking + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractOperations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTracking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTracking + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTracking + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractOperations = append(m.ContractOperations, ContractOperationInfo{}) + if err := m.ContractOperations[len(m.ContractOperations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTracking(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTracking + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipTracking(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 From fc2d41ea5cdeb91042bad9d51b812c4c13494e87 Mon Sep 17 00:00:00 2001 From: edjroz Date: Thu, 28 Jul 2022 15:43:27 +0000 Subject: [PATCH 04/27] test tracking module genesis imports & exports --- x/tracking/keeper/genesis_test.go | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 x/tracking/keeper/genesis_test.go diff --git a/x/tracking/keeper/genesis_test.go b/x/tracking/keeper/genesis_test.go new file mode 100644 index 00000000..16a62544 --- /dev/null +++ b/x/tracking/keeper/genesis_test.go @@ -0,0 +1,56 @@ +package keeper_test + +import ( + "math/rand" + + "github.com/archway-network/archway/x/tracking/types" +) + +func (s *KeeperTestSuite) TestGenesisExport() { + rand.Seed(86) + chain := s.chain + ctx, keeper := chain.GetContext(), chain.GetApp().TrackingKeeper + operationsToExecute := 100 + + for i := 0; i < operationsToExecute; i++ { + keeper.TrackNewTx(ctx) + keeper.TrackNewContractOperation(ctx, chain.GetAccount(rand.Intn(5)).Address, types.ContractOperation(rand.Int31n(8)-1), 1, 1) + } + p := keeper.GetParams(ctx) + p.GasTrackingEnabled = false + keeper.SetParams(ctx, p) + + genesis := keeper.ExportGenesis(ctx) + s.Require().Nil(genesis.Validate()) + s.Require().False(genesis.Params.GasTrackingEnabled) + s.Require().Equal(operationsToExecute, len(genesis.ContractOpInfos)) + s.Require().Equal(operationsToExecute, len(genesis.TxInfos)) +} + +func (s *KeeperTestSuite) TestGenesisImport() { + chain := s.chain + ctx, keeper := chain.GetContext(), chain.GetApp().TrackingKeeper + genesis := types.DefaultGenesisState() + genesis.Params.GasTrackingEnabled = false + operationsToExecute := 100 + + // Ids must be greater than 0 + for i := 1; i <= operationsToExecute; i++ { + txInfo := types.TxInfo{uint64(i), 0, 2} + contractOperation := types.ContractOperationInfo{ + txInfo.Id, + txInfo.Id, + chain.GetAccount(rand.Intn(5)).Address.String(), + types.ContractOperation(rand.Int31n(8) - 1), + 1, + 1, + } + genesis.TxInfos = append(genesis.TxInfos, txInfo) + genesis.ContractOpInfos = append(genesis.ContractOpInfos, contractOperation) + } + + s.Require().Nil(genesis.Validate()) + keeper.InitGenesis(ctx, genesis) + newGenesis := keeper.ExportGenesis(ctx) + s.Require().Equal(genesis, newGenesis) +} From f2123704fb7c334721452bdd350d4126d8140a26 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Fri, 29 Jul 2022 14:21:14 +0300 Subject: [PATCH 05/27] x/tracking refactoring; x/rewards added with WASM bindings refactored --- app/ante.go | 18 +- app/app.go | 130 +- docs/proto/proto-docs.md | 245 +++- e2e/common_voter_test.go | 11 +- e2e/contracts/voter.wasm | Bin 369550 -> 366085 bytes e2e/gastracking_test.go | 29 +- e2e/testing/chain.go | 31 +- e2e/testing/chain_ops.go | 2 +- e2e/testing/chain_ops_contract.go | 25 +- e2e/testing/ibc_path.go | 10 +- e2e/voter_test.go | 79 +- go.mod | 2 +- go.sum | 4 +- pkg/cli_args.go | 17 + pkg/cli_flags.go | 30 + pkg/coins.go | 23 + pkg/coins_test.go | 66 + pkg/dec.go | 8 + proto/archway/rewards/v1beta1/events.proto | 49 + proto/archway/rewards/v1beta1/genesis.proto | 8 + proto/archway/rewards/v1beta1/query.proto | 31 + proto/archway/rewards/v1beta1/rewards.proto | 62 +- proto/archway/rewards/v1beta1/tx.proto | 1 + proto/archway/tracking/v1beta1/genesis.proto | 4 - proto/archway/tracking/v1beta1/query.proto | 17 +- proto/archway/tracking/v1beta1/tracking.proto | 8 - x/gastracker/mintbankkeeper/keeper.go | 73 -- x/rewards/abci.go | 23 + x/rewards/ante/fee_deduction.go | 129 ++ x/rewards/client/cli/flags.go | 16 + x/rewards/client/cli/query.go | 140 +++ x/rewards/client/cli/tx.go | 68 ++ x/rewards/keeper/distribution.go | 205 ++++ x/rewards/keeper/genesis.go | 25 + x/rewards/keeper/grpc_query.go | 47 +- x/rewards/keeper/keeper.go | 98 +- x/rewards/keeper/msg_server.go | 4 +- x/rewards/keeper/params.go | 20 +- x/rewards/keeper/state.go | 29 +- x/rewards/keeper/state_block_rewards.go | 83 ++ x/rewards/keeper/state_metadata.go | 8 +- x/rewards/keeper/state_tx_rewards.go | 156 +++ x/rewards/mintbankkeeper/keeper.go | 78 ++ x/rewards/module.go | 181 +++ x/rewards/types/codec.go | 14 +- x/rewards/types/errors.go | 4 +- x/rewards/types/events.go | 41 + x/rewards/types/events.pb.go | 1065 +++++++++++++++++ x/rewards/types/genesis.go | 47 +- x/rewards/types/genesis.pb.go | 170 ++- x/rewards/types/keys.go | 34 +- x/rewards/types/metadata.go | 54 + x/rewards/types/msg.go | 23 +- x/rewards/types/params.go | 29 +- x/rewards/types/query.pb.go | 759 +++++++++++- x/rewards/types/query.pb.gw.go | 124 ++ x/rewards/types/rewards.go | 69 +- x/rewards/types/rewards.pb.go | 854 +++++++++++-- x/rewards/types/tx.pb.go | 1 + x/rewards/wasmbinding/interfaces.go | 22 + x/rewards/wasmbinding/msg_plugin.go | 69 ++ x/rewards/wasmbinding/plugin.go | 13 + x/rewards/wasmbinding/query_plugin.go | 79 ++ x/rewards/wasmbinding/types/msg.go | 105 ++ x/rewards/wasmbinding/types/msg_test.go | 68 ++ x/rewards/wasmbinding/types/query.go | 78 ++ x/rewards/wasmbinding/types/query_test.go | 49 + x/tracking/abci.go | 8 +- x/tracking/ante/tracking.go | 7 +- x/tracking/client/cli/query.go | 30 +- x/tracking/keeper/common_test.go | 6 +- x/tracking/keeper/gas_processor.go | 11 +- x/tracking/keeper/genesis.go | 5 +- x/tracking/keeper/genesis_test.go | 25 +- x/tracking/keeper/grpc_query.go | 17 +- x/tracking/keeper/keeper.go | 26 +- x/tracking/keeper/params.go | 24 - x/tracking/keeper/state.go | 3 +- x/tracking/keeper/state_contract_op.go | 14 +- x/tracking/keeper/state_test.go | 1 + x/tracking/keeper/state_tx_info.go | 19 +- x/tracking/module.go | 14 +- x/tracking/types/codec.go | 1 + x/tracking/types/genesis.go | 8 +- x/tracking/types/genesis.pb.go | 81 +- x/tracking/types/params.go | 66 - x/tracking/types/query.pb.go | 373 +----- x/tracking/types/query.pb.gw.go | 62 - x/tracking/types/tracking.go | 35 +- x/tracking/types/tracking.pb.go | 245 +--- 90 files changed, 5731 insertions(+), 1414 deletions(-) create mode 100644 pkg/cli_args.go create mode 100644 pkg/cli_flags.go create mode 100644 pkg/coins.go create mode 100644 pkg/coins_test.go create mode 100644 pkg/dec.go create mode 100644 proto/archway/rewards/v1beta1/events.proto delete mode 100644 x/gastracker/mintbankkeeper/keeper.go create mode 100644 x/rewards/abci.go create mode 100644 x/rewards/ante/fee_deduction.go create mode 100644 x/rewards/client/cli/flags.go create mode 100644 x/rewards/client/cli/query.go create mode 100644 x/rewards/client/cli/tx.go create mode 100644 x/rewards/keeper/distribution.go create mode 100644 x/rewards/keeper/genesis.go create mode 100644 x/rewards/keeper/state_block_rewards.go create mode 100644 x/rewards/keeper/state_tx_rewards.go create mode 100644 x/rewards/mintbankkeeper/keeper.go create mode 100644 x/rewards/module.go create mode 100644 x/rewards/types/events.go create mode 100644 x/rewards/types/events.pb.go create mode 100644 x/rewards/types/metadata.go create mode 100644 x/rewards/wasmbinding/interfaces.go create mode 100644 x/rewards/wasmbinding/msg_plugin.go create mode 100644 x/rewards/wasmbinding/plugin.go create mode 100644 x/rewards/wasmbinding/query_plugin.go create mode 100644 x/rewards/wasmbinding/types/msg.go create mode 100644 x/rewards/wasmbinding/types/msg_test.go create mode 100644 x/rewards/wasmbinding/types/query.go create mode 100644 x/rewards/wasmbinding/types/query_test.go delete mode 100644 x/tracking/keeper/params.go delete mode 100644 x/tracking/types/params.go diff --git a/app/ante.go b/app/ante.go index 64c90dc8..36b20c29 100644 --- a/app/ante.go +++ b/app/ante.go @@ -2,17 +2,17 @@ package app import ( + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + rewardsAnte "github.com/archway-network/archway/x/rewards/ante" + rewardsKeeper "github.com/archway-network/archway/x/rewards/keeper" + trackingAnte "github.com/archway-network/archway/x/tracking/ante" + trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" channelkeeper "github.com/cosmos/ibc-go/v2/modules/core/04-channel/keeper" ibcante "github.com/cosmos/ibc-go/v2/modules/core/ante" - - wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" - - trackingAnte "github.com/archway-network/archway/x/tracking/ante" - trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC @@ -26,6 +26,7 @@ type HandlerOptions struct { TXCounterStoreKey sdk.StoreKey TrackingKeeper trackingKeeper.Keeper + RewardsKeeper rewardsKeeper.Keeper } func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { @@ -60,8 +61,6 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), - // custom archway fee deduction, which splits fees between gastracker and auths fee collector - //gastrackerante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.GasTrackingKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), @@ -69,7 +68,10 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewAnteDecorator(options.IBCChannelkeeper), + // Custom Archway interceptor to track new transactions trackingAnte.NewTxGasTrackingDecorator(options.TrackingKeeper), + // Custom Archway fee deduction, which splits fees between x/rewards and x/auth fee collector + rewardsAnte.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.RewardsKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/app/app.go b/app/app.go index 4de5b5b5..366c2764 100644 --- a/app/app.go +++ b/app/app.go @@ -2,21 +2,15 @@ package app import ( "fmt" - "github.com/archway-network/archway/x/tracking" - trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" - trackingTypes "github.com/archway-network/archway/x/tracking/types" "io" "net/http" "os" "path/filepath" "strings" - "github.com/archway-network/archway/x/gastracker/mintbankkeeper" - wasmdKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" cosmwasm "github.com/CosmWasm/wasmvm" - "github.com/archway-network/archway/x/gastracker/wasmbinding" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/grpc/tmservice" @@ -84,7 +78,7 @@ import ( upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - transfer "github.com/cosmos/ibc-go/v2/modules/apps/transfer" + "github.com/cosmos/ibc-go/v2/modules/apps/transfer" ibctransferkeeper "github.com/cosmos/ibc-go/v2/modules/apps/transfer/keeper" ibctransfertypes "github.com/cosmos/ibc-go/v2/modules/apps/transfer/types" ibc "github.com/cosmos/ibc-go/v2/modules/core" @@ -104,13 +98,19 @@ import ( tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" + "github.com/archway-network/archway/x/rewards" + rewardsKeeper "github.com/archway-network/archway/x/rewards/keeper" + "github.com/archway-network/archway/x/rewards/mintbankkeeper" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" + "github.com/archway-network/archway/x/rewards/wasmbinding" + "github.com/archway-network/archway/x/tracking" + trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" + trackingTypes "github.com/archway-network/archway/x/tracking/types" + "github.com/CosmWasm/wasmd/x/wasm" wasmclient "github.com/CosmWasm/wasmd/x/wasm/client" - archwayappparams "github.com/archway-network/archway/app/params" - "github.com/archway-network/archway/x/gastracker" - gastrackerkeeper "github.com/archway-network/archway/x/gastracker/keeper" - gastrackermodule "github.com/archway-network/archway/x/gastracker/module" + archwayappparams "github.com/archway-network/archway/app/params" // unnamed import of statik for swagger UI support _ "github.com/cosmos/cosmos-sdk/client/docs/statik" @@ -204,21 +204,21 @@ var ( transfer.AppModuleBasic{}, vesting.AppModuleBasic{}, wasm.AppModuleBasic{}, - gastrackermodule.AppModuleBasic{}, tracking.AppModuleBasic{}, + rewards.AppModuleBasic{}, ) // module account permissions maccPerms = map[string][]string{ - gastracker.ContractRewardCollector: nil, - authtypes.FeeCollectorName: nil, - distrtypes.ModuleName: nil, - minttypes.ModuleName: {authtypes.Minter}, - stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, - stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, - govtypes.ModuleName: {authtypes.Burner}, - ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - wasm.ModuleName: {authtypes.Burner}, + rewardsTypes.ContractRewardCollector: nil, + authtypes.FeeCollectorName: nil, + distrtypes.ModuleName: nil, + minttypes.ModuleName: {authtypes.Minter}, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + govtypes.ModuleName: {authtypes.Burner}, + ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + wasm.ModuleName: {authtypes.Burner}, } ) @@ -242,25 +242,25 @@ type ArchwayApp struct { memKeys map[string]*sdk.MemoryStoreKey // keepers - AccountKeeper authkeeper.AccountKeeper - BankKeeper bankkeeper.Keeper - CapabilityKeeper *capabilitykeeper.Keeper - StakingKeeper stakingkeeper.Keeper - slashingKeeper slashingkeeper.Keeper - MintKeeper mintkeeper.Keeper - DistrKeeper distrkeeper.Keeper - GovKeeper govkeeper.Keeper - CrisisKeeper crisiskeeper.Keeper - UpgradeKeeper upgradekeeper.Keeper - ParamsKeeper paramskeeper.Keeper - IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly - EvidenceKeeper evidencekeeper.Keeper - TransferKeeper ibctransferkeeper.Keeper - FeeGrantKeeper feegrantkeeper.Keeper - AuthzKeeper authzkeeper.Keeper - WASMKeeper wasm.Keeper - GasTrackingKeeper gastrackerkeeper.Keeper - TrackingKeeper trackingKeeper.Keeper + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + CapabilityKeeper *capabilitykeeper.Keeper + StakingKeeper stakingkeeper.Keeper + slashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + DistrKeeper distrkeeper.Keeper + GovKeeper govkeeper.Keeper + CrisisKeeper crisiskeeper.Keeper + UpgradeKeeper upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + AuthzKeeper authzkeeper.Keeper + WASMKeeper wasm.Keeper + TrackingKeeper trackingKeeper.Keeper + RewardsKeeper rewardsKeeper.Keeper ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper @@ -305,8 +305,8 @@ func NewArchwayApp( minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, - feegrant.StoreKey, authzkeeper.StoreKey, wasm.StoreKey, gastracker.StoreKey, - trackingTypes.StoreKey, + feegrant.StoreKey, authzkeeper.StoreKey, wasm.StoreKey, + trackingTypes.StoreKey, rewardsTypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -457,19 +457,10 @@ func NewArchwayApp( defaultGasRegister := wasmdKeeper.NewDefaultWasmGasRegister() - app.GasTrackingKeeper = gastrackerkeeper.NewGasTrackingKeeper( - keys[gastracker.StoreKey], - app.appCodec, - app.getSubspace(gastracker.DefaultParamSpace), - nil, - defaultGasRegister, - ) - app.TrackingKeeper = trackingKeeper.NewKeeper( appCodec, keys[trackingTypes.StoreKey], defaultGasRegister, - app.getSubspace(trackingTypes.ModuleName), ) wasmDir := filepath.Join(homePath, "wasm") @@ -486,10 +477,11 @@ func NewArchwayApp( if err != nil { panic(err) } + trackingWasmVm := wasmdTypes.NewTrackingWasmerEngine(wasmer, &wasmdTypes.NoOpContractGasProcessor{}) wasmOpts = append(wasmOpts, wasmdKeeper.WithWasmEngine(trackingWasmVm), wasmdKeeper.WithGasRegister(defaultGasRegister)) - wasmOpts = append(wasmOpts, wasmbinding.GetCustomWasmOptions(&app.GasTrackingKeeper)...) + wasmOpts = append(wasmOpts, wasmbinding.GetCustomWasmOptions(&app.RewardsKeeper)...) // using a pointer as the keeper is initialized below app.WASMKeeper = wasm.NewKeeper( appCodec, @@ -510,22 +502,31 @@ func NewArchwayApp( supportedFeatures, wasmOpts..., ) - app.GasTrackingKeeper.SetContractInfoView(app.WASMKeeper) // post initialization - // note we set up mint keeper after gastracking keeper + // Setting gas recorder here to avoid cyclic loop + trackingWasmVm.SetGasRecorder(app.TrackingKeeper) + + app.RewardsKeeper = rewardsKeeper.NewKeeper( + appCodec, + keys[rewardsTypes.StoreKey], + app.WASMKeeper, + app.TrackingKeeper, + app.AccountKeeper, + app.BankKeeper, + app.getSubspace(rewardsTypes.ModuleName), + ) + + // Note we set up mint keeper after the x/rewards keeper app.MintKeeper = mintkeeper.NewKeeper( appCodec, keys[minttypes.StoreKey], app.getSubspace(minttypes.ModuleName), &stakingKeeper, app.AccountKeeper, - mintbankkeeper.NewKeeper(app.BankKeeper, app.GasTrackingKeeper), + mintbankkeeper.NewKeeper(app.BankKeeper, app.RewardsKeeper), authtypes.FeeCollectorName, ) - // Setting gas recorder here to avoid cyclic loop - trackingWasmVm.SetGasRecorder(app.TrackingKeeper) - // The gov proposal types can be individually enabled if len(enabledProposals) != 0 { govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.WASMKeeper, enabledProposals)) @@ -574,8 +575,8 @@ func NewArchwayApp( ibc.NewAppModule(app.IBCKeeper), params.NewAppModule(app.ParamsKeeper), transferModule, - gastrackermodule.NewAppModule(app.appCodec, app.GasTrackingKeeper, app.BankKeeper), tracking.NewAppModule(app.appCodec, app.TrackingKeeper), + rewards.NewAppModule(app.appCodec, app.RewardsKeeper), crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants), // always be last to make sure that it checks for all invariants and not only part of them ) @@ -587,7 +588,6 @@ func NewArchwayApp( upgradetypes.ModuleName, capabilitytypes.ModuleName, minttypes.ModuleName, - gastracker.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName, evidencetypes.ModuleName, @@ -608,6 +608,7 @@ func NewArchwayApp( wasm.ModuleName, // wasm gas tracking trackingTypes.ModuleName, + rewardsTypes.ModuleName, ) app.mm.SetOrderEndBlockers( @@ -633,8 +634,8 @@ func NewArchwayApp( // wasm wasm.ModuleName, // wasm gas tracking - gastracker.ModuleName, trackingTypes.ModuleName, + rewardsTypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -651,7 +652,6 @@ func NewArchwayApp( distrtypes.ModuleName, stakingtypes.ModuleName, slashingtypes.ModuleName, - gastracker.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName, @@ -669,6 +669,7 @@ func NewArchwayApp( wasm.ModuleName, // wasm gas tracking trackingTypes.ModuleName, + rewardsTypes.ModuleName, ) // Uncomment if you want to set a custom migration order here. @@ -700,7 +701,6 @@ func NewArchwayApp( wasm.NewAppModule(appCodec, &app.WASMKeeper, app.StakingKeeper), ibc.NewAppModule(app.IBCKeeper), transferModule, - gastrackermodule.NewAppModule(app.appCodec, app.GasTrackingKeeper, app.BankKeeper), ) app.sm.RegisterStoreDecoders() @@ -723,6 +723,7 @@ func NewArchwayApp( WasmConfig: &wasmConfig, TXCounterStoreKey: keys[wasm.StoreKey], TrackingKeeper: app.TrackingKeeper, + RewardsKeeper: app.RewardsKeeper, }, ) if err != nil { @@ -884,8 +885,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(wasm.ModuleName) - paramsKeeper.Subspace(gastracker.DefaultParamSpace) - paramsKeeper.Subspace(trackingTypes.ModuleName) + paramsKeeper.Subspace(rewardsTypes.ModuleName) return paramsKeeper } diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index 143a6a54..a7f29610 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -34,18 +34,30 @@ - [Msg](#archway.gastracker.v1.Msg) - [archway/rewards/v1beta1/rewards.proto](#archway/rewards/v1beta1/rewards.proto) + - [BlockRewards](#archway.rewards.v1beta1.BlockRewards) + - [BlockTracking](#archway.rewards.v1beta1.BlockTracking) - [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) - [Params](#archway.rewards.v1beta1.Params) + - [TxRewards](#archway.rewards.v1beta1.TxRewards) + +- [archway/rewards/v1beta1/events.proto](#archway/rewards/v1beta1/events.proto) + - [ContractMetadataSetEvent](#archway.rewards.v1beta1.ContractMetadataSetEvent) + - [ContractRewardCalculationEvent](#archway.rewards.v1beta1.ContractRewardCalculationEvent) + - [ContractRewardDistributionEvent](#archway.rewards.v1beta1.ContractRewardDistributionEvent) - [archway/rewards/v1beta1/genesis.proto](#archway/rewards/v1beta1/genesis.proto) - [GenesisContractMetadata](#archway.rewards.v1beta1.GenesisContractMetadata) - [GenesisState](#archway.rewards.v1beta1.GenesisState) - [archway/rewards/v1beta1/query.proto](#archway/rewards/v1beta1/query.proto) + - [QueryBlockRewardsTrackingRequest](#archway.rewards.v1beta1.QueryBlockRewardsTrackingRequest) + - [QueryBlockRewardsTrackingResponse](#archway.rewards.v1beta1.QueryBlockRewardsTrackingResponse) - [QueryContractMetadataRequest](#archway.rewards.v1beta1.QueryContractMetadataRequest) - [QueryContractMetadataResponse](#archway.rewards.v1beta1.QueryContractMetadataResponse) - [QueryParamsRequest](#archway.rewards.v1beta1.QueryParamsRequest) - [QueryParamsResponse](#archway.rewards.v1beta1.QueryParamsResponse) + - [QueryRewardsPoolRequest](#archway.rewards.v1beta1.QueryRewardsPoolRequest) + - [QueryRewardsPoolResponse](#archway.rewards.v1beta1.QueryRewardsPoolResponse) - [Query](#archway.rewards.v1beta1.Query) @@ -58,7 +70,6 @@ - [archway/tracking/v1beta1/tracking.proto](#archway/tracking/v1beta1/tracking.proto) - [BlockTracking](#archway.tracking.v1beta1.BlockTracking) - [ContractOperationInfo](#archway.tracking.v1beta1.ContractOperationInfo) - - [Params](#archway.tracking.v1beta1.Params) - [TxInfo](#archway.tracking.v1beta1.TxInfo) - [TxTracking](#archway.tracking.v1beta1.TxTracking) @@ -70,8 +81,6 @@ - [archway/tracking/v1beta1/query.proto](#archway/tracking/v1beta1/query.proto) - [QueryBlockGasTrackingRequest](#archway.tracking.v1beta1.QueryBlockGasTrackingRequest) - [QueryBlockGasTrackingResponse](#archway.tracking.v1beta1.QueryBlockGasTrackingResponse) - - [QueryParamsRequest](#archway.tracking.v1beta1.QueryParamsRequest) - - [QueryParamsResponse](#archway.tracking.v1beta1.QueryParamsResponse) - [Query](#archway.tracking.v1beta1.Query) @@ -430,16 +439,49 @@ Msg defines the gastracker msg service + + +### BlockRewards +BlockRewards defines block related rewards distribution data. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `height` | [int64](#int64) | | height defines the block height. | +| `inflation_rewards` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | inflation_rewards is the rewards to be distributed. | +| `max_gas` | [int64](#int64) | | max_gas defines the maximum gas that can be used for the block (consensus parameter). | + + + + + + + + +### BlockTracking +BlockTracking is the tracking information for a block. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `inflation_rewards` | [BlockRewards](#archway.rewards.v1beta1.BlockRewards) | | inflation_rewards defines the inflation rewards for the block. | +| `tx_rewards` | [TxRewards](#archway.rewards.v1beta1.TxRewards) | repeated | tx_rewards defines the transaction rewards for the block. | + + + + + + ### ContractMetadata -ContractMetadata defines the contract rewards distribution options. +ContractMetadata defines the contract rewards distribution options for a particular contract. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `owner_address` | [string](#string) | | owner_address is the contract owner address that can modify contract reward options (bech32 encoded). | -| `rewards_address` | [string](#string) | | rewards_address is an address to distribute rewards to (bech32 encoded). | +| `owner_address` | [string](#string) | | owner_address is the contract owner address that can modify contract reward options (bech32 encoded). That could be the contract admin or the contract itself. If owner_address is set to contract address, contract can modify the metadata on its own using WASM bindings. | +| `rewards_address` | [string](#string) | | rewards_address is an address to distribute rewards to (bech32 encoded). If not set (empty), rewards are not distributed for this contract. | @@ -454,9 +496,94 @@ Params defines the module parameters. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `rewards_enabled` | [bool](#bool) | | rewards_enabled flag indicates whether rewards calculation and distribution is enabled. | -| `inflation_rewards_ratio` | [string](#string) | | | -| `tx_fee_rebate_ratio` | [string](#string) | | | +| `inflation_rewards_ratio` | [string](#string) | | inflation_rewards_ratio defines the percentage of minted inflation tokens that are used for dApp rewards [0.0, 1.0]. If set to 0.0, no inflation rewards are distributed. | +| `tx_fee_rebate_ratio` | [string](#string) | | tx_fee_rebate_ratio defines the percentage of tx fees that are used for dApp rewards [0.0, 1.0]. If set to 0.0, no fee rewards are distributed. | + + + + + + + + +### TxRewards +TxRewards defines transaction related rewards distribution data. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `tx_id` | [uint64](#uint64) | | tx_id is the tracking transaction ID (x/tracking is the data source for this value). | +| `height` | [int64](#int64) | | height defines the block height. | +| `fee_rewards` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | fee_rewards is the rewards to be distributed. | + + + + + + + + + + + + + + + + +

Top

+ +## archway/rewards/v1beta1/events.proto + + + + + +### ContractMetadataSetEvent +ContractMetadataSetEvent is emitted when the contract metadata is created or updated. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `contract_address` | [string](#string) | | contract_address defines the contract address. | +| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata defines the new contract metadata state. | + + + + + + + + +### ContractRewardCalculationEvent +ContractRewardCalculationEvent is emitted when the contract reward is calculated. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `contract_address` | [string](#string) | | contract_address defines the contract address. | +| `gas_consumed` | [uint64](#uint64) | | gas_consumed defines the total gas consumption by all WASM operations within one transaction. | +| `inflation_rewards` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | inflation_rewards defines the inflation rewards portions of the rewards. | +| `fee_rebate_rewards` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | fee_rebate_rewards defines the fee rebate rewards portions of the rewards. | +| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata defines the contract metadata (if set). | + + + + + + + + +### ContractRewardDistributionEvent +ContractRewardDistributionEvent is emitted when the contract reward is distributed to the corresponding rewards address. +This event might not follow the ContractRewardCalculationEvent if the contract has no metadata set or rewards address is empty. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `contract_address` | [string](#string) | | contract_address defines the contract address. | +| `reward_address` | [string](#string) | | rewards_address defines the rewards address rewards are distributed to. | +| `rewards` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | rewards defines the total rewards being distributed. | @@ -505,6 +632,8 @@ GenesisState defines the initial state of the tracking module. | ----- | ---- | ----- | ----------- | | `params` | [Params](#archway.rewards.v1beta1.Params) | | params defines all the module parameters. | | `contracts_metadata` | [GenesisContractMetadata](#archway.rewards.v1beta1.GenesisContractMetadata) | repeated | contracts_metadata defines a list of all contracts metadata. | +| `block_rewards` | [BlockRewards](#archway.rewards.v1beta1.BlockRewards) | repeated | block_rewards defines a list of all block rewards objects. | +| `tx_rewards` | [TxRewards](#archway.rewards.v1beta1.TxRewards) | repeated | tx_rewards defines a list of all tx rewards objects. | @@ -527,6 +656,31 @@ GenesisState defines the initial state of the tracking module. + + +### QueryBlockRewardsTrackingRequest +QueryBlockRewardsTrackingRequest is the request for Query.BlockRewardsTracking. + + + + + + + + +### QueryBlockRewardsTrackingResponse +QueryBlockRewardsTrackingResponse is the response for Query.BlockRewardsTracking. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `block` | [BlockTracking](#archway.rewards.v1beta1.BlockTracking) | | | + + + + + + ### QueryContractMetadataRequest @@ -581,6 +735,31 @@ QueryParamsResponse is the response for Query.Params. + + + +### QueryRewardsPoolRequest +QueryRewardsPoolRequest is the request for Query.RewardsPool. + + + + + + + + +### QueryRewardsPoolResponse +QueryRewardsPoolResponse is the response for Query.RewardsPool. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `funds` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | + + + + + @@ -597,6 +776,8 @@ Query service for the tracking module. | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `Params` | [QueryParamsRequest](#archway.rewards.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#archway.rewards.v1beta1.QueryParamsResponse) | Params returns module parameters. | GET|/archway/rewards/v1/params| | `ContractMetadata` | [QueryContractMetadataRequest](#archway.rewards.v1beta1.QueryContractMetadataRequest) | [QueryContractMetadataResponse](#archway.rewards.v1beta1.QueryContractMetadataResponse) | ContractMetadata returns the contract rewards parameters (metadata). | GET|/archway/rewards/v1/contract_metadata| +| `BlockRewardsTracking` | [QueryBlockRewardsTrackingRequest](#archway.rewards.v1beta1.QueryBlockRewardsTrackingRequest) | [QueryBlockRewardsTrackingResponse](#archway.rewards.v1beta1.QueryBlockRewardsTrackingResponse) | BlockRewardsTracking returns block rewards tracking for the current block. | GET|/archway/rewards/v1/block_rewards_tracking| +| `RewardsPool` | [QueryRewardsPoolRequest](#archway.rewards.v1beta1.QueryRewardsPoolRequest) | [QueryRewardsPoolResponse](#archway.rewards.v1beta1.QueryRewardsPoolResponse) | RewardsPool returns the current undistributed rewards pool funds. | GET|/archway/rewards/v1/rewards_pool| @@ -619,7 +800,7 @@ MsgSetContractMetadata is the request for Msg.SetContractMetadata. | ----- | ---- | ----- | ----------- | | `sender_address` | [string](#string) | | sender_address is the msg sender address (bech32 encoded). | | `contract_address` | [string](#string) | | contract_address is the target contract address (bech32 encoded). | -| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata is the contract metadata to set / update. | +| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata is the contract metadata to set / update. If metadata exists, non-empty fields will be updated. | @@ -698,21 +879,6 @@ Object is being created by the IngestGasRecord call from the wasmd. - - -### Params -Params defines the module parameters. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `gas_tracking_enabled` | [bool](#bool) | | gas_tracking_enabled flag indicates whether gas tracking is enabled (TXs and ContractOperations creation). | - - - - - - ### TxInfo @@ -789,7 +955,6 @@ GenesisState defines the initial state of the tracking module. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `params` | [Params](#archway.tracking.v1beta1.Params) | | params defines all the module parameters. | | `tx_infos` | [TxInfo](#archway.tracking.v1beta1.TxInfo) | repeated | tx_infos defines a list of all the tracked transactions. | | `contract_op_infos` | [ContractOperationInfo](#archway.tracking.v1beta1.ContractOperationInfo) | repeated | contract_op_infos defines a list of all the tracked contract operations. | @@ -838,31 +1003,6 @@ QueryBlockGasTrackingResponse is the response for Query.BlockGasTracking. - - - -### QueryParamsRequest -QueryParamsRequest is the request for Query.Params. - - - - - - - - -### QueryParamsResponse -QueryParamsResponse is the response for Query.Params. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `params` | [Params](#archway.tracking.v1beta1.Params) | | | - - - - - @@ -877,8 +1017,7 @@ Query service for the tracking module. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `Params` | [QueryParamsRequest](#archway.tracking.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#archway.tracking.v1beta1.QueryParamsResponse) | Params returns module parameters. | GET|/archway/tracking/v1/params| -| `BlockGasTracking` | [QueryBlockGasTrackingRequest](#archway.tracking.v1beta1.QueryBlockGasTrackingRequest) | [QueryBlockGasTrackingResponse](#archway.tracking.v1beta1.QueryBlockGasTrackingResponse) | BlockGasTracking returns block gas tracking for the latest block | GET|/archway/tracking/v1/block_gas_tracking| +| `BlockGasTracking` | [QueryBlockGasTrackingRequest](#archway.tracking.v1beta1.QueryBlockGasTrackingRequest) | [QueryBlockGasTrackingResponse](#archway.tracking.v1beta1.QueryBlockGasTrackingResponse) | BlockGasTracking returns block gas tracking for the current block | GET|/archway/tracking/v1/block_gas_tracking| diff --git a/e2e/common_voter_test.go b/e2e/common_voter_test.go index 5882681c..fc976a63 100644 --- a/e2e/common_voter_test.go +++ b/e2e/common_voter_test.go @@ -12,9 +12,10 @@ import ( cwMath "github.com/CosmWasm/cosmwasm-go/std/math" cwSdkTypes "github.com/CosmWasm/cosmwasm-go/std/types" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" - e2eTesting "github.com/archway-network/archway/e2e/testing" sdk "github.com/cosmos/cosmos-sdk/types" channelTypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + + e2eTesting "github.com/archway-network/archway/e2e/testing" ) // Voter contract related helpers. @@ -70,7 +71,7 @@ func (s *E2ETestSuite) VoterNewVoting(chain *e2eTesting.TestChain, contractAddr }), } - _, res, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) + _, res, _, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) txRes := chain.ParseSDKResultData(res) s.Require().Len(txRes.Data, 1) @@ -146,7 +147,7 @@ func (s *E2ETestSuite) VoterIBCVote(chain *e2eTesting.TestChain, contractAddr sd }), } - _, res, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) + _, res, _, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) // Assemble the IBC packet from the response var packet channelTypes.Packet @@ -208,7 +209,7 @@ func (s *E2ETestSuite) VoterRelease(chain *e2eTesting.TestChain, contractAddr sd Msg: reqBz, } - _, res, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) + _, res, _, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) txRes := chain.ParseSDKResultData(res) s.Require().Len(txRes.Data, 1) @@ -333,7 +334,7 @@ func (s *E2ETestSuite) VoterUpdateMetadata(chain *e2eTesting.TestChain, contract Msg: reqBz, } - _, _, err = chain.SendMsgs(acc, expPass, []sdk.Msg{&msg}) + _, _, _, err = chain.SendMsgs(acc, expPass, []sdk.Msg{&msg}) return err } diff --git a/e2e/contracts/voter.wasm b/e2e/contracts/voter.wasm index 3215f1f0f2e3891882238dc2473c7f8985a6e82c..10ef4f0421107cbd2fbab5c4673f880257006fbe 100755 GIT binary patch delta 62197 zcmd44cYKt^7C*c*vztw_B^%NU$!=(&_a;&v=_<`GQbklkuSzqaNhp$p1tus6C`zwE z77(S_P*6ZoumGV6DhMbbipcvt^E}V)M!om`-uL&;~4lXM0$|5(Nn8*CN{3PT4-l8%S{uf2{ z4mbEU&aBMFBZbvwvs!!+j)bger-*h7X9cG-ibYshjD<15?2Os*f5xICEzzQ4M0BEE zL|6p3SRCA9lgs+r(sCnE(Z;!rF)oA^|HuE_RvUM#U+6^G=}$COiWD}R&0^zLYoy?w zSVxj4l1E}R7L^<;SVW~1R=J83?IN{VF=6A^a1t6KFaR<2x)n!qI@f^lHv0!H?7 z$@tA#Zd5{Igs@tfl}9*4Y79$dA}s=_$3#R3j2UTXwQ8qCxzb(fQFY4OIjhUlcs;>* zeYEC0nm1@@w?~za=8ZTyrcqqPMrB0AWyIYT*X-{2`1nlTJkw&a2LFe4pnYT{ zO(Y3(z$j&kF{u{*8n%YDzvtGcNA&M+InN{d^&K>5Xg|vZZXeNK|M>%VjTk*-)PTYL zYmFMvZ{SGFkN!eiLhesIqW8#AeMgM4T;!3eX5Uf$Eth!oQ+hi}{mkPA3>npb#M6EI z_3u5V|A>(Th7Rf7#B!NC1`I)4bV{|ZaC`sf`}Z4-pI5nk@PKDVQ0_0>I&$<=LoL5@ z+lc~Fd0?-P+w^>^;3qG5ge4eURvH~w1w;N`+{XvRZFkFwnIzZ#L8`X`U? zJ96xhegmE!i)jxX)_e4j=LQUU%5t0g4@D%U{`L3b5&c#19qwoLc$Vi+v}Zfluy!lh zVivtDKjB)*z4js8ab>GVOvI zrVDbpk2xc3yp{f+mwD#@B3SqtH_Ig@((E2h99`* z-%xIz*~CswI>)u3rJNHt%FI@r;EJzrKgE4kR4Hj6KTxpO{dbNfmVBJloSF3^sCjJ4 zSQ=|~%9~~Lo2TVc{<~?R{3z;cX!#gUpidQSN-dNZk- z%Qx1nrqC+#)%1W;UK=fi6)VY6_cLE>p6~a^Wep(kLe>VJ=l9pH@S+Yf{a;n+?hE5` zo7bwhrcShEkH@EI*R5h4FZTQEw6E`9Sn*(t-XP1_i04yr$#a!H5`5luf2*n$2=uR- zU1i>NYff!u@kVuY3GL=Bt2UK+BR#dUtlAWIFSyjIu~EqPZ>idn=l$isUbP{C8r8}t z=lx~PA%2ML=;Gc;?am$hy)KJ(Xtuv^wL}guw%W@?y@cvdSk3826P3o-9?eequhuSa zKMgh@v=ZuEVJ5B-jrcZBnep{jMicekz56}0xtika=4q6@s`*o9Hm$FpwTt)HXyKru z@olP?Jk=s2xR$hL{+C+TW@r5Gv}{Q={%U!=Oylocsf8Nfrf->S)-KLHb%|9gr`9N& zxpD}1SDi#iE&5}oIY`Dt}l?vTp z8`y|@oK_?}BT9Z6T#mZ=Ye*uhCJc45@~UdIUe!ufRYhl{0{#}mx>29Q3R&bRqYr=f zh>8_Pkx;OC2}!Te@>mX`Z*e%GaTVUgn}!cD>ahi@(Q+ zcf+grD~+7X#*}Ou`Jm!S*O*}?)1R*xTpYz^TgSFz!%J?D-NX2?!jj$NAFz^2)BEJw zQh9YXZz`8I5LqQ-^P+=I-LyV)Ce`;017+H}Ko`$&2mTE6AD&c&J@5a0QhPSquT8E; ztU7w~x6KdDvE{(J@VUIv(7gDi897;r-stdTlGin2gfH2fjEcgjSn|@8>kR!(nO2Dy zY4x-pf{1u%O<$c}nX|F}4`%em-zqbYuu=X$XI`VKzs$-AT1rY^rOj!?hLt=pXQ|@g zYXx&nda2!5R9GiCBMZ&QLNh8{m@qm_iyLYj1jsG=!)&fLz|^^+=0SqIKX(RD@9g&y zKEwP;LDUub=gw;w95LAB=)CHn;o+Ha{>1r9(Ks-_GX5Sej`#mEKZUw+EvR3%oBL$b ze|9rZQa8Kh4`{r)Snt9|&94>LD%-r~%hlOL|Kl%LWyAbaUOtFA{)b*!9d9l!kwSx! zr^r!mQJt~{79Uduk1VR<2y5ZbUv$Bwj#5YC7guL5_*X1$gF!AXzCnnbeYIK;5w*or zmR5;>!K5`aEhf}_XlaOWiq>P6b!5~1yO(vRe$rp-$a?7;-ABu8!zPMUqD6Qk8}Uf& zqLqHKZegP=WJ59e*b%~zuH8v zR4|JKLH7=^NXM2A8T-reoQ$c81(QvH42s4Z(hXmj}=-?iK%FwNf|x%+N!sHSPN!`4gA$%@cQ zi)>nHq5rAfOVO!qPfz^qx2FpJ&QgC%)ZcH_U$K|+tM9Fc`S((Pi}ns-Gv~hN%bLkF z%$$6J2t`;I(+NSEucJ$;%+~K^qxGQo%A@tn_eSCOo%ekB>wBO2d+7aT_FJ4=bJ+{B zXofY_|M8+Y|C$dwn=?_$K6hUY5$&1b-}FIKo2Lzl$>AS~Al-~AwLsNPA2iV`_ z@_nxWF(uKtraM0a;X`I|!*L@~&pnG+Faw^P%98N8ESfdPXCc4IkwFfe|Io*o9N_B5 zEn?2_Ea9~fe_J%+S?F)^35w?Wdw-G|`7(odg~9xjK1ppG93Ebu^1amXrr)S*8Vqk{ z=);4j$ZzAChdjVb^ZlitwC#fCMi=A<4;!AvFgm%IwCAC)2Es_t_E?7aFi{8$%xhp4 zAxPdNDS8?hNk?_Yb7?Z8_ScFryjMofqQx`cziEGFlJ2M)LwQ+FC(wh+&hM|5rB9)Y zl{!$4q~$(%xDH1Z^a<~ps?|U6tj~~Kv?eGfB4IKFEO2s^W4ZG{{fb5{k^@1XR;XHD zHV73N3jA@OHa59H357xa1ue>IMTD6Ii3Dphtj=o zFsB3MbdExqur(RMD8Q=1;(5a#d3X+c(=QM2!QaO}|JJ!2E21AgfI(V)F_pbh^1&Bc zP!uSk9sA`YkeB`eUtWozjZ?V5-}|daY8Wg>A~?vHq%LV2wY2CbH8`O0VyDgbpZY4< zp>HoRnCFb&dbDTCclvfCW(IR`b;eRLNBeHRf85awA4+wZz_jcf?O3R;m(xMXvHAY( zM{DO^GtZ?kj8R7k5>Q%kKdD&cdo8rF)wYS$cTW_?QM+B=OI}XW0a+TgBkok~qj4Y; zRtttfmemtWnR@^JXO6{JJqg=KV|Q69I=KVxNvS&TBBChcff@b=9qlYXc7M!T2t%c9 z(l8CrYdC>vQsK|}wtFV!<>h%AgM2rE#98HbXqX*!Oe8Jo{&i!{)|JftHj=Xq{#TAa zi@(+rL)c3tBTozru9u7U`41=WW|L*+E}r0WV-T;+GtPlOQ>2D0Hs0T>bQYU5_guVO zvWv$c?LL*n#`!Cs%3{;}9Z%I^ll|jP<>2qRQ`zpxO5|s8Y*h5%PdlB(#`s&D_M*7= z>58f2HLI?zqEj8Bm0~2U#BGa*`uEt{k(H1}C{W&b|DMwgF~)DFF@~&r#hM_f&sJxi zK%a}wcyXNh&Y8Mws{ittmMqs_=WG#1*?X2oF?3?oKS!y62~<4S2;Dw$u1vSf&vk&^ zdg)v?Ov=RX+hd4c-ycHd+UJwi?EO8?)8q%8CzM`0U#9I(=bHh6>-&!$LU1CbsX0kTX0(M!I*a9FtwYk#c9N=lCYcvo;uly8xKu?{Pg>;aZ$ z4=jT->nZRLy_m_0`~??%tiZqNVsqMJS1xvAbEIbzPgMjf^!L3q-MT#rhoP4mvNXT_ z=dGpySDo(rxn^x+fdnmd6#Zee+RQVBIR!+4oeUddH89;RT7rs~yRk|BF_%F%S>$3# z71Z45gbvm!s`>=l@ZiGXRMj)hf8=ug6n!9{4I6xGbsaw;*>ftG%A| z54h?ls{D2JYjfIRzJ5vcuP+2?tWH1t*J^>rrR`X<|C?*|KvmcEuW`tA{(5B=@Vjq3 zj+|$2G-L&`WoMS)FS+p{+vXql+mpyX{#zCNwcYGlXFJm(b&d`q@8E*N#@cCcul6{}JsX8--Sdynd3h*HOZ#xXRdW!& zwttS;`Y)e%2h$>gB`}HYVRKb0vB|y$wq=UU~+xI&uhOS4?&wH(3tgEV#F(E>M`uot&ADMuB94 z^=Lyz{%?O+pEQ6(!n5H8V2b{c!zo8sRw=p;2ENeutECXqKsZIz&yFBv~ z&R7(=NlzV&K&OTB=Lpu%`gs&{$f98^O%AiOg(k+dZ)JQW3vOJ}X8*Qvt$*9Na#$p5 z$tKB-kr1i+)@9@5#YhZ4O}e8%g2}RF6ib3&dNhhPWA93T6zdFdI*L7r?b$e*jRIH~ z&7K3O>|pnZFBPG+9VK6y^BX0y(2Zrxl^?ko zq_d2UVKuQtfu=Dm>k8U0EXO)q--Qn&7nQ>6 zoCY4<6BQm45)~e$bwz?8`h1Ycnt~E{60tM$WRE0;!<-~mg->C!IEj@9^nZPoj-&&( zlGqYq-iMTL#IKMuBUh!d;n-?v>8uI%-$Uu_7j{OrFV9{EI9;CQpsZ5{#x9UUGuYkc z5rEvB!764zFdJe_cd|irtG1Eh7Eim|b0%;tgPmb$f6U8wItz_!VE5?}PqH63l22!=Gft%w(dAtTR!uq$Yn$1%n@6=GD zt$a;IzLqtC$r<@fO(6TeoKq7ESs-`SWYrS=L75+}E9ISWYLfJwoc6dJEd$NeA;>FUhN%P~z^Jc?&E#SkCL)lDHI=E%P~vviqs7wdwOXYNv~ zUT_y1!#c2NCTc)ug-GQnpoQ zHCKhxnyVJ;nj`aL*|~+v+|)v4e%*p?V4uhtEmh{lmMSy86+54}pJ_=tSCv`QSdEAi zsIIZ8L2@fqw&NZMXEl4DOlr-tfmN&4Y#BQ$Pq${>k!s$CI$zKM6dBisJyz#faPNf= zpz9x8&HqCSOWu~f&ev|0E84Q#rrJ?@e?vR4q8hrRK5D#d(Vn$sU&^WNAz;gk>!S&t$p%ysJ#hf^~4R~8re@m@ANI1pKCa?<^*n#or0->=x}xBJ=K?6559#9+!w za8z9Y*s|}k&xwl$Dnr(1KeEuOxq;E#E^IY6Zu71ztIiky!K{t`4`ywkpew8-+7@-@ zDccA8m5fi*XGxR29)QKDwkO$$*qCJaU{4MYBs|DAGxKT{}qd@=;cUeJa0vR559j#}t$Hd5mpmpUKq6 zRp!LURpuLyvqE-IHtJ3^kS~75Xjc@13^Dqyh?B>=vwIT{G0jj@;jAZ{KcRU0(I=QY zcppUmgdEnBwFAz9o=TKVSjSWBhFLCu@2OU#MlXn$+4BBgB~h?vcCWp7qZnVPy6;V9!p9H;s}_f}HJ)rai}vOzh*;q$(%DroU%U$zGQt$b3U z^2w7*Kwo%LA(7TkAOsg;=6kNt@T~3^Vj)dGmzC*!3{0MpZ85W6!y>vUB zd;Bu-Sv6YwXEECBe^(q6o@FUkXgRx#9mcxI3(vA6#DVV)VB|88?=0^Ops_-1Xx|@F z6Qpgz_)y-=VdK%>AM!ZtMT-#w0G{|yK8Nf*h*dX|KcL;T4vRvp|~#H zPLZDuX3_(`+}+{0j1+{F{qvR3 zD9*=1&X(KqmC*P$U#;gK`DjrnkIYbp(eE?VppUqwk3Th>d zUM)~c`5=LU1%)iL4&)gRwhYQMQxS`QC}P>AkR7EhkX@uUe&-@ZkikXlOd0hb8mXH7 z#!{vE|38m6Tu$_}O*Cjo$EL|4^U6v%xlv`19sD;%`#+n@+y!cb~jQR7pv5n#q0y5R=uja+yAPP0YB*}*AkVgxkM4{{w2^0 z1#-p`wWOPtu->dx#x7M$T6ZaHfwEysRax;;H26>kma?waISA~OFo5G^#xhl>=Q64j zn6`{X5mE)ODKz%J1{@2e{dF}|<=2&AJ>Yd^2EFn+dkJM#m#dmRmMf$t5Ga(3ma~U2 z@YUsN;FLGm7s$Ny25Zn7Tgj`l34DA6mH2`zijC!Udca1$@bausx%Mee@W{-1>P^+{ z>^Bwru6t7IkVXG`Bkr8iO0V}ycYAe*V2CM*afkL%a3fZ2kSR2|b)%B5RQ%7qx z!bVb?WzQ-#UF&K!-A1cfE_&FyTCK>j)oQvoSF5p;)~M+YTBGoqw}wqZ&BV2;W|Ot5 z=3{GB&F9vtng`aZn%CBuQJn~<6< zdu&quOxy$mv_S6P#H!k`Ob0D;V{`Zr?#)V~vl5b$vQY^;j_%^Os1BNJQQdXdQ!h|z zwp_YJb+=~=c&9){yu}&=w0KLQ;oGX(wcV=PJ)@^)QEIkaw^geJ;173fyODR zy#+Sy5n#hG?xz9O{%U~vvcM{5E#WJ8&hqyqY_JVI7s^L;@ccGbKM@k{g3&7M3^%Z6 z8!KS{?={J0XhyG*@^vPiZ*5K4tkfZ zgr-T@#ij!+-i1SqGxEn>I959&pWV%70Q|BW#`hVyb`N_|pkLYJBe<^J_QF9uBUkKY zcLAKfpQ3|rW!=wIA>0N!ae)&ZC-;1Y&c2bZgNog2 z9%OY%7kTvM4PU5{2U$W;7m-68@E>M~M|)Gw_<}va5ABr4zhDp3{2CmA1#c3ZJiNe< zUqbpLo>?wF#->n}tgk_>@GA1qH*62vDCd659%Jj|Pv5dB?7STM9eO$+NITA+Wk^mv z0m*qm9y!5&ww{NBE2p1e8S?B&cva_Ri&EB-y3Q>{C9`YgJ%4?Qy}{>fmU*YyZgl{x zA_bXT(t$PcKl-6t7M@{k%@#__mY!jc0*fYR*%fpttDR%7o8@#ZBbS}!bL7+CW7c_AK7T@^avIqCp8vnvie;-+TUzPrRXScL^k*OqP-EaTSr#Of4N0;ZmDHpmaU@2 zYtxQca{S&GECF~s4KK3KMi z0d?VZ;NAqnK;72abz2?|NJ^Al+p{8V){0+RA$Jm7zefIb8AJiUc&~&S zDz2P$h1KFkE9Ki)SS9DGm9+D-y;iKPzs19el3&G5B$`#a${sMsqu3ZZ`6{c;e_tU> zuCj_$;p?j`__#s!d+ZlBj(siJZ>+u@ohTFjrC-@<f zlda>8^?tKr8u3#75ZJ1f>W9Eq?IO#`0y>^o8NG(Efb~E=Fptx7L;m^)8_O@wmqTu` zsstC_f|mPDzHZGqlk*gL&tI&9d0WA74S}KL$iG;{>c;&9 zQ%$GPV+=%T9AQqoLL=k{anBgJ_b({!$h%C(Ms_)wlSdb2mQYw5zFyqFl1tjH6gDE0tP0o8RvwI*dg~m)=~_#%%=id3z^n*0z}^T&3>7az1GwzG zHF|l#&fB0*iBt+6wL!3G0CXneg%I)hh%}SsuXZ&d0~Ak ze{PNUVJwrw%ZJvrT>8Xcn4GzLe7rtxx=n#SrV)%U5WvUI8z zt)?+Fn%@&WM$6LsET{K*G+OnU>`;9+cZB-Pai~7WIaHsU9A*3b!=d_Y>Ezu*OQ3I{ z6;8DThn>7JXdmU`om0k9gov>l5Hu3}IYkb0@r=~}Sj^-yJ5P(mi4d$x&jh*O#W%CJ znUH0g3mKQ!$hHI2s)5)eYKgP5EO*qog^K>>d88Sk0b-ZqpM|cGOr8-cO~;0 zq+Kp0^BX39^Z-fzoWh@EuLioMV#~8ra&Q_yOcQC9&Ry*P4+~a7UM|nuWdC0+l%oKSX}~9|WCb5K(_6BW4}n_5-&X&gyW<0SK0bpzT!!%@i5E#EMH1(C0D~*ehq0q> z5}KeFMl|6?jfnV&@<$M}dv4#Kws}tF~nol_(Ce5{KaC zyb`f+az&j(T36%^_}o=;Y(>Q(ODlpEf0GBP6b$f3Mg9-s7=^tnbL z5|s>WEQ+0kj(Tz$t$YN9bPb*v>{(ro-m1x~#F{6oy&Q1Yw%M+YNG?XvVQYkXY+BahLs`6Nb<4iG)fAtxh9$NK~+E)XMhz|LUtO=-kC z0=-WgK?iP;v5k2ESbp4?H?~rMX29BnuL~{@h11KOO|gA{QI`9+P5Fl=Qz(90dlzrd zuFGq8@c{t6n(@1djEkD_rF`0+K#RNiUycv_L6jWrxLz@__m3&!@#8l5O9dw1fWvm>%zXO-&T z8Q#f3`DhoFn%RZ##*xH*T~+FZt{CE5>F!3UfYyztFkAvZ@qj9v^8mla+;ZlFupZ9H z4G;2~4!1Yen+742;t9y}52{+J55aUkBQHP1e?=(3nTJ(o;v@WbL<@KxRjJmGV$3h4 z^)X5X8b1c3gl&`0KdzE%9;c699F?28tGZ|L*b3c!`2;xZ3mMfzW!~L`Ps1Va-X8o_ zoWk_&sT$7fN!WfS*Y{G%Q@yC4|U4WQ@P?v)#jTg`F6zn&FiO9ANAv(u(##hr&Q{Lr!c{- za#w$q`lUaZWS?C9v`QU+njZ(<_AKP}<FzCHqJ~Bk5W(+~!jx@dijuAI85za7nM>lnVHV z^K{1Y<;D>(P-e;_BcS{8<@FJ~C9r5X62x-Lfg^e4Y!}=f^-3KdDIkN>>(Ya>_l2KT z*6`%Z?Wm0l!qSnv33^Hyr8>N86s9#xJ~N8%#i@R^(Q548qahSh1iub`~>EF z@Ht)(?;`yf4;zuRozT|er%R4_9%lO)8F-%e1Etc&ay(;_O#zJXqnWbjSe|BcdDC!d zJdyHC)ZODuxeWQ8T%cbhoy&h^(Jf~9C^%3#8k#_i_BI-LJTn<`!|NOi)p0?H+i^}3 zH4gpnM|HPnrmQ(mjhljTJ5m1E$af-txSpSi{37I6IEQ=(b$>k6J?yVmh9!+4XO}#T zHo=&)U&n!%`7(99Vy~Oyv5nla=>*U%U(TPvv+ZthunXwCKS7cE_5_I3e3>~>k^BCM zyrIKI$1RGEuE6Yxh~lq=hiK=F@yjU^d>@*gN4p9f?ZExR7kFl+mzZ|GOw|kFRd1qd z6skt&^2R}wJLD>qhvsrE){V7WnvjF-C$!~&F1aTcn$9gxQ~qnH z+@Z}zA6Q};IVB9~c2gA6gQxIL!0zoSP+V?#X$tRb#hV$IY&n%D0*6PYD%PGjRpGgH zs>1WwRE4K)8h=TV_LecUN1^s-XlSlYf14t=XUf2fXjvq`ei5uP4|#FOyRGMCPDkDf zqh9Oj+*b(l7HsxYhg$L&(Hx z%k|}v-_HsgqT*~d#C@~*!-^knChGi`I9&=v;gU^*e z>#3e|6dt*A2oJe-4u2n2h8JK;2aWOO7hv))$+rsBAK$(OIM_ z)+|yLyBDd7nR9vh4n~hmd)=5Nj(xyj%R{rIFkbA6p>2$ieTn0z^PuIhW!T>b~J zUF!!D-virdEWjZ@_hliDWtGtd4tOxc>QEOdJT_m(%~M^png@AZAd}|v_0DYW^hJ^? zv-+64I-l3#Sy6J?!#qi93t)`p%N`3bkbdMlQ|2wu*=K_>5F&js(8ka}+&BToW?#TF z1%#u#fDRhqcnb@?IjkA^GsSk}_}8YDg!+JOO6R{N(pJnrt+XXnfSpJJ7veHXSr8m* z45Z`Q7WrE-{}_u7ZP}W?#Uy){Cq`&YXNC}g)b<-EmRz#it*AKIHY>!ac!Fnyuzp8V*7bR=m^a~)Ad<_?D!ft-%QM;&{9M;2TES! z<4L>MUJf=cl0BC5Mn2HXxCx_JF`yS4)|tAiE?Lgig;_a$NJQHy-AFd_@5}kj;EK?D z898SKj6)+JI8xJUk$9PnYo&`A5~f>v>uwU6$jj*dC&{BP@zP8it2o_F2yk@1PS%QdK^TO z&(U!sWVRmuW}l^Wb$I;SJmlaV5rv1O%h&24PRXJzL!Q&$>JpySSUq!PtxY_`2&!_}!}GWt(|DD|V|z7LH&8<;3kQRz6t5RTzvGjDN$#w~!sAN5R=BMB8t^6Z!)s z^pfq;?KGPnppA>CwAfGAsu-})&6Di*EK4Bv598{xPlS%52?bL$d5e}^KJu21auh`Z zYJu%<@j*e?O}VXg0{lJ@WkLXpU=T&V8c?h7F6CX^pp&IEzNUoSGFB`qXPgwUv@krVAJ_L== zI>ai`0z%>2$#MK_ffs{Oph1`iAcx!>WQa(bQhe4us5D^!!DlWP$#-1 zZnb28T|D}nCV$u!a@*0I&bv`Aw6hy!^WD6%Z6nm3RhI7N8S=&5FrRYetGjWy`OaGM z>Kh}OxChDi*3zq-WI1>bs^rP3dtiBukz4nGRC)5~9^PK}z_a$ky)8qGJMZ!COv>)> z^SfBFoDaayt(Ax0hvl$P*8BjcQn-ox086+~p8SA!=J^|B?GIJqtPlBYlJF@Xaci(o zb)J;Hk5^zX%lr3n`UsO8y^rrQ$5ftu%a3_`%zXOCyc@vRAM-lYkK+>_Tecs%&gOY* z<*Lusv5bDBJ@f!iFnd!UW574D%I%(K^Fk17xKP74J<7pPHsZ zZ(b0+0504G12f$Dg8yz}7_4YpiT#xz*M81B5lz(P{C!{X;5UQRY1L0(!ET-+n;ym1 znj)tiRVPP*6-RL~WOk^|%c8#KofCe8MyDf7x@)PUe?DQ`JUQrV-WG3)Hh;~Z1xWiw zzYr+=hW`@mLT%rdzQdUuoWSpRXUD#IHVu#OAXkc|=QwXj9MJwa*8DZO9Kd*Ynnj<- z^E&7cZVlD-qf9vgr8Hi)JHcy3O@fLZ-WDJIlNoJTVupU5X2wYdU-{7MD7tjqbOP4s zH2K8|UZ<0O8s)PG-?iHHLG;bQuvw1mAbFOi1_-MLM-MklYFr&Vx}55Il2^z5%7l~H z7AJPdw@>oQnOlN_Prv;Pe$#_GzqDgPsb0rW82?h|#tzxG6jCTp=9J=SV2oT`%Ez$@ zGWitm2QuBc&a-UzW({`7>!*lt3r_Q2h^eog=C1__A7lpp^IBQ=T!^UyKb+%5!D{iO zlc$}Bxql|G_BxYpAXI|IC;>p&N<%A+yw#mWn77v?5*s8@mKh>jzeHd zr{+{l`STS}`AuTR3Uc&S{&?N+HFt$`r2gdE8upA=zYv#quJR{%bd!#q<}yM*}g zm0z)fmaqOFz(sYwX1!c&6`6s3TvS$8)G3=NFI`sA^zRMsMcn}E-V?0G zJ`3EjiQkxcaEx>BmFo1_7Ae~4dOV?mVkkR_IJb=n-$*GGsT+eHhw#wGgBAYMWA_qqcQtEF; zi{`eiWDLn+(IP|Q%fh7kGaRBh-@8Hfbck9Y;B1GeVLO0Yk+P3NWXkUx!WogreAToF zS>zDOGQufhd`D2ht_#mB_14*L%1rvE1m-9kIRym=^l{?AKTl3_iUwfZtxi$TsTda$ zpW)PBUUQ0jjX8UwgJzbUt_a4!Msu}sAXf;Wmb_sew z>(sX)9=7V|cMgTsIGN#AB-7lAWb|;=Z7c{09PP>$`CUECah+Sxy~amwq494w;5o9W zX6{9Gzd@L^juDkGr2#RbW_4pP(rt#i$pHOT@B$*gLf@F60nToadt&fGXG7QoJNr@Z z%;OO?YX>{CmF+AZol#6oRG4dK$NnDV5t~86%vekfVHmMuDN<+kRAf1^jExVhE+-l? z-CR2pCwc{4B()9hPZaIhCOI!rw1BzxMWPrC@vS9^r`ZO%GD$QenQ$&iJdWI!$>K49 z;$)#7SH7Ptf**VfZP+|qX{ikh{r^8UEI+uutkU{DP1IvmjoUGLDupj3YK3}ylgo>j zuZ1{=rQ27{g4nw=@}ctLAdZ(RW(Z|}t;-OTAmeIhV!E4T|4c#l*Xx;r1mF2gYzxS; zD6i=E4_Q`#AVpJq{<|z&yg`;$5OkHN8(PH`#R^k6D6{?EN}^f06C2g_VH5>X2v2L$ zy0VgJz;ABE6JU|fFKv`R5rickRayA>jV*y1l_5;bp5my**eZffGhVAAj<6r)bJ-yM zkMeM~sLL;HlGduCGDUdSs4AB8!<*#iRYes_->NFs;6h|YHBlwDXfr*MBhvSSrm<^hnJ{>af=>RsA3H1n|<_|Psf{qJ2gcphE9>+Q5)>5drj%O z*QAH}gv6{(g|W%WwZ%hWQkG(#$c@6KXIvdY_G803qE5Qnpgybm@|7+^tYjI2I5)P) zNp(c3A=&9$H*!lIQTCZVX?=WBM*8XsdS-7J1!2-k|C$bodXiR#XAqQDE_|+vn!i+6 zA+({cDXo%XLe8A-#GR}MNnWv@lH_;SgSdj+&#k8<`TBYS0V7JHk@!!j4>_+RpNywf zA`^Kp)d%m5k%#JwMrmWr&++IVMhKd-G(mh6$E%BvwhhEnL2gy6zoj8$mLbm~$ZoRH z9}DR^3+Xz#)KzD3Dgsu$W*aX(jYLH(Lc>OC{!EwF!7nn{Kt6OJhc{C5_csz%bTyEW zth%HCMLd@ZstXIG;DtsyhbJ`_w@eOKA<^ZVgz!`HRv~HLgzNahgevnr9XYm%s0RF& zH~ClmB7h%#F`~4I!jCsq>+`o;a;sLnorHa|9MTlpWQ&~MRQSXgINnZtor5INv8JL; zke14etom%W?uM0ut; z_AB;hbPH&J1A#Ry#K%EFpF(maR}EiZ&kroxJt>hGQG9mCvdr=C1D=?v> zSi#tzvf_QBE5PXc#6YaZsry8GzI3~+c0UyE9$9q1*v-C|4|Eb6P{=!@@Q3a4zRqF_ zau0SEFCzDmE}|WOaff`hix}*pmmskST+gyWxS&eEXZ4k_aGjlDo2`?KSpJjC#^j+ec9U9u-ZzCJwKKMnWh#fDN$`hhc_|oD(ItZ?T0Fy7Y$W7mmj8< z!}!1l?tV>|$XJdihN)TP4pXz(I_&>w7BC~6!$oF78I<)|z=miwT*<_q!1tSzz8T$Tm{R68bBNSFQM<}dnj}-N4{rBaK_a!zeYI{-YGB7mO0G zfYkLyLo`9dj#ge({%G+gShMyRQ6)UU8j`{cu%_)ZbPTv>f}A%-d~d%D36?HkXJTKm1{Q73uVH~c%rUp-pDvWPHA;0i?8i_>qWH%Li_!0{6`jiy8l^ zME*EayhYPnHcL(K@GLPJwc5{C)0;ROvK%w{^d*Q4LbADzWV}MMMHrI$_gQ8Jk_&KP z15{cTiu6vmz#RyWVcKq3b0pREc6%(rh6&zuNHAPk?I}}ZZ>UDRwhs4f6pXR55cBuT zeTAaDeJ1iKKHy>@XjmlOMWTFF{o@H3?ZYyC;hVB_U_%jD3ApA?#>M?ZMc5|!a z6oEdoiCqW)Y1 z<$&|)SLB3w@N~DzzvhVm$h&pESj!M&)=!E@__R&(Z7F)$r@`UMLS&$~SZv|>^W|5? zKw~X#_{A_@h!5;76zQpJaJMl$%j&Z7Rv7WS)Eu4*1X8pW@5v<#p$pc_w-<^`zWP1+ z9jfD<;O`4zi3H@tm&F}KxJ`UTVR7dbF&m@LUL@W}S+~XFdA_Jb?q3Yg^vBKe+G3a% zSn^q~swIE>RWTAvUV8~xd0F7;B{=^9M{imx`Z}%|=d(6k8kAoqTJpEo%U;XGd`$G( zGBD6qIrlZu1C1}g2G%|ksP?+JkH?y=;&9jy=}o|y@r!SW?!fNU8)6pP41QB=0{Jsn zi1HouTTd+7cgCVQ6>A+2Em|zdiwk%&3QR9Q5h{-(9fu&26>1eXt-vZy-7OzqNvkMl ztQ6-tf@4Rlg0BT1f72?Mkx>6wMXBwjW4%=(A0!&JTKw#w#fFLF&dG|EKTj5ka>^R< zGEBgXwPG$`vP*7Wt8A~*wV?4C`Q$o9uZ8PGE^U#N4LC($CuO5epyn*OdXwm8|7w?2 ztAz#Un=xT^Aed0urwhWeMp0O#m~Iux%bUfckaq1$1Zm(wB~X9krQGK!91XytoZVR>kXO)$NcxtK|pVVbHFUm$$>jSS&m4fcd^!7VUtGv{lx7 zTl_+CQ`ZeA?A2qC6+AiP(!1Dwven zd&Ng&d|%zG7$EaKLI31IVElU`)@EACIAy*`SC#mlfp*iXtYjxdu3;t1P5Z>is26u4 zq*3{JH9r=QHZ#=g-#+!KzAg(l3X#{Q)g1m!Q>%Vxvg>2<2$m%AlW?Oscpx1GjY^)_ z1D`0PdGseZ#GAa}TLg`VdtSe6llwmr}>{a}+_@|FESZI}FIKk1Ri#)1a{R`FM z6JIEO{OK2ZwqvPLVE50fDccMkb;_Z+i9&gM&lkque zZ(}^RjiL7mk=__Bk>1?KXs@g8>dN`wi8S?g#Vy}?Sfm6#`%aV#eij5DrNK*CxLub^ zMFM7QJ0-q~dIQ99Dkizgt?}~aDJbMsa>!}eo5ix^v>0Gr$u%y0XGNSmbVfL2i!+cs zU#yco&WN5=CW2+1*h-mkR&3^*cFNDsDuzEN_SrY=wrc4h|G{%OrQ#p$l;^*P<%37` ziRWRPZIySQ7a#D`yQR1Q1LDWsvgCsJ7RF7%58^?`55aJgSh_Y(3Rr&>FLBB?f=*&& z=bs@uH($iQ{yy->MbVM5A7q=K#R7h1xBTvBwZhStMPK`hJyxwAq~nOoqL{rQ9akV$ zwgwJe!HG6I7pVG+xSJuo|LI@FEV`8Z^;hV*74o@jqIs-&ZAbxgc=ZMa^T9QUrWMk0 zoeVFz;<|X#z8|xMy(b^KLH){<-}Fs8`Zu_ne9bkv^`#VD$`il^O$NcK%$G?p zpZUB5XEUFVU?KBmc|Gm2`8?*UKpDl%SCQZ%=Bq?-Df3k(xSaW_5M0T8*#z-{k*b6W zzUk4AAii?(RKW3vIM3vvmLfX-Q2BvbF1*fnX-lEVoa*Vl9PyWUO{U)#-7>(hc^jKI z7R7GV*oY6UyHyRZi$I}#;f`1;Q~nYyWuL!9%KR6suSnk=(Z``}OvuTK(K~yJS)Z1l zGi&|%$=0WHll7+g2Fx?yP5dK5RQ-wpFBq`YfX57Y$bkC{xZ8l+47kyND-F2RfW-#v zR%ralH(;ItZzdWD81RAtOAUC;fQJmY&w#sSGiI%xs}-i^WW^h_(Qc;XWF?r1QY7Mx z1cCfieWW}CUP;l@7YumJfQJmY&w#rPxXpkY4Y(38mpWc*WE2~)(17^{%roFkgXUKZ zc)@_B20UiKLk8Suz}*JiX26XGT$$|6Rg1UO$S4NXO4D+(5=|N`1$AQ0L@^S{MuI?L zx=w(61LhgjD{s^@;5GwpG~h}DE;V4W0SgV7Z@@eQ z-ZUt6CD-_I!GNU(JZ3=r8x(4V_8D-u0k;`&qXAbMaH#={)4fihe$0`Rl|r5jg$b!| zPBd!7iz!Z&uJ?-FIk|cv>IKgW6ZB`laXK&_0lT!d9vrIbwJ$pGwGR53sQ;S`E^T>g zj{Y;&%vogSB=LNkwRJ1$Pu}ea_%nl@liwF70A0-t*yW9rz%I{*4Aij7R#C@h{Dl z3*JFEweOTtcH?-HlycOS*c@Dxd9vc9TUfnu*U*Rhz5{~JJ@{CP6K8UC`H-u=h3zC; z&S~0m<-$%toywLo!wC@Ps~>r~w3~5w!=vRnl^Kbxr;-=U--9DN#K(2f7P{ z1Ej5*S1t$I#--)1#g7d9*a+wY+ya;YI2AApa2sGXz@2~<0CxjI4r=*;6#?G|tPVIE zum<2hz?y)CfM8ke0AORlLx7b4j{sH%JO)?`QcRnNA5D<)9bi+yQoy?a&jMxwUI45O zcoDD};1$5T0gC~f16~7c0eBOzCE%Zc^sqfIF2~mja4Mh%m=Aal;B3IwfQ5iMcnz>S;Gcj`0Op}Qw+DU{<3~@x<(Nq? zz(q*+23!i*hw=gY0zn8N^euPVVK_#FRJJ(rFFv|qgzv?Hi+;Qd%&{qT_m@IXLY1v% z<)Q$6mYdw1vXz}-l_Sl{3s4!C0=fUFt?zUl52soCWz@#4z&|RJq%e{8n3Y$cvVQ4R z7LTZ~%JD|!Tx}z2XZ%aokzuuy&8|N~|hkspMx%VmgSFLiCriY0E0 zrIQ<+X+iEIZS`h&Dcj-A^{F3TCH!gq4L(!xxkWkzJo3r8b-!qlW%n12-_khBF?r=<~#cpbp@j zL(DzHTDPd+88A^8>rze&1(-QK z@R<5*(R!V@RBwOZlg1jvdY{DktE?MuP3zu^)+4*jdN6%Gvc0{H_2~0omxG8zLx-N` z=*uBHIjqS&^b@kbO(S$oWf0#8W((5L;c}~9iT3++VMnxg1s6@xUhcsNxgpVZ;P0aC ze^UA=_DwmpCI5z@J2(;%+HDe1v9j?m8{$0KS<@1qi+>u=8T@xjo%9c^8cB4?bJY@~ zs++2zx@K*krGC>tC0~(FhVHT?>L8vfB!CHsnxO|7PVJ8wBpXL-p|2Zx-O7}5_}mpd zidkckgJW(t{?RS9uDSQqx>nSgQ0<#I+){feUD4agOFP@)?W~}_&6FxI#5wU}w#$J_ zRl+3n$y{Tb8IP!9LKj})+f3JOxu$Xpy|FTuI##D8HmT12+1SrC5b3quA-xv5BQ*4y z@g@teQ1y1O6|(tm2Yn_?>9zMAzSxjnt7-}j=vs518G=#YXE6vV*g`Kj<*o>8wOm-P zW(!@^DIp6g(-{ z8C+~8F5p7og2+pqv_M5@A8wVd7;9=nQ^%J@#H%BcY#@^GH=@WMG1kgv%%}tZDxxvz zWHpe^SBarExCLH^NwaS9gBWY2m(GgtXb?KneMUHhzw?S^;o-vQY$>x z$}S~qvgoY@)>69TK*lK)p@)Av#22esNW8-Cbl?Rr@pV#geB!X@%zr*2k=D@){}B(fAr{+0EQYLY5O_X=R*!qtLU$*Wle3Z(Giv$H9QBcNZ&&40=D|ZG5jvG1s#989 z3Xjp@#n}pZCDb}S3!50=ZqQzkot)fq~0paL0CwisqL@yWNVFD&Pz5gHIPv2dNx}A5ob*+S58X}PC;$e@v=(1wNh?766W4AN}7Z@Sjy{d zZz$;w|5ZsxTl%zC;HVqDve&jM@BHbkJt{E;`(1$~8r^@4pyLMr0Ll}B9L&WLpKO_n{IktLod3o&^9aB?ir}ow$R$N-C%mFhVgnsr`hmC zX!tCpZ%v%h&al8$JFng@8SQ92GC~xE5Ui63krg6aX0VXR_MDcfQ#)uS!M(;Ywn??B zd~GyN)3LYypW?m+zN+Hd`|N#Y=j3rtazfq@;GDxNAWsEU1Yx5f;sdm{+S=Qy#oqox zA4)B@#oH4!YA#Y6EjUr5rWQ4=v5oywleST#rW$M1s8ORujW)EYjSwVi)F}7A*35pK zfZX1G_xpYFi~DhA&#YPRS+iz_lo0uNCT+8&h|%WN8XH$@Ox5Zb zm&Z=j9KZaC9G?+RXACD?xU~C{P=NXJb&kOCQ+!`D$4^mTyPTT^KZzP5Y&3Y-nCgC~ zIex184sxbA9x)dvcLyDqmH3}?{4iKf<P$6@gE8hiu%2Q)O5GB;_m6HJo90aNRDt6^rSP8nrRMXd?tGjd)3YuSM3Z{t*fFC z+=2=4Y8`QF^>KGnL0jh$v?8V2|FA1mwJskZR)#4j&$85KVxG$x2$aJC!C+v8B7HfB zNoz7I;qw(?^t&>K02}75G834-gfBZYSd%2-z`NSa#LQK`PqXpq$(ZS7M;=A(D%ie7 z6*L3=T{bPqSge!nn?) zVR?3p;lgwDJIv`9-9ynQvJF&Wt~^*OV#(u3VvAEGR@=WJE9PT!f9-_ynID11PfG$eLF!PK?sg^yTygJ z*hj0cU1rXTWN<@lwmftk<9?@w;28BCL{A9;<|1IW9DKlRr3k@v$LTqeqt^U@JZmyc z`~-WU+Zx%6g{moqdWvQdY;_)Ni`>!#Thd-Mu1j+Xv^otMkJIWi$k9ilxQch^E+F>Z zhuF7VkuSo@*+ej{P3NRWI-|ZwXOzb5UZiue3kpX%7b{3qhJD1+?M$Vr!^)*SDz)mc zQ}txb?y2pcxg2TmWBql@+882S392dma9ouho29vG$`QFrIf4`HK7On1ZYbmd6c55iYCmQM-}*>ZTYW&SjbA3JHgO2W57=m0;0c51h1{DK!g{8D~N z6(F&j$DwWcIJ5-`ZOc{9Tw{*uQmP-8H>3yeGwdPtrrGIhh1r5G5#A^lqEX{bJ~vIw zII~5SZFI`o4GvzKT)ecYG7U}(usR`x2QXEfpMsZ;e0k|oQ6?{(E+&4SdW6|ZWR%d| zj#LcR`7mgMuYf^SIA9-49EnZFvX<#f|DLExQRtyfnnnMJK zkxYVNY+8bQi`$VjB&tCBRhXk`31SUA6ss{^Qt1e+c?ZeTY-1w`SU{HoxFHCM6YM)c zOoF#nw_&z4$jc~{ z8)qSyi5ir!adfyVRffA^2_4;bILYJ?KKACdk4uqEa3m!PA+dp&mcy7|=2szxOdn%sSch4JI>)dNfSNXBD_W z2h2Yd4P&TRqhS=cT6vFfZPV!od(Yn}?&#vJjd+-b54vbqu6*Mtu`t?JI$0 zo)N5zwXb@RvNBo;q<$oDfftW+Bf3jjw+$f8iv~oxhl9DKv5Vv#>qMH&njH$G3LC-o6BNnu^0YX|@0`Y>I1WV6SVgeKyj9W$xr6QT;xSU>>) z38=lB%W2<-oeC1i-a^$8NE)@(heGO>E+j-$A)D1<3v2-I@D@f3RR+1W5{mgCtrnz_ zhqf@~;s5+KC-&$M=9q(e41+rU8YQM3FH|IrkRraE5K{ zun!3ESwspBu(jx}vLBCaYVAD_L$4Au>8|BXz*&^84~DLp_8;Y?^TZ^$nfQKK+dmKi zT%^aDh#d}w6PPWdmm_2Ya2*T7y~Zz9kpw9Nwj|Lf&A3H&)zv<=&@vgG+ih>hGm9x+ zLLA9`Bj>u&s4d7pHy~%R?+FhzlgXJoNT|^hurG-dqgQh~| zzqKt8(PSGn?^gtPW}U!_pg<{eV$^n3P)~BhjmI;Kco=K*Q2|*4JD=|;5wk-TFV=?B z?!`090J$_&oRSD)l}WlqKkQEY?(?R>DZXJ$4d(SU@EFmM`5^jXJfj={C>h+cX8;v} zil9Ei>hukywSW<@y90kh5LA&D0Kh>tjCJsW2RBd?Jei8F4~FIG$B8MlKESR5qq5Zd z)?ylb)gl4b)E z;qJ75F}Afjd`n%rrDC@wjF@z_wM=o0t}MT&&`-o53^04q>^v5FDeijn7~(EMKDgT* z_znxrU1I{=#g=B5Dl;rx?ivw_yNXh5O;ZtZS4?hRh}aW51NqQ+;HGr)XXgZpmD`|3 ztJ`5P@sk!YXgfS>i&TqSW(a3I1%2YB@q^&LG=A@^da6*1ccgMdERVc%H>;aCh7Cfl z*2kovNHY;bc=X3J>Hvd)kJ34;Ta@dF})9i6ri{h}+R1O={95(M*q)_%z!#@2r zgy+NRuidJktG|Zvd<6Z~uZp|+YXr|n(q9Ak{eMM&jiMsI{u%@e{0sW4BI$79)2VDQ zUUhwJ*iRqA3ig=8cy$iNpktUj<^*a%6<2jNc>MNEN<$YMq9oDMGrA>C{vp#1=GvvJ zZO}~Cn8IXL@P|FsMXpbc!&sj?Ud%8%isk)N#l(56qdJKQi2ivTRINCu3!6Ur{Ne6m zrK1Lq7rCUPwA~^Lri>F57K{_wCXOx$QeC7AILJ^8`6HHN?bku@`7~G~p0!Z4d$*mq z)q1UoK2RE}ncnIJD=oNBQFn)0KpyjQOwSookv`LAk1QbbCoCSSVh++jwP7TWwI0d> z0*WfKfJ(t(>{+HQAO=^ybRyDxSR}%#El;U7C>y&!sO@2opVp3IgI$b%Xy8aRrPw?o z+uZMs$V4sF2uT zH0ak>Jr3SkLy^zlr#o}gQYffe!ap>f1E1X!1fA&B?x14=cc?NwLDvNKa#MC)NeX+_ zmk@g$l^jHQJt(ijA|bwo1yl~t2vuhHIHBKRex&drq5=Voa>)tAqt6Sf2Z`0DEG}be(I+&a&u`VCnae8(Sn}wEgGdj35`SYH&Sec1Jy|^rLgCzsOv`*qD7p} zQ9Yx88>{3e*e`g3EI>W?A3hC4-!SmI5@w%U+fIZ>>b>cN7uwW|QN#67s!fb!lDz4m z;xF3r5J5Jy%Is0CaaYPYhut z9~!D6Z9asC=#+Qu9*kgFGDmo@+FhweDp^DG3J8<%GEU#AW!W^3j15MdBg-&qfb{x~ zEX%gv-UWivrbT_4!DwWm*4SW(30$+Etl6~&&-%8?yRBx5V2V+Ze|xzC5f(v#h#ELL zNQ#N(0F^Q)NM7+6(E;@p0wamdlN7A4`b*r1E!A)!mVu)|-BA!~`LkCBGkh3WV}qqX zrlPXwkPH4>GW#*BN-@LgesmJD~-E zGS@k%#|zCQJG|Ql+~$zuq+Pu_JWu0$yu|=+)gcP8O}ij+(ppiT^hxY4e2Ny^+!mX$ zAxjrl1;QVtAKHVg`WjWSX17?QLQ2(Ly=u};5aJ${1UepHNd7Ap*;qZ-ZZIpI?(`%LVW)2L{o4Or88M;)xHEu&y zAcM~WZC7OIR>i8^Vx!owlj&6LlA%YH88uxaIc73SdsE5KmxRzcQ!|7?XWBW%BGtjS zB|g}pNZB;eZ;@2Y+wM10Ez(*NYRxkQZ7so^B z%PQd0Nun^=$oHXHHu8V*+H-LH7u}GL(|0Sp^ttUMd(0H$wA*A>?^oq|+;UwGj(bgq z)dy6WE)U1u3de(~I379@iqGSiGP*v<^Te15FnPKbbCN!PtQlG)Kr<}F>u|JaNJf;> zI&}n)u!4Zbj3R(fsWp6Re6pB4PW*I}c0s}2Nql;GB?Vs&n@T1Rl}UBTU<%G7$~-=PGzZeog! zs-MWZkwtXT4)*>>`dv^8ea`u3E5?jsu1@cgC_ba%x;4x;Kqx4 zOwd>_hKpI5jK^WBayKI7!lDWO=_HAz*f)VB5!YjItu3pJ&%t#Eu5)p%!Id|Fz;za$ zx8u41*J@m6<64L7R9x$EJqp(bT&F;qC*zN@H74PYvNb}O15CQ3cTAe)t^qZ0p}*70 z;u*2&7}dhYhGIxW$iXF!JvLSb;y6qrj$M`FCdRcClFva7Vxb(hQ@R|hj zY^v$Z^_8J3&>#(u6X~#2g?94v2nN08J$4AIXK8UR?-mDl9|tgOyIWxEOP;nHQlpD6 z^NCSJjq~EgNT7|GD}yzO;5`Y9O4lYbw2A7+w>|iFBEU7H@9+pyeZRr|9{XR>_kaXV zMhp`xgl+Sb1fSuAMM*d|l8_dnEB&nn0)b@Cv;dyc(dPozL(5MCI?{oTY~Uq{srnG^ zA~AARfQD=j4YBZLXl?RoWt)H~MjNJx30-Lv2_S8a^BO5=fQ7`BIOkKN#;zeUP<3mN zQA6EH$X6GK!@On z>#TLY8pc<@x(9puVWFHNI0Oybn7Q9x!ru}Oynlq}joD_vKuSv?k)F63$A(gO2tyn! zSyM*b?LMB0N2DLcgIZizEHWaLic(OCO)uGx0FvG+bcRF(S`MqD^EeL9xY3 zHpVhGCNiR>F<$9ZW$3MS2r<=0Vv;uGNG(E^ML1r9WrGeHXgmFX1r3mYjR!!f&@l7= z4h@;((U9q&f#~C+0c+<84HdLK4o-5x4~IbmbSiC9r-PF8u)|19*8UA*tMG3K4e42+ zJu1U;TZjlQE-n^gHyL`lF-r0)n^%0h323FtwqZ$d=U@-)IK^t36+|_ zQJI$}3bNC{<3V9T+i7T^%*vd5D7k6&58?$-Y6Z|gXpA))kP#~*O;7wbZFS^m1_%m+ z+s;PY=>Ux+IUSr!niLC?U~HXglW1d_^ME$y0bR&mjN`bXcsAO~Ml%r-G1N`8oVPlH z6fSOrx?DzGj%8nla?qHu^i60vo75u^L-+x3s?Ss{&Q%Dkf#wBpC_tNhPDFTt_Hzp3 z5i4XSLb=$@q(`w=27ZLeQolj;%aC=5QW%)PRO48}g6KXY2K$VC4_)=~eW;HNvatmK zB5)?s*6l{F4a_nT-N!G;{p0=_gbEmKv=4Fm6O>YRbgvPEA*YQH-5RksVsRKk4fD?h zA40(}6@&*sTPnH*vCCpHfTp&y>;`Vsmiw z9t9CdpM)Ton0tYpP)}SFdcs;>^`QZfW!vvS8>bUw$T3wmbe9Jmwsa&bs<9yyB4CqF z7s(X_AQ&PAIFJU144jIHIr$`fNs#4(kFpVJ7lsVp13o0-%5YTmcp-}wo{61ZgMiJI zu|jZKA<0;pqns}Wk7=icvT-Q=n7CO$oRy%(@x2x_%7A1+%Q>u|<#~dJ%wEOtFyJYY zmPV46lOkyh6Qlt7!ALY<_`v-?i01&Z9FnvglC(6|?0KtkgP9Mqsj~nsHn0MmWG6_{ z(zK+dX-Ug-B#o;jNh6i-v;mT`n?fT#N7AtIe$BdhjH$r7RJ4phULAZoAQ}RYGoL$Gv3af(OHtOFXZ+Sj>YXpboki5aK zrF}qMuE*A(%vUs(>PQ^>L8M{GbwJ-p;>aCK()l{n=Pc#1LX`Ol$-r6wg35=|0>GXW z@lVM0q|{UH={Oxh3jkz{g)IwtzN(g0ppZe?x^@S`xO`p(W*Bgrqd~x9tZ-*GP6j#=z)6j3x0UJW9u^KU0D7bZ(?}yF^p3a-{sN7ZbidmX zqDB%DI_`Xfxl22s)*jjD5UoxHm*0_zTWkvCbgTozIUNJ-@@_kE8^&}qVX@77-LA%T zcrVMBiAiQdiCnr&los#CjHs@p54Sqp+FK&Oy-Z9udx}-5?Ov%GuT*u3>{=$u%Q<|; zX~fiM6(==top4}oI#Co9w|BVh#q&s^S`_V!H}y`78{{?P(6b*Qr8P4mfah(>Rh^pPKdDfYfR9iqMl1 zD*(Hyj04?4EVRU86q2}lu4iVjHZ2~si?RNLaNLOI!i$qi__<0ZE5f~90SbD#^iVBM+CquF)d%

rF+ucP~<)j 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 z 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 F{{x2z?", txGasUsed) } diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 1e4a7c7a..36e53c3b 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -10,7 +10,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/CosmWasm/wasmd/x/wasm" - "github.com/archway-network/archway/app" "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" cryptoCodec "github.com/cosmos/cosmos-sdk/crypto/codec" @@ -29,6 +28,8 @@ import ( tmProto "github.com/tendermint/tendermint/proto/tendermint/types" tmTypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" + + "github.com/archway-network/archway/app" ) // TestChain keeps a test chain state and provides helper functions to simulate various operations. @@ -255,11 +256,13 @@ func (chain *TestChain) GetApp() *app.ArchwayApp { } // NextBlock starts a new block with options time shift. -func (chain *TestChain) NextBlock(skipTime time.Duration) { - chain.endBlock() +func (chain *TestChain) NextBlock(skipTime time.Duration) []abci.Event { + ebEvents := chain.endBlock() chain.curHeader.Time = chain.curHeader.Time.Add(skipTime) - chain.beginBlock() + bbEvents := chain.beginBlock() + + return append(ebEvents, bbEvents...) } type SendMsgOption func(opt *sendMsgOptions) @@ -276,7 +279,7 @@ func SendMsgWithFees(coins sdk.Coins) SendMsgOption { } // SendMsgs sends a series of messages. -func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg, opts ...SendMsgOption) (sdk.GasInfo, *sdk.Result, error) { +func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg, opts ...SendMsgOption) (sdk.GasInfo, *sdk.Result, []abci.Event, error) { options := &sendMsgOptions{ fees: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)), gasLimit: 10_000_000, @@ -315,10 +318,10 @@ func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg require.Nil(t, res) } - chain.endBlock() - chain.beginBlock() + ebEvents := chain.endBlock() + bbEvents := chain.beginBlock() - return gasInfo, res, err + return gasInfo, res, append(ebEvents, bbEvents...), err } // ParseSDKResultData converts TX result data into a slice of Msgs. @@ -334,7 +337,7 @@ func (chain *TestChain) ParseSDKResultData(r *sdk.Result) sdk.TxMsgData { } // beginBlock begins a new block. -func (chain *TestChain) beginBlock() { +func (chain *TestChain) beginBlock() []abci.Event { const blockDur = 5 * time.Second chain.lastHeader = chain.curHeader @@ -345,11 +348,15 @@ func (chain *TestChain) beginBlock() { chain.curHeader.ValidatorsHash = chain.valSet.Hash() chain.curHeader.NextValidatorsHash = chain.valSet.Hash() - chain.app.BeginBlock(abci.RequestBeginBlock{Header: chain.curHeader}) + res := chain.app.BeginBlock(abci.RequestBeginBlock{Header: chain.curHeader}) + + return res.Events } // endBlock finalizes the current block. -func (chain *TestChain) endBlock() { - chain.app.EndBlock(abci.RequestEndBlock{Height: chain.curHeader.Height}) +func (chain *TestChain) endBlock() []abci.Event { + res := chain.app.EndBlock(abci.RequestEndBlock{Height: chain.curHeader.Height}) chain.app.Commit() + + return res.Events } diff --git a/e2e/testing/chain_ops.go b/e2e/testing/chain_ops.go index 2c1f07d2..1cf51c58 100644 --- a/e2e/testing/chain_ops.go +++ b/e2e/testing/chain_ops.go @@ -21,7 +21,7 @@ func (chain *TestChain) ExecuteGovProposal(proposerAcc Account, expPass bool, pr msg, err := govTypes.NewMsgSubmitProposal(proposalContent, depositCoin, proposerAcc.Address) require.NoError(t, err) - _, res, _ := chain.SendMsgs(proposerAcc, true, []sdk.Msg{msg}) + _, res, _, _ := chain.SendMsgs(proposerAcc, true, []sdk.Msg{msg}) txRes := chain.ParseSDKResultData(res) require.Len(t, txRes.Data, 1) diff --git a/e2e/testing/chain_ops_contract.go b/e2e/testing/chain_ops_contract.go index 94ee8e12..b16c54a7 100644 --- a/e2e/testing/chain_ops_contract.go +++ b/e2e/testing/chain_ops_contract.go @@ -4,8 +4,9 @@ import ( "encoding/json" "io/ioutil" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/archway-network/archway/x/gastracker" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) @@ -23,7 +24,7 @@ func (chain *TestChain) UploadContract(sender Account, wasmPath string, instanti InstantiatePermission: &instantiatePerms, } - _, res, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) + _, res, _, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) require.NoError(t, err) txRes := chain.ParseSDKResultData(res) @@ -56,7 +57,7 @@ func (chain *TestChain) InstantiateContract(sender Account, codeID uint64, admin Funds: funds, } - _, res, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) + _, res, _, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) require.NoError(t, err) txRes := chain.ParseSDKResultData(res) @@ -101,25 +102,27 @@ func (chain *TestChain) GetContractInfo(contractAddr sdk.AccAddress) wasmdTypes. } // GetContractMetadata returns a contract metadata. -func (chain *TestChain) GetContractMetadata(contractAddr sdk.AccAddress) gastracker.ContractInstanceMetadata { +func (chain *TestChain) GetContractMetadata(contractAddr sdk.AccAddress) rewardsTypes.ContractMetadata { t := chain.t - metadata, err := chain.app.GasTrackingKeeper.GetContractMetadata(chain.GetContext(), contractAddr) - require.NoError(t, err) + state := chain.app.RewardsKeeper.GetState().ContractMetadataState(chain.GetContext()) + + metadata, found := state.GetContractMetadata(contractAddr) + require.True(t, found) return metadata } // SetContractMetadata sets a contract metadata. -func (chain *TestChain) SetContractMetadata(sender Account, contractAddr sdk.AccAddress, metadata gastracker.ContractInstanceMetadata) { +func (chain *TestChain) SetContractMetadata(sender Account, contractAddr sdk.AccAddress, metadata rewardsTypes.ContractMetadata) { t := chain.t - txMsg := gastracker.MsgSetContractMetadata{ - Sender: sender.Address.String(), + txMsg := rewardsTypes.MsgSetContractMetadata{ + SenderAddress: sender.Address.String(), ContractAddress: contractAddr.String(), - Metadata: &metadata, + Metadata: metadata, } - _, _, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) + _, _, _, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) require.NoError(t, err) } diff --git a/e2e/testing/ibc_path.go b/e2e/testing/ibc_path.go index 9bc9499a..b2822de6 100644 --- a/e2e/testing/ibc_path.go +++ b/e2e/testing/ibc_path.go @@ -297,7 +297,7 @@ func (e *IBCEndpoint) createIBCClient() { ) require.NoError(t, err) - _, res, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) + _, res, _, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) clientID := GetStringEventAttribute(res.Events, clientTypes.EventTypeCreateClient, clientTypes.AttributeKeyClientID) require.NotEmpty(t, clientID) @@ -346,7 +346,7 @@ func (e *IBCEndpoint) sendConnectionOpenInit() { srcChainSenderAcc.Address.String(), ) - _, res, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) + _, res, _, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) e.connectionID = GetStringEventAttribute(res.Events, connectionTypes.EventTypeConnectionOpenInit, connectionTypes.AttributeKeyConnectionID) require.NotEmpty(t, e.connectionID) @@ -386,7 +386,7 @@ func (e *IBCEndpoint) sendConnectionOpenTry() { srcChainSenderAcc.Address.String(), ) - _, res, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) + _, res, _, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) if srcChainConnectionID == "" { e.connectionID = GetStringEventAttribute(res.Events, connectionTypes.EventTypeConnectionOpenTry, connectionTypes.AttributeKeyConnectionID) @@ -460,7 +460,7 @@ func (e *IBCEndpoint) sendChannelOpenInit() { srcChainSenderAcc.Address.String(), ) - _, res, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) + _, res, _, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) e.channelID = GetStringEventAttribute(res.Events, channelTypes.EventTypeChannelOpenInit, channelTypes.AttributeKeyChannelID) require.NotEmpty(t, e.channelID) @@ -491,7 +491,7 @@ func (e *IBCEndpoint) sendChannelOpenTry() { srcChainSenderAcc.Address.String(), ) - _, res, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) + _, res, _, _ := srcChain.SendMsgs(srcChainSenderAcc, true, []sdk.Msg{msg}) if e.channelID == "" { e.channelID = GetStringEventAttribute(res.Events, channelTypes.EventTypeChannelOpenTry, channelTypes.AttributeKeyChannelID) diff --git a/e2e/voter_test.go b/e2e/voter_test.go index 1df1bbf2..5c350831 100644 --- a/e2e/voter_test.go +++ b/e2e/voter_test.go @@ -6,6 +6,8 @@ import ( "strconv" "time" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" + voterPkg "github.com/CosmWasm/cosmwasm-go/example/voter/src/pkg" voterCustomTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/pkg/archway/custom" voterState "github.com/CosmWasm/cosmwasm-go/example/voter/src/state" @@ -13,12 +15,12 @@ import ( cwStd "github.com/CosmWasm/cosmwasm-go/std" cwTypes "github.com/CosmWasm/cosmwasm-go/std/types" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" - e2eTesting "github.com/archway-network/archway/e2e/testing" - "github.com/archway-network/archway/x/gastracker" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" channelTypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types" + + e2eTesting "github.com/archway-network/archway/e2e/testing" ) const ( @@ -761,15 +763,12 @@ func (s *E2ETestSuite) TestVoter_WASMBindingsMetadataQuery() { acc1, acc2 := chain.GetAccount(0), chain.GetAccount(1) contractAddr := s.VoterUploadAndInstantiate(chain, acc1) - cmpMetas := func(metaExp gastracker.ContractInstanceMetadata, metaRcv voterCustomTypes.ContractMetadataResponse) { - s.Assert().EqualValues(metaExp.DeveloperAddress, metaRcv.DeveloperAddress) - s.Assert().EqualValues(metaExp.RewardAddress, metaRcv.RewardAddress) - s.Assert().EqualValues(metaExp.GasRebateToUser, metaRcv.GasRebateToUserEnabled) - s.Assert().EqualValues(metaExp.CollectPremium, metaRcv.PremiumEnabled) - s.Assert().EqualValues(metaExp.PremiumPercentageCharged, metaRcv.PremiumPercentage) + cmpMetas := func(metaExp rewardsTypes.ContractMetadata, metaRcv voterCustomTypes.ContractMetadataResponse) { + s.Assert().EqualValues(metaExp.OwnerAddress, metaRcv.OwnerAddress) + s.Assert().EqualValues(metaExp.RewardsAddress, metaRcv.RewardsAddress) } - getAndCmpMetas := func(metaExp gastracker.ContractInstanceMetadata) { + getAndCmpMetas := func(metaExp rewardsTypes.ContractMetadata) { metaRcvStargate := s.VoterGetMetadata(chain, contractAddr, true, true) cmpMetas(metaExp, metaRcvStargate) @@ -777,38 +776,22 @@ func (s *E2ETestSuite) TestVoter_WASMBindingsMetadataQuery() { cmpMetas(metaExp, metaRcvCustom) } - var metaExp gastracker.ContractInstanceMetadata + var metaExp rewardsTypes.ContractMetadata s.Run("No metadata", func() { s.VoterGetMetadata(chain, contractAddr, true, false) }) s.Run("Set initial meta", func() { - metaExp.DeveloperAddress = acc1.Address.String() - metaExp.RewardAddress = acc1.Address.String() + metaExp.OwnerAddress = acc1.Address.String() + metaExp.RewardsAddress = acc1.Address.String() chain.SetContractMetadata(acc1, contractAddr, metaExp) getAndCmpMetas(metaExp) }) s.Run("Change RewardAddress", func() { - metaExp.RewardAddress = acc2.Address.String() - chain.SetContractMetadata(acc1, contractAddr, metaExp) - - getAndCmpMetas(metaExp) - }) - - s.Run("Set GasRebateToUser", func() { - metaExp.GasRebateToUser = true - chain.SetContractMetadata(acc1, contractAddr, metaExp) - - getAndCmpMetas(metaExp) - }) - - s.Run("Set Premium", func() { - metaExp.GasRebateToUser = false - metaExp.CollectPremium = true - metaExp.PremiumPercentageCharged = 50 + metaExp.RewardsAddress = acc2.Address.String() chain.SetContractMetadata(acc1, contractAddr, metaExp) getAndCmpMetas(metaExp) @@ -824,56 +807,56 @@ func (s *E2ETestSuite) TestVoter_WASMBindingsMetadataUpdate() { s.Run("Fail: no metadata", func() { req := voterCustomTypes.UpdateMetadataRequest{ - DeveloperAddress: acc2.Address.String(), + OwnerAddress: acc2.Address.String(), } err := s.VoterUpdateMetadata(chain, contractAddr, acc1, req, false) - s.Assert().Contains(err.Error(), "not found") + s.Assert().Contains(err.Error(), "unauthorized") }) - // Set initial meta (admin as the DeveloperAddress) + // Set initial meta (admin as the OwnerAddress) { - meta := gastracker.ContractInstanceMetadata{ - DeveloperAddress: acc1.Address.String(), - RewardAddress: acc1.Address.String(), + meta := rewardsTypes.ContractMetadata{ + OwnerAddress: acc1.Address.String(), + RewardsAddress: acc1.Address.String(), } chain.SetContractMetadata(acc1, contractAddr, meta) } - s.Run("Fail: update DeveloperAddress: unauthorized", func() { + s.Run("Fail: update OwnerAddress: unauthorized", func() { req := voterCustomTypes.UpdateMetadataRequest{ - DeveloperAddress: acc2.Address.String(), + OwnerAddress: acc2.Address.String(), } err := s.VoterUpdateMetadata(chain, contractAddr, acc1, req, false) - s.Assert().Contains(err.Error(), "does not have permission") + s.Assert().Contains(err.Error(), "unauthorized") }) - // Update meta (set ContractAddress as the DeveloperAddress) + // Update meta (set ContractAddress as the OwnerAddress) { - meta := gastracker.ContractInstanceMetadata{ - DeveloperAddress: contractAddr.String(), + meta := rewardsTypes.ContractMetadata{ + OwnerAddress: contractAddr.String(), } chain.SetContractMetadata(acc1, contractAddr, meta) } s.Run("OK: update RewardAddress", func() { req := voterCustomTypes.UpdateMetadataRequest{ - RewardAddress: acc2.Address.String(), + RewardsAddress: acc2.Address.String(), } s.VoterUpdateMetadata(chain, contractAddr, acc1, req, true) meta := chain.GetContractMetadata(contractAddr) - s.Assert().Equal(contractAddr.String(), meta.DeveloperAddress) - s.Assert().Equal(acc2.Address.String(), meta.RewardAddress) + s.Assert().Equal(contractAddr.String(), meta.OwnerAddress) + s.Assert().Equal(acc2.Address.String(), meta.RewardsAddress) }) - s.Run("OK: update DeveloperAddress (change ownership)", func() { + s.Run("OK: update OwnerAddress (change ownership)", func() { req := voterCustomTypes.UpdateMetadataRequest{ - DeveloperAddress: acc1.Address.String(), + OwnerAddress: acc1.Address.String(), } s.VoterUpdateMetadata(chain, contractAddr, acc1, req, true) meta := chain.GetContractMetadata(contractAddr) - s.Assert().Equal(acc1.Address.String(), meta.DeveloperAddress) - s.Assert().Equal(acc2.Address.String(), meta.RewardAddress) + s.Assert().Equal(acc1.Address.String(), meta.OwnerAddress) + s.Assert().Equal(acc2.Address.String(), meta.RewardsAddress) }) } diff --git a/go.mod b/go.mod index 234cf8aa..8e6cf339 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/archway-network/archway go 1.18 require ( - github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220719123407-a0448ffb23f6 + github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220729111547-079232ac0432 github.com/CosmWasm/wasmd v0.25.0 github.com/CosmWasm/wasmvm v1.0.0-rc.0 github.com/cosmos/cosmos-sdk v0.45.1 diff --git a/go.sum b/go.sum index 5cf8f243..7b459caf 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220719123407-a0448ffb23f6 h1:aNPZ+lxgtnsDPuDld0y+/1YKOfqPIEWEOoJ9Yfxnr58= -github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220719123407-a0448ffb23f6/go.mod h1:qCTzr8cQYwoYdA9AT4azEVbiYGjULS1nrUgw6YScXks= +github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220729111547-079232ac0432 h1:51VJ/RwtL5rm+vAovcxAray9B4zQuBGzfxmnhQXIhCY= +github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220729111547-079232ac0432/go.mod h1:qCTzr8cQYwoYdA9AT4azEVbiYGjULS1nrUgw6YScXks= github.com/CosmWasm/tinyjson v0.9.0 h1:sPjgikATp5W0vD/v/Qz99uQ6G/lh/SuK0Wfskqua4Co= github.com/CosmWasm/tinyjson v0.9.0/go.mod h1:5+7QnSKrkIWnpIdhUT2t2EYzXnII3/3MlM0oDsBSbc8= github.com/CosmWasm/wasmvm v1.0.0-rc.0 h1:YI0ytwQZewPhSNxlqsrZ3/bVKTYXmrR1bfVapleCXWk= diff --git a/pkg/cli_args.go b/pkg/cli_args.go new file mode 100644 index 00000000..211fba41 --- /dev/null +++ b/pkg/cli_args.go @@ -0,0 +1,17 @@ +package pkg + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ParseAccAddressArg is a helper function to parse an account address CLI argument. +func ParseAccAddressArg(argName, argValue string) (sdk.AccAddress, error) { + addr, err := sdk.AccAddressFromBech32(argValue) + if err != nil { + return sdk.AccAddress{}, fmt.Errorf("parsing %s argument: invalid address: %w", argName, err) + } + + return addr, nil +} diff --git a/pkg/cli_flags.go b/pkg/cli_flags.go new file mode 100644 index 00000000..1ecb44b4 --- /dev/null +++ b/pkg/cli_flags.go @@ -0,0 +1,30 @@ +package pkg + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/spf13/cobra" +) + +// ParseAccAddressFlag is a helper function to parse an account address CLI flag. +func ParseAccAddressFlag(cmd *cobra.Command, flagName string, isRequired bool) (*sdk.AccAddress, error) { + v, err := cmd.Flags().GetString(flagName) + if err != nil { + return nil, fmt.Errorf("parsing %s flag: %w", flagName, err) + } + + if v == "" { + if isRequired { + return nil, fmt.Errorf("parsing %s flag: value is required", flagName) + } + return nil, nil + } + + addr, err := sdk.AccAddressFromBech32(v) + if err != nil { + return nil, fmt.Errorf("parsing %s flag: invalid address: %w", flagName, err) + } + + return &addr, nil +} diff --git a/pkg/coins.go b/pkg/coins.go new file mode 100644 index 00000000..79689306 --- /dev/null +++ b/pkg/coins.go @@ -0,0 +1,23 @@ +package pkg + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// SplitCoins splits coins in a proportion defined by the ratio. +// CONTRACT: inputs must be valid. +func SplitCoins(coins sdk.Coins, ratio sdk.Dec) (stack1, stack2 sdk.Coins) { + stack1 = make([]sdk.Coin, len(coins)) + stack2 = make([]sdk.Coin, len(coins)) + + for i, coin := range coins { + stack1Coin := sdk.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.ToDec().Mul(ratio).TruncateInt(), + } + stack2Coin := coin.Sub(stack1Coin) + + stack1[i] = stack1Coin + stack2[i] = stack2Coin + } + + return +} diff --git a/pkg/coins_test.go b/pkg/coins_test.go new file mode 100644 index 00000000..9a7793c7 --- /dev/null +++ b/pkg/coins_test.go @@ -0,0 +1,66 @@ +package pkg + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSplitCoins(t *testing.T) { + type testCase struct { + coins string + ratio string + stack1Expected string + stack2Expected string + } + + testCases := []testCase{ + { + coins: "100uatom", + ratio: "0.5", + stack1Expected: "50uatom", + stack2Expected: "50uatom", + }, + { + coins: "100uatom", + ratio: "0.75", + stack1Expected: "75uatom", + stack2Expected: "25uatom", + }, + { + coins: "11uatom", + ratio: "0.50", + stack1Expected: "5uatom", + stack2Expected: "6uatom", + }, + { + coins: "13uatom,20ubtc", + ratio: "0.25", + stack1Expected: "3uatom,5ubtc", + stack2Expected: "10uatom,15ubtc", + }, + } + + for _, tc := range testCases { + t.Run(fmt.Sprintf("%s -> {%s , %s} with %s", tc.coins, tc.stack1Expected, tc.stack2Expected, tc.ratio), func(t *testing.T) { + coins, err := sdk.ParseCoinsNormalized(tc.coins) + require.NoError(t, err) + + ratio, err := sdk.NewDecFromStr(tc.ratio) + require.NoError(t, err) + + stack1Expected, err := sdk.ParseCoinsNormalized(tc.stack1Expected) + require.NoError(t, err) + + stack2Expected, err := sdk.ParseCoinsNormalized(tc.stack2Expected) + require.NoError(t, err) + + stack1Received, stack2Received := SplitCoins(coins, ratio) + assert.ElementsMatch(t, stack1Expected, stack1Received) + assert.ElementsMatch(t, stack2Expected, stack2Received) + }) + } +} diff --git a/pkg/dec.go b/pkg/dec.go new file mode 100644 index 00000000..18e4540c --- /dev/null +++ b/pkg/dec.go @@ -0,0 +1,8 @@ +package pkg + +import sdk "github.com/cosmos/cosmos-sdk/types" + +// NewDecFromUint64 converts a uint64 value to the sdk.Dec. +func NewDecFromUint64(v uint64) sdk.Dec { + return sdk.NewDecFromInt(sdk.NewIntFromUint64(v)) +} diff --git a/proto/archway/rewards/v1beta1/events.proto b/proto/archway/rewards/v1beta1/events.proto new file mode 100644 index 00000000..8fd037f3 --- /dev/null +++ b/proto/archway/rewards/v1beta1/events.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; +package archway.rewards.v1beta1; + +option go_package = "github.com/archway-network/archway/x/rewards/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "archway/rewards/v1beta1/rewards.proto"; + +// ContractMetadataSetEvent is emitted when the contract metadata is created or updated. +message ContractMetadataSetEvent { + // contract_address defines the contract address. + string contract_address = 1; + // metadata defines the new contract metadata state. + ContractMetadata metadata = 2 [ + (gogoproto.nullable) = false + ]; +} + +// ContractRewardCalculationEvent is emitted when the contract reward is calculated. +message ContractRewardCalculationEvent { + // contract_address defines the contract address. + string contract_address = 1; + // gas_consumed defines the total gas consumption by all WASM operations within one transaction. + uint64 gas_consumed = 2; + // inflation_rewards defines the inflation rewards portions of the rewards. + cosmos.base.v1beta1.Coin inflation_rewards = 3 [ + (gogoproto.nullable) = false + ]; + // fee_rebate_rewards defines the fee rebate rewards portions of the rewards. + repeated cosmos.base.v1beta1.Coin fee_rebate_rewards = 4 [ + (gogoproto.nullable) = false + ]; + // metadata defines the contract metadata (if set). + ContractMetadata metadata = 5; +} + +// ContractRewardDistributionEvent is emitted when the contract reward is distributed to the corresponding rewards address. +// This event might not follow the ContractRewardCalculationEvent if the contract has no metadata set or rewards address is empty. +message ContractRewardDistributionEvent { + // contract_address defines the contract address. + string contract_address = 1; + // rewards_address defines the rewards address rewards are distributed to. + string reward_address = 2; + // rewards defines the total rewards being distributed. + repeated cosmos.base.v1beta1.Coin rewards = 3 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/rewards/v1beta1/genesis.proto b/proto/archway/rewards/v1beta1/genesis.proto index a3b63989..5cabe9f9 100644 --- a/proto/archway/rewards/v1beta1/genesis.proto +++ b/proto/archway/rewards/v1beta1/genesis.proto @@ -16,6 +16,14 @@ message GenesisState { repeated GenesisContractMetadata contracts_metadata = 2 [ (gogoproto.nullable) = false ]; + // block_rewards defines a list of all block rewards objects. + repeated BlockRewards block_rewards = 3 [ + (gogoproto.nullable) = false + ]; + // tx_rewards defines a list of all tx rewards objects. + repeated TxRewards tx_rewards = 4 [ + (gogoproto.nullable) = false + ]; } // GenesisContractMetadata is used init ContractMetadata state via module genesis. diff --git a/proto/archway/rewards/v1beta1/query.proto b/proto/archway/rewards/v1beta1/query.proto index 52d0ef15..0692e8dc 100644 --- a/proto/archway/rewards/v1beta1/query.proto +++ b/proto/archway/rewards/v1beta1/query.proto @@ -5,6 +5,7 @@ option go_package = "github.com/archway-network/archway/x/rewards/types"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "archway/rewards/v1beta1/rewards.proto"; // Query service for the tracking module. @@ -18,6 +19,16 @@ service Query { rpc ContractMetadata(QueryContractMetadataRequest) returns (QueryContractMetadataResponse) { option (google.api.http).get = "/archway/rewards/v1/contract_metadata"; } + + // BlockRewardsTracking returns block rewards tracking for the current block. + rpc BlockRewardsTracking(QueryBlockRewardsTrackingRequest) returns (QueryBlockRewardsTrackingResponse) { + option (google.api.http).get = "/archway/rewards/v1/block_rewards_tracking"; + } + + // RewardsPool returns the current undistributed rewards pool funds. + rpc RewardsPool(QueryRewardsPoolRequest) returns (QueryRewardsPoolResponse) { + option (google.api.http).get = "/archway/rewards/v1/rewards_pool"; + } } // QueryParamsRequest is the request for Query.Params. @@ -42,3 +53,23 @@ message QueryContractMetadataResponse { (gogoproto.nullable) = false ]; } + +// QueryBlockRewardsTrackingRequest is the request for Query.BlockRewardsTracking. +message QueryBlockRewardsTrackingRequest {} + +// QueryBlockRewardsTrackingResponse is the response for Query.BlockRewardsTracking. +message QueryBlockRewardsTrackingResponse { + BlockTracking block = 1 [ + (gogoproto.nullable) = false + ]; +} + +// QueryRewardsPoolRequest is the request for Query.RewardsPool. +message QueryRewardsPoolRequest {} + +// QueryRewardsPoolResponse is the response for Query.RewardsPool. +message QueryRewardsPoolResponse { + repeated cosmos.base.v1beta1.Coin funds = 1 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/rewards/v1beta1/rewards.proto b/proto/archway/rewards/v1beta1/rewards.proto index b07462ea..44488966 100644 --- a/proto/archway/rewards/v1beta1/rewards.proto +++ b/proto/archway/rewards/v1beta1/rewards.proto @@ -4,32 +4,78 @@ package archway.rewards.v1beta1; option go_package = "github.com/archway-network/archway/x/rewards/types"; import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; // Params defines the module parameters. message Params { option (gogoproto.goproto_stringer) = false; - // rewards_enabled flag indicates whether rewards calculation and distribution is enabled. - bool rewards_enabled = 1; - - string inflation_rewards_ratio = 2 [ + // inflation_rewards_ratio defines the percentage of minted inflation tokens that are used for dApp rewards [0.0, 1.0]. + // If set to 0.0, no inflation rewards are distributed. + string inflation_rewards_ratio = 1 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; - - string tx_fee_rebate_ratio = 3 [ + // tx_fee_rebate_ratio defines the percentage of tx fees that are used for dApp rewards [0.0, 1.0]. + // If set to 0.0, no fee rewards are distributed. + string tx_fee_rebate_ratio = 2 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false ]; } -// ContractMetadata defines the contract rewards distribution options. +// ContractMetadata defines the contract rewards distribution options for a particular contract. message ContractMetadata { option (gogoproto.goproto_stringer) = false; // owner_address is the contract owner address that can modify contract reward options (bech32 encoded). + // That could be the contract admin or the contract itself. + // If owner_address is set to contract address, contract can modify the metadata on its own using WASM bindings. string owner_address = 1; - // rewards_address is an address to distribute rewards to (bech32 encoded). + // If not set (empty), rewards are not distributed for this contract. string rewards_address = 2; } + +// BlockRewards defines block related rewards distribution data. +message BlockRewards { + option (gogoproto.goproto_stringer) = false; + + // height defines the block height. + int64 height = 1; + // inflation_rewards is the rewards to be distributed. + cosmos.base.v1beta1.Coin inflation_rewards = 2 [ + (gogoproto.nullable) = false + ]; + // max_gas defines the maximum gas that can be used for the block (consensus parameter). + int64 max_gas = 3; +} + +// TxRewards defines transaction related rewards distribution data. +message TxRewards { + option (gogoproto.goproto_stringer) = false; + + // tx_id is the tracking transaction ID (x/tracking is the data source for this value). + uint64 tx_id = 1; + // height defines the block height. + int64 height = 2; + // fee_rewards is the rewards to be distributed. + repeated cosmos.base.v1beta1.Coin fee_rewards = 3 [ + (gogoproto.nullable) = false + ]; +} + +// BlockTracking is the tracking information for a block. +message BlockTracking { + option (gogoproto.goproto_stringer) = false; + + // inflation_rewards defines the inflation rewards for the block. + BlockRewards inflation_rewards = 1 [ + (gogoproto.nullable) = false + ]; + + // tx_rewards defines the transaction rewards for the block. + repeated TxRewards tx_rewards = 2 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/rewards/v1beta1/tx.proto b/proto/archway/rewards/v1beta1/tx.proto index f1405154..3b415f85 100644 --- a/proto/archway/rewards/v1beta1/tx.proto +++ b/proto/archway/rewards/v1beta1/tx.proto @@ -20,6 +20,7 @@ message MsgSetContractMetadata { // contract_address is the target contract address (bech32 encoded). string contract_address = 2; // metadata is the contract metadata to set / update. + // If metadata exists, non-empty fields will be updated. ContractMetadata metadata = 3 [ (gogoproto.nullable) = false ]; diff --git a/proto/archway/tracking/v1beta1/genesis.proto b/proto/archway/tracking/v1beta1/genesis.proto index ba7aeccb..b8fc5951 100644 --- a/proto/archway/tracking/v1beta1/genesis.proto +++ b/proto/archway/tracking/v1beta1/genesis.proto @@ -8,10 +8,6 @@ import "archway/tracking/v1beta1/tracking.proto"; // GenesisState defines the initial state of the tracking module. message GenesisState { - // params defines all the module parameters. - Params params = 1 [ - (gogoproto.nullable) = false] - ; // tx_infos defines a list of all the tracked transactions. repeated TxInfo tx_infos = 2 [ (gogoproto.nullable) = false diff --git a/proto/archway/tracking/v1beta1/query.proto b/proto/archway/tracking/v1beta1/query.proto index 5011afca..2c7306d2 100644 --- a/proto/archway/tracking/v1beta1/query.proto +++ b/proto/archway/tracking/v1beta1/query.proto @@ -9,27 +9,12 @@ import "archway/tracking/v1beta1/tracking.proto"; // Query service for the tracking module. service Query { - // Params returns module parameters. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/archway/tracking/v1/params"; - } - - // BlockGasTracking returns block gas tracking for the latest block + // BlockGasTracking returns block gas tracking for the current block rpc BlockGasTracking(QueryBlockGasTrackingRequest) returns (QueryBlockGasTrackingResponse) { option (google.api.http).get = "/archway/tracking/v1/block_gas_tracking"; } } -// QueryParamsRequest is the request for Query.Params. -message QueryParamsRequest {} - -// QueryParamsResponse is the response for Query.Params. -message QueryParamsResponse { - Params params = 1 [ - (gogoproto.nullable) = false - ]; -} - // QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. message QueryBlockGasTrackingRequest {} diff --git a/proto/archway/tracking/v1beta1/tracking.proto b/proto/archway/tracking/v1beta1/tracking.proto index 33edd0dd..ce008f96 100644 --- a/proto/archway/tracking/v1beta1/tracking.proto +++ b/proto/archway/tracking/v1beta1/tracking.proto @@ -5,14 +5,6 @@ option go_package = "github.com/archway-network/archway/x/tracking/types"; import "gogoproto/gogo.proto"; -// Params defines the module parameters. -message Params { - option (gogoproto.goproto_stringer) = false; - - // gas_tracking_enabled flag indicates whether gas tracking is enabled (TXs and ContractOperations creation). - bool gas_tracking_enabled = 1; -} - // ContractOperation denotes which operation consumed gas. enum ContractOperation { CONTRACT_OPERATION_UNSPECIFIED = 0; // Invalid or unknown operation diff --git a/x/gastracker/mintbankkeeper/keeper.go b/x/gastracker/mintbankkeeper/keeper.go deleted file mode 100644 index 76f884b5..00000000 --- a/x/gastracker/mintbankkeeper/keeper.go +++ /dev/null @@ -1,73 +0,0 @@ -package mintbankkeeper - -import ( - "fmt" - "github.com/archway-network/archway/x/gastracker" - "github.com/archway-network/archway/x/gastracker/common" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" -) - -var ( - _ minttypes.BankKeeper = (*Keeper)(nil) -) - -type GasTrackingKeeper interface { - GetParams(ctx sdk.Context) gastracker.Params - UpdateDappInflationaryRewards(ctx sdk.Context, rewards sdk.Coin) -} - -func NewKeeper(bk minttypes.BankKeeper, gtk GasTrackingKeeper) Keeper { - return Keeper{ - bk: bk, - gtk: gtk, - } -} - -// Keeper mocks the behaviour of the bank keeper required -// by the mint module and splits inflationary rewards -// between the gas tracking module and auth's fee collector -type Keeper struct { - bk minttypes.BankKeeper - gtk GasTrackingKeeper -} - -// SendCoinsFromModuleToModule overrides the behaviour of mint's BankKeeper and redirects part of inflationary -// rewards towards the gastracker module. -func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error { - // we only care about this if the recipient is fee collector - // (which for instance is always the case) - if recipientModule != authtypes.FeeCollectorName { - return k.bk.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, amt) - } - - ratio := k.gtk.GetParams(ctx).DappInflationRewardsRatio - stakingRewards, dappRewards := common.SplitCoins(ratio, amt) - - // send to auth's fee collector - err := k.bk.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, stakingRewards) - if err != nil { - return err - } - // send to gastracker - err = k.bk.SendCoinsFromModuleToModule(ctx, senderModule, gastracker.ContractRewardCollector, dappRewards) - if err != nil { - return err - } - - if len(dappRewards) != 1 { - panic(fmt.Errorf("unexpected dapp rewards: %s", dappRewards)) - } - k.gtk.UpdateDappInflationaryRewards(ctx, dappRewards[0]) // note the minted coin is only and always one - - return nil -} - -func (k Keeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { - return k.bk.SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt) -} - -func (k Keeper) MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error { - return k.bk.MintCoins(ctx, name, amt) -} diff --git a/x/rewards/abci.go b/x/rewards/abci.go new file mode 100644 index 00000000..5ae4268f --- /dev/null +++ b/x/rewards/abci.go @@ -0,0 +1,23 @@ +package rewards + +import ( + "time" + + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/keeper" + "github.com/archway-network/archway/x/rewards/types" +) + +// BeginBlocker calculates and distributes dApp rewards for the previous block. +func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { + defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) + + curBlockHeight := ctx.BlockHeight() + if curBlockHeight <= 1 { + return + } + + k.DistributeRewards(ctx, curBlockHeight-1) +} diff --git a/x/rewards/ante/fee_deduction.go b/x/rewards/ante/fee_deduction.go new file mode 100644 index 00000000..a8cf5386 --- /dev/null +++ b/x/rewards/ante/fee_deduction.go @@ -0,0 +1,129 @@ +package ante + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/archway-network/archway/pkg" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +// RewardsKeeperExpected defines the expected interface for the x/rewards keeper. +type RewardsKeeperExpected interface { + TxFeeRewardsEnabled(ctx sdk.Context) bool + TxFeeRebateRatio(ctx sdk.Context) sdk.Dec + TrackFeeRebatesRewards(ctx sdk.Context, rewards sdk.Coins) +} + +// DeductFeeDecorator deducts fees from the first signer of the tx. +// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error. +// Call next AnteHandler if fees successfully deducted. +// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator. +type DeductFeeDecorator struct { + ak ante.AccountKeeper + bankKeeper authTypes.BankKeeper + feegrantKeeper ante.FeegrantKeeper + rewardsKeeper RewardsKeeperExpected +} + +// NewDeductFeeDecorator returns a new DeductFeeDecorator instance. +func NewDeductFeeDecorator(ak ante.AccountKeeper, bk authTypes.BankKeeper, fk ante.FeegrantKeeper, rk RewardsKeeperExpected) DeductFeeDecorator { + return DeductFeeDecorator{ + ak: ak, + bankKeeper: bk, + feegrantKeeper: fk, + rewardsKeeper: rk, + } +} + +// AnteHandle implements the ante.AnteHandler interface. +func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, sdkErrors.Wrap(sdkErrors.ErrTxDecode, "Tx must be a FeeTx") + } + + if addr := dfd.ak.GetModuleAddress(authTypes.FeeCollectorName); addr == nil { + return ctx, fmt.Errorf("fee collector module account (%s) has not been set", authTypes.FeeCollectorName) + } + + fee := feeTx.GetFee() + feePayer := feeTx.FeePayer() + feeGranter := feeTx.FeeGranter() + + deductFeesFrom := feePayer + + // If feegranter set, deduct fee from feegranter account (only when feegrant is enabled) + if feeGranter != nil { + if dfd.feegrantKeeper == nil { + return ctx, sdkErrors.Wrap(sdkErrors.ErrInvalidRequest, "fee grants are not enabled") + } + + if !feeGranter.Equals(feePayer) { + if err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs()); err != nil { + return ctx, sdkErrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer) + } + } + + deductFeesFrom = feeGranter + } + + deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom) + if deductFeesFromAcc == nil { + return ctx, sdkErrors.Wrapf(sdkErrors.ErrUnknownAddress, "fee payer address (%s) does not exist", deductFeesFrom) + } + + // Deduct the fees + if !feeTx.GetFee().IsZero() { + if err := dfd.deductFees(ctx, deductFeesFromAcc, feeTx.GetFee()); err != nil { + return ctx, err + } + } + + events := sdk.Events{sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyFee, feeTx.GetFee().String()), + )} + ctx.EventManager().EmitEvents(events) + + return next(ctx, tx, simulate) +} + +// deductFees deducts fees from the given account if rewards calculation and distribution is enabled. +// If rewards module is disabled, all the fees are sent to the fee collector account. +// NOTE: this is the only logic being changed. +func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, acc authTypes.AccountI, fees sdk.Coins) error { + // TODO: we need to identify Msg type to only deduct fees for the WASM operation (not all of them) + + if !fees.IsValid() { + return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFee, "invalid fee amount: %s", fees) + } + + // Send everything to the fee collector account if rewards are disabled + if !dfd.rewardsKeeper.TxFeeRewardsEnabled(ctx) { + if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, fees); err != nil { + return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + } + return nil + } + + // Split the fees between the fee collector account and the rewards collector account + rebateRatio := dfd.rewardsKeeper.TxFeeRebateRatio(ctx) + authFees, rewardsFees := pkg.SplitCoins(fees, rebateRatio) + + if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, authFees); err != nil { + return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + } + + if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), rewardsTypes.ContractRewardCollector, rewardsFees); err != nil { + return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + } + + // Track transaction fee rewards + dfd.rewardsKeeper.TrackFeeRebatesRewards(ctx, rewardsFees) + + return nil +} diff --git a/x/rewards/client/cli/flags.go b/x/rewards/client/cli/flags.go new file mode 100644 index 00000000..56ce962d --- /dev/null +++ b/x/rewards/client/cli/flags.go @@ -0,0 +1,16 @@ +package cli + +import "github.com/spf13/cobra" + +const ( + flagOwnerAddress = "owner-address" + flagRewardsAddress = "rewards-address" +) + +func addOwnerAddressFlag(cmd *cobra.Command) { + cmd.Flags().String(flagOwnerAddress, "", "Address of the contract owner (bech 32)") +} + +func addRewardsAddressFlag(cmd *cobra.Command) { + cmd.Flags().String(flagRewardsAddress, "", "Rewards address to distribute contract rewards to (bech 32)") +} diff --git a/x/rewards/client/cli/query.go b/x/rewards/client/cli/query.go new file mode 100644 index 00000000..1517a74b --- /dev/null +++ b/x/rewards/client/cli/query.go @@ -0,0 +1,140 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + "github.com/archway-network/archway/pkg" + "github.com/archway-network/archway/x/rewards/types" +) + +// GetQueryCmd builds query command group for the module. +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the tracking module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + cmd.AddCommand( + getQueryParamsCmd(), + getQueryBlockRewardsTrackingCmd(), + getQueryContractMetadataCmd(), + getQueryUndistributedPoolFundsCmd(), + ) + + return cmd +} + +func getQueryParamsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Args: cobra.NoArgs, + Short: "Query module parameters", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func getQueryBlockRewardsTrackingCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "block-rewards-tracking", + Args: cobra.NoArgs, + Short: "Query rewards tracking data for the current block height", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.BlockRewardsTracking(cmd.Context(), &types.QueryBlockRewardsTrackingRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func getQueryContractMetadataCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "contract-metadata [contract-address]", + Args: cobra.ExactArgs(1), + Short: "Query contract metadata (contract rewards parameters)", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + contractAddr, err := pkg.ParseAccAddressArg("contract-address", args[0]) + if err != nil { + return err + } + + res, err := queryClient.ContractMetadata(cmd.Context(), &types.QueryContractMetadataRequest{ + ContractAddress: contractAddr.String(), + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Metadata) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +func getQueryUndistributedPoolFundsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "pool", + Args: cobra.NoArgs, + Short: "Query undistributed rewards pool funds", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.RewardsPool(cmd.Context(), &types.QueryRewardsPoolRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/rewards/client/cli/tx.go b/x/rewards/client/cli/tx.go new file mode 100644 index 00000000..03700584 --- /dev/null +++ b/x/rewards/client/cli/tx.go @@ -0,0 +1,68 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/spf13/cobra" + + "github.com/archway-network/archway/pkg" + "github.com/archway-network/archway/x/rewards/types" +) + +// GetTxCmd builds tx command group for the module. +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the rewards module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + cmd.AddCommand( + getTxSetContractMetadataCmd(), + ) + + return cmd +} + +func getTxSetContractMetadataCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-contract-metadata [contract-address]", + Args: cobra.ExactArgs(1), + Short: "Create / modify contract metadata (contract rewards parameters)", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + senderAddr := clientCtx.GetFromAddress() + + contractAddress, err := pkg.ParseAccAddressArg("contract-address", args[0]) + if err != nil { + return err + } + + ownerAddress, err := pkg.ParseAccAddressFlag(cmd, flagOwnerAddress, false) + if err != nil { + return err + } + + rewardsAddress, err := pkg.ParseAccAddressFlag(cmd, flagRewardsAddress, false) + if err != nil { + return err + } + + msg := types.NewMsgSetContractMetadata(senderAddr, contractAddress, ownerAddress, rewardsAddress) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + addOwnerAddressFlag(cmd) + addRewardsAddressFlag(cmd) + + return cmd +} diff --git a/x/rewards/keeper/distribution.go b/x/rewards/keeper/distribution.go new file mode 100644 index 00000000..a047f919 --- /dev/null +++ b/x/rewards/keeper/distribution.go @@ -0,0 +1,205 @@ +package keeper + +import ( + "fmt" + "sort" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/pkg" + "github.com/archway-network/archway/x/rewards/types" +) + +type ( + // blockRewardsDistributionState is used to gather gas usage and rewards for a block. + blockRewardsDistributionState struct { + Height int64 // block height + GasUsed sdk.Dec // total gas used by the block + Txs []*txRewardsDistributionState + } + + // txRewardsDistributionState is used to gather gas usage and rewards for a transaction. + txRewardsDistributionState struct { + TxID uint64 // transaction ID (x/tracking unique ID) + GasUsed sdk.Dec // total gas used by the transaction + Contracts []*contractRewardsDistributionState + } + + // contractRewardsDistributionState is used to gather gas usage and rewards for a contract (merge contract operations data). + contractRewardsDistributionState struct { + ContractAddress sdk.AccAddress // contract address + GasUsed sdk.Dec // total gas used by all the contract operations + FeeRewards sdk.Coins // fee rewards for this contract + InflationaryRewards sdk.Coin // inflation rewards for this contract + Metadata *types.ContractMetadata // metadata for this contract (might be nil if not set) + } +) + +// DistributeRewards distributes rewards for the given block height. +func (k Keeper) DistributeRewards(ctx sdk.Context, height int64) { + blockDistrState := k.estimateBlockGasUsage(ctx, height) + blockDistrState = k.estimateBlockRewards(ctx, blockDistrState) + k.distributeBlockRewards(ctx, blockDistrState) +} + +// estimateBlockGasUsage creates a new distribution state for the given block height. +// Func iterates over all tracked transactions and estimates gas usage for: block, txs and contracts. +func (k Keeper) estimateBlockGasUsage(ctx sdk.Context, height int64) *blockRewardsDistributionState { + metadataState := k.state.ContractMetadataState(ctx) + + // Create a new block rewards distribution state and fill it up + blockDistrState := &blockRewardsDistributionState{ + Height: height, + GasUsed: sdk.ZeroDec(), + } + + // Get all tracked transactions by the x/tracking module + blockGasTrackingInfo := k.trackingView.GetBlockTrackingInfo(ctx, height) + blockDistrState.Txs = make([]*txRewardsDistributionState, 0, len(blockGasTrackingInfo.Txs)) + + // Fill up gas usage per transaction + for _, txGasTrackingInfo := range blockGasTrackingInfo.Txs { + // Skip noop transaction (tx rewards will stay in the pool) + if !txGasTrackingInfo.Info.HasGasUsage() { + continue + } + + // Estimate contract operations total gas used (could be multiple ops per contract, so we merge them) + contractDistrStatesSet := make(map[string]*contractRewardsDistributionState, len(txGasTrackingInfo.ContractOperations)) + for _, contractOp := range txGasTrackingInfo.ContractOperations { + opGasUsed, opEligible := contractOp.GasUsed() + if !opEligible { + // Skip noop operation (should not happen since we're tracking an actual WASM usage) + k.Logger(ctx).Debug("Noop contract operation found", "txID", contractOp.TxId, "opID", contractOp.Id) + continue + } + + contractDistrState := contractDistrStatesSet[contractOp.ContractAddress] + if contractDistrState == nil { + contractDistrState = &contractRewardsDistributionState{ + ContractAddress: contractOp.MustGetContractAddress(), + GasUsed: sdk.ZeroDec(), + } + if metadata, found := metadataState.GetContractMetadata(contractDistrState.ContractAddress); found { + contractDistrState.Metadata = &metadata + } + + contractDistrStatesSet[contractOp.ContractAddress] = contractDistrState + } + contractDistrState.GasUsed = contractDistrState.GasUsed.Add(pkg.NewDecFromUint64(opGasUsed)) + } + + // Create a new tx rewards distribution state and fill it up + // We sort the operations slice to prevent the consensus failure due to the order of operations + txDistState := &txRewardsDistributionState{ + TxID: txGasTrackingInfo.Info.Id, + GasUsed: pkg.NewDecFromUint64(txGasTrackingInfo.Info.TotalGas), + Contracts: make([]*contractRewardsDistributionState, 0, len(contractDistrStatesSet)), + } + for _, contractRewardsState := range contractDistrStatesSet { + txDistState.Contracts = append(txDistState.Contracts, contractRewardsState) + } + sort.Slice(txDistState.Contracts, func(i, j int) bool { + return txDistState.Contracts[i].ContractAddress.String() < txDistState.Contracts[j].ContractAddress.String() + }) + + // Append tx distr state updating the block gas used + blockDistrState.GasUsed = blockDistrState.GasUsed.Add(txDistState.GasUsed) + blockDistrState.Txs = append(blockDistrState.Txs, txDistState) + } + + return blockDistrState +} + +// estimateBlockRewards update block distribution state with tracked rewards calculating reward shares per contract. +// Func iterates over all tracked transactions and estimates rewards for each contract. +func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewardsDistributionState) *blockRewardsDistributionState { + txRewardsState := k.state.TxRewardsState(ctx) + + // Get tracked block rewards by the x/rewards module (might not be found in case this reward is disabled) + blockRewards, blockRewardsFound := k.state.BlockRewardsState(ctx).GetBlockRewards(blockDistrState.Height) + + // Estimate reward shares for each contract operation + for _, txDistrState := range blockDistrState.Txs { + // Get tracked transaction rewards by the x/rewards module (might not be found in case this reward is disabled) + txRewards, txRewardsFound := txRewardsState.GetTxRewards(txDistrState.TxID) + + for _, contractDistrState := range txDistrState.Contracts { + // Estimate contract fee rewards + if txRewardsFound && txRewards.HasRewards() { + rewardsShare := contractDistrState.GasUsed.Quo(txDistrState.GasUsed) + + rewardCoins := sdk.NewCoins() + for _, feeCoin := range txRewards.FeeRewards { + rewardCoins = rewardCoins.Add(sdk.NewCoin( + feeCoin.Denom, + feeCoin.Amount.ToDec().Mul(rewardsShare).TruncateInt(), + )) + } + contractDistrState.FeeRewards = rewardCoins + } + + // Estimate contract inflation rewards + if blockRewardsFound && blockRewards.HasRewards() { + rewardsShare := contractDistrState.GasUsed.Quo(blockDistrState.GasUsed) + + contractDistrState.InflationaryRewards = sdk.NewCoin( + blockRewards.InflationRewards.Denom, + blockRewards.InflationRewards.Amount.ToDec().Mul(rewardsShare).TruncateInt(), + ) + } + } + } + + return blockDistrState +} + +// distributeBlockRewards distributes block rewards to respective reward addresses if set (otherwise, skip) and emit events. +// Func sends rewards to the respective reward addresses (is set) and emits events. +// Leftovers caused by Int truncation or by a tx-less block (inflation rewards are tracked even +// if there were no transactions) stay in the pool. +func (k Keeper) distributeBlockRewards(ctx sdk.Context, blockDistrState *blockRewardsDistributionState) { + for _, txDistrState := range blockDistrState.Txs { + for _, contractDistrState := range txDistrState.Contracts { + // Emit calculation event + types.EmitContractRewardCalculationEvent( + ctx, + contractDistrState.ContractAddress, + uint64(contractDistrState.GasUsed.TruncateInt64()), + contractDistrState.InflationaryRewards, + contractDistrState.FeeRewards, + contractDistrState.Metadata, + ) + + // Skip cases + if contractDistrState.Metadata == nil { + k.Logger(ctx).Debug("Contract rewards distribution skipped (no metadata found)", "contractAddress", contractDistrState.ContractAddress) + continue + } + if !contractDistrState.Metadata.HasRewardsAddress() { + k.Logger(ctx).Debug("Contract rewards distribution skipped (rewards address not set)", "contractAddress", contractDistrState.ContractAddress) + continue + } + rewardsAddr := contractDistrState.Metadata.MustGetRewardsAddress() + + // Distribute + rewards := sdk.NewCoins(contractDistrState.FeeRewards...).Add(contractDistrState.InflationaryRewards) + if rewards.IsZero() { + k.Logger(ctx).Debug("Contract rewards distribution skipped (no rewards)", "contractAddress", contractDistrState.ContractAddress) + continue + } + + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ContractRewardCollector, rewardsAddr, rewards); err != nil { + panic(fmt.Errorf("sending rewards (%s) to rewards address (%s) for the contract (%s): %w", contractDistrState.FeeRewards, rewardsAddr, contractDistrState.ContractAddress, err)) + } + + // Emit distribution event + types.EmitContractRewardDistributionEvent( + ctx, + contractDistrState.ContractAddress, + rewardsAddr, + rewards, + ) + } + } +} diff --git a/x/rewards/keeper/genesis.go b/x/rewards/keeper/genesis.go new file mode 100644 index 00000000..343472df --- /dev/null +++ b/x/rewards/keeper/genesis.go @@ -0,0 +1,25 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/types" +) + +// ExportGenesis exports the module genesis for the current block. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + return types.NewGenesisState( + k.GetParams(ctx), + k.state.ContractMetadataState(ctx).Export(), + k.state.BlockRewardsState(ctx).Export(), + k.state.TxRewardsState(ctx).Export(), + ) +} + +// InitGenesis initializes the module genesis state. +func (k Keeper) InitGenesis(ctx sdk.Context, state *types.GenesisState) { + k.SetParams(ctx, state.Params) + k.state.ContractMetadataState(ctx).Import(state.ContractsMetadata) + k.state.BlockRewardsState(ctx).Import(state.BlockRewards) + k.state.TxRewardsState(ctx).Import(state.TxRewards) +} diff --git a/x/rewards/keeper/grpc_query.go b/x/rewards/keeper/grpc_query.go index 3a0c6d81..7110c841 100644 --- a/x/rewards/keeper/grpc_query.go +++ b/x/rewards/keeper/grpc_query.go @@ -2,10 +2,12 @@ package keeper import ( "context" - "github.com/archway-network/archway/x/rewards/types" + sdk "github.com/cosmos/cosmos-sdk/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/archway-network/archway/x/rewards/types" ) var _ types.QueryServer = &QueryServer{} @@ -47,14 +49,49 @@ func (s *QueryServer) ContractMetadata(c context.Context, request *types.QueryCo } ctx := sdk.UnwrapSDKContext(c) - metaState := s.keeper.state.ContractMetadataState(ctx) - meta, found := metaState.GetContractMetadata(contractAddr) - if !found { + meta := s.keeper.GetContractMetadata(ctx, contractAddr) + if meta == nil { return nil, status.Errorf(codes.NotFound, "metadata for the contract: not found") } return &types.QueryContractMetadataResponse{ - Metadata: meta, + Metadata: *meta, + }, nil +} + +// BlockRewardsTracking implements the types.QueryServer interface. +func (s *QueryServer) BlockRewardsTracking(c context.Context, request *types.QueryBlockRewardsTrackingRequest) (*types.QueryBlockRewardsTrackingResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + height := ctx.BlockHeight() + + blockRewards, found := s.keeper.state.BlockRewardsState(ctx).GetBlockRewards(height) + if !found { + blockRewards.Height = ctx.BlockHeight() + } + txRewards := s.keeper.state.TxRewardsState(ctx).GetTxRewardsByBlock(height) + + return &types.QueryBlockRewardsTrackingResponse{ + Block: types.BlockTracking{ + InflationRewards: blockRewards, + TxRewards: txRewards, + }, + }, nil +} + +// RewardsPool implements the types.QueryServer interface. +func (s *QueryServer) RewardsPool(c context.Context, request *types.QueryRewardsPoolRequest) (*types.QueryRewardsPoolResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + return &types.QueryRewardsPoolResponse{ + Funds: s.keeper.UndistributedRewardsPool(ctx), }, nil } diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index 09539730..aff8b7b7 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -2,29 +2,52 @@ package keeper import ( wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/archway-network/archway/x/rewards/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" + + "github.com/archway-network/archway/x/rewards/types" + trackingTypes "github.com/archway-network/archway/x/tracking/types" ) -// ContractInfoReaderExpected defines the interface for the wasmd module dependency. +// ContractInfoReaderExpected defines the interface for the x/wasmd module dependency. type ContractInfoReaderExpected interface { GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmTypes.ContractInfo } +// TrackingReaderExpected defines the interface for the x/tracking module dependency. +type TrackingReaderExpected interface { + GetCurrentTxID(ctx sdk.Context) uint64 + GetBlockTrackingInfo(ctx sdk.Context, height int64) trackingTypes.BlockTracking +} + +// AuthKeeperExpected defines the interface for the x/auth module dependency. +type AuthKeeperExpected interface { + GetModuleAccount(ctx sdk.Context, name string) authTypes.ModuleAccountI +} + +// BankKeeperExpected defines the interface for the x/bank module dependency. +type BankKeeperExpected interface { + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error +} + // Keeper provides module state operations. type Keeper struct { cdc codec.Codec paramStore paramTypes.Subspace state State contractInfoView ContractInfoReaderExpected + trackingView TrackingReaderExpected + authKeeper AuthKeeperExpected + bankKeeper BankKeeperExpected } // NewKeeper creates a new Keeper instance. -func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInfoReaderExpected, ps paramTypes.Subspace) Keeper { +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInfoReaderExpected, trackingReader TrackingReaderExpected, ak AuthKeeperExpected, bk BankKeeperExpected, ps paramTypes.Subspace) Keeper { if !ps.HasKeyTable() { ps = ps.WithKeyTable(types.ParamKeyTable()) } @@ -34,6 +57,9 @@ func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInf paramStore: ps, state: NewState(cdc, key), contractInfoView: contractInfoReader, + trackingView: trackingReader, + authKeeper: ak, + bankKeeper: bk, } } @@ -45,7 +71,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // SetContractMetadata creates or updates the contract metadata verifying the ownership: // * Meta could be created by the contract admin (if set); // * Meta could be modified by the contract owner; -func (k Keeper) SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sdk.AccAddress, requestedMeta types.ContractMetadata) error { +func (k Keeper) SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sdk.AccAddress, metaUpdates types.ContractMetadata) error { state := k.state.ContractMetadataState(ctx) // Check if the contract exists @@ -55,9 +81,9 @@ func (k Keeper) SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sd } // Check ownership - existingMeta, found := state.GetContractMetadata(contractAddr) - if found { - if existingMeta.OwnerAddress != senderAddr.String() { + metaOld, metaExists := state.GetContractMetadata(contractAddr) + if metaExists { + if metaOld.OwnerAddress != senderAddr.String() { return sdkErrors.Wrap(types.ErrUnauthorized, "metadata can only be changed by the contract owner") } } else { @@ -66,8 +92,64 @@ func (k Keeper) SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sd } } + // Build the updated meta + metaNew := metaOld + if !metaExists { + metaNew.OwnerAddress = senderAddr.String() + } + if metaUpdates.HasOwnerAddress() { + metaNew.OwnerAddress = metaUpdates.OwnerAddress + } + if metaUpdates.HasRewardsAddress() { + metaNew.RewardsAddress = metaUpdates.RewardsAddress + } + // Set - state.SetContractMetadata(contractAddr, requestedMeta) + state.SetContractMetadata(contractAddr, metaNew) + + // Emit event + types.EmitContractMetadataSetEvent( + ctx, + contractAddr, + metaNew, + ) return nil } + +// GetContractMetadata returns the contract metadata for the given contract address (if found). +func (k Keeper) GetContractMetadata(ctx sdk.Context, contractAddr sdk.AccAddress) *types.ContractMetadata { + meta, found := k.state.ContractMetadataState(ctx).GetContractMetadata(contractAddr) + if !found { + return nil + } + + return &meta +} + +// TrackFeeRebatesRewards creates a new transaction fee rebate reward record for the current transaction. +// Unique transaction ID is taken from the tracking module. +// CONTRACT: tracking Ante handler must be called before this module's Ante handler (tracking provides the primary key). +func (k Keeper) TrackFeeRebatesRewards(ctx sdk.Context, rewards sdk.Coins) { + txID := k.trackingView.GetCurrentTxID(ctx) + k.state.TxRewardsState(ctx).CreateTxRewards( + txID, + ctx.BlockHeight(), + rewards, + ) +} + +// TrackInflationRewards creates a new inflation reward record for the current block. +func (k Keeper) TrackInflationRewards(ctx sdk.Context, rewards sdk.Coin) { + k.state.BlockRewardsState(ctx).CreateBlockRewards( + ctx.BlockHeight(), + rewards, + ctx.ConsensusParams().Block.MaxGas, + ) +} + +// UndistributedRewardsPool returns the current undistributed rewards leftovers. +func (k Keeper) UndistributedRewardsPool(ctx sdk.Context) sdk.Coins { + poolAcc := k.authKeeper.GetModuleAccount(ctx, types.ContractRewardCollector) + return k.bankKeeper.GetAllBalances(ctx, poolAcc.GetAddress()) +} diff --git a/x/rewards/keeper/msg_server.go b/x/rewards/keeper/msg_server.go index 58279594..e4d19af2 100644 --- a/x/rewards/keeper/msg_server.go +++ b/x/rewards/keeper/msg_server.go @@ -2,10 +2,12 @@ package keeper import ( "context" - "github.com/archway-network/archway/x/rewards/types" + sdk "github.com/cosmos/cosmos-sdk/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/archway-network/archway/x/rewards/types" ) var _ types.MsgServer = (*MsgServer)(nil) diff --git a/x/rewards/keeper/params.go b/x/rewards/keeper/params.go index efad253f..33446316 100644 --- a/x/rewards/keeper/params.go +++ b/x/rewards/keeper/params.go @@ -1,15 +1,10 @@ package keeper import ( - "github.com/archway-network/archway/x/rewards/types" sdk "github.com/cosmos/cosmos-sdk/types" -) -// RewardsEnabled return rewards calculation and distribution enabled param flag. -func (k Keeper) RewardsEnabled(ctx sdk.Context) (res bool) { - k.paramStore.Get(ctx, types.RewardsEnabledParamKey, &res) - return -} + "github.com/archway-network/archway/x/rewards/types" +) // InflationRewardsRatio return inflation rewards params ratio. func (k Keeper) InflationRewardsRatio(ctx sdk.Context) (res sdk.Dec) { @@ -17,16 +12,25 @@ func (k Keeper) InflationRewardsRatio(ctx sdk.Context) (res sdk.Dec) { return } +// InflationRewardsEnabled return inflation rewards enabled flag. +func (k Keeper) InflationRewardsEnabled(ctx sdk.Context) bool { + return !k.InflationRewardsRatio(ctx).IsZero() +} + // TxFeeRebateRatio return tx fee rebate rewards params ratio. func (k Keeper) TxFeeRebateRatio(ctx sdk.Context) (res sdk.Dec) { k.paramStore.Get(ctx, types.TxFeeRebateRatioParamKey, &res) return } +// TxFeeRewardsEnabled return tx fee rewards enabled flag. +func (k Keeper) TxFeeRewardsEnabled(ctx sdk.Context) bool { + return !k.TxFeeRebateRatio(ctx).IsZero() +} + // GetParams return all module parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams( - k.RewardsEnabled(ctx), k.InflationRewardsRatio(ctx), k.TxFeeRebateRatio(ctx), ) diff --git a/x/rewards/keeper/state.go b/x/rewards/keeper/state.go index 932f29e2..3e17d22a 100644 --- a/x/rewards/keeper/state.go +++ b/x/rewards/keeper/state.go @@ -1,10 +1,11 @@ package keeper import ( - "github.com/archway-network/archway/x/rewards/types" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/types" ) // State is a wrapper around the module storage state. @@ -30,3 +31,29 @@ func (s State) ContractMetadataState(ctx sdk.Context) ContractMetadataState { ctx: ctx, } } + +// BlockRewardsState returns types.BlockRewards repository. +func (s State) BlockRewardsState(ctx sdk.Context) BlockRewardsState { + baseStore := ctx.KVStore(s.key) + return BlockRewardsState{ + stateStore: prefix.NewStore(baseStore, types.BlockRewardsStatePrefix), + cdc: s.cdc, + ctx: ctx, + } +} + +// TxRewardsState returns types.TxRewards repository. +func (s State) TxRewardsState(ctx sdk.Context) TxRewardsState { + baseStore := ctx.KVStore(s.key) + return TxRewardsState{ + stateStore: prefix.NewStore(baseStore, types.TxRewardsStatePrefix), + cdc: s.cdc, + ctx: ctx, + } +} + +// GetState returns the module storage state. +// Only for testing purposes. +func (k Keeper) GetState() State { + return k.state +} diff --git a/x/rewards/keeper/state_block_rewards.go b/x/rewards/keeper/state_block_rewards.go new file mode 100644 index 00000000..906a2cb7 --- /dev/null +++ b/x/rewards/keeper/state_block_rewards.go @@ -0,0 +1,83 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/types" +) + +// BlockRewardsState provides access to the types.BlockRewards objects storage operations. +type BlockRewardsState struct { + stateStore storeTypes.KVStore + cdc codec.Codec + ctx sdk.Context +} + +// CreateBlockRewards creates a types.BlockRewards object. +func (s BlockRewardsState) CreateBlockRewards(height int64, rewards sdk.Coin, blockMaxGas int64) types.BlockRewards { + obj := types.BlockRewards{ + Height: height, + InflationRewards: rewards, + MaxGas: blockMaxGas, + } + s.setBlockRewards(&obj) + + return obj +} + +// GetBlockRewards returns a types.BlockRewards object by block height. +func (s BlockRewardsState) GetBlockRewards(height int64) (types.BlockRewards, bool) { + store := prefix.NewStore(s.stateStore, types.BlockRewardsPrefix) + key := s.buildBlockRewardsKey(height) + + bz := store.Get(key) + if bz == nil { + return types.BlockRewards{}, false + } + + var obj types.BlockRewards + s.cdc.MustUnmarshal(bz, &obj) + + return obj, true +} + +// Import initializes state from the module genesis data. +func (s BlockRewardsState) Import(objs []types.BlockRewards) { + for _, obj := range objs { + s.setBlockRewards(&obj) + } +} + +// Export returns the module genesis data for the state. +func (s BlockRewardsState) Export() (objs []types.BlockRewards) { + store := prefix.NewStore(s.stateStore, types.BlockRewardsPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var obj types.BlockRewards + s.cdc.MustUnmarshal(iterator.Value(), &obj) + + objs = append(objs, obj) + } + + return +} + +// buildBlockRewardsKey returns the key used to store a types.BlockRewards object. +func (s BlockRewardsState) buildBlockRewardsKey(height int64) []byte { + return sdk.Uint64ToBigEndian(uint64(height)) +} + +// setBlockRewards sets a types.BlockRewards object. +func (s BlockRewardsState) setBlockRewards(obj *types.BlockRewards) { + store := prefix.NewStore(s.stateStore, types.BlockRewardsPrefix) + store.Set( + s.buildBlockRewardsKey(obj.Height), + s.cdc.MustMarshal(obj), + ) +} diff --git a/x/rewards/keeper/state_metadata.go b/x/rewards/keeper/state_metadata.go index 5067942d..c72a801a 100644 --- a/x/rewards/keeper/state_metadata.go +++ b/x/rewards/keeper/state_metadata.go @@ -2,11 +2,13 @@ package keeper import ( "fmt" - "github.com/archway-network/archway/x/rewards/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" storeTypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/types" ) // ContractMetadataState provides access to the types.ContractMetadata objects storage operations. @@ -17,11 +19,11 @@ type ContractMetadataState struct { } // SetContractMetadata creates or modifies a types.ContractMetadata object. -func (s ContractMetadataState) SetContractMetadata(contractAddr sdk.AccAddress, meta types.ContractMetadata) { +func (s ContractMetadataState) SetContractMetadata(contractAddr sdk.AccAddress, obj types.ContractMetadata) { store := prefix.NewStore(s.stateStore, types.ContractMetadataPrefix) store.Set( s.buildContractMetadataKey(contractAddr), - s.cdc.MustMarshal(&meta), + s.cdc.MustMarshal(&obj), ) } diff --git a/x/rewards/keeper/state_tx_rewards.go b/x/rewards/keeper/state_tx_rewards.go new file mode 100644 index 00000000..6a832de4 --- /dev/null +++ b/x/rewards/keeper/state_tx_rewards.go @@ -0,0 +1,156 @@ +package keeper + +import ( + "fmt" + "math" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/types" +) + +// TxRewardsState provides access to the types.TxRewards objects storage operations. +type TxRewardsState struct { + stateStore storeTypes.KVStore + cdc codec.Codec + ctx sdk.Context +} + +// CreateTxRewards creates a new types.TxRewards object. +func (s TxRewardsState) CreateTxRewards(txID uint64, height int64, rewards sdk.Coins) types.TxRewards { + obj := types.TxRewards{ + TxId: txID, + Height: height, + FeeRewards: rewards, + } + + s.setTxRewards(&obj) + s.setBlockIndex(obj.Height, obj.TxId) + + return obj +} + +// GetTxRewards returns a types.TxRewards object by txID. +func (s TxRewardsState) GetTxRewards(txID uint64) (types.TxRewards, bool) { + obj := s.getTxRewards(txID) + if obj == nil { + return types.TxRewards{}, false + } + + return *obj, true +} + +// GetTxRewardsByBlock returns a list of types.TxRewards objects by block height. +func (s TxRewardsState) GetTxRewardsByBlock(height int64) (objs []types.TxRewards) { + store := prefix.NewStore(s.stateStore, types.TxRewardsBlockIndexPrefix) + + iterator := sdk.KVStorePrefixIterator(store, s.buildBlockIndexPrefix(height)) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + _, txID := s.parseBlockIndexKey(iterator.Key()) + + obj, found := s.GetTxRewards(txID) + if !found { + panic(fmt.Errorf("invalid TxRewards Block index state: txId (%d): not found", txID)) + } + objs = append(objs, obj) + } + + return +} + +// Import initializes state from the module genesis data. +func (s TxRewardsState) Import(objs []types.TxRewards) { + for _, obj := range objs { + s.setTxRewards(&obj) + s.setBlockIndex(obj.Height, obj.TxId) + } +} + +// Export returns the module genesis data for the state. +func (s TxRewardsState) Export() (objs []types.TxRewards) { + store := prefix.NewStore(s.stateStore, types.TxRewardsPrefix) + + iterator := store.Iterator(nil, nil) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var obj types.TxRewards + s.cdc.MustUnmarshal(iterator.Value(), &obj) + objs = append(objs, obj) + } + + return +} + +// buildTxRewardsKey returns the key used to store a types.TxRewards object. +func (s TxRewardsState) buildTxRewardsKey(txID uint64) []byte { + return sdk.Uint64ToBigEndian(txID) +} + +// setTxRewards sets a types.TxRewards object. +func (s TxRewardsState) setTxRewards(obj *types.TxRewards) { + store := prefix.NewStore(s.stateStore, types.TxRewardsPrefix) + store.Set( + s.buildTxRewardsKey(obj.TxId), + s.cdc.MustMarshal(obj), + ) +} + +// getContractOpInfo returns a types.ContractOperationInfo object by ID. +func (s TxRewardsState) getTxRewards(txID uint64) *types.TxRewards { + store := prefix.NewStore(s.stateStore, types.TxRewardsPrefix) + + bz := store.Get(s.buildTxRewardsKey(txID)) + if bz == nil { + return nil + } + + var obj types.TxRewards + s.cdc.MustUnmarshal(bz, &obj) + + return &obj +} + +// buildBlockIndexPrefix returns the key prefix used to maintain types.TxRewards's block index. +func (s TxRewardsState) buildBlockIndexPrefix(height int64) []byte { + return sdk.Uint64ToBigEndian(uint64(height)) +} + +// buildBlockIndexKey returns the key used to maintain types.TxRewards's block index. +func (s TxRewardsState) buildBlockIndexKey(height int64, txID uint64) []byte { + return append( + s.buildBlockIndexPrefix(height), + sdk.Uint64ToBigEndian(txID)..., + ) +} + +// parseBlockIndexKey parses the types.TxRewards's block index key. +func (s TxRewardsState) parseBlockIndexKey(key []byte) (height int64, txID uint64) { + if len(key) != 16 { + panic(fmt.Errorf("invalid TxRewards Block index key length: %d", len(key))) + } + + heightRaw := sdk.BigEndianToUint64(key[:8]) + if heightRaw > math.MaxInt64 { + panic(fmt.Errorf("invalid TxRewards Block index key height: %d", heightRaw)) + } + height = int64(heightRaw) + + txID = sdk.BigEndianToUint64(key[8:]) + + return +} + +// setBlockIndex adds the types.TxRewards's block index entry. +func (s TxRewardsState) setBlockIndex(height int64, txID uint64) { + store := prefix.NewStore(s.stateStore, types.TxRewardsBlockIndexPrefix) + store.Set( + s.buildBlockIndexKey(height, txID), + []byte{}, + ) +} diff --git a/x/rewards/mintbankkeeper/keeper.go b/x/rewards/mintbankkeeper/keeper.go new file mode 100644 index 00000000..570f5b06 --- /dev/null +++ b/x/rewards/mintbankkeeper/keeper.go @@ -0,0 +1,78 @@ +package mintbankkeeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" + mintTypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + "github.com/archway-network/archway/pkg" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +var _ mintTypes.BankKeeper = Keeper{} + +// RewardsKeeperExpected defines the expected interface for the x/rewards keeper. +type RewardsKeeperExpected interface { + InflationRewardsEnabled(ctx sdk.Context) bool + InflationRewardsRatio(ctx sdk.Context) sdk.Dec + TrackInflationRewards(ctx sdk.Context, rewards sdk.Coin) +} + +// Keeper is the x/bank keeper decorator that is used by the x/mint module. +// Decorator is used to split inflation tokens between the rewards collector and the fee collector accounts. +type Keeper struct { + bankKeeper mintTypes.BankKeeper + rewardsKeeper RewardsKeeperExpected +} + +// NewKeeper creates a new Keeper instance. +func NewKeeper(bk mintTypes.BankKeeper, rk RewardsKeeperExpected) Keeper { + return Keeper{ + bankKeeper: bk, + rewardsKeeper: rk, + } +} + +// SendCoinsFromModuleToModule implements the mintTypes.BankKeeper interface. +func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error { + // Perform the split only if the recipient is fee collector (which for instance is always the case) and + // inflation rewards are enabled. + if recipientModule != authTypes.FeeCollectorName || !k.rewardsKeeper.InflationRewardsEnabled(ctx) { + return k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, amt) + } + + ratio := k.rewardsKeeper.InflationRewardsRatio(ctx) + stakingRewards, dappRewards := pkg.SplitCoins(amt, ratio) + + // Send to the x/auth fee collector account + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, stakingRewards); err != nil { + return err + } + + // Send to the x/rewards account + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, rewardsTypes.ContractRewardCollector, dappRewards); err != nil { + return err + } + + // Check that only one coin has been minted + if len(dappRewards) != 1 { + panic(fmt.Errorf("unexpected dApp rewards: %s", dappRewards)) + } + + // Track inflation rewards + k.rewardsKeeper.TrackInflationRewards(ctx, dappRewards[0]) + + return nil +} + +// SendCoinsFromModuleToAccount implements the mintTypes.BankKeeper interface. +func (k Keeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt) +} + +// MintCoins implements the mintTypes.BankKeeper interface. +func (k Keeper) MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error { + return k.bankKeeper.MintCoins(ctx, name, amt) +} diff --git a/x/rewards/module.go b/x/rewards/module.go new file mode 100644 index 00000000..4642bafd --- /dev/null +++ b/x/rewards/module.go @@ -0,0 +1,181 @@ +// Package rewards defines a module that tracks dApp rewards (fee rebate and inflation rewards) and +// distributes them to contracts' rewards addresses (if set). +// CONTRACT: module's Ante handler must be called after the x/tracking Ante since it relies on transaction ID tracking generates. +// TODO: collected tracking data should be pruned. +package rewards + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codecTypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simTypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/archway-network/archway/x/rewards/client/cli" + "github.com/archway-network/archway/x/rewards/keeper" + "github.com/archway-network/archway/x/rewards/types" +) + +var ( + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModule = AppModule{} +) + +// AppModuleBasic defines the basic application module for this module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// Name returns the module's name. +func (a AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the module's types on the given LegacyAmino codec. +func (a AppModuleBasic) RegisterLegacyAminoCodec(amino *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(amino) +} + +// RegisterInterfaces registers the module's interface types. +func (a AppModuleBasic) RegisterInterfaces(registry codecTypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the module. +func (a AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the module. +func (a AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var state types.GenesisState + if err := cdc.UnmarshalJSON(bz, &state); err != nil { + return fmt.Errorf("failed to unmarshal x/%s genesis state: %w", types.ModuleName, err) + } + + return state.Validate() +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module. +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, serveMux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(clientCtx)); err != nil { + panic(fmt.Errorf("registering query handler for x/%s: %w", types.ModuleName, err)) + } +} + +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} + +// GetTxCmd returns the root tx command for the module. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns no root query command for the module. +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// AppModule implements an application module for this module. +type AppModule struct { + AppModuleBasic + + cdc codec.Codec + keeper keeper.Keeper +} + +// NewAppModule creates a new AppModule object. +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: keeper, + } +} + +// RegisterInvariants registers the module invariants. +func (a AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// Route returns the message routing key for the module. +// Deprecated. +func (AppModule) Route() sdk.Route { return sdk.Route{} } + +// QuerierRoute returns the module's querier route name. +func (a AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// LegacyQuerierHandler returns the staking module sdk.Querier. +func (a AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// RegisterServices registers the module services. +func (a AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServer(a.keeper)) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServer(a.keeper)) +} + +// InitGenesis performs genesis initialization for the module. It returns no validator updates. +func (a AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, bz json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(bz, &genesisState) + + a.keeper.InitGenesis(ctx, &genesisState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the module. +func (a AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + state := a.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(state) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (a AppModule) ConsensusVersion() uint64 { + return 1 +} + +// BeginBlock returns the begin blocker for the module. +func (a AppModule) BeginBlock(ctx sdk.Context, block abci.RequestBeginBlock) { + BeginBlocker(ctx, a.keeper) +} + +// EndBlock returns the end blocker for the module. It returns no validator updates. +func (a AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the module. +func (a AppModule) GenerateGenesisState(input *module.SimulationState) {} + +// ProposalContents doesn't return any content functions for governance proposals. +func (a AppModule) ProposalContents(_ module.SimulationState) []simTypes.WeightedProposalContent { + return []simTypes.WeightedProposalContent{} +} + +// RandomizedParams creates randomized param changes for the simulator. +func (a AppModule) RandomizedParams(r *rand.Rand) []simTypes.ParamChange { + return []simTypes.ParamChange{} +} + +// RegisterStoreDecoder registers a decoder for the module's types. +func (a AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { + +} + +// WeightedOperations returns all the module operations with their respective weights. +func (a AppModule) WeightedOperations(_ module.SimulationState) []simTypes.WeightedOperation { + return []simTypes.WeightedOperation{} +} diff --git a/x/rewards/types/codec.go b/x/rewards/types/codec.go index 5a8505bd..c648c552 100644 --- a/x/rewards/types/codec.go +++ b/x/rewards/types/codec.go @@ -5,14 +5,23 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" cryptoCodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" ) // RegisterLegacyAminoCodec registers the necessary interfaces and concrete types on the provided LegacyAmino codec. // These types are used for Amino JSON serialization. -func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {} +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgSetContractMetadata{}, "rewards/MsgSetContractMetadata", nil) +} // RegisterInterfaces registers interfaces types with the interface registry. -func RegisterInterfaces(registry types.InterfaceRegistry) {} +func RegisterInterfaces(registry types.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgSetContractMetadata{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} var ( ModuleCdc = codec.NewAminoCodec(amino) @@ -23,4 +32,5 @@ func init() { RegisterLegacyAminoCodec(amino) cryptoCodec.RegisterCrypto(amino) sdk.RegisterLegacyAminoCodec(amino) + amino.Seal() } diff --git a/x/rewards/types/errors.go b/x/rewards/types/errors.go index a407a6b6..626efa85 100644 --- a/x/rewards/types/errors.go +++ b/x/rewards/types/errors.go @@ -6,5 +6,7 @@ var ( DefaultCodespace = ModuleName ErrInternal = sdkErrors.Register(DefaultCodespace, 0, "internal error") // smth went wrong ErrContractNotFound = sdkErrors.Register(DefaultCodespace, 1, "contract not found") // contract info not found - ErrUnauthorized = sdkErrors.Register(DefaultCodespace, 2, "unauthorized operation") // contract ownership issue + ErrMetadataNotFound = sdkErrors.Register(DefaultCodespace, 2, "metadata not found") // contract metadata not found + ErrUnauthorized = sdkErrors.Register(DefaultCodespace, 3, "unauthorized operation") // contract ownership issue + ErrInvalidRequest = sdkErrors.Register(DefaultCodespace, 4, "invalid request") // request parsing issue ) diff --git a/x/rewards/types/events.go b/x/rewards/types/events.go new file mode 100644 index 00000000..eaacf2d1 --- /dev/null +++ b/x/rewards/types/events.go @@ -0,0 +1,41 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func EmitContractMetadataSetEvent(ctx sdk.Context, contractAddr sdk.AccAddress, metadata ContractMetadata) { + err := ctx.EventManager().EmitTypedEvent(&ContractMetadataSetEvent{ + ContractAddress: contractAddr.String(), + Metadata: metadata, + }) + if err != nil { + panic(fmt.Errorf("sending ContractMetadataSetEvent event: %w", err)) + } +} + +func EmitContractRewardCalculationEvent(ctx sdk.Context, contractAddr sdk.AccAddress, gasConsumed uint64, inflationRewards sdk.Coin, feeRebateRewards sdk.Coins, metadata *ContractMetadata) { + err := ctx.EventManager().EmitTypedEvent(&ContractRewardCalculationEvent{ + ContractAddress: contractAddr.String(), + GasConsumed: gasConsumed, + InflationRewards: inflationRewards, + FeeRebateRewards: feeRebateRewards, + Metadata: metadata, + }) + if err != nil { + panic(fmt.Errorf("sending ContractRewardCalculationEvent event: %w", err)) + } +} + +func EmitContractRewardDistributionEvent(ctx sdk.Context, contractAddr, rewardAddress sdk.AccAddress, rewards sdk.Coins) { + err := ctx.EventManager().EmitTypedEvent(&ContractRewardDistributionEvent{ + ContractAddress: contractAddr.String(), + RewardAddress: rewardAddress.String(), + Rewards: rewards, + }) + if err != nil { + panic(fmt.Errorf("sending ContractRewardDistributionEvent event: %w", err)) + } +} diff --git a/x/rewards/types/events.pb.go b/x/rewards/types/events.pb.go new file mode 100644 index 00000000..7dd6adc1 --- /dev/null +++ b/x/rewards/types/events.pb.go @@ -0,0 +1,1065 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: archway/rewards/v1beta1/events.proto + +package types + +import ( + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ContractMetadataSetEvent is emitted when the contract metadata is created or updated. +type ContractMetadataSetEvent struct { + // contract_address defines the contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // metadata defines the new contract metadata state. + Metadata ContractMetadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata"` +} + +func (m *ContractMetadataSetEvent) Reset() { *m = ContractMetadataSetEvent{} } +func (m *ContractMetadataSetEvent) String() string { return proto.CompactTextString(m) } +func (*ContractMetadataSetEvent) ProtoMessage() {} +func (*ContractMetadataSetEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_ad2689b4f7dc3cd8, []int{0} +} +func (m *ContractMetadataSetEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractMetadataSetEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractMetadataSetEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContractMetadataSetEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractMetadataSetEvent.Merge(m, src) +} +func (m *ContractMetadataSetEvent) XXX_Size() int { + return m.Size() +} +func (m *ContractMetadataSetEvent) XXX_DiscardUnknown() { + xxx_messageInfo_ContractMetadataSetEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractMetadataSetEvent proto.InternalMessageInfo + +func (m *ContractMetadataSetEvent) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *ContractMetadataSetEvent) GetMetadata() ContractMetadata { + if m != nil { + return m.Metadata + } + return ContractMetadata{} +} + +// ContractRewardCalculationEvent is emitted when the contract reward is calculated. +type ContractRewardCalculationEvent struct { + // contract_address defines the contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // gas_consumed defines the total gas consumption by all WASM operations within one transaction. + GasConsumed uint64 `protobuf:"varint,2,opt,name=gas_consumed,json=gasConsumed,proto3" json:"gas_consumed,omitempty"` + // inflation_rewards defines the inflation rewards portions of the rewards. + InflationRewards types.Coin `protobuf:"bytes,3,opt,name=inflation_rewards,json=inflationRewards,proto3" json:"inflation_rewards"` + // fee_rebate_rewards defines the fee rebate rewards portions of the rewards. + FeeRebateRewards []types.Coin `protobuf:"bytes,4,rep,name=fee_rebate_rewards,json=feeRebateRewards,proto3" json:"fee_rebate_rewards"` + // metadata defines the contract metadata (if set). + Metadata *ContractMetadata `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (m *ContractRewardCalculationEvent) Reset() { *m = ContractRewardCalculationEvent{} } +func (m *ContractRewardCalculationEvent) String() string { return proto.CompactTextString(m) } +func (*ContractRewardCalculationEvent) ProtoMessage() {} +func (*ContractRewardCalculationEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_ad2689b4f7dc3cd8, []int{1} +} +func (m *ContractRewardCalculationEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractRewardCalculationEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractRewardCalculationEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContractRewardCalculationEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractRewardCalculationEvent.Merge(m, src) +} +func (m *ContractRewardCalculationEvent) XXX_Size() int { + return m.Size() +} +func (m *ContractRewardCalculationEvent) XXX_DiscardUnknown() { + xxx_messageInfo_ContractRewardCalculationEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractRewardCalculationEvent proto.InternalMessageInfo + +func (m *ContractRewardCalculationEvent) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *ContractRewardCalculationEvent) GetGasConsumed() uint64 { + if m != nil { + return m.GasConsumed + } + return 0 +} + +func (m *ContractRewardCalculationEvent) GetInflationRewards() types.Coin { + if m != nil { + return m.InflationRewards + } + return types.Coin{} +} + +func (m *ContractRewardCalculationEvent) GetFeeRebateRewards() []types.Coin { + if m != nil { + return m.FeeRebateRewards + } + return nil +} + +func (m *ContractRewardCalculationEvent) GetMetadata() *ContractMetadata { + if m != nil { + return m.Metadata + } + return nil +} + +// ContractRewardDistributionEvent is emitted when the contract reward is distributed to the corresponding rewards address. +// This event might not follow the ContractRewardCalculationEvent if the contract has no metadata set or rewards address is empty. +type ContractRewardDistributionEvent struct { + // contract_address defines the contract address. + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + // rewards_address defines the rewards address rewards are distributed to. + RewardAddress string `protobuf:"bytes,2,opt,name=reward_address,json=rewardAddress,proto3" json:"reward_address,omitempty"` + // rewards defines the total rewards being distributed. + Rewards []types.Coin `protobuf:"bytes,3,rep,name=rewards,proto3" json:"rewards"` +} + +func (m *ContractRewardDistributionEvent) Reset() { *m = ContractRewardDistributionEvent{} } +func (m *ContractRewardDistributionEvent) String() string { return proto.CompactTextString(m) } +func (*ContractRewardDistributionEvent) ProtoMessage() {} +func (*ContractRewardDistributionEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_ad2689b4f7dc3cd8, []int{2} +} +func (m *ContractRewardDistributionEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractRewardDistributionEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractRewardDistributionEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ContractRewardDistributionEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractRewardDistributionEvent.Merge(m, src) +} +func (m *ContractRewardDistributionEvent) XXX_Size() int { + return m.Size() +} +func (m *ContractRewardDistributionEvent) XXX_DiscardUnknown() { + xxx_messageInfo_ContractRewardDistributionEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractRewardDistributionEvent proto.InternalMessageInfo + +func (m *ContractRewardDistributionEvent) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *ContractRewardDistributionEvent) GetRewardAddress() string { + if m != nil { + return m.RewardAddress + } + return "" +} + +func (m *ContractRewardDistributionEvent) GetRewards() []types.Coin { + if m != nil { + return m.Rewards + } + return nil +} + +func init() { + proto.RegisterType((*ContractMetadataSetEvent)(nil), "archway.rewards.v1beta1.ContractMetadataSetEvent") + proto.RegisterType((*ContractRewardCalculationEvent)(nil), "archway.rewards.v1beta1.ContractRewardCalculationEvent") + proto.RegisterType((*ContractRewardDistributionEvent)(nil), "archway.rewards.v1beta1.ContractRewardDistributionEvent") +} + +func init() { + proto.RegisterFile("archway/rewards/v1beta1/events.proto", fileDescriptor_ad2689b4f7dc3cd8) +} + +var fileDescriptor_ad2689b4f7dc3cd8 = []byte{ + // 423 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcf, 0x6e, 0xd3, 0x40, + 0x10, 0xc6, 0xbd, 0x69, 0xf8, 0xb7, 0xe5, 0x4f, 0xb1, 0x90, 0x30, 0x3d, 0x6c, 0x43, 0x45, 0xa5, + 0xf6, 0xc0, 0x5a, 0x2d, 0x27, 0x8e, 0x34, 0xf4, 0x44, 0x72, 0x31, 0x37, 0x2e, 0xd6, 0x7a, 0x3d, + 0x71, 0x2c, 0xe2, 0xdd, 0x68, 0x77, 0x9d, 0x90, 0xb7, 0x40, 0x3c, 0x08, 0xcf, 0x91, 0x63, 0xc4, + 0x89, 0x13, 0x42, 0xc9, 0x8b, 0xa0, 0xac, 0xd7, 0x26, 0x20, 0x45, 0x4a, 0x7a, 0xb3, 0x67, 0x7f, + 0xf3, 0xcd, 0x37, 0x9f, 0x06, 0xbf, 0x62, 0x8a, 0x0f, 0xa7, 0x6c, 0x16, 0x2a, 0x98, 0x32, 0x95, + 0xea, 0x70, 0x72, 0x99, 0x80, 0x61, 0x97, 0x21, 0x4c, 0x40, 0x18, 0x4d, 0xc7, 0x4a, 0x1a, 0xe9, + 0x3f, 0x77, 0x14, 0x75, 0x14, 0x75, 0xd4, 0xf1, 0xb3, 0x4c, 0x66, 0xd2, 0x32, 0xe1, 0xfa, 0xab, + 0xc2, 0x8f, 0x09, 0x97, 0xba, 0x90, 0x3a, 0x4c, 0x98, 0x86, 0x46, 0x90, 0xcb, 0x5c, 0xb8, 0xf7, + 0xb3, 0x6d, 0x43, 0x6b, 0x79, 0x8b, 0x9d, 0x7e, 0x43, 0x38, 0xe8, 0x4a, 0x61, 0x14, 0xe3, 0xa6, + 0x0f, 0x86, 0xa5, 0xcc, 0xb0, 0x8f, 0x60, 0x6e, 0xd6, 0xce, 0xfc, 0x0b, 0x7c, 0xc4, 0xdd, 0x5b, + 0xcc, 0xd2, 0x54, 0x81, 0xd6, 0x01, 0xea, 0xa0, 0xf3, 0x07, 0xd1, 0x93, 0xba, 0xfe, 0xae, 0x2a, + 0xfb, 0x1f, 0xf0, 0xfd, 0xc2, 0xb5, 0x07, 0xad, 0x0e, 0x3a, 0x3f, 0xbc, 0xba, 0xa0, 0x5b, 0x16, + 0xa2, 0xff, 0xcf, 0xbb, 0x6e, 0xcf, 0x7f, 0x9d, 0x78, 0x51, 0x23, 0x70, 0xfa, 0xa3, 0x85, 0x49, + 0x0d, 0x45, 0xb6, 0xb9, 0xcb, 0x46, 0xbc, 0x1c, 0x31, 0x93, 0x4b, 0xb1, 0xb7, 0xb5, 0x97, 0xf8, + 0x61, 0xc6, 0x74, 0xcc, 0xa5, 0xd0, 0x65, 0x01, 0xa9, 0xb5, 0xd7, 0x8e, 0x0e, 0x33, 0xa6, 0xbb, + 0xae, 0xe4, 0xf7, 0xf0, 0xd3, 0x5c, 0x0c, 0x2a, 0xfd, 0xd8, 0xd9, 0x0d, 0x0e, 0xec, 0x1a, 0x2f, + 0x68, 0x15, 0x34, 0x5d, 0x07, 0xbd, 0xb1, 0x42, 0x2e, 0x9c, 0xed, 0xa3, 0xa6, 0xb3, 0xb2, 0xaa, + 0xfd, 0x3e, 0xf6, 0x07, 0x00, 0xb1, 0x82, 0x84, 0x19, 0x68, 0xe4, 0xda, 0x9d, 0x83, 0x9d, 0xe4, + 0x06, 0x00, 0x91, 0xed, 0xac, 0xe5, 0x6e, 0x36, 0xa2, 0xbd, 0xb3, 0x67, 0xb4, 0x1b, 0xa1, 0x7e, + 0x47, 0xf8, 0xe4, 0xdf, 0x50, 0xdf, 0xe7, 0xda, 0xa8, 0x3c, 0x29, 0x6f, 0x95, 0xea, 0x19, 0x7e, + 0x5c, 0x0d, 0x6f, 0xc0, 0x96, 0x05, 0x1f, 0x55, 0xd5, 0x1a, 0x7b, 0x8b, 0xef, 0xfd, 0xcd, 0x73, + 0xa7, 0x00, 0x6a, 0xfe, 0xba, 0x37, 0x5f, 0x12, 0xb4, 0x58, 0x12, 0xf4, 0x7b, 0x49, 0xd0, 0xd7, + 0x15, 0xf1, 0x16, 0x2b, 0xe2, 0xfd, 0x5c, 0x11, 0xef, 0xd3, 0x55, 0x96, 0x9b, 0x61, 0x99, 0x50, + 0x2e, 0x8b, 0xd0, 0x25, 0xf1, 0x5a, 0x80, 0x99, 0x4a, 0xf5, 0xb9, 0xfe, 0x0f, 0xbf, 0x34, 0x87, + 0x6f, 0x66, 0x63, 0xd0, 0xc9, 0x5d, 0x7b, 0xef, 0x6f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x78, + 0x80, 0xef, 0x41, 0x8d, 0x03, 0x00, 0x00, +} + +func (m *ContractMetadataSetEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractMetadataSetEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractMetadataSetEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ContractRewardCalculationEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractRewardCalculationEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractRewardCalculationEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Metadata != nil { + { + size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.FeeRebateRewards) > 0 { + for iNdEx := len(m.FeeRebateRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FeeRebateRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + { + size, err := m.InflationRewards.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if m.GasConsumed != 0 { + i = encodeVarintEvents(dAtA, i, uint64(m.GasConsumed)) + i-- + dAtA[i] = 0x10 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ContractRewardDistributionEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ContractRewardDistributionEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractRewardDistributionEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rewards) > 0 { + for iNdEx := len(m.Rewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Rewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.RewardAddress) > 0 { + i -= len(m.RewardAddress) + copy(dAtA[i:], m.RewardAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.RewardAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ContractMetadataSetEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = m.Metadata.Size() + n += 1 + l + sovEvents(uint64(l)) + return n +} + +func (m *ContractRewardCalculationEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if m.GasConsumed != 0 { + n += 1 + sovEvents(uint64(m.GasConsumed)) + } + l = m.InflationRewards.Size() + n += 1 + l + sovEvents(uint64(l)) + if len(m.FeeRebateRewards) > 0 { + for _, e := range m.FeeRebateRewards { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + if m.Metadata != nil { + l = m.Metadata.Size() + n += 1 + l + sovEvents(uint64(l)) + } + return n +} + +func (m *ContractRewardDistributionEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.RewardAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if len(m.Rewards) > 0 { + for _, e := range m.Rewards { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ContractMetadataSetEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractMetadataSetEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractMetadataSetEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractRewardCalculationEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractRewardCalculationEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractRewardCalculationEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasConsumed", wireType) + } + m.GasConsumed = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasConsumed |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationRewards.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeRebateRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeRebateRewards = append(m.FeeRebateRewards, types.Coin{}) + if err := m.FeeRebateRewards[len(m.FeeRebateRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Metadata == nil { + m.Metadata = &ContractMetadata{} + } + if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractRewardDistributionEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ContractRewardDistributionEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractRewardDistributionEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rewards = append(m.Rewards, types.Coin{}) + if err := m.Rewards[len(m.Rewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvents + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/rewards/types/genesis.go b/x/rewards/types/genesis.go index 8e08b458..954e316c 100644 --- a/x/rewards/types/genesis.go +++ b/x/rewards/types/genesis.go @@ -2,9 +2,30 @@ package types import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" ) +// NewGenesisState creates a new GenesisState object. +func NewGenesisState(params Params, contractsMetadata []GenesisContractMetadata, blockRewards []BlockRewards, txRewards []TxRewards) *GenesisState { + return &GenesisState{ + Params: params, + ContractsMetadata: contractsMetadata, + BlockRewards: blockRewards, + TxRewards: txRewards, + } +} + +// DefaultGenesisState returns a default genesis state. +func DefaultGenesisState() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + ContractsMetadata: []GenesisContractMetadata{}, + BlockRewards: []BlockRewards{}, + TxRewards: []TxRewards{}, + } +} + // Validate perform object fields validation. func (m GenesisState) Validate() error { if err := m.Params.Validate(); err != nil { @@ -23,6 +44,28 @@ func (m GenesisState) Validate() error { contractAddrSet[meta.ContractAddress] = struct{}{} } + blockRewardsHeightSet := make(map[int64]struct{}) + for i, blockRewards := range m.BlockRewards { + if err := blockRewards.Validate(); err != nil { + return fmt.Errorf("blockRewards [%d]: %w", i, err) + } + if _, ok := blockRewardsHeightSet[blockRewards.Height]; ok { + return fmt.Errorf("blockRewards [%d]: duplicated height: %d", i, blockRewards.Height) + } + blockRewardsHeightSet[blockRewards.Height] = struct{}{} + } + + txRewardsIdSet := make(map[uint64]struct{}) + for i, txRewards := range m.TxRewards { + if err := txRewards.Validate(); err != nil { + return fmt.Errorf("txRewards [%d]: %w", i, err) + } + if _, ok := txRewardsIdSet[txRewards.TxId]; ok { + return fmt.Errorf("txRewards [%d]: duplicated txId: %d", i, txRewards.TxId) + } + txRewardsIdSet[txRewards.TxId] = struct{}{} + } + return nil } @@ -31,7 +74,7 @@ func (m GenesisContractMetadata) Validate() error { if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { return fmt.Errorf("contractAddress: %w", err) } - if err := m.Metadata.Validate(); err != nil { + if err := m.Metadata.Validate(true); err != nil { return fmt.Errorf("metadata: %w", err) } @@ -39,7 +82,7 @@ func (m GenesisContractMetadata) Validate() error { } // MustGetContractAddress returns the contract address parsed. -// Contract: panics of error. +// CONTRACT: panics of error. func (m GenesisContractMetadata) MustGetContractAddress() sdk.AccAddress { addr, err := sdk.AccAddressFromBech32(m.ContractAddress) if err != nil { diff --git a/x/rewards/types/genesis.pb.go b/x/rewards/types/genesis.pb.go index 97a469c5..02bad0dc 100644 --- a/x/rewards/types/genesis.pb.go +++ b/x/rewards/types/genesis.pb.go @@ -29,6 +29,10 @@ type GenesisState struct { Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // contracts_metadata defines a list of all contracts metadata. ContractsMetadata []GenesisContractMetadata `protobuf:"bytes,2,rep,name=contracts_metadata,json=contractsMetadata,proto3" json:"contracts_metadata"` + // block_rewards defines a list of all block rewards objects. + BlockRewards []BlockRewards `protobuf:"bytes,3,rep,name=block_rewards,json=blockRewards,proto3" json:"block_rewards"` + // tx_rewards defines a list of all tx rewards objects. + TxRewards []TxRewards `protobuf:"bytes,4,rep,name=tx_rewards,json=txRewards,proto3" json:"tx_rewards"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -78,6 +82,20 @@ func (m *GenesisState) GetContractsMetadata() []GenesisContractMetadata { return nil } +func (m *GenesisState) GetBlockRewards() []BlockRewards { + if m != nil { + return m.BlockRewards + } + return nil +} + +func (m *GenesisState) GetTxRewards() []TxRewards { + if m != nil { + return m.TxRewards + } + return nil +} + // GenesisContractMetadata is used init ContractMetadata state via module genesis. type GenesisContractMetadata struct { // contract_address defines the contract address. @@ -143,26 +161,30 @@ func init() { } var fileDescriptor_cdced50517b403fe = []byte{ - // 303 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4d, 0x2c, 0x4a, 0xce, - 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x4a, 0x2d, 0x4f, 0x2c, 0x4a, 0x29, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, - 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, - 0xc9, 0x17, 0x12, 0x87, 0x2a, 0xd3, 0x83, 0x2a, 0xd3, 0x83, 0x2a, 0x93, 0x12, 0x49, 0xcf, 0x4f, - 0xcf, 0x07, 0xab, 0xd1, 0x07, 0xb1, 0x20, 0xca, 0xa5, 0x70, 0x9a, 0x0a, 0xd3, 0x0e, 0x56, 0xa6, - 0xb4, 0x85, 0x91, 0x8b, 0xc7, 0x1d, 0x62, 0x4f, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x90, 0x2d, 0x17, - 0x5b, 0x41, 0x62, 0x51, 0x62, 0x6e, 0xb1, 0x04, 0xa3, 0x02, 0xa3, 0x06, 0xb7, 0x91, 0xbc, 0x1e, - 0x0e, 0x7b, 0xf5, 0x02, 0xc0, 0xca, 0x9c, 0x58, 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0x6a, 0x12, - 0x4a, 0xe5, 0x12, 0x4a, 0xce, 0xcf, 0x2b, 0x29, 0x4a, 0x4c, 0x2e, 0x29, 0x8e, 0xcf, 0x4d, 0x2d, - 0x49, 0x4c, 0x49, 0x2c, 0x49, 0x94, 0x60, 0x52, 0x60, 0xd6, 0xe0, 0x36, 0x32, 0xc0, 0x69, 0x14, - 0xd4, 0x05, 0xce, 0x50, 0x9d, 0xbe, 0x50, 0x7d, 0x50, 0xb3, 0x05, 0xe1, 0x26, 0xc2, 0x24, 0x94, - 0x26, 0x32, 0x72, 0x89, 0xe3, 0xd0, 0x24, 0xa4, 0xc9, 0x25, 0x00, 0xd3, 0x10, 0x9f, 0x98, 0x92, - 0x52, 0x94, 0x5a, 0x0c, 0xf1, 0x0b, 0x67, 0x10, 0x3f, 0x4c, 0xdc, 0x11, 0x22, 0x2c, 0xe4, 0xcd, - 0xc5, 0x81, 0xe4, 0x46, 0x90, 0x77, 0x35, 0x71, 0xba, 0x11, 0x87, 0xe3, 0xe0, 0x06, 0x38, 0xf9, - 0x9c, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, - 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x51, 0x7a, 0x66, 0x49, 0x46, - 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0x3e, 0xd4, 0x78, 0xdd, 0xbc, 0xd4, 0x92, 0xf2, 0xfc, 0xa2, - 0x6c, 0x18, 0x5f, 0xbf, 0x02, 0x1e, 0x51, 0x25, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0xf8, - 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x70, 0x6f, 0x45, 0x36, 0x1e, 0x02, 0x00, 0x00, + // 353 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x4e, 0xf2, 0x40, + 0x10, 0xc7, 0x5b, 0x20, 0xe4, 0x63, 0xe1, 0x8b, 0xba, 0x31, 0x81, 0x70, 0x28, 0x84, 0x84, 0x04, + 0x0e, 0xb6, 0x82, 0x67, 0x0f, 0xe2, 0x81, 0x83, 0x9a, 0x10, 0xf4, 0xe4, 0x85, 0x4c, 0xdb, 0x4d, + 0x21, 0x08, 0x4b, 0x76, 0x47, 0x81, 0xb7, 0xd0, 0xb7, 0xe2, 0x26, 0x47, 0x4f, 0xc6, 0xc0, 0x8b, + 0x18, 0xda, 0xdd, 0x06, 0x0f, 0x7b, 0x6b, 0xff, 0xfd, 0xcd, 0x6f, 0x76, 0xa7, 0x43, 0x9a, 0x20, + 0x82, 0xf1, 0x12, 0xd6, 0x9e, 0x60, 0x4b, 0x10, 0xa1, 0xf4, 0xde, 0x3a, 0x3e, 0x43, 0xe8, 0x78, + 0x11, 0x9b, 0x33, 0x39, 0x91, 0xee, 0x42, 0x70, 0xe4, 0xb4, 0xac, 0x30, 0x57, 0x61, 0xae, 0xc2, + 0xaa, 0xe7, 0x11, 0x8f, 0x78, 0xcc, 0x78, 0x87, 0xa7, 0x04, 0xaf, 0x1a, 0xad, 0xba, 0x3c, 0xc6, + 0x1a, 0x9f, 0x19, 0x52, 0xea, 0x27, 0x7d, 0x1e, 0x11, 0x90, 0xd1, 0x6b, 0x92, 0x5f, 0x80, 0x80, + 0x99, 0xac, 0xd8, 0x75, 0xbb, 0x55, 0xec, 0xd6, 0x5c, 0x43, 0x5f, 0x77, 0x10, 0x63, 0xbd, 0xdc, + 0xe6, 0xbb, 0x66, 0x0d, 0x55, 0x11, 0x65, 0x84, 0x06, 0x7c, 0x8e, 0x02, 0x02, 0x94, 0xa3, 0x19, + 0x43, 0x08, 0x01, 0xa1, 0x92, 0xa9, 0x67, 0x5b, 0xc5, 0xee, 0xa5, 0x51, 0xa5, 0x4e, 0x70, 0xab, + 0x2a, 0x1f, 0x54, 0x9d, 0x72, 0x9f, 0xa5, 0x46, 0xfd, 0x81, 0x0e, 0xc8, 0x7f, 0xff, 0x85, 0x07, + 0xd3, 0x91, 0x32, 0x55, 0xb2, 0x71, 0x87, 0xa6, 0xb1, 0x43, 0xef, 0x40, 0x0f, 0x93, 0x50, 0x69, + 0x4b, 0xfe, 0x51, 0x46, 0xfb, 0x84, 0xe0, 0x2a, 0xd5, 0xe5, 0x62, 0x5d, 0xc3, 0xa8, 0x7b, 0x5a, + 0xfd, 0x75, 0x15, 0x50, 0x07, 0x8d, 0x0f, 0x9b, 0x94, 0x0d, 0xf7, 0xa1, 0x6d, 0x72, 0xaa, 0xef, + 0x32, 0x82, 0x30, 0x14, 0x4c, 0x26, 0x63, 0x2e, 0x0c, 0x4f, 0x74, 0x7e, 0x93, 0xc4, 0xf4, 0x8e, + 0xfc, 0x3b, 0x1a, 0xdf, 0xe1, 0x4f, 0xb4, 0x8d, 0xa7, 0x31, 0xcc, 0x2d, 0x15, 0xf4, 0xee, 0x37, + 0x3b, 0xc7, 0xde, 0xee, 0x1c, 0xfb, 0x67, 0xe7, 0xd8, 0xef, 0x7b, 0xc7, 0xda, 0xee, 0x1d, 0xeb, + 0x6b, 0xef, 0x58, 0xcf, 0xdd, 0x68, 0x82, 0xe3, 0x57, 0xdf, 0x0d, 0xf8, 0xcc, 0x53, 0xfa, 0x8b, + 0x39, 0xc3, 0x25, 0x17, 0x53, 0xfd, 0xee, 0xad, 0xd2, 0x1d, 0xc2, 0xf5, 0x82, 0x49, 0x3f, 0x1f, + 0xaf, 0xce, 0xd5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x74, 0x11, 0x3c, 0xba, 0xb9, 0x02, 0x00, + 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -185,6 +207,34 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.TxRewards) > 0 { + for iNdEx := len(m.TxRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TxRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.BlockRewards) > 0 { + for iNdEx := len(m.BlockRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.BlockRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } if len(m.ContractsMetadata) > 0 { for iNdEx := len(m.ContractsMetadata) - 1; iNdEx >= 0; iNdEx-- { { @@ -277,6 +327,18 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.BlockRewards) > 0 { + for _, e := range m.BlockRewards { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.TxRewards) > 0 { + for _, e := range m.TxRewards { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -397,6 +459,74 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.BlockRewards = append(m.BlockRewards, BlockRewards{}) + if err := m.BlockRewards[len(m.BlockRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxRewards = append(m.TxRewards, TxRewards{}) + if err := m.TxRewards[len(m.TxRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/rewards/types/keys.go b/x/rewards/types/keys.go index 4fb90241..56cb74c6 100644 --- a/x/rewards/types/keys.go +++ b/x/rewards/types/keys.go @@ -9,6 +9,9 @@ const ( QuerierRoute = ModuleName // RouterKey is the msg router key for the module. RouterKey = ModuleName + + // ContractRewardCollector is the module holding rewards collected by dApps. + ContractRewardCollector = ModuleName ) // ContractMetadata prefixed store state keys. @@ -17,7 +20,34 @@ var ( ContractMetadataStatePrefix = []byte{0x00} // ContractMetadataPrefix defines the prefix for storing ContractMetadata objects. - // Key: ContractMetadataStatePrefix | ContractMetadataPrefix | {contractAddress} + // Key: ContractMetadataStatePrefix | ContractMetadataPrefix | {ContractAddress} // Value: ContractMetadata - ContractMetadataPrefix = []byte{0x01} + ContractMetadataPrefix = []byte{0x00} +) + +// BlockRewards prefixed store state keys. +var ( + // BlockRewardsStatePrefix defines the state global prefix. + BlockRewardsStatePrefix = []byte{0x01} + + // BlockRewardsPrefix defines the prefix for storing BlockRewards objects. + // Key: BlockRewardsStatePrefix | BlockRewardsPrefix | {Height} + // Value: BlockRewards + BlockRewardsPrefix = []byte{0x00} +) + +// TxRewards prefixed store state keys. +var ( + // TxRewardsStatePrefix defines the state global prefix. + TxRewardsStatePrefix = []byte{0x02} + + // TxRewardsPrefix defines the prefix for storing TxRewards objects. + // Key: TxRewardsStatePrefix | TxRewardsPrefix | {TxID} + // Value: TxRewards + TxRewardsPrefix = []byte{0x00} + + // TxRewardsBlockIndexPrefix defines the prefix for storing TxRewards's block index. + // Key: TxRewardsStatePrefix | TxRewardsBlockIndexPrefix | {Height} | {TxID} + // Value: None + TxRewardsBlockIndexPrefix = []byte{0x01} ) diff --git a/x/rewards/types/metadata.go b/x/rewards/types/metadata.go new file mode 100644 index 00000000..6beec313 --- /dev/null +++ b/x/rewards/types/metadata.go @@ -0,0 +1,54 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + "sigs.k8s.io/yaml" +) + +// HasOwnerAddress returns true if the rewards address is set. +func (m ContractMetadata) HasOwnerAddress() bool { + return m.OwnerAddress != "" +} + +// HasRewardsAddress returns true if the rewards address is set. +func (m ContractMetadata) HasRewardsAddress() bool { + return m.RewardsAddress != "" +} + +// MustGetRewardsAddress returns the rewards address. +// CONTRACT: panics in case of an error. +func (m ContractMetadata) MustGetRewardsAddress() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(m.RewardsAddress) + if err != nil { + panic(fmt.Errorf("parsing rewards address (%s): %s", m.RewardsAddress, err)) + } + + return addr +} + +// Validate performs object fields validation. +// genesisValidation flag perform strict validation of the genesis state (some field must be set). +func (m ContractMetadata) Validate(genesisValidation bool) error { + if genesisValidation || m.OwnerAddress != "" { + if _, err := sdk.AccAddressFromBech32(m.OwnerAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid owner address") + } + } + + if m.RewardsAddress != "" { + if _, err := sdk.AccAddressFromBech32(m.RewardsAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid rewards address") + } + } + + return nil +} + +// String implements the fmt.Stringer interface. +func (m ContractMetadata) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} diff --git a/x/rewards/types/msg.go b/x/rewards/types/msg.go index 63ad3687..d96e6453 100644 --- a/x/rewards/types/msg.go +++ b/x/rewards/types/msg.go @@ -2,6 +2,7 @@ package types import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -15,15 +16,21 @@ var ( ) // NewMsgSetContractMetadata creates a new MsgSetContractMetadata instance. -func NewMsgSetContractMetadata(senderAddr, contractAddr, ownerAddr, rewardsAddr sdk.AccAddress) *MsgSetContractMetadata { - return &MsgSetContractMetadata{ +func NewMsgSetContractMetadata(senderAddr, contractAddr sdk.AccAddress, ownerAddr, rewardsAddr *sdk.AccAddress) *MsgSetContractMetadata { + msg := &MsgSetContractMetadata{ SenderAddress: senderAddr.String(), ContractAddress: contractAddr.String(), - Metadata: ContractMetadata{ - OwnerAddress: ownerAddr.String(), - RewardsAddress: rewardsAddr.String(), - }, + Metadata: ContractMetadata{}, + } + + if ownerAddr != nil { + msg.Metadata.OwnerAddress = ownerAddr.String() } + if rewardsAddr != nil { + msg.Metadata.RewardsAddress = rewardsAddr.String() + } + + return msg } // Route implements the sdk.Msg interface. @@ -36,7 +43,7 @@ func (m MsgSetContractMetadata) Type() string { return TypeMsgSetContractMetadat func (m MsgSetContractMetadata) GetSigners() []sdk.AccAddress { senderAddr, err := sdk.AccAddressFromBech32(m.SenderAddress) if err != nil { - panic(fmt.Errorf("parsing sender address: %w", err)) + panic(fmt.Errorf("parsing sender address (%s): %w", m.SenderAddress, err)) } return []sdk.AccAddress{senderAddr} @@ -58,7 +65,7 @@ func (m MsgSetContractMetadata) ValidateBasic() error { return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid contract address") } - if err := m.Metadata.Validate(); err != nil { + if err := m.Metadata.Validate(false); err != nil { return err } diff --git a/x/rewards/types/params.go b/x/rewards/types/params.go index 37eb27d9..47a572f3 100644 --- a/x/rewards/types/params.go +++ b/x/rewards/types/params.go @@ -2,12 +2,13 @@ package types import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" + "sigs.k8s.io/yaml" ) var ( - RewardsEnabledParamKey = []byte("RewardsEnabled") InflationRewardsRatioParamKey = []byte("InflationRewardsRatio") TxFeeRebateRatioParamKey = []byte("TxFeeRebateRatio") ) @@ -20,9 +21,8 @@ func ParamKeyTable() paramTypes.KeyTable { } // NewParams creates a new Params instance. -func NewParams(rewardsEnabled bool, inflationRewardsRatio, txFeeRebateRatio sdk.Dec) Params { +func NewParams(inflationRewardsRatio, txFeeRebateRatio sdk.Dec) Params { return Params{ - RewardsEnabled: rewardsEnabled, InflationRewardsRatio: inflationRewardsRatio, TxFeeRebateRatio: txFeeRebateRatio, } @@ -33,13 +33,12 @@ func DefaultParams() Params { defInflationRatio := sdk.MustNewDecFromStr("0.20") // 20% defTxFeeRebateRatio := sdk.MustNewDecFromStr("0.50") // 50% - return NewParams(true, defInflationRatio, defTxFeeRebateRatio) + return NewParams(defInflationRatio, defTxFeeRebateRatio) } // ParamSetPairs Implements the paramTypes.ParamSet interface. func (m *Params) ParamSetPairs() paramTypes.ParamSetPairs { return paramTypes.ParamSetPairs{ - paramTypes.NewParamSetPair(RewardsEnabledParamKey, &m.RewardsEnabled, validateRewardsEnabled), paramTypes.NewParamSetPair(InflationRewardsRatioParamKey, &m.InflationRewardsRatio, validateInflationRewardsRatio), paramTypes.NewParamSetPair(TxFeeRebateRatioParamKey, &m.TxFeeRebateRatio, validateTxFeeRebateRatio), } @@ -47,9 +46,6 @@ func (m *Params) ParamSetPairs() paramTypes.ParamSetPairs { // Validate perform object fields validation. func (m Params) Validate() error { - if err := validateRewardsEnabled(m.RewardsEnabled); err != nil { - return err - } if err := validateInflationRewardsRatio(m.InflationRewardsRatio); err != nil { return err } @@ -60,19 +56,10 @@ func (m Params) Validate() error { return nil } -func validateRewardsEnabled(v interface{}) (retErr error) { - defer func() { - if retErr != nil { - retErr = fmt.Errorf("rewardsEnabled param: %w", retErr) - } - }() - - v, ok := v.(bool) - if !ok { - return fmt.Errorf("invalid parameter type: %T", v) - } - - return +// String implements the fmt.Stringer interface. +func (m Params) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) } func validateInflationRewardsRatio(v interface{}) (retErr error) { diff --git a/x/rewards/types/query.pb.go b/x/rewards/types/query.pb.go index 7a629f0f..3168d2f7 100644 --- a/x/rewards/types/query.pb.go +++ b/x/rewards/types/query.pb.go @@ -6,6 +6,7 @@ package types import ( context "context" fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -202,11 +203,179 @@ func (m *QueryContractMetadataResponse) GetMetadata() ContractMetadata { return ContractMetadata{} } +// QueryBlockRewardsTrackingRequest is the request for Query.BlockRewardsTracking. +type QueryBlockRewardsTrackingRequest struct { +} + +func (m *QueryBlockRewardsTrackingRequest) Reset() { *m = QueryBlockRewardsTrackingRequest{} } +func (m *QueryBlockRewardsTrackingRequest) String() string { return proto.CompactTextString(m) } +func (*QueryBlockRewardsTrackingRequest) ProtoMessage() {} +func (*QueryBlockRewardsTrackingRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{4} +} +func (m *QueryBlockRewardsTrackingRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBlockRewardsTrackingRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBlockRewardsTrackingRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryBlockRewardsTrackingRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBlockRewardsTrackingRequest.Merge(m, src) +} +func (m *QueryBlockRewardsTrackingRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryBlockRewardsTrackingRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBlockRewardsTrackingRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBlockRewardsTrackingRequest proto.InternalMessageInfo + +// QueryBlockRewardsTrackingResponse is the response for Query.BlockRewardsTracking. +type QueryBlockRewardsTrackingResponse struct { + Block BlockTracking `protobuf:"bytes,1,opt,name=block,proto3" json:"block"` +} + +func (m *QueryBlockRewardsTrackingResponse) Reset() { *m = QueryBlockRewardsTrackingResponse{} } +func (m *QueryBlockRewardsTrackingResponse) String() string { return proto.CompactTextString(m) } +func (*QueryBlockRewardsTrackingResponse) ProtoMessage() {} +func (*QueryBlockRewardsTrackingResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{5} +} +func (m *QueryBlockRewardsTrackingResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryBlockRewardsTrackingResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryBlockRewardsTrackingResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryBlockRewardsTrackingResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryBlockRewardsTrackingResponse.Merge(m, src) +} +func (m *QueryBlockRewardsTrackingResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryBlockRewardsTrackingResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryBlockRewardsTrackingResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryBlockRewardsTrackingResponse proto.InternalMessageInfo + +func (m *QueryBlockRewardsTrackingResponse) GetBlock() BlockTracking { + if m != nil { + return m.Block + } + return BlockTracking{} +} + +// QueryRewardsPoolRequest is the request for Query.RewardsPool. +type QueryRewardsPoolRequest struct { +} + +func (m *QueryRewardsPoolRequest) Reset() { *m = QueryRewardsPoolRequest{} } +func (m *QueryRewardsPoolRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRewardsPoolRequest) ProtoMessage() {} +func (*QueryRewardsPoolRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{6} +} +func (m *QueryRewardsPoolRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRewardsPoolRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRewardsPoolRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRewardsPoolRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRewardsPoolRequest.Merge(m, src) +} +func (m *QueryRewardsPoolRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRewardsPoolRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRewardsPoolRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRewardsPoolRequest proto.InternalMessageInfo + +// QueryRewardsPoolResponse is the response for Query.RewardsPool. +type QueryRewardsPoolResponse struct { + Funds []types.Coin `protobuf:"bytes,1,rep,name=funds,proto3" json:"funds"` +} + +func (m *QueryRewardsPoolResponse) Reset() { *m = QueryRewardsPoolResponse{} } +func (m *QueryRewardsPoolResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRewardsPoolResponse) ProtoMessage() {} +func (*QueryRewardsPoolResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{7} +} +func (m *QueryRewardsPoolResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRewardsPoolResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRewardsPoolResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryRewardsPoolResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRewardsPoolResponse.Merge(m, src) +} +func (m *QueryRewardsPoolResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRewardsPoolResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRewardsPoolResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRewardsPoolResponse proto.InternalMessageInfo + +func (m *QueryRewardsPoolResponse) GetFunds() []types.Coin { + if m != nil { + return m.Funds + } + return nil +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "archway.rewards.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "archway.rewards.v1beta1.QueryParamsResponse") proto.RegisterType((*QueryContractMetadataRequest)(nil), "archway.rewards.v1beta1.QueryContractMetadataRequest") proto.RegisterType((*QueryContractMetadataResponse)(nil), "archway.rewards.v1beta1.QueryContractMetadataResponse") + proto.RegisterType((*QueryBlockRewardsTrackingRequest)(nil), "archway.rewards.v1beta1.QueryBlockRewardsTrackingRequest") + proto.RegisterType((*QueryBlockRewardsTrackingResponse)(nil), "archway.rewards.v1beta1.QueryBlockRewardsTrackingResponse") + proto.RegisterType((*QueryRewardsPoolRequest)(nil), "archway.rewards.v1beta1.QueryRewardsPoolRequest") + proto.RegisterType((*QueryRewardsPoolResponse)(nil), "archway.rewards.v1beta1.QueryRewardsPoolResponse") } func init() { @@ -214,32 +383,43 @@ func init() { } var fileDescriptor_078e0e66cc6cb70d = []byte{ - // 397 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x92, 0x31, 0x4b, 0xf3, 0x40, - 0x1c, 0xc6, 0x93, 0xf2, 0xbe, 0x45, 0xcf, 0xc1, 0x72, 0x16, 0x94, 0x50, 0x53, 0x89, 0x14, 0x2d, - 0xda, 0x1c, 0xad, 0xe8, 0xe6, 0x60, 0x9d, 0x44, 0x05, 0x2d, 0x4e, 0x2e, 0x72, 0x4d, 0x8e, 0xb4, - 0xd8, 0xe6, 0xd2, 0xbb, 0xab, 0xb5, 0xab, 0x8b, 0xab, 0xe0, 0x17, 0xf1, 0x43, 0x38, 0x74, 0x2c, - 0xb8, 0x38, 0x89, 0xb4, 0x7e, 0x10, 0x69, 0xee, 0x12, 0xb0, 0x35, 0xa2, 0x5b, 0x78, 0xee, 0xf9, - 0x3f, 0xcf, 0x2f, 0xff, 0x3b, 0xb0, 0x8e, 0x99, 0xd3, 0xe8, 0xe1, 0x3e, 0x62, 0xa4, 0x87, 0x99, - 0xcb, 0xd1, 0x4d, 0xb9, 0x4e, 0x04, 0x2e, 0xa3, 0x4e, 0x97, 0xb0, 0xbe, 0x1d, 0x30, 0x2a, 0x28, - 0x5c, 0x56, 0x26, 0x5b, 0x99, 0x6c, 0x65, 0x32, 0xb2, 0x1e, 0xf5, 0x68, 0xe8, 0x41, 0x93, 0x2f, - 0x69, 0x37, 0x72, 0x1e, 0xa5, 0x5e, 0x8b, 0x20, 0x1c, 0x34, 0x11, 0xf6, 0x7d, 0x2a, 0xb0, 0x68, - 0x52, 0x9f, 0xab, 0xd3, 0x42, 0x52, 0x63, 0x14, 0x1e, 0xda, 0xac, 0x2c, 0x80, 0xe7, 0x13, 0x84, - 0x33, 0xcc, 0x70, 0x9b, 0xd7, 0x48, 0xa7, 0x4b, 0xb8, 0xb0, 0x2e, 0xc0, 0xd2, 0x17, 0x95, 0x07, - 0xd4, 0xe7, 0x04, 0xee, 0x83, 0x74, 0x10, 0x2a, 0x2b, 0xfa, 0x9a, 0xbe, 0xb9, 0x50, 0xc9, 0xdb, - 0x09, 0xc4, 0xb6, 0x1c, 0xac, 0xfe, 0x1b, 0xbc, 0xe5, 0xb5, 0x9a, 0x1a, 0xb2, 0x8e, 0x40, 0x2e, - 0x4c, 0x3d, 0xa4, 0xbe, 0x60, 0xd8, 0x11, 0xa7, 0x44, 0x60, 0x17, 0x0b, 0xac, 0x5a, 0x61, 0x11, - 0x64, 0x1c, 0x75, 0x74, 0x85, 0x5d, 0x97, 0x11, 0x2e, 0x8b, 0xe6, 0x6b, 0x8b, 0x91, 0x7e, 0x20, - 0x65, 0xab, 0x05, 0x56, 0x13, 0xa2, 0x14, 0xea, 0x31, 0x98, 0x6b, 0x2b, 0x4d, 0xc1, 0x16, 0x13, - 0x61, 0xa7, 0x43, 0x14, 0x76, 0x1c, 0x50, 0x79, 0x4e, 0x81, 0xff, 0x61, 0x1d, 0xbc, 0xd7, 0x41, - 0x5a, 0xfe, 0x1b, 0xdc, 0x4a, 0xcc, 0x9b, 0x5d, 0xa8, 0xb1, 0xfd, 0x3b, 0xb3, 0x84, 0xb7, 0xac, - 0xbb, 0x97, 0x8f, 0xc7, 0x54, 0x0e, 0x1a, 0x68, 0xf6, 0x12, 0x91, 0x5c, 0x26, 0x7c, 0xd2, 0x41, - 0x66, 0x1a, 0x1c, 0xee, 0xfe, 0x5c, 0x93, 0xb0, 0x78, 0x63, 0xef, 0xaf, 0x63, 0x8a, 0xb3, 0x14, - 0x72, 0x6e, 0xc0, 0xc2, 0x77, 0x9c, 0xf1, 0x55, 0x46, 0x6b, 0xac, 0x9e, 0x0c, 0x46, 0xa6, 0x3e, - 0x1c, 0x99, 0xfa, 0xfb, 0xc8, 0xd4, 0x1f, 0xc6, 0xa6, 0x36, 0x1c, 0x9b, 0xda, 0xeb, 0xd8, 0xd4, - 0x2e, 0x2b, 0x5e, 0x53, 0x34, 0xba, 0x75, 0xdb, 0xa1, 0xed, 0x28, 0xaa, 0xe4, 0x13, 0xd1, 0xa3, - 0xec, 0x3a, 0x8e, 0xbe, 0x8d, 0xc3, 0x45, 0x3f, 0x20, 0xbc, 0x9e, 0x0e, 0x1f, 0xf0, 0xce, 0x67, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xa0, 0xb7, 0x95, 0x59, 0x5b, 0x03, 0x00, 0x00, + // 572 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xb1, 0x6f, 0xd3, 0x40, + 0x14, 0xc6, 0x63, 0x20, 0x11, 0x5c, 0x06, 0xaa, 0x23, 0x52, 0x5b, 0x2b, 0xb8, 0xc1, 0xa8, 0x90, + 0x42, 0x6b, 0x93, 0xa0, 0x22, 0x81, 0xc4, 0x40, 0x98, 0x10, 0x20, 0xb5, 0x51, 0x27, 0x96, 0xe8, + 0xe2, 0x1c, 0xae, 0x95, 0xc4, 0xcf, 0xf5, 0x5d, 0x08, 0x59, 0x59, 0x58, 0x91, 0x58, 0xd9, 0x59, + 0xf9, 0x17, 0xd8, 0x3a, 0x56, 0x62, 0x61, 0x42, 0x28, 0xe1, 0x0f, 0x41, 0xb9, 0x7b, 0x17, 0x95, + 0x26, 0x8e, 0x68, 0xb7, 0xea, 0xbd, 0xef, 0x7d, 0xdf, 0xaf, 0xe7, 0x4f, 0x21, 0xb7, 0x59, 0x1a, + 0x1c, 0x0e, 0xd9, 0xc8, 0x4f, 0xf9, 0x90, 0xa5, 0x1d, 0xe1, 0xbf, 0xab, 0xb5, 0xb9, 0x64, 0x35, + 0xff, 0x68, 0xc0, 0xd3, 0x91, 0x97, 0xa4, 0x20, 0x81, 0xae, 0xa2, 0xc8, 0x43, 0x91, 0x87, 0x22, + 0xbb, 0x14, 0x42, 0x08, 0x4a, 0xe3, 0x4f, 0xff, 0xd2, 0x72, 0xbb, 0x1c, 0x02, 0x84, 0x3d, 0xee, + 0xb3, 0x24, 0xf2, 0x59, 0x1c, 0x83, 0x64, 0x32, 0x82, 0x58, 0xe0, 0xd6, 0x09, 0x40, 0xf4, 0x41, + 0xf8, 0x6d, 0x26, 0xf8, 0x2c, 0x2d, 0x80, 0x28, 0xc6, 0xfd, 0x66, 0x16, 0x91, 0x09, 0x57, 0x32, + 0xb7, 0x44, 0xe8, 0xfe, 0x14, 0x71, 0x8f, 0xa5, 0xac, 0x2f, 0x9a, 0xfc, 0x68, 0xc0, 0x85, 0x74, + 0x0f, 0xc8, 0x8d, 0x7f, 0xa6, 0x22, 0x81, 0x58, 0x70, 0xfa, 0x94, 0x14, 0x12, 0x35, 0x59, 0xb3, + 0x2a, 0x56, 0xb5, 0x58, 0xdf, 0xf0, 0x32, 0xfe, 0x23, 0x4f, 0x1f, 0x36, 0xae, 0x1c, 0xff, 0xda, + 0xc8, 0x35, 0xf1, 0xc8, 0x7d, 0x41, 0xca, 0xca, 0xf5, 0x39, 0xc4, 0x32, 0x65, 0x81, 0x7c, 0xcd, + 0x25, 0xeb, 0x30, 0xc9, 0x30, 0x95, 0x6e, 0x91, 0x95, 0x00, 0x57, 0x2d, 0xd6, 0xe9, 0xa4, 0x5c, + 0xe8, 0xa0, 0x6b, 0xcd, 0xeb, 0x66, 0xfe, 0x4c, 0x8f, 0xdd, 0x1e, 0xb9, 0x99, 0x61, 0x85, 0xa8, + 0x2f, 0xc9, 0xd5, 0x3e, 0xce, 0x10, 0x76, 0x2b, 0x13, 0xf6, 0xac, 0x09, 0x62, 0xcf, 0x0c, 0x5c, + 0x97, 0x54, 0x54, 0x5a, 0xa3, 0x07, 0x41, 0xb7, 0xa9, 0xaf, 0x0f, 0x52, 0x16, 0x74, 0xa3, 0x38, + 0x34, 0x4f, 0x16, 0x92, 0x5b, 0x4b, 0x34, 0x48, 0xd5, 0x20, 0xf9, 0xf6, 0x74, 0x8f, 0x48, 0x77, + 0x32, 0x91, 0x94, 0x8b, 0x39, 0x47, 0x1e, 0x7d, 0xea, 0xae, 0x93, 0x55, 0x15, 0x84, 0x19, 0x7b, + 0x00, 0x3d, 0xc3, 0xb0, 0x4f, 0xd6, 0xe6, 0x57, 0x18, 0xbd, 0x4b, 0xf2, 0x6f, 0x07, 0x71, 0x67, + 0xfa, 0xa2, 0x97, 0xab, 0xc5, 0xfa, 0xba, 0xa7, 0xfb, 0xe3, 0x4d, 0xfb, 0x73, 0xea, 0x25, 0xa2, + 0xd8, 0xa4, 0x29, 0x75, 0xfd, 0x6b, 0x9e, 0xe4, 0x95, 0x27, 0xfd, 0x68, 0x91, 0x82, 0xfe, 0xac, + 0xf4, 0x7e, 0x26, 0xf7, 0x7c, 0x97, 0xec, 0xed, 0xff, 0x13, 0x6b, 0x4c, 0xd7, 0xfd, 0xf0, 0xe3, + 0xcf, 0xe7, 0x4b, 0x65, 0x6a, 0xfb, 0xf3, 0xfd, 0xf5, 0x75, 0x8f, 0xe8, 0x37, 0x8b, 0xac, 0x9c, + 0xfd, 0x66, 0x74, 0x77, 0x79, 0x4c, 0x46, 0xe7, 0xec, 0x47, 0xe7, 0x3d, 0x43, 0xce, 0x1d, 0xc5, + 0x79, 0x97, 0x6e, 0x2e, 0xe2, 0x9c, 0xb5, 0xd8, 0x34, 0x88, 0x7e, 0xb7, 0x48, 0x69, 0x51, 0x33, + 0xe8, 0xe3, 0xe5, 0xf9, 0x4b, 0x1a, 0x67, 0x3f, 0xb9, 0xc8, 0x29, 0xe2, 0xd7, 0x15, 0xfe, 0x36, + 0xbd, 0xb7, 0x08, 0x5f, 0xf5, 0xac, 0x85, 0x83, 0x96, 0x34, 0xa8, 0x5f, 0x2c, 0x52, 0x3c, 0xd5, + 0x2c, 0xfa, 0x60, 0x79, 0xfe, 0x7c, 0x3f, 0xed, 0xda, 0x39, 0x2e, 0x10, 0xb4, 0xaa, 0x40, 0x5d, + 0x5a, 0x59, 0x04, 0x6a, 0x10, 0x13, 0x80, 0x5e, 0xe3, 0xd5, 0xf1, 0xd8, 0xb1, 0x4e, 0xc6, 0x8e, + 0xf5, 0x7b, 0xec, 0x58, 0x9f, 0x26, 0x4e, 0xee, 0x64, 0xe2, 0xe4, 0x7e, 0x4e, 0x9c, 0xdc, 0x9b, + 0x7a, 0x18, 0xc9, 0xc3, 0x41, 0xdb, 0x0b, 0xa0, 0x6f, 0x5c, 0x76, 0x62, 0x2e, 0x87, 0x90, 0x76, + 0x67, 0xae, 0xef, 0x67, 0xbe, 0x72, 0x94, 0x70, 0xd1, 0x2e, 0xa8, 0x9f, 0xc7, 0x87, 0x7f, 0x03, + 0x00, 0x00, 0xff, 0xff, 0x55, 0x73, 0x38, 0x81, 0xd9, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -258,6 +438,10 @@ type QueryClient interface { Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) // ContractMetadata returns the contract rewards parameters (metadata). ContractMetadata(ctx context.Context, in *QueryContractMetadataRequest, opts ...grpc.CallOption) (*QueryContractMetadataResponse, error) + // BlockRewardsTracking returns block rewards tracking for the current block. + BlockRewardsTracking(ctx context.Context, in *QueryBlockRewardsTrackingRequest, opts ...grpc.CallOption) (*QueryBlockRewardsTrackingResponse, error) + // RewardsPool returns the current undistributed rewards pool funds. + RewardsPool(ctx context.Context, in *QueryRewardsPoolRequest, opts ...grpc.CallOption) (*QueryRewardsPoolResponse, error) } type queryClient struct { @@ -286,12 +470,34 @@ func (c *queryClient) ContractMetadata(ctx context.Context, in *QueryContractMet return out, nil } +func (c *queryClient) BlockRewardsTracking(ctx context.Context, in *QueryBlockRewardsTrackingRequest, opts ...grpc.CallOption) (*QueryBlockRewardsTrackingResponse, error) { + out := new(QueryBlockRewardsTrackingResponse) + err := c.cc.Invoke(ctx, "/archway.rewards.v1beta1.Query/BlockRewardsTracking", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RewardsPool(ctx context.Context, in *QueryRewardsPoolRequest, opts ...grpc.CallOption) (*QueryRewardsPoolResponse, error) { + out := new(QueryRewardsPoolResponse) + err := c.cc.Invoke(ctx, "/archway.rewards.v1beta1.Query/RewardsPool", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Params returns module parameters. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) // ContractMetadata returns the contract rewards parameters (metadata). ContractMetadata(context.Context, *QueryContractMetadataRequest) (*QueryContractMetadataResponse, error) + // BlockRewardsTracking returns block rewards tracking for the current block. + BlockRewardsTracking(context.Context, *QueryBlockRewardsTrackingRequest) (*QueryBlockRewardsTrackingResponse, error) + // RewardsPool returns the current undistributed rewards pool funds. + RewardsPool(context.Context, *QueryRewardsPoolRequest) (*QueryRewardsPoolResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -304,6 +510,12 @@ func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsReq func (*UnimplementedQueryServer) ContractMetadata(ctx context.Context, req *QueryContractMetadataRequest) (*QueryContractMetadataResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ContractMetadata not implemented") } +func (*UnimplementedQueryServer) BlockRewardsTracking(ctx context.Context, req *QueryBlockRewardsTrackingRequest) (*QueryBlockRewardsTrackingResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method BlockRewardsTracking not implemented") +} +func (*UnimplementedQueryServer) RewardsPool(ctx context.Context, req *QueryRewardsPoolRequest) (*QueryRewardsPoolResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RewardsPool not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -345,6 +557,42 @@ func _Query_ContractMetadata_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _Query_BlockRewardsTracking_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryBlockRewardsTrackingRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).BlockRewardsTracking(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.rewards.v1beta1.Query/BlockRewardsTracking", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).BlockRewardsTracking(ctx, req.(*QueryBlockRewardsTrackingRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RewardsPool_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRewardsPoolRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RewardsPool(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.rewards.v1beta1.Query/RewardsPool", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RewardsPool(ctx, req.(*QueryRewardsPoolRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "archway.rewards.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -357,6 +605,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "ContractMetadata", Handler: _Query_ContractMetadata_Handler, }, + { + MethodName: "BlockRewardsTracking", + Handler: _Query_BlockRewardsTracking_Handler, + }, + { + MethodName: "RewardsPool", + Handler: _Query_RewardsPool_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "archway/rewards/v1beta1/query.proto", @@ -481,6 +737,122 @@ func (m *QueryContractMetadataResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *QueryBlockRewardsTrackingRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryBlockRewardsTrackingRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBlockRewardsTrackingRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryBlockRewardsTrackingResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryBlockRewardsTrackingResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryBlockRewardsTrackingResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Block.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryRewardsPoolRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRewardsPoolRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRewardsPoolRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryRewardsPoolResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryRewardsPoolResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRewardsPoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -536,20 +908,64 @@ func (m *QueryContractMetadataResponse) Size() (n int) { return n } -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *QueryBlockRewardsTrackingRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n } -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *QueryBlockRewardsTrackingResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Block.Size() + n += 1 + l + sovQuery(uint64(l)) + return n } -func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { + +func (m *QueryRewardsPoolRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryRewardsPoolResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { return ErrIntOverflowQuery } if iNdEx >= l { @@ -840,6 +1256,273 @@ func (m *QueryContractMetadataResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryBlockRewardsTrackingRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryBlockRewardsTrackingRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBlockRewardsTrackingRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryBlockRewardsTrackingResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryBlockRewardsTrackingResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryBlockRewardsTrackingResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Block", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Block.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRewardsPoolRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRewardsPoolRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRewardsPoolRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRewardsPoolResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryRewardsPoolResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRewardsPoolResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/rewards/types/query.pb.gw.go b/x/rewards/types/query.pb.gw.go index 737de3e1..3048376c 100644 --- a/x/rewards/types/query.pb.gw.go +++ b/x/rewards/types/query.pb.gw.go @@ -85,6 +85,42 @@ func local_request_Query_ContractMetadata_0(ctx context.Context, marshaler runti } +func request_Query_BlockRewardsTracking_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBlockRewardsTrackingRequest + var metadata runtime.ServerMetadata + + msg, err := client.BlockRewardsTracking(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_BlockRewardsTracking_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryBlockRewardsTrackingRequest + var metadata runtime.ServerMetadata + + msg, err := server.BlockRewardsTracking(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_RewardsPool_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRewardsPoolRequest + var metadata runtime.ServerMetadata + + msg, err := client.RewardsPool(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RewardsPool_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRewardsPoolRequest + var metadata runtime.ServerMetadata + + msg, err := server.RewardsPool(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -131,6 +167,46 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_BlockRewardsTracking_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_BlockRewardsTracking_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BlockRewardsTracking_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RewardsPool_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RewardsPool_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RewardsPool_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -212,6 +288,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_BlockRewardsTracking_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_BlockRewardsTracking_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_BlockRewardsTracking_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RewardsPool_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_RewardsPool_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RewardsPool_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -219,10 +335,18 @@ var ( pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_ContractMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "contract_metadata"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_BlockRewardsTracking_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "block_rewards_tracking"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_RewardsPool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "rewards_pool"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( forward_Query_Params_0 = runtime.ForwardResponseMessage forward_Query_ContractMetadata_0 = runtime.ForwardResponseMessage + + forward_Query_BlockRewardsTracking_0 = runtime.ForwardResponseMessage + + forward_Query_RewardsPool_0 = runtime.ForwardResponseMessage ) diff --git a/x/rewards/types/rewards.go b/x/rewards/types/rewards.go index 8f0c49a8..b4427b13 100644 --- a/x/rewards/types/rewards.go +++ b/x/rewards/types/rewards.go @@ -1,25 +1,80 @@ package types import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" - sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" "sigs.k8s.io/yaml" ) +// HasRewards returns true if the block rewards have been set. +func (m BlockRewards) HasRewards() bool { + return !m.InflationRewards.IsZero() +} + // Validate performs object fields validation. -func (m ContractMetadata) Validate() error { - if _, err := sdk.AccAddressFromBech32(m.OwnerAddress); err != nil { - return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid owner address") +func (m BlockRewards) Validate() error { + if m.Height < 0 { + return fmt.Errorf("height: must be GTE 0") + } + + if m.InflationRewards.Denom != "" { + if err := sdk.ValidateDenom(m.InflationRewards.Denom); err != nil { + return fmt.Errorf("inflationRewards: denom: %w", err) + } + } + if m.InflationRewards.Amount.IsNegative() { + return fmt.Errorf("inflationRewards: amount: is negative") } - if _, err := sdk.AccAddressFromBech32(m.RewardsAddress); err != nil { - return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid rewards address") + + if m.MaxGas <= 0 { + return fmt.Errorf("maxGas: must be GT 0") } return nil } // String implements the fmt.Stringer interface. -func (m ContractMetadata) String() string { +func (m BlockRewards) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} + +// HasRewards returns true if the transaction rewards have been set. +func (m TxRewards) HasRewards() bool { + return !sdk.Coins(m.FeeRewards).IsZero() +} + +// Validate performs object fields validation. +func (m TxRewards) Validate() error { + if m.TxId <= 0 { + return fmt.Errorf("txId: must be GT 0") + } + + if m.Height < 0 { + return fmt.Errorf("height: must be GTE 0") + } + + for i, coin := range m.FeeRewards { + if err := sdk.ValidateDenom(coin.Denom); err != nil { + return fmt.Errorf("feeRewards [%d]: denom: %w", i, err) + } + if coin.Amount.IsNegative() { + return fmt.Errorf("feeRewards [%d]: amount: is negative", i) + } + } + + return nil +} + +// String implements the fmt.Stringer interface. +func (m TxRewards) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} + +// String implements the fmt.Stringer interface. +func (m BlockTracking) String() string { bz, _ := yaml.Marshal(m) return string(bz) } diff --git a/x/rewards/types/rewards.pb.go b/x/rewards/types/rewards.pb.go index d68ead5a..af92cdd1 100644 --- a/x/rewards/types/rewards.pb.go +++ b/x/rewards/types/rewards.pb.go @@ -6,6 +6,7 @@ package types import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -26,10 +27,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the module parameters. type Params struct { - // rewards_enabled flag indicates whether rewards calculation and distribution is enabled. - RewardsEnabled bool `protobuf:"varint,1,opt,name=rewards_enabled,json=rewardsEnabled,proto3" json:"rewards_enabled,omitempty"` - InflationRewardsRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=inflation_rewards_ratio,json=inflationRewardsRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation_rewards_ratio"` - TxFeeRebateRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,3,opt,name=tx_fee_rebate_ratio,json=txFeeRebateRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"tx_fee_rebate_ratio"` + // inflation_rewards_ratio defines the percentage of minted inflation tokens that are used for dApp rewards [0.0, 1.0]. + // If set to 0.0, no inflation rewards are distributed. + InflationRewardsRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,1,opt,name=inflation_rewards_ratio,json=inflationRewardsRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"inflation_rewards_ratio"` + // tx_fee_rebate_ratio defines the percentage of tx fees that are used for dApp rewards [0.0, 1.0]. + // If set to 0.0, no fee rewards are distributed. + TxFeeRebateRatio github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=tx_fee_rebate_ratio,json=txFeeRebateRatio,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"tx_fee_rebate_ratio"` } func (m *Params) Reset() { *m = Params{} } @@ -64,18 +67,14 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo -func (m *Params) GetRewardsEnabled() bool { - if m != nil { - return m.RewardsEnabled - } - return false -} - -// ContractMetadata defines the contract rewards distribution options. +// ContractMetadata defines the contract rewards distribution options for a particular contract. type ContractMetadata struct { // owner_address is the contract owner address that can modify contract reward options (bech32 encoded). + // That could be the contract admin or the contract itself. + // If owner_address is set to contract address, contract can modify the metadata on its own using WASM bindings. OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` // rewards_address is an address to distribute rewards to (bech32 encoded). + // If not set (empty), rewards are not distributed for this contract. RewardsAddress string `protobuf:"bytes,2,opt,name=rewards_address,json=rewardsAddress,proto3" json:"rewards_address,omitempty"` } @@ -125,9 +124,192 @@ func (m *ContractMetadata) GetRewardsAddress() string { return "" } +// BlockRewards defines block related rewards distribution data. +type BlockRewards struct { + // height defines the block height. + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + // inflation_rewards is the rewards to be distributed. + InflationRewards types.Coin `protobuf:"bytes,2,opt,name=inflation_rewards,json=inflationRewards,proto3" json:"inflation_rewards"` + // max_gas defines the maximum gas that can be used for the block (consensus parameter). + MaxGas int64 `protobuf:"varint,3,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"` +} + +func (m *BlockRewards) Reset() { *m = BlockRewards{} } +func (*BlockRewards) ProtoMessage() {} +func (*BlockRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_50f478faffe74434, []int{2} +} +func (m *BlockRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockRewards.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockRewards.Merge(m, src) +} +func (m *BlockRewards) XXX_Size() int { + return m.Size() +} +func (m *BlockRewards) XXX_DiscardUnknown() { + xxx_messageInfo_BlockRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockRewards proto.InternalMessageInfo + +func (m *BlockRewards) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *BlockRewards) GetInflationRewards() types.Coin { + if m != nil { + return m.InflationRewards + } + return types.Coin{} +} + +func (m *BlockRewards) GetMaxGas() int64 { + if m != nil { + return m.MaxGas + } + return 0 +} + +// TxRewards defines transaction related rewards distribution data. +type TxRewards struct { + // tx_id is the tracking transaction ID (x/tracking is the data source for this value). + TxId uint64 `protobuf:"varint,1,opt,name=tx_id,json=txId,proto3" json:"tx_id,omitempty"` + // height defines the block height. + Height int64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` + // fee_rewards is the rewards to be distributed. + FeeRewards []types.Coin `protobuf:"bytes,3,rep,name=fee_rewards,json=feeRewards,proto3" json:"fee_rewards"` +} + +func (m *TxRewards) Reset() { *m = TxRewards{} } +func (*TxRewards) ProtoMessage() {} +func (*TxRewards) Descriptor() ([]byte, []int) { + return fileDescriptor_50f478faffe74434, []int{3} +} +func (m *TxRewards) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TxRewards) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TxRewards.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TxRewards) XXX_Merge(src proto.Message) { + xxx_messageInfo_TxRewards.Merge(m, src) +} +func (m *TxRewards) XXX_Size() int { + return m.Size() +} +func (m *TxRewards) XXX_DiscardUnknown() { + xxx_messageInfo_TxRewards.DiscardUnknown(m) +} + +var xxx_messageInfo_TxRewards proto.InternalMessageInfo + +func (m *TxRewards) GetTxId() uint64 { + if m != nil { + return m.TxId + } + return 0 +} + +func (m *TxRewards) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *TxRewards) GetFeeRewards() []types.Coin { + if m != nil { + return m.FeeRewards + } + return nil +} + +// BlockTracking is the tracking information for a block. +type BlockTracking struct { + // inflation_rewards defines the inflation rewards for the block. + InflationRewards BlockRewards `protobuf:"bytes,1,opt,name=inflation_rewards,json=inflationRewards,proto3" json:"inflation_rewards"` + // tx_rewards defines the transaction rewards for the block. + TxRewards []TxRewards `protobuf:"bytes,2,rep,name=tx_rewards,json=txRewards,proto3" json:"tx_rewards"` +} + +func (m *BlockTracking) Reset() { *m = BlockTracking{} } +func (*BlockTracking) ProtoMessage() {} +func (*BlockTracking) Descriptor() ([]byte, []int) { + return fileDescriptor_50f478faffe74434, []int{4} +} +func (m *BlockTracking) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BlockTracking) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_BlockTracking.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *BlockTracking) XXX_Merge(src proto.Message) { + xxx_messageInfo_BlockTracking.Merge(m, src) +} +func (m *BlockTracking) XXX_Size() int { + return m.Size() +} +func (m *BlockTracking) XXX_DiscardUnknown() { + xxx_messageInfo_BlockTracking.DiscardUnknown(m) +} + +var xxx_messageInfo_BlockTracking proto.InternalMessageInfo + +func (m *BlockTracking) GetInflationRewards() BlockRewards { + if m != nil { + return m.InflationRewards + } + return BlockRewards{} +} + +func (m *BlockTracking) GetTxRewards() []TxRewards { + if m != nil { + return m.TxRewards + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "archway.rewards.v1beta1.Params") proto.RegisterType((*ContractMetadata)(nil), "archway.rewards.v1beta1.ContractMetadata") + proto.RegisterType((*BlockRewards)(nil), "archway.rewards.v1beta1.BlockRewards") + proto.RegisterType((*TxRewards)(nil), "archway.rewards.v1beta1.TxRewards") + proto.RegisterType((*BlockTracking)(nil), "archway.rewards.v1beta1.BlockTracking") } func init() { @@ -135,29 +317,40 @@ func init() { } var fileDescriptor_50f478faffe74434 = []byte{ - // 344 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0xcf, 0x4e, 0xc2, 0x40, - 0x10, 0xc6, 0xbb, 0x6a, 0x88, 0x6c, 0xfc, 0x43, 0xaa, 0x06, 0xe2, 0xa1, 0x10, 0x8c, 0xca, 0x85, - 0x36, 0xe8, 0xcd, 0x9b, 0xf8, 0xe7, 0xa4, 0x89, 0xe9, 0xd1, 0xc4, 0x34, 0xd3, 0x76, 0x0a, 0x04, - 0xe8, 0x92, 0xdd, 0xd5, 0xc2, 0x5b, 0x78, 0xf4, 0xe8, 0xe3, 0x70, 0xe4, 0x68, 0x3c, 0x10, 0x03, - 0xef, 0x61, 0x0c, 0xdb, 0x6d, 0xc3, 0xd9, 0xd3, 0xee, 0xf7, 0xe5, 0x37, 0xdf, 0x64, 0x66, 0xe8, - 0x29, 0xf0, 0xa0, 0x9b, 0xc0, 0xc4, 0xe1, 0x98, 0x00, 0x0f, 0x85, 0xf3, 0xd6, 0xf2, 0x51, 0x42, - 0x2b, 0xd3, 0xf6, 0x88, 0x33, 0xc9, 0xcc, 0xb2, 0xc6, 0xec, 0xcc, 0xd6, 0xd8, 0xf1, 0x61, 0x87, - 0x75, 0x98, 0x62, 0x9c, 0xd5, 0x2f, 0xc5, 0xeb, 0xbf, 0x84, 0x16, 0x9e, 0x80, 0xc3, 0x50, 0x98, - 0xe7, 0x74, 0x5f, 0xd7, 0x78, 0x18, 0x83, 0x3f, 0xc0, 0xb0, 0x42, 0x6a, 0xa4, 0xb1, 0xed, 0xee, - 0x69, 0xfb, 0x2e, 0x75, 0xcd, 0x88, 0x96, 0x7b, 0x71, 0x34, 0x00, 0xd9, 0x63, 0xb1, 0x97, 0x95, - 0xf0, 0x95, 0xac, 0x6c, 0xd4, 0x48, 0xa3, 0xd8, 0xb6, 0xa7, 0xf3, 0xaa, 0xf1, 0x3d, 0xaf, 0x9e, - 0x75, 0x7a, 0xb2, 0xfb, 0xea, 0xdb, 0x01, 0x1b, 0x3a, 0x01, 0x13, 0x43, 0x26, 0xf4, 0xd3, 0x14, - 0x61, 0xdf, 0x91, 0x93, 0x11, 0x0a, 0xfb, 0x16, 0x03, 0xf7, 0x28, 0x8f, 0x73, 0xd3, 0x34, 0x77, - 0x25, 0xcc, 0x17, 0x7a, 0x20, 0xc7, 0x5e, 0x84, 0xe8, 0x71, 0xf4, 0x41, 0xa2, 0xee, 0xb1, 0xf9, - 0xaf, 0x1e, 0x25, 0x39, 0xbe, 0x47, 0x74, 0x55, 0x90, 0x8a, 0xbf, 0xda, 0xfa, 0xf8, 0xac, 0x1a, - 0xf5, 0x88, 0x96, 0x6e, 0x58, 0x2c, 0x39, 0x04, 0xf2, 0x11, 0x25, 0x84, 0x20, 0xc1, 0x3c, 0xa1, - 0xbb, 0x2c, 0x89, 0x91, 0x7b, 0x10, 0x86, 0x1c, 0x85, 0x50, 0x7b, 0x28, 0xba, 0x3b, 0xca, 0xbc, - 0x4e, 0xbd, 0xf5, 0x75, 0x65, 0x98, 0x9a, 0x3e, 0x5f, 0x97, 0x06, 0xd3, 0x3e, 0xed, 0x87, 0xe9, - 0xc2, 0x22, 0xb3, 0x85, 0x45, 0x7e, 0x16, 0x16, 0x79, 0x5f, 0x5a, 0xc6, 0x6c, 0x69, 0x19, 0x5f, - 0x4b, 0xcb, 0x78, 0xbe, 0x58, 0x9b, 0x40, 0x1f, 0xaf, 0x19, 0xa3, 0x4c, 0x18, 0xef, 0x67, 0xda, - 0x19, 0xe7, 0x57, 0x57, 0x13, 0xf9, 0x05, 0x75, 0xbd, 0xcb, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x95, 0x22, 0x66, 0x3b, 0x15, 0x02, 0x00, 0x00, + // 518 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0xe3, 0xb5, 0x14, 0xd5, 0xdb, 0xa0, 0x64, 0x40, 0xc7, 0x0e, 0xe9, 0x54, 0x34, 0xe0, + 0x32, 0x47, 0x1b, 0x37, 0x4e, 0xd0, 0x21, 0x26, 0xa4, 0x21, 0xa1, 0x68, 0x07, 0x84, 0x84, 0xa2, + 0x97, 0xc4, 0x49, 0xa3, 0x2e, 0xf1, 0x64, 0x1b, 0xea, 0xdd, 0xf8, 0x08, 0x48, 0x5c, 0x38, 0xf2, + 0x31, 0xf8, 0x08, 0x3b, 0xee, 0x82, 0x84, 0x38, 0x4c, 0xa8, 0xfd, 0x22, 0x28, 0xb6, 0x53, 0xb5, + 0x40, 0x25, 0xb4, 0x53, 0xf2, 0x5e, 0x5e, 0x7e, 0xef, 0xff, 0xfe, 0xcf, 0xc6, 0x3b, 0xc0, 0xe3, + 0xe1, 0x18, 0xce, 0x7c, 0x4e, 0xc7, 0xc0, 0x13, 0xe1, 0x7f, 0xd8, 0x8b, 0xa8, 0x84, 0xbd, 0x3a, + 0x26, 0xa7, 0x9c, 0x49, 0xe6, 0x76, 0x6d, 0x19, 0xa9, 0xd3, 0xb6, 0x6c, 0xeb, 0x76, 0xc6, 0x32, + 0xa6, 0x6b, 0xfc, 0xea, 0xcd, 0x94, 0x6f, 0x79, 0x31, 0x13, 0x05, 0x13, 0x7e, 0x04, 0x82, 0xce, + 0x88, 0x31, 0xcb, 0x4b, 0xf3, 0xbd, 0xff, 0x1d, 0xe1, 0xd6, 0x6b, 0xe0, 0x50, 0x08, 0x37, 0xc5, + 0xdd, 0xbc, 0x4c, 0x4f, 0x40, 0xe6, 0xac, 0x0c, 0x2d, 0x3d, 0xe4, 0x55, 0xb8, 0x89, 0xb6, 0xd1, + 0xa3, 0xf6, 0x80, 0x9c, 0x5f, 0xf6, 0x9c, 0x9f, 0x97, 0xbd, 0x07, 0x59, 0x2e, 0x87, 0xef, 0x23, + 0x12, 0xb3, 0xc2, 0xb7, 0x78, 0xf3, 0xd8, 0x15, 0xc9, 0xc8, 0x97, 0x67, 0xa7, 0x54, 0x90, 0xe7, + 0x34, 0x0e, 0xee, 0xcc, 0x70, 0x81, 0xa1, 0x05, 0x55, 0xe0, 0xbe, 0xc3, 0x1b, 0x52, 0x85, 0x29, + 0xa5, 0x21, 0xa7, 0x11, 0x48, 0x6a, 0x7b, 0xac, 0x5c, 0xa9, 0x47, 0x47, 0xaa, 0x17, 0x94, 0x06, + 0x1a, 0xa4, 0xf1, 0x4f, 0x9a, 0x5f, 0xbe, 0xf6, 0x9c, 0x7e, 0x8a, 0x3b, 0x07, 0xac, 0x94, 0x1c, + 0x62, 0xf9, 0x8a, 0x4a, 0x48, 0x40, 0x82, 0x7b, 0x1f, 0xaf, 0xb3, 0x71, 0x49, 0x79, 0x08, 0x49, + 0xc2, 0xa9, 0x10, 0x66, 0xac, 0x60, 0x4d, 0x27, 0x9f, 0x99, 0x9c, 0xfb, 0x10, 0xdf, 0xac, 0x67, + 0xaf, 0xcb, 0xb4, 0xb2, 0xe0, 0x86, 0x4d, 0xdb, 0x42, 0xdb, 0xe7, 0x33, 0xc2, 0x6b, 0x83, 0x13, + 0x16, 0x8f, 0xec, 0x88, 0xee, 0x5d, 0xdc, 0x1a, 0xd2, 0x3c, 0x1b, 0x4a, 0x4d, 0x6f, 0x04, 0x36, + 0x72, 0x8f, 0xf0, 0xad, 0xbf, 0xdc, 0xd5, 0xe4, 0xd5, 0xfd, 0x7b, 0xc4, 0x8c, 0x46, 0xaa, 0x25, + 0xd5, 0xfb, 0x24, 0x07, 0x2c, 0x2f, 0x07, 0xcd, 0xca, 0x8e, 0xa0, 0xf3, 0xa7, 0x91, 0x6e, 0x17, + 0x5f, 0x2f, 0x40, 0x85, 0x19, 0x88, 0xcd, 0x86, 0x69, 0x53, 0x80, 0x3a, 0x84, 0x5a, 0xd5, 0x47, + 0x84, 0xdb, 0xc7, 0xaa, 0x2e, 0xde, 0xc0, 0xd7, 0xa4, 0x0a, 0xf3, 0x44, 0x2b, 0x6a, 0x06, 0x4d, + 0xa9, 0x5e, 0x26, 0x73, 0x3a, 0x57, 0x16, 0x74, 0x3e, 0xc5, 0xab, 0x66, 0x35, 0x46, 0x61, 0x63, + 0xbb, 0xf1, 0x3f, 0x0a, 0x71, 0x5a, 0x2d, 0x41, 0xff, 0x62, 0x25, 0x7c, 0x43, 0x78, 0x5d, 0x1b, + 0x73, 0xcc, 0x21, 0x1e, 0xe5, 0x65, 0xe6, 0xbe, 0xf9, 0x97, 0x03, 0x48, 0x3b, 0xb0, 0x43, 0x96, + 0x9c, 0x6a, 0x32, 0xef, 0xed, 0x52, 0x37, 0x0e, 0x31, 0x96, 0x6a, 0xce, 0xd4, 0x4a, 0x72, 0x7f, + 0x29, 0x72, 0x66, 0x8c, 0xe5, 0xb5, 0xa5, 0x5a, 0x90, 0x3e, 0x38, 0x3a, 0x9f, 0x78, 0xe8, 0x62, + 0xe2, 0xa1, 0x5f, 0x13, 0x0f, 0x7d, 0x9a, 0x7a, 0xce, 0xc5, 0xd4, 0x73, 0x7e, 0x4c, 0x3d, 0xe7, + 0xed, 0xfe, 0xdc, 0xa9, 0xb4, 0xf8, 0xdd, 0x92, 0xca, 0x31, 0xe3, 0xa3, 0x3a, 0xf6, 0xd5, 0xec, + 0x02, 0xeb, 0x53, 0x1a, 0xb5, 0xf4, 0x45, 0x7b, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xe6, + 0xe9, 0x18, 0xe0, 0x03, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -189,7 +382,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintRewards(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a + dAtA[i] = 0x12 { size := m.InflationRewardsRatio.Size() i -= size @@ -199,17 +392,7 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintRewards(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 - if m.RewardsEnabled { - i-- - if m.RewardsEnabled { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x8 - } + dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -250,6 +433,143 @@ func (m *ContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *BlockRewards) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.MaxGas != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.MaxGas)) + i-- + dAtA[i] = 0x18 + } + { + size, err := m.InflationRewards.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.Height != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TxRewards) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TxRewards) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TxRewards) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FeeRewards) > 0 { + for iNdEx := len(m.FeeRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FeeRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.Height != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x10 + } + if m.TxId != 0 { + i = encodeVarintRewards(dAtA, i, uint64(m.TxId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *BlockTracking) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BlockTracking) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BlockTracking) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TxRewards) > 0 { + for iNdEx := len(m.TxRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TxRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.InflationRewards.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRewards(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintRewards(dAtA []byte, offset int, v uint64) int { offset -= sovRewards(v) base := offset @@ -267,9 +587,6 @@ func (m *Params) Size() (n int) { } var l int _ = l - if m.RewardsEnabled { - n += 2 - } l = m.InflationRewardsRatio.Size() n += 1 + l + sovRewards(uint64(l)) l = m.TxFeeRebateRatio.Size() @@ -294,6 +611,61 @@ func (m *ContractMetadata) Size() (n int) { return n } +func (m *BlockRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovRewards(uint64(m.Height)) + } + l = m.InflationRewards.Size() + n += 1 + l + sovRewards(uint64(l)) + if m.MaxGas != 0 { + n += 1 + sovRewards(uint64(m.MaxGas)) + } + return n +} + +func (m *TxRewards) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TxId != 0 { + n += 1 + sovRewards(uint64(m.TxId)) + } + if m.Height != 0 { + n += 1 + sovRewards(uint64(m.Height)) + } + if len(m.FeeRewards) > 0 { + for _, e := range m.FeeRewards { + l = e.Size() + n += 1 + l + sovRewards(uint64(l)) + } + } + return n +} + +func (m *BlockTracking) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.InflationRewards.Size() + n += 1 + l + sovRewards(uint64(l)) + if len(m.TxRewards) > 0 { + for _, e := range m.TxRewards { + l = e.Size() + n += 1 + l + sovRewards(uint64(l)) + } + } + return n +} + func sovRewards(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -330,26 +702,6 @@ func (m *Params) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RewardsEnabled", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRewards - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.RewardsEnabled = bool(v != 0) - case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field InflationRewardsRatio", wireType) } @@ -383,7 +735,7 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 3: + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxFeeRebateRatio", wireType) } @@ -552,6 +904,366 @@ func (m *ContractMetadata) Unmarshal(dAtA []byte) error { } return nil } +func (m *BlockRewards) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationRewards.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxGas", wireType) + } + m.MaxGas = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxGas |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TxRewards) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TxRewards: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TxRewards: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxId", wireType) + } + m.TxId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeRewards = append(m.FeeRewards, types.Coin{}) + if err := m.FeeRewards[len(m.FeeRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *BlockTracking) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: BlockTracking: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: BlockTracking: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InflationRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InflationRewards.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TxRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TxRewards = append(m.TxRewards, TxRewards{}) + if err := m.TxRewards[len(m.TxRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRewards(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRewards + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRewards(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/rewards/types/tx.pb.go b/x/rewards/types/tx.pb.go index 23589020..cfecef4d 100644 --- a/x/rewards/types/tx.pb.go +++ b/x/rewards/types/tx.pb.go @@ -35,6 +35,7 @@ type MsgSetContractMetadata struct { // contract_address is the target contract address (bech32 encoded). ContractAddress string `protobuf:"bytes,2,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` // metadata is the contract metadata to set / update. + // If metadata exists, non-empty fields will be updated. Metadata ContractMetadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata"` } diff --git a/x/rewards/wasmbinding/interfaces.go b/x/rewards/wasmbinding/interfaces.go new file mode 100644 index 00000000..c230dab7 --- /dev/null +++ b/x/rewards/wasmbinding/interfaces.go @@ -0,0 +1,22 @@ +package wasmbinding + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +// ContractMetadataReader defines the GasTrackerKeeper expected operations. +type ContractMetadataReader interface { + GetContractMetadata(ctx sdk.Context, contractAddr sdk.AccAddress) *rewardsTypes.ContractMetadata +} + +// ContractMetadataWriter defines the GasTrackerKeeper expected operations. +type ContractMetadataWriter interface { + SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sdk.AccAddress, metaUpdates rewardsTypes.ContractMetadata) error +} + +type ContractMetadataReaderWriter interface { + ContractMetadataReader + ContractMetadataWriter +} diff --git a/x/rewards/wasmbinding/msg_plugin.go b/x/rewards/wasmbinding/msg_plugin.go new file mode 100644 index 00000000..2a63e5a7 --- /dev/null +++ b/x/rewards/wasmbinding/msg_plugin.go @@ -0,0 +1,69 @@ +package wasmbinding + +import ( + "encoding/json" + "fmt" + + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmVmTypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" + "github.com/archway-network/archway/x/rewards/wasmbinding/types" +) + +var _ wasmKeeper.Messenger = &MsgPlugin{} + +// CustomMessageDecorator creates a new CustomQueryPlugin for WASM bindings. +func CustomMessageDecorator(gtKeeper ContractMetadataWriter) func(old wasmKeeper.Messenger) wasmKeeper.Messenger { + return func(old wasmKeeper.Messenger) wasmKeeper.Messenger { + return NewMsgPlugin(old, gtKeeper) + } +} + +// MsgPlugin provides custom WASM message handlers. +type MsgPlugin struct { + rewardsKeeper ContractMetadataWriter + wrappedMessenger wasmKeeper.Messenger +} + +// NewMsgPlugin creates a new MsgPlugin. +func NewMsgPlugin(wrappedMessenger wasmKeeper.Messenger, rk ContractMetadataWriter) *MsgPlugin { + return &MsgPlugin{ + wrappedMessenger: wrappedMessenger, + rewardsKeeper: rk, + } +} + +// DispatchMsg validates and executes a custom WASM msg. +func (p MsgPlugin) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmVmTypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { + if msg.Custom != nil { + // Parse and validate the input + var customMsg types.Msg + if err := json.Unmarshal(msg.Custom, &customMsg); err != nil { + return nil, nil, sdkErrors.Wrap(rewardsTypes.ErrInvalidRequest, fmt.Sprintf("custom msg JSON unmarshal: %v", err)) + } + if err := customMsg.Validate(); err != nil { + return nil, nil, sdkErrors.Wrap(rewardsTypes.ErrInvalidRequest, fmt.Sprintf("custom msg validation: %v", err)) + } + + // Execute custom msgs one by one + var resEvents []sdk.Event + var resData [][]byte + if customMsg.UpdateMetadata != nil { + if err := p.updateContractMetadata(ctx, contractAddr, *customMsg.UpdateMetadata); err != nil { + return nil, nil, fmt.Errorf("updateMetadata: %w", err) + } + } + + return resEvents, resData, nil + } + + return p.wrappedMessenger.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) +} + +// updateContractMetadata updates the contract metadata. +func (p MsgPlugin) updateContractMetadata(ctx sdk.Context, contractAddr sdk.AccAddress, req types.UpdateMetadataRequest) error { + return p.rewardsKeeper.SetContractMetadata(ctx, contractAddr, contractAddr, req.ToMetadata()) +} diff --git a/x/rewards/wasmbinding/plugin.go b/x/rewards/wasmbinding/plugin.go new file mode 100644 index 00000000..62666722 --- /dev/null +++ b/x/rewards/wasmbinding/plugin.go @@ -0,0 +1,13 @@ +package wasmbinding + +import ( + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" +) + +// GetCustomWasmOptions returns WASM options for the custom querier and for the custom msg handler. +func GetCustomWasmOptions(gasTrackerKeeper ContractMetadataReaderWriter) []wasmKeeper.Option { + return []wasmKeeper.Option{ + wasmKeeper.WithQueryPlugins(CustomQueryPlugin(gasTrackerKeeper)), + wasmKeeper.WithMessageHandlerDecorator(CustomMessageDecorator(gasTrackerKeeper)), + } +} diff --git a/x/rewards/wasmbinding/query_plugin.go b/x/rewards/wasmbinding/query_plugin.go new file mode 100644 index 00000000..5712768a --- /dev/null +++ b/x/rewards/wasmbinding/query_plugin.go @@ -0,0 +1,79 @@ +package wasmbinding + +import ( + "encoding/json" + "fmt" + + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" + "github.com/archway-network/archway/x/rewards/wasmbinding/types" +) + +//var _ wasmKeeper.CustomQuerier = (*QueryPlugin)(nil).DispatchQuery + +// CustomQueryPlugin creates a new custom query plugin for WASM bindings. +func CustomQueryPlugin(gtKeeper ContractMetadataReader) *wasmKeeper.QueryPlugins { + qp := NewQueryPlugin(gtKeeper) + + return &wasmKeeper.QueryPlugins{ + Custom: qp.DispatchQuery, + } +} + +// QueryPlugin provides custom WASM queries. +type QueryPlugin struct { + rewardsKeeper ContractMetadataReader +} + +// NewQueryPlugin creates a new QueryPlugin. +func NewQueryPlugin(rk ContractMetadataReader) *QueryPlugin { + return &QueryPlugin{ + rewardsKeeper: rk, + } +} + +// DispatchQuery validates and executes a custom WASM query. +func (qp QueryPlugin) DispatchQuery(ctx sdk.Context, request json.RawMessage) ([]byte, error) { + // Parse and validate the input + var req types.Query + if err := json.Unmarshal(request, &req); err != nil { + return nil, sdkErrors.Wrap(rewardsTypes.ErrInvalidRequest, fmt.Sprintf("request JSON unmarshal: %v", err)) + } + if err := req.Validate(); err != nil { + return nil, sdkErrors.Wrap(rewardsTypes.ErrInvalidRequest, fmt.Sprintf("request validation: %v", err)) + } + + // Execute the custom query (one of) + var resData interface{} + var resErr error + switch { + case req.Metadata != nil: + resData, resErr = qp.getContractMetadata(ctx, req.Metadata.MustGetContractAddress()) + default: + resErr = sdkErrors.Wrap(rewardsTypes.ErrInvalidRequest, "unknown request") + } + if resErr != nil { + return nil, resErr + } + + // Encode the response + res, err := json.Marshal(resData) + if err != nil { + return nil, sdkErrors.Wrap(rewardsTypes.ErrInternal, fmt.Sprintf("response JSON marshal: %v", err)) + } + + return res, nil +} + +// getContractMetadata returns the contract metadata. +func (qp QueryPlugin) getContractMetadata(ctx sdk.Context, contractAddr sdk.AccAddress) (types.ContractMetadataResponse, error) { + meta := qp.rewardsKeeper.GetContractMetadata(ctx, contractAddr) + if meta == nil { + return types.ContractMetadataResponse{}, rewardsTypes.ErrMetadataNotFound + } + + return types.NewContractMetadataResponse(*meta), nil +} diff --git a/x/rewards/wasmbinding/types/msg.go b/x/rewards/wasmbinding/types/msg.go new file mode 100644 index 00000000..47d7589f --- /dev/null +++ b/x/rewards/wasmbinding/types/msg.go @@ -0,0 +1,105 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +type Msg struct { + // UpdateMetadata is a request to update the contract metadata. + // Request is authorized only if the contract address is set as the DeveloperAddress (metadata field). + UpdateMetadata *UpdateMetadataRequest `json:"update_metadata"` +} + +// Validate validates the msg fields. +func (m Msg) Validate() error { + cnt := 0 + + if m.UpdateMetadata != nil { + if err := m.UpdateMetadata.Validate(); err != nil { + return fmt.Errorf("updateMetadata: %w", err) + } + cnt++ + } + + if cnt == 0 { + return fmt.Errorf("empty msg") + } + + return nil +} + +// UpdateMetadataRequest is the Msg.SetMetadata request. +type UpdateMetadataRequest struct { + // OwnerAddress if not empty, changes the contract metadata ownership. + OwnerAddress string `json:"owner_address"` + // RewardsAddress if not empty, changes the rewards distribution destination address. + RewardsAddress string `json:"rewards_address"` +} + +// Validate performs request fields validation. +func (r UpdateMetadataRequest) Validate() error { + changeCnt := 0 + + if r.OwnerAddress != "" { + if _, err := sdk.AccAddressFromBech32(r.OwnerAddress); err != nil { + return fmt.Errorf("ownerAddress: parsing: %w", err) + } + changeCnt++ + } + + if r.RewardsAddress != "" { + if _, err := sdk.AccAddressFromBech32(r.RewardsAddress); err != nil { + return fmt.Errorf("rewardsAddress: parsing: %w", err) + } + changeCnt++ + } + + if changeCnt == 0 { + return fmt.Errorf("empty request") + } + + return nil +} + +// ToMetadata convert the UpdateMetadataRequest to a rewardsTypes.Metadata. +func (r UpdateMetadataRequest) ToMetadata() rewardsTypes.ContractMetadata { + return rewardsTypes.ContractMetadata{ + OwnerAddress: r.OwnerAddress, + RewardsAddress: r.RewardsAddress, + } +} + +// MustGetOwnerAddressOk returns the contract owner address as sdk.AccAddress if set to be updated. +// CONTRACT: panics in case of an error. +func (r UpdateMetadataRequest) MustGetOwnerAddressOk() (*sdk.AccAddress, bool) { + if r.OwnerAddress == "" { + return nil, false + } + + addr, err := sdk.AccAddressFromBech32(r.OwnerAddress) + if err != nil { + // Should not happen since we validate the request before this call + panic(fmt.Errorf("wasm bindings: meta update: parsing ownerAddress: %w", err)) + } + + return &addr, true +} + +// MustGetRewardsAddressOk returns the rewards address as sdk.AccAddress if set to be updated. +func (r UpdateMetadataRequest) MustGetRewardsAddressOk() (*sdk.AccAddress, bool) { + if r.RewardsAddress == "" { + return nil, false + } + + addr, err := sdk.AccAddressFromBech32(r.RewardsAddress) + if err != nil { + // Should not happen since we validate the request before this call + panic(fmt.Errorf("wasm bindings: meta update: parsing rewardsAddress: %w", err)) + } + + return &addr, true +} diff --git a/x/rewards/wasmbinding/types/msg_test.go b/x/rewards/wasmbinding/types/msg_test.go new file mode 100644 index 00000000..dfb22c4f --- /dev/null +++ b/x/rewards/wasmbinding/types/msg_test.go @@ -0,0 +1,68 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMsgValidate(t *testing.T) { + type testCase struct { + name string + msg Msg + errExpected bool + } + + testCases := []testCase{ + { + name: "OK", + msg: Msg{ + UpdateMetadata: &UpdateMetadataRequest{ + OwnerAddress: "cosmos1zj8lgj0zp06c8n4rreyzgu3tls9yhy4mm4vu8c", + RewardsAddress: "cosmos1zj8lgj0zp06c8n4rreyzgu3tls9yhy4mm4vu8c", + }, + }, + }, + { + name: "Fail: invalid UpdateMetadataRequest: no changes", + msg: Msg{ + UpdateMetadata: &UpdateMetadataRequest{}, + }, + errExpected: true, + }, + { + name: "Fail: invalid UpdateMetadataRequest: invalid OwnerAddress", + msg: Msg{ + UpdateMetadata: &UpdateMetadataRequest{ + OwnerAddress: "invalid", + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid UpdateMetadataRequest: invalid RewardsAddress", + msg: Msg{ + UpdateMetadata: &UpdateMetadataRequest{ + RewardsAddress: "invalid", + }, + }, + errExpected: true, + }, + { + name: "Fail: empty", + msg: Msg{}, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/rewards/wasmbinding/types/query.go b/x/rewards/wasmbinding/types/query.go new file mode 100644 index 00000000..7b77523e --- /dev/null +++ b/x/rewards/wasmbinding/types/query.go @@ -0,0 +1,78 @@ +package types + +import ( + "fmt" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Query is a container for custom WASM queries. +type Query struct { + // Metadata returns the contract metadata. + Metadata *ContractMetadataRequest `json:"metadata"` +} + +// Validate validates the query fields. +func (q Query) Validate() error { + cnt := 0 + + if q.Metadata != nil { + if err := q.Metadata.Validate(); err != nil { + return fmt.Errorf("metadata: %w", err) + } + cnt++ + } + + if cnt != 1 { + return fmt.Errorf("one and only one field must be set") + } + + return nil +} + +type ( + // ContractMetadataRequest is the Query.Metadata request. + ContractMetadataRequest struct { + // ContractAddress is the bech32 encoded contract address. + ContractAddress string `json:"contract_address"` + } + + // ContractMetadataResponse is the Query.Metadata response. + ContractMetadataResponse struct { + // OwnerAddress is the address of the contract owner (the one who can modify rewards parameters). + OwnerAddress string `json:"owner_address"` + // RewardsAddress is the target address for rewards distribution. + RewardsAddress string `json:"rewards_address"` + } +) + +// NewContractMetadataResponse converts rewardsTypes.ContractMetadata to ContractMetadataResponse. +func NewContractMetadataResponse(meta rewardsTypes.ContractMetadata) ContractMetadataResponse { + return ContractMetadataResponse{ + OwnerAddress: meta.OwnerAddress, + RewardsAddress: meta.RewardsAddress, + } +} + +// Validate performs request fields validation. +func (r ContractMetadataRequest) Validate() error { + if _, err := sdk.AccAddressFromBech32(r.ContractAddress); err != nil { + return fmt.Errorf("contractAddress: parsing: %w", err) + } + + return nil +} + +// MustGetContractAddress returns the contract address as sdk.AccAddress. +// CONTRACT: panics in case of an error. +func (r ContractMetadataRequest) MustGetContractAddress() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(r.ContractAddress) + if err != nil { + // Should not happen since we validate the request before this call + panic(fmt.Errorf("wasm bindings: meta request: parsing contractAddress: %w", err)) + } + + return addr +} diff --git a/x/rewards/wasmbinding/types/query_test.go b/x/rewards/wasmbinding/types/query_test.go new file mode 100644 index 00000000..1dff52d9 --- /dev/null +++ b/x/rewards/wasmbinding/types/query_test.go @@ -0,0 +1,49 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestQueryValidate(t *testing.T) { + type testCase struct { + name string + query Query + errExpected bool + } + + testCases := []testCase{ + { + name: "OK", + query: Query{ + Metadata: &ContractMetadataRequest{ + ContractAddress: "cosmos1zj8lgj0zp06c8n4rreyzgu3tls9yhy4mm4vu8c", + }, + }, + }, + { + name: "Fail: invalid Metadata", + query: Query{ + Metadata: &ContractMetadataRequest{}, + }, + errExpected: true, + }, + { + name: "Fail: empty", + query: Query{}, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.query.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/tracking/abci.go b/x/tracking/abci.go index 344f904f..c1067d2a 100644 --- a/x/tracking/abci.go +++ b/x/tracking/abci.go @@ -1,12 +1,14 @@ package tracking import ( - "github.com/archway-network/archway/x/tracking/keeper" - "github.com/archway-network/archway/x/tracking/types" + "time" + "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" - "time" + + "github.com/archway-network/archway/x/tracking/keeper" + "github.com/archway-network/archway/x/tracking/types" ) // EndBlocker modifies tracked transactions using tracked contract operations. diff --git a/x/tracking/ante/tracking.go b/x/tracking/ante/tracking.go index 231ddf53..1934b86a 100644 --- a/x/tracking/ante/tracking.go +++ b/x/tracking/ante/tracking.go @@ -18,9 +18,10 @@ type TxGasTrackingDecorator struct { // AnteHandle implements the AnteDecorator interface. func (d TxGasTrackingDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - if ctx.BlockHeight() <= 1 { - return next(ctx, tx, simulate) - } + // TODO: commented out because we need to have x/tracking and x/rewards in sync. + //if ctx.BlockHeight() <= 1 { + // return next(ctx, tx, simulate) + //} d.keeper.TrackNewTx(ctx) diff --git a/x/tracking/client/cli/query.go b/x/tracking/client/cli/query.go index 8312c0aa..4b495098 100644 --- a/x/tracking/client/cli/query.go +++ b/x/tracking/client/cli/query.go @@ -1,10 +1,11 @@ package cli import ( - "github.com/archway-network/archway/x/tracking/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" + + "github.com/archway-network/archway/x/tracking/types" ) // GetQueryCmd builds query command group for the module. @@ -17,39 +18,12 @@ func GetQueryCmd() *cobra.Command { RunE: client.ValidateCmd, } cmd.AddCommand( - getQueryParamsCmd(), getQueryBlockGasTrackingCmd(), ) return cmd } -func getQueryParamsCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "params", - Args: cobra.NoArgs, - Short: "Query the current tracking parameters", - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - queryClient := types.NewQueryClient(clientCtx) - - res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) - if err != nil { - return err - } - - return clientCtx.PrintProto(&res.Params) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} - func getQueryBlockGasTrackingCmd() *cobra.Command { cmd := &cobra.Command{ Use: "block-gas-tracking", diff --git a/x/tracking/keeper/common_test.go b/x/tracking/keeper/common_test.go index 6211dd3b..6c6805c0 100644 --- a/x/tracking/keeper/common_test.go +++ b/x/tracking/keeper/common_test.go @@ -1,11 +1,13 @@ package keeper_test import ( + "testing" + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/stretchr/testify/suite" + e2eTesting "github.com/archway-network/archway/e2e/testing" "github.com/archway-network/archway/x/tracking/types" - "github.com/stretchr/testify/suite" - "testing" ) type KeeperTestSuite struct { diff --git a/x/tracking/keeper/gas_processor.go b/x/tracking/keeper/gas_processor.go index f8eb02a9..5c96a4a2 100644 --- a/x/tracking/keeper/gas_processor.go +++ b/x/tracking/keeper/gas_processor.go @@ -2,9 +2,11 @@ package keeper import ( "fmt" + wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" - "github.com/archway-network/archway/x/tracking/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/tracking/types" ) var _ wasmTypes.ContractGasProcessor = &Keeper{} @@ -12,11 +14,6 @@ var _ wasmTypes.ContractGasProcessor = &Keeper{} // IngestGasRecord implements the wasmTypes.ContractGasProcessor interface. // It is called by the wasmd to track contract gas records. func (k Keeper) IngestGasRecord(ctx sdk.Context, records []wasmTypes.ContractGasRecord) error { - // Skip ingesting if not enabled - if !k.GasTrackingEnabled(ctx) { - return nil - } - // Ingest operation for every record for _, record := range records { contractAddr, err := sdk.AccAddressFromBech32(record.ContractAddress) @@ -70,7 +67,7 @@ func (k Keeper) IngestGasRecord(ctx sdk.Context, records []wasmTypes.ContractGas // It is called by the wasmd to get the gas consumption adjustment function for a contract. // This is a no-op function since we don't change gas values atm. func (k Keeper) GetGasCalculationFn(ctx sdk.Context, contractAddrBz string) (func(operationId uint64, gasInfo wasmTypes.GasConsumptionInfo) wasmTypes.GasConsumptionInfo, error) { - return func(operationId uint64, gasConsumptionInfo wasmTypes.GasConsumptionInfo) wasmTypes.GasConsumptionInfo { + return func(operationID uint64, gasConsumptionInfo wasmTypes.GasConsumptionInfo) wasmTypes.GasConsumptionInfo { return gasConsumptionInfo }, nil } diff --git a/x/tracking/keeper/genesis.go b/x/tracking/keeper/genesis.go index 98ee2a2c..5fe86ebf 100644 --- a/x/tracking/keeper/genesis.go +++ b/x/tracking/keeper/genesis.go @@ -1,14 +1,14 @@ package keeper import ( - "github.com/archway-network/archway/x/tracking/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/tracking/types" ) // ExportGenesis exports the module genesis for the current block. func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return types.NewGenesisState( - k.GetParams(ctx), k.state.TxInfoState(ctx).Export(), k.state.ContractOpInfoState(ctx).Export(), ) @@ -16,7 +16,6 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { // InitGenesis initializes the module genesis state. func (k Keeper) InitGenesis(ctx sdk.Context, state *types.GenesisState) { - k.SetParams(ctx, state.Params) k.state.TxInfoState(ctx).Import(state.TxInfos) k.state.ContractOpInfoState(ctx).Import(state.ContractOpInfos) } diff --git a/x/tracking/keeper/genesis_test.go b/x/tracking/keeper/genesis_test.go index 16a62544..539db6d3 100644 --- a/x/tracking/keeper/genesis_test.go +++ b/x/tracking/keeper/genesis_test.go @@ -16,22 +16,17 @@ func (s *KeeperTestSuite) TestGenesisExport() { keeper.TrackNewTx(ctx) keeper.TrackNewContractOperation(ctx, chain.GetAccount(rand.Intn(5)).Address, types.ContractOperation(rand.Int31n(8)-1), 1, 1) } - p := keeper.GetParams(ctx) - p.GasTrackingEnabled = false - keeper.SetParams(ctx, p) genesis := keeper.ExportGenesis(ctx) - s.Require().Nil(genesis.Validate()) - s.Require().False(genesis.Params.GasTrackingEnabled) - s.Require().Equal(operationsToExecute, len(genesis.ContractOpInfos)) - s.Require().Equal(operationsToExecute, len(genesis.TxInfos)) + s.Require().NoError(genesis.Validate()) + s.Assert().Equal(operationsToExecute, len(genesis.TxInfos)) + s.Assert().Equal(operationsToExecute, len(genesis.ContractOpInfos)) } func (s *KeeperTestSuite) TestGenesisImport() { chain := s.chain ctx, keeper := chain.GetContext(), chain.GetApp().TrackingKeeper - genesis := types.DefaultGenesisState() - genesis.Params.GasTrackingEnabled = false + genesisExpected := types.DefaultGenesisState() operationsToExecute := 100 // Ids must be greater than 0 @@ -45,12 +40,12 @@ func (s *KeeperTestSuite) TestGenesisImport() { 1, 1, } - genesis.TxInfos = append(genesis.TxInfos, txInfo) - genesis.ContractOpInfos = append(genesis.ContractOpInfos, contractOperation) + genesisExpected.TxInfos = append(genesisExpected.TxInfos, txInfo) + genesisExpected.ContractOpInfos = append(genesisExpected.ContractOpInfos, contractOperation) } + s.Require().NoError(genesisExpected.Validate()) - s.Require().Nil(genesis.Validate()) - keeper.InitGenesis(ctx, genesis) - newGenesis := keeper.ExportGenesis(ctx) - s.Require().Equal(genesis, newGenesis) + keeper.InitGenesis(ctx, genesisExpected) + genesisReceived := keeper.ExportGenesis(ctx) + s.Assert().Equal(genesisExpected, genesisReceived) } diff --git a/x/tracking/keeper/grpc_query.go b/x/tracking/keeper/grpc_query.go index 02168b8a..97215bc8 100644 --- a/x/tracking/keeper/grpc_query.go +++ b/x/tracking/keeper/grpc_query.go @@ -2,10 +2,12 @@ package keeper import ( "context" - "github.com/archway-network/archway/x/tracking/types" + sdk "github.com/cosmos/cosmos-sdk/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + "github.com/archway-network/archway/x/tracking/types" ) var _ types.QueryServer = &QueryServer{} @@ -22,19 +24,6 @@ func NewQueryServer(keeper Keeper) *QueryServer { } } -// Params implements the types.QueryServer interface. -func (s *QueryServer) Params(c context.Context, request *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { - if request == nil { - return nil, status.Error(codes.InvalidArgument, "empty request") - } - - ctx := sdk.UnwrapSDKContext(c) - - return &types.QueryParamsResponse{ - Params: s.keeper.GetParams(ctx), - }, nil -} - // BlockGasTracking implements the types.QueryServer interface. func (s *QueryServer) BlockGasTracking(c context.Context, request *types.QueryBlockGasTrackingRequest) (*types.QueryBlockGasTrackingResponse, error) { if request == nil { diff --git a/x/tracking/keeper/keeper.go b/x/tracking/keeper/keeper.go index 62f83470..47d61451 100644 --- a/x/tracking/keeper/keeper.go +++ b/x/tracking/keeper/keeper.go @@ -2,11 +2,12 @@ package keeper import ( wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" - "github.com/archway-network/archway/x/tracking/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" + + "github.com/archway-network/archway/x/tracking/types" ) // Keeper provides module state operations. @@ -19,15 +20,10 @@ type Keeper struct { } // NewKeeper creates a new Keeper instance. -func NewKeeper(cdc codec.Codec, key sdk.StoreKey, gasRegister wasmKeeper.GasRegister, ps paramTypes.Subspace) Keeper { - if !ps.HasKeyTable() { - ps = ps.WithKeyTable(types.ParamKeyTable()) - } - +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, gasRegister wasmKeeper.GasRegister) Keeper { return Keeper{ cdc: cdc, WasmGasRegister: gasRegister, - paramStore: ps, state: NewState(cdc, key), } } @@ -43,10 +39,22 @@ func (k Keeper) TrackNewTx(ctx sdk.Context) { k.state.TxInfoState(ctx).CreateEmptyTxInfo() } +// GetCurrentTxID returns the current transaction ID being tracked. +// That ID is used to link new contract operations and rewards tracking to the current transaction. +func (k Keeper) GetCurrentTxID(ctx sdk.Context) uint64 { + return k.state.TxInfoState(ctx).GetCurrentTxID() +} + // TrackNewContractOperation creates a new contract operation tracking entry with a unique ID using the current transaction ID. func (k Keeper) TrackNewContractOperation(ctx sdk.Context, contractAddr sdk.AccAddress, opType types.ContractOperation, vmGasConsumed, sdkGasConsumed uint64) { - curTxID := k.state.TxInfoState(ctx).GetCurrentTxID() - k.state.ContractOpInfoState(ctx).CreateContractOpInfo(curTxID, contractAddr, opType, vmGasConsumed, sdkGasConsumed) + curTxID := k.GetCurrentTxID(ctx) + k.state.ContractOpInfoState(ctx).CreateContractOpInfo( + curTxID, + contractAddr, + opType, + vmGasConsumed, + sdkGasConsumed, + ) } // FinalizeBlockTxTracking updates block transactions total gas consumed value using tracked contract operations. diff --git a/x/tracking/keeper/params.go b/x/tracking/keeper/params.go deleted file mode 100644 index de7a8688..00000000 --- a/x/tracking/keeper/params.go +++ /dev/null @@ -1,24 +0,0 @@ -package keeper - -import ( - "github.com/archway-network/archway/x/tracking/types" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// GasTrackingEnabled return gas tracking enabled param flag. -func (k Keeper) GasTrackingEnabled(ctx sdk.Context) (res bool) { - k.paramStore.Get(ctx, types.GasTrackingEnabledParamKey, &res) - return -} - -// GetParams return all module parameters. -func (k Keeper) GetParams(ctx sdk.Context) types.Params { - return types.NewParams( - k.GasTrackingEnabled(ctx), - ) -} - -// SetParams sets all module parameters. -func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { - k.paramStore.SetParamSet(ctx, ¶ms) -} diff --git a/x/tracking/keeper/state.go b/x/tracking/keeper/state.go index e3802480..aca05aac 100644 --- a/x/tracking/keeper/state.go +++ b/x/tracking/keeper/state.go @@ -1,10 +1,11 @@ package keeper import ( - "github.com/archway-network/archway/x/tracking/types" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/tracking/types" ) // State is a wrapper around the module storage state. diff --git a/x/tracking/keeper/state_contract_op.go b/x/tracking/keeper/state_contract_op.go index 2eaa03e0..eaaaa255 100644 --- a/x/tracking/keeper/state_contract_op.go +++ b/x/tracking/keeper/state_contract_op.go @@ -2,11 +2,13 @@ package keeper import ( "fmt" - "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" storeTypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/tracking/types" ) // ContractOpInfoState provides access to the types.ContractOperationInfo objects storage operations. @@ -56,7 +58,7 @@ func (s ContractOpInfoState) GetContractOpInfoByTxID(txID uint64) (objs []types. obj, found := s.GetContractOpInfo(id) if !found { - panic(fmt.Errorf("invalid ContractOpInfo tx index state: id (%d): not found", id)) + panic(fmt.Errorf("invalid ContractOpInfo TxInfo index state: id (%d): not found", id)) } objs = append(objs, obj) } @@ -138,12 +140,12 @@ func (s ContractOpInfoState) getContractOpInfo(id uint64) *types.ContractOperati return &obj } -// buildTxIndexPrefix returns the key prefix used to maintain types.ContractOperationInfo tx index. +// buildTxIndexPrefix returns the key prefix used to maintain types.ContractOperationInfo's tx index. func (s ContractOpInfoState) buildTxIndexPrefix(txID uint64) []byte { return sdk.Uint64ToBigEndian(txID) } -// buildTxIndexKey returns the key used to maintain types.ContractOperationInfo tx index. +// buildTxIndexKey returns the key used to maintain types.ContractOperationInfo's tx index. func (s ContractOpInfoState) buildTxIndexKey(txID, id uint64) []byte { return append( s.buildTxIndexPrefix(txID), @@ -151,7 +153,7 @@ func (s ContractOpInfoState) buildTxIndexKey(txID, id uint64) []byte { ) } -// parseTxIndexKey parses the types.ContractOperationInfo tx index key. +// parseTxIndexKey parses the types.ContractOperationInfo's tx index key. func (s ContractOpInfoState) parseTxIndexKey(key []byte) (txID, id uint64) { if len(key) != 16 { panic(fmt.Errorf("invalid ContractOpInfo TxInfo index key length: %d", len(key))) @@ -163,7 +165,7 @@ func (s ContractOpInfoState) parseTxIndexKey(key []byte) (txID, id uint64) { return } -// setTxIndex adds the types.ContractOperationInfo tx index entry. +// setTxIndex adds the types.ContractOperationInfo's tx index entry. func (s ContractOpInfoState) setTxIndex(txID, id uint64) { store := prefix.NewStore(s.stateStore, types.ContractOpInfoTxIndexPrefix) store.Set( diff --git a/x/tracking/keeper/state_test.go b/x/tracking/keeper/state_test.go index e3e28e87..3e905aaf 100644 --- a/x/tracking/keeper/state_test.go +++ b/x/tracking/keeper/state_test.go @@ -2,6 +2,7 @@ package keeper_test import ( wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/archway-network/archway/x/tracking/types" ) diff --git a/x/tracking/keeper/state_tx_info.go b/x/tracking/keeper/state_tx_info.go index 65268edf..0a009389 100644 --- a/x/tracking/keeper/state_tx_info.go +++ b/x/tracking/keeper/state_tx_info.go @@ -2,11 +2,13 @@ package keeper import ( "fmt" - "github.com/archway-network/archway/x/tracking/types" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" storeTypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/tracking/types" ) // TxInfoState provides access to the types.TxInfo objects storage operations. @@ -38,7 +40,8 @@ func (s TxInfoState) CreateEmptyTxInfo() types.TxInfo { return obj } -// SetTxInfo sets a types.TxInfo object overwriting and existing one. +// SetTxInfo sets a types.TxInfo object overwriting an existing one. +// CONTRACT: Block index is not updated. func (s TxInfoState) SetTxInfo(obj types.TxInfo) { store := prefix.NewStore(s.stateStore, types.TxInfoPrefix) store.Set( @@ -69,7 +72,7 @@ func (s TxInfoState) GetTxInfosByBlock(height int64) (objs []types.TxInfo) { obj, found := s.GetTxInfo(id) if !found { - panic(fmt.Errorf("invalid TxInfo block index state: id (%d): not found", id)) + panic(fmt.Errorf("invalid TxInfo Block index state: id (%d): not found", id)) } objs = append(objs, obj) } @@ -142,12 +145,12 @@ func (s TxInfoState) getTxInfo(id uint64) *types.TxInfo { return &obj } -// buildBlockIndexPrefix returns the key prefix used to maintain types.TxInfo block index. +// buildBlockIndexPrefix returns the key prefix used to maintain types.TxInfo's block index. func (s TxInfoState) buildBlockIndexPrefix(height int64) []byte { return sdk.Uint64ToBigEndian(uint64(height)) } -// buildBlockIndexKey returns the key used to maintain types.TxInfo block index. +// buildBlockIndexKey returns the key used to maintain types.TxInfo's block index. func (s TxInfoState) buildBlockIndexKey(height int64, id uint64) []byte { return append( s.buildBlockIndexPrefix(height), @@ -155,10 +158,10 @@ func (s TxInfoState) buildBlockIndexKey(height int64, id uint64) []byte { ) } -// parseBlockIndexKey parses the types.TxInfo block index key. +// parseBlockIndexKey parses the types.TxInfo's block index key. func (s TxInfoState) parseBlockIndexKey(key []byte) (height int64, id uint64) { if len(key) != 16 { - panic(fmt.Errorf("invalid TxInfo block index key length: %d", len(key))) + panic(fmt.Errorf("invalid TxInfo Block index key length: %d", len(key))) } height = int64(sdk.BigEndianToUint64(key[:8])) @@ -167,7 +170,7 @@ func (s TxInfoState) parseBlockIndexKey(key []byte) (height int64, id uint64) { return } -// setBlockIndex adds the types.TxInfo block index entry. +// setBlockIndex adds the types.TxInfo's block index entry. func (s TxInfoState) setBlockIndex(height int64, id uint64) { store := prefix.NewStore(s.stateStore, types.TxInfoBlockIndexPrefix) store.Set( diff --git a/x/tracking/module.go b/x/tracking/module.go index 7958389d..a2c7c846 100644 --- a/x/tracking/module.go +++ b/x/tracking/module.go @@ -1,13 +1,14 @@ // Package tracking defines a module that tracks WASM contracts gas usage per transaction. +// Module is not configurable and tracking is always enabled. +// TODO: collected tracking data should be pruned. package tracking import ( "context" "encoding/json" "fmt" - "github.com/archway-network/archway/x/tracking/client/cli" - "github.com/archway-network/archway/x/tracking/keeper" - "github.com/archway-network/archway/x/tracking/types" + "math/rand" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -18,7 +19,10 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" - "math/rand" + + "github.com/archway-network/archway/x/tracking/client/cli" + "github.com/archway-network/archway/x/tracking/keeper" + "github.com/archway-network/archway/x/tracking/types" ) var ( @@ -138,7 +142,7 @@ func (a AppModule) ConsensusVersion() uint64 { } // BeginBlock returns the begin blocker for the module. -func (a AppModule) BeginBlock(context sdk.Context, block abci.RequestBeginBlock) {} +func (a AppModule) BeginBlock(ctx sdk.Context, block abci.RequestBeginBlock) {} // EndBlock returns the end blocker for the module. It returns no validator updates. func (a AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { diff --git a/x/tracking/types/codec.go b/x/tracking/types/codec.go index 5a8505bd..ca798861 100644 --- a/x/tracking/types/codec.go +++ b/x/tracking/types/codec.go @@ -23,4 +23,5 @@ func init() { RegisterLegacyAminoCodec(amino) cryptoCodec.RegisterCrypto(amino) sdk.RegisterLegacyAminoCodec(amino) + amino.Seal() } diff --git a/x/tracking/types/genesis.go b/x/tracking/types/genesis.go index e9a085a7..720b6c49 100644 --- a/x/tracking/types/genesis.go +++ b/x/tracking/types/genesis.go @@ -3,9 +3,8 @@ package types import "fmt" // NewGenesisState creates a new GenesisState object. -func NewGenesisState(params Params, txInfos []TxInfo, contractOpInfos []ContractOperationInfo) *GenesisState { +func NewGenesisState(txInfos []TxInfo, contractOpInfos []ContractOperationInfo) *GenesisState { return &GenesisState{ - Params: params, TxInfos: txInfos, ContractOpInfos: contractOpInfos, } @@ -14,7 +13,6 @@ func NewGenesisState(params Params, txInfos []TxInfo, contractOpInfos []Contract // DefaultGenesisState returns a default genesis state. func DefaultGenesisState() *GenesisState { return &GenesisState{ - Params: DefaultParams(), TxInfos: []TxInfo{}, ContractOpInfos: []ContractOperationInfo{}, } @@ -22,10 +20,6 @@ func DefaultGenesisState() *GenesisState { // Validate performs genesis state validation. func (m GenesisState) Validate() error { - if err := m.Params.Validate(); err != nil { - return fmt.Errorf("params: %w", err) - } - txIDSet := make(map[uint64]struct{}) for i, txInfo := range m.TxInfos { if err := txInfo.Validate(); err != nil { diff --git a/x/tracking/types/genesis.pb.go b/x/tracking/types/genesis.pb.go index 9e93964e..b57dc389 100644 --- a/x/tracking/types/genesis.pb.go +++ b/x/tracking/types/genesis.pb.go @@ -25,8 +25,6 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the initial state of the tracking module. type GenesisState struct { - // params defines all the module parameters. - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // tx_infos defines a list of all the tracked transactions. TxInfos []TxInfo `protobuf:"bytes,2,rep,name=tx_infos,json=txInfos,proto3" json:"tx_infos"` // contract_op_infos defines a list of all the tracked contract operations. @@ -66,13 +64,6 @@ func (m *GenesisState) XXX_DiscardUnknown() { var xxx_messageInfo_GenesisState proto.InternalMessageInfo -func (m *GenesisState) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - func (m *GenesisState) GetTxInfos() []TxInfo { if m != nil { return m.TxInfos @@ -96,25 +87,24 @@ func init() { } var fileDescriptor_40f994a880eb2f25 = []byte{ - // 283 bytes of a gzipped FileDescriptorProto + // 260 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4b, 0x2c, 0x4a, 0xce, 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x29, 0x4a, 0x4c, 0xce, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x80, 0xaa, 0xd3, 0x83, 0xa9, 0xd3, 0x83, 0xaa, 0x93, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x2b, 0xd2, 0x07, 0xb1, 0x20, 0xea, 0xa5, 0xd4, 0x71, 0x9a, 0x0b, 0x37, 0x00, - 0xac, 0x50, 0xe9, 0x0b, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xaa, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, - 0x3b, 0x2e, 0xb6, 0x82, 0xc4, 0xa2, 0xc4, 0xdc, 0x62, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x6e, 0x23, - 0x05, 0x3d, 0x5c, 0x56, 0xeb, 0x05, 0x80, 0xd5, 0x39, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, - 0xd5, 0x25, 0xe4, 0xc8, 0xc5, 0x51, 0x52, 0x11, 0x9f, 0x99, 0x97, 0x96, 0x5f, 0x2c, 0xc1, 0xa4, - 0xc0, 0x8c, 0xdf, 0x84, 0x90, 0x0a, 0xcf, 0xbc, 0xb4, 0x7c, 0xa8, 0x09, 0xec, 0x25, 0x60, 0x5e, - 0xb1, 0x50, 0x22, 0x97, 0x60, 0x72, 0x7e, 0x1e, 0x48, 0x71, 0x49, 0x7c, 0x7e, 0x01, 0xd4, 0x2c, - 0x66, 0xb0, 0x59, 0xfa, 0xb8, 0xcd, 0x72, 0x86, 0x6a, 0xf1, 0x2f, 0x48, 0x2d, 0x4a, 0x2c, 0xc9, - 0xcc, 0xcf, 0x43, 0x32, 0x9a, 0x3f, 0x19, 0x2e, 0x09, 0xb6, 0xc2, 0xc9, 0xf7, 0xc4, 0x23, 0x39, - 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, - 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x8c, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, - 0xf3, 0x73, 0xf5, 0xa1, 0x76, 0xe9, 0xe6, 0xa5, 0x96, 0x94, 0xe7, 0x17, 0x65, 0xc3, 0xf8, 0xfa, - 0x15, 0x88, 0x60, 0x2d, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, 0x07, 0xa6, 0x31, 0x20, 0x00, - 0x00, 0xff, 0xff, 0x84, 0xcc, 0x33, 0x99, 0xcf, 0x01, 0x00, 0x00, + 0xac, 0x50, 0x69, 0x0b, 0x23, 0x17, 0x8f, 0x3b, 0xc4, 0xaa, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, + 0x47, 0x2e, 0x8e, 0x92, 0x8a, 0xf8, 0xcc, 0xbc, 0xb4, 0xfc, 0x62, 0x09, 0x26, 0x05, 0x66, 0x0d, + 0x6e, 0x23, 0x05, 0x3d, 0x5c, 0x96, 0xeb, 0x85, 0x54, 0x78, 0xe6, 0xa5, 0xe5, 0x3b, 0xb1, 0x9c, + 0xb8, 0x27, 0xcf, 0x10, 0xc4, 0x5e, 0x02, 0xe6, 0x15, 0x0b, 0x25, 0x72, 0x09, 0x26, 0xe7, 0xe7, + 0x81, 0x14, 0x97, 0xc4, 0xe7, 0x17, 0x40, 0xcd, 0x62, 0x06, 0x9b, 0xa5, 0x8f, 0xdb, 0x2c, 0x67, + 0xa8, 0x16, 0xff, 0x82, 0xd4, 0xa2, 0xc4, 0x92, 0xcc, 0xfc, 0x3c, 0x24, 0xa3, 0xf9, 0x93, 0xe1, + 0x92, 0x60, 0x2b, 0x9c, 0x7c, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, + 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, + 0x38, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x1f, 0x6a, 0x97, 0x6e, 0x5e, + 0x6a, 0x49, 0x79, 0x7e, 0x51, 0x36, 0x8c, 0xaf, 0x5f, 0x81, 0x08, 0x96, 0x92, 0xca, 0x82, 0xd4, + 0xe2, 0x24, 0x36, 0x70, 0x60, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x55, 0x3a, 0x40, 0xc1, + 0x8f, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -165,16 +155,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } } - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -195,8 +175,6 @@ func (m *GenesisState) Size() (n int) { } var l int _ = l - l = m.Params.Size() - n += 1 + l + sovGenesis(uint64(l)) if len(m.TxInfos) > 0 { for _, e := range m.TxInfos { l = e.Size() @@ -247,39 +225,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TxInfos", wireType) diff --git a/x/tracking/types/params.go b/x/tracking/types/params.go deleted file mode 100644 index fd64f133..00000000 --- a/x/tracking/types/params.go +++ /dev/null @@ -1,66 +0,0 @@ -package types - -import ( - "fmt" - paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" - "sigs.k8s.io/yaml" -) - -var ( - GasTrackingEnabledParamKey = []byte("GasTrackingEnabled") -) - -var _ paramTypes.ParamSet = (*Params)(nil) - -// ParamKeyTable creates a new params table. -func ParamKeyTable() paramTypes.KeyTable { - return paramTypes.NewKeyTable().RegisterParamSet(&Params{}) -} - -// NewParams creates a new Params instance. -func NewParams(gasTrackingEnabled bool) Params { - return Params{ - GasTrackingEnabled: gasTrackingEnabled, - } -} - -// DefaultParams returns a default set of parameters. -func DefaultParams() Params { - return NewParams(true) -} - -// ParamSetPairs Implements the paramTypes.ParamSet interface. -func (m *Params) ParamSetPairs() paramTypes.ParamSetPairs { - return paramTypes.ParamSetPairs{ - paramTypes.NewParamSetPair(GasTrackingEnabledParamKey, &m.GasTrackingEnabled, validateGasTrackingEnabled), - } -} - -// Validate perform object fields validation. -func (m Params) Validate() error { - if err := validateGasTrackingEnabled(m.GasTrackingEnabled); err != nil { - return err - } - - return nil -} - -// String implements the fmt.Stringer interface. -func (m Params) String() string { - bz, _ := yaml.Marshal(m) - return string(bz) -} - -func validateGasTrackingEnabled(v interface{}) (retErr error) { - defer func() { - if retErr != nil { - retErr = fmt.Errorf("gasTrackingEnabled param: %w", retErr) - } - }() - - if _, ok := v.(bool); !ok { - return fmt.Errorf("invalid parameter type: %T", v) - } - - return -} diff --git a/x/tracking/types/query.pb.go b/x/tracking/types/query.pb.go index 4bae19ba..1d96fb32 100644 --- a/x/tracking/types/query.pb.go +++ b/x/tracking/types/query.pb.go @@ -29,88 +29,6 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// QueryParamsRequest is the request for Query.Params. -type QueryParamsRequest struct { -} - -func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } -func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } -func (*QueryParamsRequest) ProtoMessage() {} -func (*QueryParamsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f4819b1e6d461893, []int{0} -} -func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryParamsRequest.Merge(m, src) -} -func (m *QueryParamsRequest) XXX_Size() int { - return m.Size() -} -func (m *QueryParamsRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo - -// QueryParamsResponse is the response for Query.Params. -type QueryParamsResponse struct { - Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` -} - -func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } -func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } -func (*QueryParamsResponse) ProtoMessage() {} -func (*QueryParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f4819b1e6d461893, []int{1} -} -func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryParamsResponse.Merge(m, src) -} -func (m *QueryParamsResponse) XXX_Size() int { - return m.Size() -} -func (m *QueryParamsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo - -func (m *QueryParamsResponse) GetParams() Params { - if m != nil { - return m.Params - } - return Params{} -} - // QueryBlockGasTrackingRequest is the request for Query.BlockGasTracking. type QueryBlockGasTrackingRequest struct { } @@ -119,7 +37,7 @@ func (m *QueryBlockGasTrackingRequest) Reset() { *m = QueryBlockGasTrack func (m *QueryBlockGasTrackingRequest) String() string { return proto.CompactTextString(m) } func (*QueryBlockGasTrackingRequest) ProtoMessage() {} func (*QueryBlockGasTrackingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_f4819b1e6d461893, []int{2} + return fileDescriptor_f4819b1e6d461893, []int{0} } func (m *QueryBlockGasTrackingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -157,7 +75,7 @@ func (m *QueryBlockGasTrackingResponse) Reset() { *m = QueryBlockGasTrac func (m *QueryBlockGasTrackingResponse) String() string { return proto.CompactTextString(m) } func (*QueryBlockGasTrackingResponse) ProtoMessage() {} func (*QueryBlockGasTrackingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f4819b1e6d461893, []int{3} + return fileDescriptor_f4819b1e6d461893, []int{1} } func (m *QueryBlockGasTrackingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -194,8 +112,6 @@ func (m *QueryBlockGasTrackingResponse) GetBlock() BlockTracking { } func init() { - proto.RegisterType((*QueryParamsRequest)(nil), "archway.tracking.v1beta1.QueryParamsRequest") - proto.RegisterType((*QueryParamsResponse)(nil), "archway.tracking.v1beta1.QueryParamsResponse") proto.RegisterType((*QueryBlockGasTrackingRequest)(nil), "archway.tracking.v1beta1.QueryBlockGasTrackingRequest") proto.RegisterType((*QueryBlockGasTrackingResponse)(nil), "archway.tracking.v1beta1.QueryBlockGasTrackingResponse") } @@ -205,31 +121,27 @@ func init() { } var fileDescriptor_f4819b1e6d461893 = []byte{ - // 377 bytes of a gzipped FileDescriptorProto + // 306 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x49, 0x2c, 0x4a, 0xce, 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x29, 0x4a, 0x4c, 0xce, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x80, 0xaa, 0xd2, 0x83, 0xa9, 0xd2, 0x83, 0xaa, 0x92, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x2b, 0xd2, 0x07, 0xb1, 0x20, 0xea, 0xa5, 0x64, 0xd2, 0xf3, 0xf3, 0xd3, 0x73, 0x52, 0xf5, 0x13, 0x0b, 0x32, 0xf5, 0x13, 0xf3, 0xf2, 0xf2, 0x4b, 0x12, 0x4b, 0x32, 0xf3, 0xf3, 0x8a, 0xa1, - 0xb2, 0xea, 0x38, 0xed, 0x84, 0x1b, 0x0f, 0x56, 0xa8, 0x24, 0xc2, 0x25, 0x14, 0x08, 0x72, 0x45, - 0x40, 0x62, 0x51, 0x62, 0x6e, 0x71, 0x50, 0x6a, 0x61, 0x69, 0x6a, 0x71, 0x89, 0x52, 0x28, 0x97, - 0x30, 0x8a, 0x68, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x90, 0x1d, 0x17, 0x5b, 0x01, 0x58, 0x44, - 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x41, 0x0f, 0x97, 0xa3, 0xf5, 0x20, 0x3a, 0x9d, 0x58, - 0x4e, 0xdc, 0x93, 0x67, 0x08, 0x82, 0xea, 0x52, 0x92, 0xe3, 0x92, 0x01, 0x1b, 0xeb, 0x94, 0x93, - 0x9f, 0x9c, 0xed, 0x9e, 0x58, 0x1c, 0x02, 0xd5, 0x05, 0xb3, 0x36, 0x85, 0x4b, 0x16, 0x87, 0x3c, - 0xd4, 0x01, 0xce, 0x5c, 0xac, 0x49, 0x20, 0x39, 0xa8, 0xfd, 0xea, 0xb8, 0xed, 0x07, 0x1b, 0x01, - 0xd3, 0x0f, 0x75, 0x06, 0x44, 0xaf, 0xd1, 0x69, 0x26, 0x2e, 0x56, 0xb0, 0x35, 0x42, 0x5d, 0x8c, - 0x5c, 0x6c, 0x10, 0x87, 0x0a, 0xe9, 0xe0, 0x36, 0x0a, 0x33, 0x7c, 0xa4, 0x74, 0x89, 0x54, 0x0d, - 0x71, 0xb6, 0x92, 0x72, 0xd3, 0xe5, 0x27, 0x93, 0x99, 0x64, 0x85, 0xa4, 0xf5, 0xb1, 0x44, 0x8b, - 0x3e, 0x24, 0x70, 0x84, 0xb6, 0x30, 0x72, 0x09, 0xa0, 0x7b, 0x5c, 0xc8, 0x8c, 0x80, 0x45, 0x38, - 0x42, 0x52, 0xca, 0x9c, 0x64, 0x7d, 0x50, 0xa7, 0xea, 0x83, 0x9d, 0xaa, 0x29, 0xa4, 0x8e, 0xd5, - 0xa9, 0xe0, 0x00, 0x8c, 0x4f, 0x4f, 0x2c, 0x8e, 0x87, 0x89, 0x3a, 0xf9, 0x9e, 0x78, 0x24, 0xc7, - 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, - 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x71, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, - 0x7e, 0x2e, 0xcc, 0x30, 0xdd, 0xbc, 0xd4, 0x92, 0xf2, 0xfc, 0xa2, 0x6c, 0xb8, 0xe1, 0x15, 0x08, - 0xe3, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xc9, 0xd2, 0x18, 0x10, 0x00, 0x00, 0xff, - 0xff, 0x5b, 0xae, 0x35, 0x10, 0x35, 0x03, 0x00, 0x00, + 0xb2, 0xea, 0x38, 0xed, 0x84, 0x1b, 0x0f, 0x56, 0xa8, 0x24, 0xc7, 0x25, 0x13, 0x08, 0x72, 0x85, + 0x53, 0x4e, 0x7e, 0x72, 0xb6, 0x7b, 0x62, 0x71, 0x08, 0x54, 0x3a, 0x28, 0xb5, 0xb0, 0x34, 0xb5, + 0xb8, 0x44, 0x29, 0x85, 0x4b, 0x16, 0x87, 0x7c, 0x71, 0x41, 0x7e, 0x5e, 0x71, 0xaa, 0x90, 0x33, + 0x17, 0x6b, 0x12, 0x48, 0x4e, 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x5d, 0x0f, 0x97, 0x3f, + 0xf4, 0xc0, 0x46, 0xc0, 0xf4, 0x3b, 0xb1, 0x9c, 0xb8, 0x27, 0xcf, 0x10, 0x04, 0xd1, 0x6b, 0xb4, + 0x8f, 0x91, 0x8b, 0x15, 0x6c, 0x8d, 0xd0, 0x16, 0x46, 0x2e, 0x01, 0x74, 0xbb, 0x84, 0xcc, 0x70, + 0x1b, 0x8a, 0xcf, 0xf1, 0x52, 0xe6, 0x24, 0xeb, 0x83, 0x78, 0x4a, 0x49, 0xbf, 0xe9, 0xf2, 0x93, + 0xc9, 0x4c, 0x9a, 0x42, 0xea, 0xfa, 0x58, 0xc2, 0x51, 0x1f, 0xec, 0xe6, 0xf8, 0xf4, 0xc4, 0xe2, + 0x78, 0x98, 0xa8, 0x93, 0xef, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, + 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x19, + 0xa7, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xc2, 0x0c, 0xd3, 0xcd, 0x4b, 0x2d, + 0x29, 0xcf, 0x2f, 0xca, 0x86, 0x1b, 0x5e, 0x81, 0x30, 0xbe, 0xa4, 0xb2, 0x20, 0xb5, 0x38, 0x89, + 0x0d, 0x1c, 0x39, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc3, 0xcc, 0xbc, 0x3a, 0x3b, 0x02, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -244,9 +156,7 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type QueryClient interface { - // Params returns module parameters. - Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) - // BlockGasTracking returns block gas tracking for the latest block + // BlockGasTracking returns block gas tracking for the current block BlockGasTracking(ctx context.Context, in *QueryBlockGasTrackingRequest, opts ...grpc.CallOption) (*QueryBlockGasTrackingResponse, error) } @@ -258,15 +168,6 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { return &queryClient{cc} } -func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { - out := new(QueryParamsResponse) - err := c.cc.Invoke(ctx, "/archway.tracking.v1beta1.Query/Params", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *queryClient) BlockGasTracking(ctx context.Context, in *QueryBlockGasTrackingRequest, opts ...grpc.CallOption) (*QueryBlockGasTrackingResponse, error) { out := new(QueryBlockGasTrackingResponse) err := c.cc.Invoke(ctx, "/archway.tracking.v1beta1.Query/BlockGasTracking", in, out, opts...) @@ -278,9 +179,7 @@ func (c *queryClient) BlockGasTracking(ctx context.Context, in *QueryBlockGasTra // QueryServer is the server API for Query service. type QueryServer interface { - // Params returns module parameters. - Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) - // BlockGasTracking returns block gas tracking for the latest block + // BlockGasTracking returns block gas tracking for the current block BlockGasTracking(context.Context, *QueryBlockGasTrackingRequest) (*QueryBlockGasTrackingResponse, error) } @@ -288,9 +187,6 @@ type QueryServer interface { type UnimplementedQueryServer struct { } -func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") -} func (*UnimplementedQueryServer) BlockGasTracking(ctx context.Context, req *QueryBlockGasTrackingRequest) (*QueryBlockGasTrackingResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method BlockGasTracking not implemented") } @@ -299,24 +195,6 @@ func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) } -func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryParamsRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(QueryServer).Params(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/archway.tracking.v1beta1.Query/Params", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) - } - return interceptor(ctx, in, info, handler) -} - func _Query_BlockGasTracking_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryBlockGasTrackingRequest) if err := dec(in); err != nil { @@ -339,10 +217,6 @@ var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "archway.tracking.v1beta1.Query", HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "Params", - Handler: _Query_Params_Handler, - }, { MethodName: "BlockGasTracking", Handler: _Query_BlockGasTracking_Handler, @@ -352,62 +226,6 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Metadata: "archway/tracking/v1beta1/query.proto", } -func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - return len(dAtA) - i, nil -} - func (m *QueryBlockGasTrackingRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -475,26 +293,6 @@ func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *QueryParamsRequest) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *QueryParamsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = m.Params.Size() - n += 1 + l + sovQuery(uint64(l)) - return n -} - func (m *QueryBlockGasTrackingRequest) Size() (n int) { if m == nil { return 0 @@ -521,139 +319,6 @@ func sovQuery(x uint64) (n int) { func sozQuery(x uint64) (n int) { return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthQuery - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipQuery(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthQuery - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *QueryBlockGasTrackingRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/tracking/types/query.pb.gw.go b/x/tracking/types/query.pb.gw.go index 73332f0a..08b57475 100644 --- a/x/tracking/types/query.pb.gw.go +++ b/x/tracking/types/query.pb.gw.go @@ -31,24 +31,6 @@ var _ = runtime.String var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage -func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryParamsRequest - var metadata runtime.ServerMetadata - - msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryParamsRequest - var metadata runtime.ServerMetadata - - msg, err := server.Params(ctx, &protoReq) - return msg, metadata, err - -} - func request_Query_BlockGasTracking_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryBlockGasTrackingRequest var metadata runtime.ServerMetadata @@ -73,26 +55,6 @@ func local_request_Query_BlockGasTracking_0(ctx context.Context, marshaler runti // Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { - mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Query_BlockGasTracking_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -154,26 +116,6 @@ func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc // "QueryClient" to call the correct interceptors. func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { - mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_Query_BlockGasTracking_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -198,13 +140,9 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "tracking", "v1", "params"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_Query_BlockGasTracking_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "tracking", "v1", "block_gas_tracking"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( - forward_Query_Params_0 = runtime.ForwardResponseMessage - forward_Query_BlockGasTracking_0 = runtime.ForwardResponseMessage ) diff --git a/x/tracking/types/tracking.go b/x/tracking/types/tracking.go index 97bf2559..32e7c83a 100644 --- a/x/tracking/types/tracking.go +++ b/x/tracking/types/tracking.go @@ -2,14 +2,14 @@ package types import ( "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" "sigs.k8s.io/yaml" ) -// String implements the fmt.Stringer interface. -func (m TxInfo) String() string { - bz, _ := yaml.Marshal(m) - return string(bz) +// HasGasUsage returns true if the transaction has contract operations. +func (m TxInfo) HasGasUsage() bool { + return m.TotalGas > 0 } // Validate performs object fields validation. @@ -22,19 +22,38 @@ func (m TxInfo) Validate() error { } // String implements the fmt.Stringer interface. -func (m ContractOperationInfo) String() string { +func (m TxInfo) String() string { bz, _ := yaml.Marshal(m) return string(bz) } +// GasUsed returns the total gas used by the operation and the flag that indicates whether operation was a noop operation. +func (m ContractOperationInfo) GasUsed() (uint64, bool) { + gasUsed := m.VmGas + m.SdkGas + return gasUsed, gasUsed > 0 +} + +// MustGetContractAddress returns the contract address. +// CONTRACT: panics on parsing error. +func (m ContractOperationInfo) MustGetContractAddress() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(m.ContractAddress) + if err != nil { + panic(fmt.Errorf("parsing contract address (%s): %w", m.ContractAddress, err)) + } + + return addr +} + // Validate performs object fields validation. func (m ContractOperationInfo) Validate() error { if m.Id == 0 { return fmt.Errorf("id: must be GT 0") } + if m.TxId == 0 { return fmt.Errorf("txId: must be GT 0") } + if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { return fmt.Errorf("contractAddress: %s", err.Error()) } @@ -42,6 +61,12 @@ func (m ContractOperationInfo) Validate() error { return nil } +// String implements the fmt.Stringer interface. +func (m ContractOperationInfo) String() string { + bz, _ := yaml.Marshal(m) + return string(bz) +} + // String implements the fmt.Stringer interface. func (m BlockTracking) String() string { bz, _ := yaml.Marshal(m) diff --git a/x/tracking/types/tracking.pb.go b/x/tracking/types/tracking.pb.go index 19f254f0..1a1659bd 100644 --- a/x/tracking/types/tracking.pb.go +++ b/x/tracking/types/tracking.pb.go @@ -67,51 +67,6 @@ func (ContractOperation) EnumDescriptor() ([]byte, []int) { return fileDescriptor_792f9386dd247ede, []int{0} } -// Params defines the module parameters. -type Params struct { - // gas_tracking_enabled flag indicates whether gas tracking is enabled (TXs and ContractOperations creation). - GasTrackingEnabled bool `protobuf:"varint,1,opt,name=gas_tracking_enabled,json=gasTrackingEnabled,proto3" json:"gas_tracking_enabled,omitempty"` -} - -func (m *Params) Reset() { *m = Params{} } -func (*Params) ProtoMessage() {} -func (*Params) Descriptor() ([]byte, []int) { - return fileDescriptor_792f9386dd247ede, []int{0} -} -func (m *Params) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Params.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Params) XXX_Merge(src proto.Message) { - xxx_messageInfo_Params.Merge(m, src) -} -func (m *Params) XXX_Size() int { - return m.Size() -} -func (m *Params) XXX_DiscardUnknown() { - xxx_messageInfo_Params.DiscardUnknown(m) -} - -var xxx_messageInfo_Params proto.InternalMessageInfo - -func (m *Params) GetGasTrackingEnabled() bool { - if m != nil { - return m.GasTrackingEnabled - } - return false -} - // TxInfo keeps a transaction gas tracking data. // Object is being created at the module EndBlocker. type TxInfo struct { @@ -127,7 +82,7 @@ type TxInfo struct { func (m *TxInfo) Reset() { *m = TxInfo{} } func (*TxInfo) ProtoMessage() {} func (*TxInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_792f9386dd247ede, []int{1} + return fileDescriptor_792f9386dd247ede, []int{0} } func (m *TxInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -199,7 +154,7 @@ type ContractOperationInfo struct { func (m *ContractOperationInfo) Reset() { *m = ContractOperationInfo{} } func (*ContractOperationInfo) ProtoMessage() {} func (*ContractOperationInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_792f9386dd247ede, []int{2} + return fileDescriptor_792f9386dd247ede, []int{1} } func (m *ContractOperationInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -279,7 +234,7 @@ type BlockTracking struct { func (m *BlockTracking) Reset() { *m = BlockTracking{} } func (*BlockTracking) ProtoMessage() {} func (*BlockTracking) Descriptor() ([]byte, []int) { - return fileDescriptor_792f9386dd247ede, []int{3} + return fileDescriptor_792f9386dd247ede, []int{2} } func (m *BlockTracking) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -326,7 +281,7 @@ type TxTracking struct { func (m *TxTracking) Reset() { *m = TxTracking{} } func (*TxTracking) ProtoMessage() {} func (*TxTracking) Descriptor() ([]byte, []int) { - return fileDescriptor_792f9386dd247ede, []int{4} + return fileDescriptor_792f9386dd247ede, []int{3} } func (m *TxTracking) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -371,7 +326,6 @@ func (m *TxTracking) GetContractOperations() []ContractOperationInfo { func init() { proto.RegisterEnum("archway.tracking.v1beta1.ContractOperation", ContractOperation_name, ContractOperation_value) - proto.RegisterType((*Params)(nil), "archway.tracking.v1beta1.Params") proto.RegisterType((*TxInfo)(nil), "archway.tracking.v1beta1.TxInfo") proto.RegisterType((*ContractOperationInfo)(nil), "archway.tracking.v1beta1.ContractOperationInfo") proto.RegisterType((*BlockTracking)(nil), "archway.tracking.v1beta1.BlockTracking") @@ -383,78 +337,43 @@ func init() { } var fileDescriptor_792f9386dd247ede = []byte{ - // 600 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcd, 0x4e, 0xdb, 0x40, - 0x18, 0x8c, 0x13, 0xc7, 0xc0, 0x87, 0xa0, 0xee, 0xf2, 0x67, 0x01, 0x32, 0x16, 0x42, 0x6a, 0xda, - 0xaa, 0x49, 0x81, 0x1b, 0xea, 0xa1, 0x49, 0x70, 0x91, 0xa5, 0x92, 0xa4, 0x1b, 0x47, 0x2a, 0xbd, - 0x58, 0x9b, 0xd8, 0x38, 0x56, 0x88, 0x37, 0xf2, 0x6e, 0xc1, 0xbc, 0x45, 0x0f, 0x3d, 0xf4, 0xd8, - 0xa7, 0xe8, 0x33, 0x70, 0xe4, 0xd8, 0x53, 0x55, 0xc1, 0x13, 0xf4, 0x0d, 0xaa, 0x6c, 0xec, 0x50, - 0x15, 0x53, 0xa9, 0xb7, 0xec, 0x7c, 0x33, 0xf3, 0xcd, 0x4e, 0xac, 0x85, 0x27, 0x24, 0xea, 0xf5, - 0x2f, 0xc8, 0x65, 0x85, 0x47, 0xa4, 0x37, 0x08, 0x42, 0xbf, 0x72, 0xbe, 0xdb, 0xf5, 0x38, 0xd9, - 0x9d, 0x02, 0xe5, 0x51, 0x44, 0x39, 0x45, 0x5a, 0x42, 0x2c, 0x4f, 0xf1, 0x84, 0xb8, 0xbe, 0xec, - 0x53, 0x9f, 0x0a, 0x52, 0x65, 0xfc, 0x6b, 0xc2, 0xdf, 0x7e, 0x0d, 0x4a, 0x8b, 0x44, 0x64, 0xc8, - 0xd0, 0x4b, 0x58, 0xf6, 0x09, 0x73, 0x52, 0x9d, 0xe3, 0x85, 0xa4, 0x7b, 0xe6, 0xb9, 0x9a, 0x64, - 0x48, 0xa5, 0x59, 0x8c, 0x7c, 0xc2, 0xec, 0x64, 0x64, 0x4e, 0x26, 0x07, 0xf2, 0x97, 0xaf, 0x5b, - 0xb9, 0xed, 0x36, 0x28, 0x76, 0x6c, 0x85, 0xa7, 0x14, 0x2d, 0x42, 0x3e, 0x98, 0xf0, 0x65, 0x9c, - 0x0f, 0x5c, 0xb4, 0x0a, 0x4a, 0xdf, 0x0b, 0xfc, 0x3e, 0xd7, 0xf2, 0x86, 0x54, 0x2a, 0xe0, 0xe4, - 0x84, 0x36, 0x60, 0x8e, 0x53, 0x4e, 0xce, 0x1c, 0x9f, 0x30, 0xad, 0x20, 0xe8, 0xb3, 0x02, 0x38, - 0x22, 0x2c, 0x31, 0xfd, 0x25, 0xc1, 0x4a, 0x9d, 0x86, 0xe3, 0x30, 0xbc, 0x39, 0xf2, 0x22, 0xc2, - 0x03, 0x1a, 0x66, 0x2e, 0x59, 0x82, 0x22, 0x8f, 0x9d, 0xc0, 0x15, 0x3b, 0x64, 0x2c, 0xf3, 0xd8, - 0x72, 0xd1, 0x53, 0x50, 0x7b, 0x89, 0xda, 0x21, 0xae, 0x1b, 0x79, 0x6c, 0xb2, 0x68, 0x0e, 0x3f, - 0x4a, 0xf1, 0xea, 0x04, 0x46, 0x18, 0x16, 0x69, 0xba, 0xc0, 0xe1, 0x97, 0x23, 0x4f, 0x93, 0x0d, - 0xa9, 0xb4, 0xb8, 0xf7, 0xbc, 0xfc, 0x50, 0x93, 0xe5, 0x7b, 0xc1, 0xf0, 0xc2, 0xd4, 0xc2, 0xbe, - 0x1c, 0x79, 0x68, 0x05, 0x94, 0xf3, 0xa1, 0xb8, 0x5d, 0x51, 0x84, 0x2a, 0x9e, 0x0f, 0x8f, 0x08, - 0x43, 0x6b, 0x30, 0xc3, 0xdc, 0x81, 0xc0, 0x15, 0x81, 0x2b, 0xcc, 0x1d, 0xdc, 0xdd, 0xb9, 0x0d, - 0x0b, 0xb5, 0x33, 0xda, 0x1b, 0xa4, 0x35, 0xa3, 0x57, 0x50, 0xe0, 0x31, 0xd3, 0x24, 0xa3, 0x50, - 0x9a, 0xdf, 0xdb, 0x79, 0x38, 0x8f, 0x1d, 0xa7, 0x92, 0x9a, 0x7c, 0xf5, 0x63, 0x2b, 0x87, 0xc7, - 0xb2, 0xc4, 0xf4, 0x9b, 0x04, 0x70, 0x37, 0x47, 0x07, 0x20, 0x07, 0xe1, 0x29, 0x15, 0xfd, 0xcd, - 0xef, 0x19, 0xff, 0xf2, 0x1c, 0xb7, 0x9d, 0xf8, 0x09, 0x0d, 0x3a, 0x85, 0xa5, 0x69, 0xa9, 0xd3, - 0xfb, 0x32, 0x2d, 0x2f, 0xe2, 0x55, 0xfe, 0xa3, 0xae, 0x3f, 0x9c, 0x51, 0xef, 0xef, 0x61, 0x12, - 0xfc, 0xd9, 0xe7, 0x3c, 0x3c, 0xbe, 0xa7, 0x44, 0xdb, 0xa0, 0xd7, 0x9b, 0x0d, 0x1b, 0x57, 0xeb, - 0xb6, 0xd3, 0x6c, 0x99, 0xb8, 0x6a, 0x5b, 0xcd, 0x86, 0xd3, 0x69, 0xb4, 0x5b, 0x66, 0xdd, 0x7a, - 0x63, 0x99, 0x87, 0x6a, 0x0e, 0xed, 0x80, 0x91, 0xc1, 0xb1, 0x1a, 0x6d, 0xbb, 0xda, 0xb0, 0x2d, - 0x71, 0x52, 0x25, 0x64, 0xc0, 0x66, 0x06, 0xcb, 0x7c, 0x6f, 0xd6, 0x3b, 0x82, 0x91, 0x47, 0x9b, - 0xa0, 0x65, 0x30, 0xde, 0x75, 0x4c, 0x7c, 0xa2, 0x16, 0x90, 0x0e, 0xeb, 0x19, 0xd3, 0x63, 0xeb, - 0x08, 0x57, 0x6d, 0x53, 0x95, 0xd1, 0x3a, 0xac, 0x66, 0xa5, 0xa8, 0xd5, 0xd5, 0x22, 0xda, 0x80, - 0xb5, 0x8c, 0x59, 0xbb, 0x73, 0xd8, 0x54, 0x95, 0x07, 0xd6, 0x62, 0xb3, 0xf5, 0xf6, 0x44, 0x9d, - 0xa9, 0x1d, 0x5f, 0xdd, 0xe8, 0xd2, 0xf5, 0x8d, 0x2e, 0xfd, 0xbc, 0xd1, 0xa5, 0x4f, 0xb7, 0x7a, - 0xee, 0xfa, 0x56, 0xcf, 0x7d, 0xbf, 0xd5, 0x73, 0x1f, 0xf6, 0xfd, 0x80, 0xf7, 0x3f, 0x76, 0xcb, - 0x3d, 0x3a, 0xac, 0x24, 0xff, 0xc5, 0x8b, 0xd0, 0xe3, 0x17, 0x34, 0x1a, 0xa4, 0xe7, 0x4a, 0x7c, - 0xf7, 0x7e, 0x8c, 0x3f, 0x75, 0xd6, 0x55, 0xc4, 0x2b, 0xb0, 0xff, 0x3b, 0x00, 0x00, 0xff, 0xff, - 0xb2, 0x14, 0x6e, 0x82, 0x60, 0x04, 0x00, 0x00, -} - -func (m *Params) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Params) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.GasTrackingEnabled { - i-- - if m.GasTrackingEnabled { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil + // 566 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0xc1, 0x4e, 0xdb, 0x40, + 0x10, 0xb5, 0x1d, 0xc7, 0x94, 0x41, 0x50, 0x77, 0x29, 0x60, 0x01, 0x32, 0x16, 0x42, 0x6a, 0xda, + 0xaa, 0xb1, 0x80, 0x1b, 0xea, 0x25, 0x31, 0x2e, 0xb2, 0x54, 0x12, 0xba, 0x71, 0xa4, 0xd2, 0x8b, + 0x65, 0x6c, 0xe3, 0x58, 0x01, 0x6f, 0x64, 0x6f, 0xc1, 0xf9, 0x8b, 0x1e, 0x7a, 0xe8, 0xb1, 0x5f, + 0xd1, 0x6f, 0xe0, 0xc8, 0xb1, 0xa7, 0xaa, 0x4a, 0xbe, 0xa0, 0x7f, 0x50, 0x65, 0xe3, 0x24, 0x55, + 0x71, 0x2a, 0xf5, 0x96, 0x79, 0xf3, 0x66, 0xde, 0x9b, 0x17, 0x2f, 0x3c, 0x73, 0x13, 0xaf, 0x73, + 0xeb, 0xf6, 0x75, 0x9a, 0xb8, 0x5e, 0x37, 0x8a, 0x43, 0xfd, 0x66, 0xff, 0x22, 0xa0, 0xee, 0xfe, + 0x14, 0xa8, 0xf6, 0x12, 0x42, 0x09, 0x52, 0x72, 0x62, 0x75, 0x8a, 0xe7, 0xc4, 0xcd, 0xa7, 0x21, + 0x09, 0x09, 0x23, 0xe9, 0xa3, 0x5f, 0x63, 0xfe, 0x6e, 0x0b, 0x24, 0x3b, 0xb3, 0xe2, 0x4b, 0x82, + 0x56, 0x40, 0x88, 0x7c, 0x85, 0xd7, 0xf8, 0x8a, 0x88, 0x85, 0xc8, 0x47, 0xeb, 0x20, 0x75, 0x82, + 0x28, 0xec, 0x50, 0x45, 0xd0, 0xf8, 0x4a, 0x09, 0xe7, 0x15, 0xda, 0x82, 0x45, 0x4a, 0xa8, 0x7b, + 0xe5, 0x84, 0x6e, 0xaa, 0x94, 0x18, 0xfd, 0x11, 0x03, 0x4e, 0xdc, 0xf4, 0x48, 0xfc, 0xf2, 0x75, + 0x87, 0xdb, 0xfd, 0xc5, 0xc3, 0x9a, 0x41, 0xe2, 0x91, 0x05, 0xda, 0xec, 0x05, 0x89, 0x4b, 0x23, + 0x12, 0x17, 0x8a, 0xac, 0x42, 0x99, 0x66, 0x4e, 0xe4, 0x33, 0x0d, 0x11, 0x8b, 0x34, 0xb3, 0x7c, + 0xf4, 0x1c, 0x64, 0x2f, 0x9f, 0x76, 0x5c, 0xdf, 0x4f, 0x82, 0x74, 0x2c, 0xb4, 0x88, 0x1f, 0x4f, + 0xf0, 0xda, 0x18, 0x46, 0x18, 0x56, 0xc8, 0x44, 0xc0, 0xa1, 0xfd, 0x5e, 0xa0, 0x88, 0x1a, 0x5f, + 0x59, 0x39, 0x78, 0x59, 0x9d, 0x97, 0x43, 0xf5, 0x81, 0x31, 0xbc, 0x3c, 0x5d, 0x61, 0xf7, 0x7b, + 0x01, 0x5a, 0x03, 0xe9, 0xe6, 0x9a, 0x5d, 0x57, 0x66, 0xa6, 0xca, 0x37, 0xd7, 0x27, 0x6e, 0x8a, + 0x36, 0x60, 0x21, 0xf5, 0xbb, 0x0c, 0x97, 0x18, 0x2e, 0xa5, 0x7e, 0x77, 0x76, 0x73, 0x0b, 0x96, + 0xeb, 0x57, 0xc4, 0xeb, 0xda, 0xb9, 0x1e, 0x7a, 0x0d, 0x25, 0x9a, 0xa5, 0x0a, 0xaf, 0x95, 0x2a, + 0x4b, 0x07, 0x7b, 0xf3, 0xfd, 0xd8, 0xd9, 0x64, 0xa4, 0x2e, 0xde, 0xfd, 0xd8, 0xe1, 0xf0, 0x68, + 0x2c, 0x5f, 0xfa, 0x8d, 0x07, 0x98, 0xf5, 0xd1, 0x11, 0x88, 0x51, 0x7c, 0x49, 0x58, 0x7e, 0x4b, + 0x07, 0xda, 0xbf, 0x76, 0x8e, 0xd2, 0xce, 0xf7, 0xb1, 0x19, 0x74, 0x09, 0xab, 0xd3, 0x50, 0xa7, + 0xf7, 0xa6, 0x8a, 0xc0, 0xec, 0xe9, 0xff, 0x11, 0xd7, 0x1f, 0x9b, 0x91, 0xf7, 0x77, 0x33, 0x37, + 0xfe, 0xe2, 0xb3, 0x00, 0x4f, 0x1e, 0x4c, 0xa2, 0x5d, 0x50, 0x8d, 0x66, 0xc3, 0xc6, 0x35, 0xc3, + 0x76, 0x9a, 0x67, 0x26, 0xae, 0xd9, 0x56, 0xb3, 0xe1, 0xb4, 0x1b, 0xad, 0x33, 0xd3, 0xb0, 0xde, + 0x58, 0xe6, 0xb1, 0xcc, 0xa1, 0x3d, 0xd0, 0x0a, 0x38, 0x56, 0xa3, 0x65, 0xd7, 0x1a, 0xb6, 0xc5, + 0x2a, 0x99, 0x47, 0x1a, 0x6c, 0x17, 0xb0, 0xcc, 0xf7, 0xa6, 0xd1, 0x66, 0x0c, 0x01, 0x6d, 0x83, + 0x52, 0xc0, 0x78, 0xd7, 0x36, 0xf1, 0xb9, 0x5c, 0x42, 0x2a, 0x6c, 0x16, 0x74, 0x4f, 0xad, 0x13, + 0x5c, 0xb3, 0x4d, 0x59, 0x44, 0x9b, 0xb0, 0x5e, 0xe4, 0xa2, 0x6e, 0xc8, 0x65, 0xb4, 0x05, 0x1b, + 0x05, 0xbd, 0x56, 0xfb, 0xb8, 0x29, 0x4b, 0x73, 0x64, 0xb1, 0x79, 0xf6, 0xf6, 0x5c, 0x5e, 0xa8, + 0x9f, 0xde, 0x0d, 0x54, 0xfe, 0x7e, 0xa0, 0xf2, 0x3f, 0x07, 0x2a, 0xff, 0x69, 0xa8, 0x72, 0xf7, + 0x43, 0x95, 0xfb, 0x3e, 0x54, 0xb9, 0x0f, 0x87, 0x61, 0x44, 0x3b, 0x1f, 0x2f, 0xaa, 0x1e, 0xb9, + 0xd6, 0xf3, 0xff, 0xe2, 0x55, 0x1c, 0xd0, 0x5b, 0x92, 0x74, 0x27, 0xb5, 0x9e, 0xcd, 0x5e, 0xff, + 0xe8, 0x53, 0x4f, 0x2f, 0x24, 0xf6, 0x86, 0x0f, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x15, 0xde, + 0x56, 0xbd, 0x1e, 0x04, 0x00, 0x00, } func (m *TxInfo) Marshal() (dAtA []byte, err error) { @@ -645,18 +564,6 @@ func encodeVarintTracking(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } -func (m *Params) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.GasTrackingEnabled { - n += 2 - } - return n -} - func (m *TxInfo) Size() (n int) { if m == nil { return 0 @@ -741,76 +648,6 @@ func sovTracking(x uint64) (n int) { func sozTracking(x uint64) (n int) { return sovTracking(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *Params) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTracking - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Params: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field GasTrackingEnabled", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTracking - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.GasTrackingEnabled = bool(v != 0) - default: - iNdEx = preIndex - skippy, err := skipTracking(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTracking - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *TxInfo) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From 29d207da3fcdcb68b7ed776ed6d47f65d56126c9 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Fri, 29 Jul 2022 19:26:42 +0300 Subject: [PATCH 06/27] x/rewards: bugfixes; inflation rewards distribution rollback to block gas limit (unlike calculating it from Txs) --- docs/proto/proto-docs.md | 2 +- proto/archway/rewards/v1beta1/rewards.proto | 4 +- x/gastracker/mintbankkeeper/keeper.go | 75 ++++++++++++++++++++ x/rewards/keeper/distribution.go | 31 +++++---- x/rewards/keeper/keeper.go | 2 +- x/rewards/keeper/state_block_rewards.go | 2 +- x/rewards/types/rewards.go | 5 ++ x/rewards/types/rewards.pb.go | 76 ++++++++++----------- 8 files changed, 141 insertions(+), 56 deletions(-) create mode 100644 x/gastracker/mintbankkeeper/keeper.go diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index a7f29610..410ba4a1 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -449,7 +449,7 @@ BlockRewards defines block related rewards distribution data. | ----- | ---- | ----- | ----------- | | `height` | [int64](#int64) | | height defines the block height. | | `inflation_rewards` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | inflation_rewards is the rewards to be distributed. | -| `max_gas` | [int64](#int64) | | max_gas defines the maximum gas that can be used for the block (consensus parameter). | +| `max_gas` | [uint64](#uint64) | | max_gas defines the maximum gas for the block that is used to distribute inflation rewards (consensus parameter). | diff --git a/proto/archway/rewards/v1beta1/rewards.proto b/proto/archway/rewards/v1beta1/rewards.proto index 44488966..f454f016 100644 --- a/proto/archway/rewards/v1beta1/rewards.proto +++ b/proto/archway/rewards/v1beta1/rewards.proto @@ -47,8 +47,8 @@ message BlockRewards { cosmos.base.v1beta1.Coin inflation_rewards = 2 [ (gogoproto.nullable) = false ]; - // max_gas defines the maximum gas that can be used for the block (consensus parameter). - int64 max_gas = 3; + // max_gas defines the maximum gas for the block that is used to distribute inflation rewards (consensus parameter). + uint64 max_gas = 3; } // TxRewards defines transaction related rewards distribution data. diff --git a/x/gastracker/mintbankkeeper/keeper.go b/x/gastracker/mintbankkeeper/keeper.go new file mode 100644 index 00000000..665028a1 --- /dev/null +++ b/x/gastracker/mintbankkeeper/keeper.go @@ -0,0 +1,75 @@ +package mintbankkeeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + + "github.com/archway-network/archway/x/gastracker" + "github.com/archway-network/archway/x/gastracker/common" +) + +var ( + _ minttypes.BankKeeper = (*Keeper)(nil) +) + +type GasTrackingKeeper interface { + GetParams(ctx sdk.Context) gastracker.Params + UpdateDappInflationaryRewards(ctx sdk.Context, rewards sdk.Coin) +} + +func NewKeeper(bk minttypes.BankKeeper, gtk GasTrackingKeeper) Keeper { + return Keeper{ + bk: bk, + gtk: gtk, + } +} + +// Keeper mocks the behaviour of the bank keeper required +// by the mint module and splits inflationary rewards +// between the gas tracking module and auth's fee collector +type Keeper struct { + bk minttypes.BankKeeper + gtk GasTrackingKeeper +} + +// SendCoinsFromModuleToModule overrides the behaviour of mint's BankKeeper and redirects part of inflationary +// rewards towards the gastracker module. +func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error { + // we only care about this if the recipient is fee collector + // (which for instance is always the case) + if recipientModule != authtypes.FeeCollectorName { + return k.bk.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, amt) + } + + ratio := k.gtk.GetParams(ctx).DappInflationRewardsRatio + stakingRewards, dappRewards := common.SplitCoins(ratio, amt) + + // send to auth's fee collector + err := k.bk.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, stakingRewards) + if err != nil { + return err + } + // send to gastracker + err = k.bk.SendCoinsFromModuleToModule(ctx, senderModule, gastracker.ContractRewardCollector, dappRewards) + if err != nil { + return err + } + + if len(dappRewards) != 1 { + panic(fmt.Errorf("unexpected dapp rewards: %s", dappRewards)) + } + k.gtk.UpdateDappInflationaryRewards(ctx, dappRewards[0]) // note the minted coin is only and always one + + return nil +} + +func (k Keeper) SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error { + return k.bk.SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt) +} + +func (k Keeper) MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error { + return k.bk.MintCoins(ctx, name, amt) +} diff --git a/x/rewards/keeper/distribution.go b/x/rewards/keeper/distribution.go index a047f919..2f73d183 100644 --- a/x/rewards/keeper/distribution.go +++ b/x/rewards/keeper/distribution.go @@ -13,9 +13,8 @@ import ( type ( // blockRewardsDistributionState is used to gather gas usage and rewards for a block. blockRewardsDistributionState struct { - Height int64 // block height - GasUsed sdk.Dec // total gas used by the block - Txs []*txRewardsDistributionState + Height int64 // block height + Txs []*txRewardsDistributionState } // txRewardsDistributionState is used to gather gas usage and rewards for a transaction. @@ -49,8 +48,7 @@ func (k Keeper) estimateBlockGasUsage(ctx sdk.Context, height int64) *blockRewar // Create a new block rewards distribution state and fill it up blockDistrState := &blockRewardsDistributionState{ - Height: height, - GasUsed: sdk.ZeroDec(), + Height: height, } // Get all tracked transactions by the x/tracking module @@ -77,8 +75,9 @@ func (k Keeper) estimateBlockGasUsage(ctx sdk.Context, height int64) *blockRewar contractDistrState := contractDistrStatesSet[contractOp.ContractAddress] if contractDistrState == nil { contractDistrState = &contractRewardsDistributionState{ - ContractAddress: contractOp.MustGetContractAddress(), - GasUsed: sdk.ZeroDec(), + ContractAddress: contractOp.MustGetContractAddress(), + GasUsed: sdk.ZeroDec(), + InflationaryRewards: sdk.Coin{Amount: sdk.ZeroInt()}, // necessary to avoid nil pointer panic on Coins.Add call } if metadata, found := metadataState.GetContractMetadata(contractDistrState.ContractAddress); found { contractDistrState.Metadata = &metadata @@ -103,8 +102,7 @@ func (k Keeper) estimateBlockGasUsage(ctx sdk.Context, height int64) *blockRewar return txDistState.Contracts[i].ContractAddress.String() < txDistState.Contracts[j].ContractAddress.String() }) - // Append tx distr state updating the block gas used - blockDistrState.GasUsed = blockDistrState.GasUsed.Add(txDistState.GasUsed) + // Append tx distr state to the block state blockDistrState.Txs = append(blockDistrState.Txs, txDistState) } @@ -117,7 +115,14 @@ func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewa txRewardsState := k.state.TxRewardsState(ctx) // Get tracked block rewards by the x/rewards module (might not be found in case this reward is disabled) + var blockGasLimit sdk.Dec blockRewards, blockRewardsFound := k.state.BlockRewardsState(ctx).GetBlockRewards(blockDistrState.Height) + if blockRewardsFound { + blockGasLimit = pkg.NewDecFromUint64(blockRewards.MaxGas) + if !blockRewards.HasRewards() || !blockRewards.HasGasLimit() { + k.Logger(ctx).Debug("No block rewards found (coins are empty or gas limit is not set)", "height", blockDistrState.Height) + } + } // Estimate reward shares for each contract operation for _, txDistrState := range blockDistrState.Txs { @@ -139,9 +144,9 @@ func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewa contractDistrState.FeeRewards = rewardCoins } - // Estimate contract inflation rewards - if blockRewardsFound && blockRewards.HasRewards() { - rewardsShare := contractDistrState.GasUsed.Quo(blockDistrState.GasUsed) + // Estimate contract inflation rewards (only if block has rewards and gas limit is set) + if blockRewardsFound && blockRewards.HasRewards() && blockRewards.HasGasLimit() { + rewardsShare := contractDistrState.GasUsed.Quo(blockGasLimit) contractDistrState.InflationaryRewards = sdk.NewCoin( blockRewards.InflationRewards.Denom, @@ -183,7 +188,7 @@ func (k Keeper) distributeBlockRewards(ctx sdk.Context, blockDistrState *blockRe rewardsAddr := contractDistrState.Metadata.MustGetRewardsAddress() // Distribute - rewards := sdk.NewCoins(contractDistrState.FeeRewards...).Add(contractDistrState.InflationaryRewards) + rewards := sdk.NewCoins().Add(contractDistrState.FeeRewards...).Add(contractDistrState.InflationaryRewards) if rewards.IsZero() { k.Logger(ctx).Debug("Contract rewards distribution skipped (no rewards)", "contractAddress", contractDistrState.ContractAddress) continue diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index aff8b7b7..e5c71278 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -144,7 +144,7 @@ func (k Keeper) TrackInflationRewards(ctx sdk.Context, rewards sdk.Coin) { k.state.BlockRewardsState(ctx).CreateBlockRewards( ctx.BlockHeight(), rewards, - ctx.ConsensusParams().Block.MaxGas, + ctx.BlockGasMeter().Limit(), ) } diff --git a/x/rewards/keeper/state_block_rewards.go b/x/rewards/keeper/state_block_rewards.go index 906a2cb7..98dac5d7 100644 --- a/x/rewards/keeper/state_block_rewards.go +++ b/x/rewards/keeper/state_block_rewards.go @@ -17,7 +17,7 @@ type BlockRewardsState struct { } // CreateBlockRewards creates a types.BlockRewards object. -func (s BlockRewardsState) CreateBlockRewards(height int64, rewards sdk.Coin, blockMaxGas int64) types.BlockRewards { +func (s BlockRewardsState) CreateBlockRewards(height int64, rewards sdk.Coin, blockMaxGas uint64) types.BlockRewards { obj := types.BlockRewards{ Height: height, InflationRewards: rewards, diff --git a/x/rewards/types/rewards.go b/x/rewards/types/rewards.go index b4427b13..0bc8292c 100644 --- a/x/rewards/types/rewards.go +++ b/x/rewards/types/rewards.go @@ -12,6 +12,11 @@ func (m BlockRewards) HasRewards() bool { return !m.InflationRewards.IsZero() } +// HasGasLimit returns true if the gas limit has been set. +func (m BlockRewards) HasGasLimit() bool { + return m.MaxGas > 0 +} + // Validate performs object fields validation. func (m BlockRewards) Validate() error { if m.Height < 0 { diff --git a/x/rewards/types/rewards.pb.go b/x/rewards/types/rewards.pb.go index af92cdd1..6ef22f44 100644 --- a/x/rewards/types/rewards.pb.go +++ b/x/rewards/types/rewards.pb.go @@ -130,8 +130,8 @@ type BlockRewards struct { Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` // inflation_rewards is the rewards to be distributed. InflationRewards types.Coin `protobuf:"bytes,2,opt,name=inflation_rewards,json=inflationRewards,proto3" json:"inflation_rewards"` - // max_gas defines the maximum gas that can be used for the block (consensus parameter). - MaxGas int64 `protobuf:"varint,3,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"` + // max_gas defines the maximum gas for the block that is used to distribute inflation rewards (consensus parameter). + MaxGas uint64 `protobuf:"varint,3,opt,name=max_gas,json=maxGas,proto3" json:"max_gas,omitempty"` } func (m *BlockRewards) Reset() { *m = BlockRewards{} } @@ -180,7 +180,7 @@ func (m *BlockRewards) GetInflationRewards() types.Coin { return types.Coin{} } -func (m *BlockRewards) GetMaxGas() int64 { +func (m *BlockRewards) GetMaxGas() uint64 { if m != nil { return m.MaxGas } @@ -317,40 +317,40 @@ func init() { } var fileDescriptor_50f478faffe74434 = []byte{ - // 518 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x6f, 0xd3, 0x30, - 0x14, 0xc7, 0xe3, 0xb5, 0x14, 0xd5, 0xdb, 0xa0, 0x64, 0x40, 0xc7, 0x0e, 0xe9, 0x54, 0x34, 0xe0, - 0x32, 0x47, 0x1b, 0x37, 0x4e, 0xd0, 0x21, 0x26, 0xa4, 0x21, 0xa1, 0x68, 0x07, 0x84, 0x84, 0xa2, - 0x97, 0xc4, 0x49, 0xa3, 0x2e, 0xf1, 0x64, 0x1b, 0xea, 0xdd, 0xf8, 0x08, 0x48, 0x5c, 0x38, 0xf2, - 0x31, 0xf8, 0x08, 0x3b, 0xee, 0x82, 0x84, 0x38, 0x4c, 0xa8, 0xfd, 0x22, 0x28, 0xb6, 0x53, 0xb5, - 0x40, 0x25, 0xb4, 0x53, 0xf2, 0x5e, 0x5e, 0x7e, 0xef, 0xff, 0xfe, 0xcf, 0xc6, 0x3b, 0xc0, 0xe3, - 0xe1, 0x18, 0xce, 0x7c, 0x4e, 0xc7, 0xc0, 0x13, 0xe1, 0x7f, 0xd8, 0x8b, 0xa8, 0x84, 0xbd, 0x3a, - 0x26, 0xa7, 0x9c, 0x49, 0xe6, 0x76, 0x6d, 0x19, 0xa9, 0xd3, 0xb6, 0x6c, 0xeb, 0x76, 0xc6, 0x32, - 0xa6, 0x6b, 0xfc, 0xea, 0xcd, 0x94, 0x6f, 0x79, 0x31, 0x13, 0x05, 0x13, 0x7e, 0x04, 0x82, 0xce, - 0x88, 0x31, 0xcb, 0x4b, 0xf3, 0xbd, 0xff, 0x1d, 0xe1, 0xd6, 0x6b, 0xe0, 0x50, 0x08, 0x37, 0xc5, - 0xdd, 0xbc, 0x4c, 0x4f, 0x40, 0xe6, 0xac, 0x0c, 0x2d, 0x3d, 0xe4, 0x55, 0xb8, 0x89, 0xb6, 0xd1, - 0xa3, 0xf6, 0x80, 0x9c, 0x5f, 0xf6, 0x9c, 0x9f, 0x97, 0xbd, 0x07, 0x59, 0x2e, 0x87, 0xef, 0x23, - 0x12, 0xb3, 0xc2, 0xb7, 0x78, 0xf3, 0xd8, 0x15, 0xc9, 0xc8, 0x97, 0x67, 0xa7, 0x54, 0x90, 0xe7, - 0x34, 0x0e, 0xee, 0xcc, 0x70, 0x81, 0xa1, 0x05, 0x55, 0xe0, 0xbe, 0xc3, 0x1b, 0x52, 0x85, 0x29, - 0xa5, 0x21, 0xa7, 0x11, 0x48, 0x6a, 0x7b, 0xac, 0x5c, 0xa9, 0x47, 0x47, 0xaa, 0x17, 0x94, 0x06, - 0x1a, 0xa4, 0xf1, 0x4f, 0x9a, 0x5f, 0xbe, 0xf6, 0x9c, 0x7e, 0x8a, 0x3b, 0x07, 0xac, 0x94, 0x1c, - 0x62, 0xf9, 0x8a, 0x4a, 0x48, 0x40, 0x82, 0x7b, 0x1f, 0xaf, 0xb3, 0x71, 0x49, 0x79, 0x08, 0x49, - 0xc2, 0xa9, 0x10, 0x66, 0xac, 0x60, 0x4d, 0x27, 0x9f, 0x99, 0x9c, 0xfb, 0x10, 0xdf, 0xac, 0x67, - 0xaf, 0xcb, 0xb4, 0xb2, 0xe0, 0x86, 0x4d, 0xdb, 0x42, 0xdb, 0xe7, 0x33, 0xc2, 0x6b, 0x83, 0x13, - 0x16, 0x8f, 0xec, 0x88, 0xee, 0x5d, 0xdc, 0x1a, 0xd2, 0x3c, 0x1b, 0x4a, 0x4d, 0x6f, 0x04, 0x36, - 0x72, 0x8f, 0xf0, 0xad, 0xbf, 0xdc, 0xd5, 0xe4, 0xd5, 0xfd, 0x7b, 0xc4, 0x8c, 0x46, 0xaa, 0x25, - 0xd5, 0xfb, 0x24, 0x07, 0x2c, 0x2f, 0x07, 0xcd, 0xca, 0x8e, 0xa0, 0xf3, 0xa7, 0x91, 0x6e, 0x17, - 0x5f, 0x2f, 0x40, 0x85, 0x19, 0x88, 0xcd, 0x86, 0x69, 0x53, 0x80, 0x3a, 0x84, 0x5a, 0xd5, 0x47, - 0x84, 0xdb, 0xc7, 0xaa, 0x2e, 0xde, 0xc0, 0xd7, 0xa4, 0x0a, 0xf3, 0x44, 0x2b, 0x6a, 0x06, 0x4d, - 0xa9, 0x5e, 0x26, 0x73, 0x3a, 0x57, 0x16, 0x74, 0x3e, 0xc5, 0xab, 0x66, 0x35, 0x46, 0x61, 0x63, - 0xbb, 0xf1, 0x3f, 0x0a, 0x71, 0x5a, 0x2d, 0x41, 0xff, 0x62, 0x25, 0x7c, 0x43, 0x78, 0x5d, 0x1b, - 0x73, 0xcc, 0x21, 0x1e, 0xe5, 0x65, 0xe6, 0xbe, 0xf9, 0x97, 0x03, 0x48, 0x3b, 0xb0, 0x43, 0x96, - 0x9c, 0x6a, 0x32, 0xef, 0xed, 0x52, 0x37, 0x0e, 0x31, 0x96, 0x6a, 0xce, 0xd4, 0x4a, 0x72, 0x7f, - 0x29, 0x72, 0x66, 0x8c, 0xe5, 0xb5, 0xa5, 0x5a, 0x90, 0x3e, 0x38, 0x3a, 0x9f, 0x78, 0xe8, 0x62, - 0xe2, 0xa1, 0x5f, 0x13, 0x0f, 0x7d, 0x9a, 0x7a, 0xce, 0xc5, 0xd4, 0x73, 0x7e, 0x4c, 0x3d, 0xe7, - 0xed, 0xfe, 0xdc, 0xa9, 0xb4, 0xf8, 0xdd, 0x92, 0xca, 0x31, 0xe3, 0xa3, 0x3a, 0xf6, 0xd5, 0xec, - 0x02, 0xeb, 0x53, 0x1a, 0xb5, 0xf4, 0x45, 0x7b, 0xfc, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xa9, 0xe6, - 0xe9, 0x18, 0xe0, 0x03, 0x00, 0x00, + // 522 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x6b, 0x13, 0x41, + 0x14, 0xc7, 0x33, 0xcd, 0x1a, 0xc9, 0xb4, 0xd5, 0xb8, 0x55, 0x53, 0x7b, 0xd8, 0x84, 0x48, 0xb5, + 0x97, 0xce, 0xd2, 0x7a, 0xf3, 0xa4, 0xa9, 0x58, 0x84, 0x0a, 0x32, 0xf4, 0x20, 0x82, 0x2c, 0x6f, + 0x77, 0x67, 0x37, 0x4b, 0xba, 0x3b, 0x65, 0x66, 0x34, 0xd3, 0x9b, 0x1f, 0x41, 0xf0, 0xe2, 0xd1, + 0x8f, 0xe1, 0x47, 0xe8, 0xb1, 0x17, 0x41, 0x3c, 0x14, 0x49, 0xbe, 0x88, 0xec, 0xec, 0x6c, 0x48, + 0xd5, 0x80, 0x78, 0x4a, 0xde, 0xcb, 0x3f, 0xbf, 0xf9, 0xbf, 0xff, 0x9b, 0xc1, 0xdb, 0x20, 0xa2, + 0xd1, 0x04, 0xce, 0x7c, 0xc1, 0x26, 0x20, 0x62, 0xe9, 0xbf, 0xdf, 0x0b, 0x99, 0x82, 0xbd, 0xba, + 0x26, 0xa7, 0x82, 0x2b, 0xee, 0x76, 0xad, 0x8c, 0xd4, 0x6d, 0x2b, 0xdb, 0xba, 0x9d, 0xf2, 0x94, + 0x1b, 0x8d, 0x5f, 0x7e, 0xab, 0xe4, 0x5b, 0x5e, 0xc4, 0x65, 0xce, 0xa5, 0x1f, 0x82, 0x64, 0x73, + 0x62, 0xc4, 0xb3, 0xa2, 0xfa, 0x7d, 0xf0, 0x0d, 0xe1, 0xd6, 0x2b, 0x10, 0x90, 0x4b, 0x37, 0xc1, + 0xdd, 0xac, 0x48, 0x4e, 0x40, 0x65, 0xbc, 0x08, 0x2c, 0x3d, 0x10, 0x65, 0xb9, 0x89, 0xfa, 0x68, + 0xa7, 0x3d, 0x24, 0xe7, 0x97, 0xbd, 0xc6, 0x8f, 0xcb, 0xde, 0x83, 0x34, 0x53, 0xa3, 0x77, 0x21, + 0x89, 0x78, 0xee, 0x5b, 0x7c, 0xf5, 0xb1, 0x2b, 0xe3, 0xb1, 0xaf, 0xce, 0x4e, 0x99, 0x24, 0xcf, + 0x58, 0x44, 0xef, 0xcc, 0x71, 0xb4, 0xa2, 0xd1, 0xb2, 0x70, 0xdf, 0xe2, 0x0d, 0xa5, 0x83, 0x84, + 0xb1, 0x40, 0xb0, 0x10, 0x14, 0xb3, 0x67, 0xac, 0xfc, 0xd7, 0x19, 0x1d, 0xa5, 0x9f, 0x33, 0x46, + 0x0d, 0xc8, 0xe0, 0x1f, 0x3b, 0x9f, 0xbf, 0xf4, 0x1a, 0x83, 0x04, 0x77, 0x0e, 0x78, 0xa1, 0x04, + 0x44, 0xea, 0x25, 0x53, 0x10, 0x83, 0x02, 0xf7, 0x3e, 0x5e, 0xe7, 0x93, 0x82, 0x89, 0x00, 0xe2, + 0x58, 0x30, 0x29, 0xab, 0xb1, 0xe8, 0x9a, 0x69, 0x3e, 0xad, 0x7a, 0xee, 0x43, 0x7c, 0xb3, 0x9e, + 0xbd, 0x96, 0x19, 0x67, 0xf4, 0x86, 0x6d, 0x5b, 0xa1, 0x3d, 0xe7, 0x13, 0xc2, 0x6b, 0xc3, 0x13, + 0x1e, 0x8d, 0xed, 0x88, 0xee, 0x5d, 0xdc, 0x1a, 0xb1, 0x2c, 0x1d, 0x29, 0x43, 0x6f, 0x52, 0x5b, + 0xb9, 0x47, 0xf8, 0xd6, 0x1f, 0xe9, 0x1a, 0xf2, 0xea, 0xfe, 0x3d, 0x52, 0x8d, 0x46, 0xca, 0x25, + 0xd5, 0xfb, 0x24, 0x07, 0x3c, 0x2b, 0x86, 0x4e, 0x19, 0x07, 0xed, 0xfc, 0x1e, 0xa4, 0xdb, 0xc5, + 0xd7, 0x73, 0xd0, 0x41, 0x0a, 0x72, 0xb3, 0xd9, 0x47, 0x3b, 0x0e, 0x6d, 0xe5, 0xa0, 0x0f, 0xa1, + 0x76, 0xf5, 0x01, 0xe1, 0xf6, 0xb1, 0xae, 0xc5, 0x1b, 0xf8, 0x9a, 0xd2, 0x41, 0x16, 0x1b, 0x47, + 0x0e, 0x75, 0x94, 0x7e, 0x11, 0x2f, 0xf8, 0x5c, 0xb9, 0xe2, 0xf3, 0x09, 0x5e, 0xad, 0x56, 0x53, + 0x39, 0x6c, 0xf6, 0x9b, 0xff, 0xe2, 0x10, 0x27, 0xe5, 0x12, 0xcc, 0x5f, 0xac, 0x85, 0xaf, 0x08, + 0xaf, 0x9b, 0x60, 0x8e, 0x05, 0x44, 0xe3, 0xac, 0x48, 0xdd, 0xd7, 0x7f, 0x4b, 0x00, 0x99, 0x04, + 0xb6, 0xc9, 0x92, 0x5b, 0x4d, 0x16, 0xb3, 0x5d, 0x9a, 0xc6, 0x21, 0xc6, 0x4a, 0x2f, 0x84, 0x5a, + 0x5a, 0x1e, 0x2c, 0x45, 0xce, 0x83, 0xb1, 0xbc, 0xb6, 0xd2, 0x57, 0xac, 0x0f, 0x8f, 0xce, 0xa7, + 0x1e, 0xba, 0x98, 0x7a, 0xe8, 0xe7, 0xd4, 0x43, 0x1f, 0x67, 0x5e, 0xe3, 0x62, 0xe6, 0x35, 0xbe, + 0xcf, 0xbc, 0xc6, 0x9b, 0xfd, 0x85, 0x5b, 0x69, 0xf1, 0xbb, 0x05, 0x53, 0x13, 0x2e, 0xc6, 0x75, + 0xed, 0xeb, 0xf9, 0x03, 0x36, 0xb7, 0x34, 0x6c, 0x99, 0x87, 0xf6, 0xe8, 0x57, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x13, 0x0b, 0x1c, 0xb3, 0xe0, 0x03, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -999,7 +999,7 @@ func (m *BlockRewards) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.MaxGas |= int64(b&0x7F) << shift + m.MaxGas |= uint64(b&0x7F) << shift if b < 0x80 { break } From 7ff10c426bd29c0166f51f68ea6d9c4872f542e2 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Sat, 30 Jul 2022 23:51:58 +0300 Subject: [PATCH 07/27] x/rewards: distribution refactoring; distribution test added e2e: chain options added --- e2e/testing/chain.go | 81 +++- e2e/testing/chain_options.go | 57 +++ e2e/testing/common.go | 31 ++ x/rewards/keeper/common_test.go | 57 +++ x/rewards/keeper/distribution.go | 258 ++++++------ x/rewards/keeper/distribution_test.go | 511 ++++++++++++++++++++++++ x/rewards/keeper/keeper.go | 6 + x/rewards/keeper/state_block_rewards.go | 6 + 8 files changed, 863 insertions(+), 144 deletions(-) create mode 100644 e2e/testing/chain_options.go create mode 100644 x/rewards/keeper/common_test.go create mode 100644 x/rewards/keeper/distribution_test.go diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 36e53c3b..72e6fc06 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -49,15 +49,39 @@ type TestChain struct { } // NewTestChain creates a new TestChain with the default amount of genesis accounts and validators. -func NewTestChain(t *testing.T, chainIdx int) *TestChain { +func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain { const ( - validatorsN = 1 - genAccsN = 5 - genBalanceAmount = "1000000000" - bondAmount = "1000000" - chainIDPrefix = "test-" + chainIDPrefix = "test-" ) + // Split options by groups (each group is applied in a different init step) + var chainCfgOpts []TestChainConfigOption + var consensusParamsOpts []TestChainConsensusParamsOption + var genStateOpts []TestChainGenesisOption + for i, opt := range opts { + switch opt.(type) { + case TestChainConfigOption: + chainCfgOpts = append(chainCfgOpts, opt.(TestChainConfigOption)) + case TestChainConsensusParamsOption: + consensusParamsOpts = append(consensusParamsOpts, opt.(TestChainConsensusParamsOption)) + case TestChainGenesisOption: + genStateOpts = append(genStateOpts, opt.(TestChainGenesisOption)) + default: + require.Fail(t, "Unknown chain option type", "optionIdx", i) + } + } + + // Define chain config + chainCfg := chainConfig{ + ValidatorsNum: 1, + GenAccountsNum: 5, + GenBalanceAmount: "1000000000", + BondAmount: "1000000", + } + for _, opt := range chainCfgOpts { + opt(&chainCfg) + } + // Create an app and a default genesis state encCfg := app.MakeEncodingConfig() @@ -80,9 +104,9 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { genState := app.NewDefaultGenesisState() // Generate validators - validators := make([]*tmTypes.Validator, 0, validatorsN) - valSigners := make([]tmTypes.PrivValidator, 0, validatorsN) - for i := 0; i < validatorsN; i++ { + validators := make([]*tmTypes.Validator, 0, chainCfg.ValidatorsNum) + valSigners := make([]tmTypes.PrivValidator, 0, chainCfg.ValidatorsNum) + for i := 0; i < chainCfg.ValidatorsNum; i++ { valPrivKey := mock.NewPV() valPubKey, err := valPrivKey.GetPubKey() require.NoError(t, err) @@ -93,9 +117,9 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { validatorSet := tmTypes.NewValidatorSet(validators) // Generate genesis accounts, gen and bond coins - genAccs := make([]authTypes.GenesisAccount, 0, genAccsN) - genAccPrivKeys := make([]cryptoTypes.PrivKey, 0, genAccsN) - for i := 0; i < genAccsN; i++ { + genAccs := make([]authTypes.GenesisAccount, 0, chainCfg.GenAccountsNum) + genAccPrivKeys := make([]cryptoTypes.PrivKey, 0, chainCfg.GenAccountsNum) + for i := 0; i < chainCfg.GenAccountsNum; i++ { accPrivKey := secp256k1.GenPrivKey() acc := authTypes.NewBaseAccount(accPrivKey.PubKey().Address().Bytes(), accPrivKey.PubKey(), uint64(i), 0) @@ -103,11 +127,11 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { genAccPrivKeys = append(genAccPrivKeys, accPrivKey) } - genAmt, ok := sdk.NewIntFromString(genBalanceAmount) + genAmt, ok := sdk.NewIntFromString(chainCfg.GenBalanceAmount) require.True(t, ok) genCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, genAmt)) - bondAmt, ok := sdk.NewIntFromString(bondAmount) + bondAmt, ok := sdk.NewIntFromString(chainCfg.BondAmount) require.True(t, ok) bondCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)) @@ -149,15 +173,15 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { // Update x/bank genesis with total supply, gen account balances and bonding pool balance totalSupply := sdk.NewCoins() bondedPoolCoins := sdk.NewCoins() - balances := make([]bankTypes.Balance, 0, genAccsN) - for i := 0; i < genAccsN; i++ { + balances := make([]bankTypes.Balance, 0, chainCfg.GenAccountsNum) + for i := 0; i < chainCfg.GenAccountsNum; i++ { balances = append(balances, bankTypes.Balance{ Address: genAccs[i].GetAddress().String(), Coins: genCoins, }) totalSupply = totalSupply.Add(genCoins...) } - for i := 0; i < validatorsN; i++ { + for i := 0; i < chainCfg.ValidatorsNum; i++ { bondedPoolCoins = bondedPoolCoins.Add(bondCoins...) totalSupply = totalSupply.Add(bondCoins...) } @@ -169,6 +193,17 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { bankGenesis := bankTypes.NewGenesisState(bankTypes.DefaultGenesisState().Params, balances, totalSupply, []bankTypes.Metadata{}) genState[bankTypes.ModuleName] = archApp.AppCodec().MustMarshalJSON(bankGenesis) + // Apply genesis options + for _, opt := range genStateOpts { + opt(archApp.AppCodec(), genState) + } + + // Apply consensus params options + consensusParams := app.DefaultConsensusParams + for _, opt := range consensusParamsOpts { + opt(consensusParams) + } + // Init chain genStateBytes, err := json.MarshalIndent(genState, "", " ") require.NoError(t, err) @@ -176,7 +211,7 @@ func NewTestChain(t *testing.T, chainIdx int) *TestChain { archApp.InitChain( abci.RequestInitChain{ Validators: []abci.ValidatorUpdate{}, - ConsensusParams: app.DefaultConsensusParams, + ConsensusParams: consensusParams, AppStateBytes: genStateBytes, }, ) @@ -222,7 +257,15 @@ func (chain *TestChain) GetBalance(accAddr sdk.AccAddress) sdk.Coins { // GetContext returns a context for the current block. func (chain *TestChain) GetContext() sdk.Context { - return chain.app.BaseApp.NewContext(false, chain.curHeader) + ctx := chain.app.BaseApp.NewContext(false, chain.curHeader) + + blockGasMeter := sdk.NewInfiniteGasMeter() + blockMaxGas := chain.app.GetConsensusParams(ctx).Block.MaxGas + if blockMaxGas >= 0 { + blockGasMeter = sdk.NewGasMeter(sdk.Gas(blockMaxGas)) + } + + return ctx.WithBlockGasMeter(blockGasMeter) } // GetAppCodec returns the application codec. diff --git a/e2e/testing/chain_options.go b/e2e/testing/chain_options.go new file mode 100644 index 00000000..44cc6a04 --- /dev/null +++ b/e2e/testing/chain_options.go @@ -0,0 +1,57 @@ +package e2eTesting + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/archway-network/archway/app" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +// chainConfig is a TestChain config which can be adjusted using options. +type chainConfig struct { + ValidatorsNum int + GenAccountsNum int + GenBalanceAmount string + BondAmount string +} + +type ( + TestChainConfigOption func(cfg *chainConfig) + + TestChainGenesisOption func(cdc codec.Codec, genesis app.GenesisState) + + TestChainConsensusParamsOption func(params *abci.ConsensusParams) +) + +// WithBlockGasLimit sets the block gas limit (not set by default). +func WithBlockGasLimit(gasLimit int64) TestChainConsensusParamsOption { + return func(params *abci.ConsensusParams) { + params.Block.MaxGas = gasLimit + } +} + +// WithInflationRewardsRatio sets x/rewards inflation rewards ratio parameter. +func WithInflationRewardsRatio(ratio sdk.Dec) TestChainGenesisOption { + return func(cdc codec.Codec, genesis app.GenesisState) { + var rewardsGenesis rewardsTypes.GenesisState + cdc.MustUnmarshalJSON(genesis[rewardsTypes.ModuleName], &rewardsGenesis) + + rewardsGenesis.Params.InflationRewardsRatio = ratio + + genesis[rewardsTypes.ModuleName] = cdc.MustMarshalJSON(&rewardsGenesis) + } +} + +// WithTxFeeRebatesRewardsRatio sets x/rewards tx fee rebates rewards ratio parameter. +func WithTxFeeRebatesRewardsRatio(ratio sdk.Dec) TestChainGenesisOption { + return func(cdc codec.Codec, genesis app.GenesisState) { + var rewardsGenesis rewardsTypes.GenesisState + cdc.MustUnmarshalJSON(genesis[rewardsTypes.ModuleName], &rewardsGenesis) + + rewardsGenesis.Params.TxFeeRebateRatio = ratio + + genesis[rewardsTypes.ModuleName] = cdc.MustMarshalJSON(&rewardsGenesis) + } +} diff --git a/e2e/testing/common.go b/e2e/testing/common.go index d5960fe3..d82fd998 100644 --- a/e2e/testing/common.go +++ b/e2e/testing/common.go @@ -1,6 +1,10 @@ package e2eTesting import ( + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/tendermint/abci/types" ) @@ -22,3 +26,30 @@ func GetStringEventAttribute(events []abci.Event, eventType, attrKey string) str return "" } + +// GenAccounts generates a list of accounts and private keys for them. +func GenAccounts(num uint) ([]sdk.AccAddress, []cryptotypes.PrivKey) { + addrs := make([]sdk.AccAddress, 0, num) + privKeys := make([]cryptotypes.PrivKey, 0, num) + + for i := 0; i < cap(addrs); i++ { + privKey := secp256k1.GenPrivKey() + + addrs = append(addrs, sdk.AccAddress(privKey.PubKey().Address())) + privKeys = append(privKeys, privKey) + } + + return addrs, privKeys +} + +// GenContractAddresses generates a list of contract addresses (codeID and instanceID are sequential). +func GenContractAddresses(num uint) []sdk.AccAddress { + addrs := make([]sdk.AccAddress, 0, num) + + for i := 0; i < cap(addrs); i++ { + contractAddr := wasmKeeper.BuildContractAddress(uint64(i), uint64(i)) + addrs = append(addrs, contractAddr) + } + + return addrs +} diff --git a/x/rewards/keeper/common_test.go b/x/rewards/keeper/common_test.go new file mode 100644 index 00000000..ff417ef0 --- /dev/null +++ b/x/rewards/keeper/common_test.go @@ -0,0 +1,57 @@ +package keeper_test + +import ( + "math/rand" + + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var allContractOperationTypes = []uint64{ + wasmdTypes.ContractOperationInstantiate, + wasmdTypes.ContractOperationExecute, + wasmdTypes.ContractOperationQuery, + wasmdTypes.ContractOperationMigrate, + wasmdTypes.ContractOperationSudo, + wasmdTypes.ContractOperationReply, + wasmdTypes.ContractOperationIbcChannelOpen, + wasmdTypes.ContractOperationIbcChannelConnect, + wasmdTypes.ContractOperationIbcChannelClose, + wasmdTypes.ContractOperationIbcPacketReceive, + wasmdTypes.ContractOperationIbcPacketAck, + wasmdTypes.ContractOperationIbcPacketTimeout, + wasmdTypes.ContractOperationUnknown, +} + +// mockContractViewer mocks x/wasmd module dependency. +type mockContractViewer struct { + contractAdminSet map[string]string // key: contractAddr, value: adminAddr +} + +func newMockContractViewer() *mockContractViewer { + return &mockContractViewer{ + contractAdminSet: make(map[string]string), + } +} + +// AddContractAdmin adds a contract admin link. +func (v *mockContractViewer) AddContractAdmin(contractAddr, adminAddr string) { + v.contractAdminSet[contractAddr] = adminAddr +} + +func (v mockContractViewer) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmdTypes.ContractInfo { + adminAddr, found := v.contractAdminSet[contractAddress.String()] + if !found { + return nil + } + + return &wasmdTypes.ContractInfo{ + Admin: adminAddr, + } +} + +// GetRandomContractOperationType returns a random wasmd contract operation type. +func GetRandomContractOperationType() uint64 { + idx := rand.Intn(len(allContractOperationTypes)) + return allContractOperationTypes[idx] +} diff --git a/x/rewards/keeper/distribution.go b/x/rewards/keeper/distribution.go index 2f73d183..2159b497 100644 --- a/x/rewards/keeper/distribution.go +++ b/x/rewards/keeper/distribution.go @@ -11,26 +11,23 @@ import ( ) type ( - // blockRewardsDistributionState is used to gather gas usage and rewards for a block. + // blockRewardsDistributionState is used to gather gas usage and rewards for a block on a contract basis. blockRewardsDistributionState struct { - Height int64 // block height - Txs []*txRewardsDistributionState + Height int64 // block height + Txs map[uint64]uint64 // gas usage per transaction [key: txID, value: total gas] + Contracts map[string]*contractRewardsDistributionState // contract rewards state [key: contract address] } - // txRewardsDistributionState is used to gather gas usage and rewards for a transaction. - txRewardsDistributionState struct { - TxID uint64 // transaction ID (x/tracking unique ID) - GasUsed sdk.Dec // total gas used by the transaction - Contracts []*contractRewardsDistributionState - } - - // contractRewardsDistributionState is used to gather gas usage and rewards for a contract (merge contract operations data). + // contractRewardsDistributionState is used to gather gas usage and rewards for a contract. contractRewardsDistributionState struct { - ContractAddress sdk.AccAddress // contract address - GasUsed sdk.Dec // total gas used by all the contract operations - FeeRewards sdk.Coins // fee rewards for this contract - InflationaryRewards sdk.Coin // inflation rewards for this contract - Metadata *types.ContractMetadata // metadata for this contract (might be nil if not set) + ContractAddress sdk.AccAddress // contract address + Metadata *types.ContractMetadata // metadata for this contract (might be nil if not set) + + BlockGasUsed uint64 // total gas used in the block (all operations across all transaction) + TxGasUsed map[uint64]uint64 // total gas used in a transaction (all operations across one transaction) [key: txID, value: gas used] + + FeeRewards sdk.Coins // fee rewards for this contract (for all txs) + InflationaryRewards sdk.Coin // inflation rewards for this contract (for the block) } ) @@ -42,116 +39,116 @@ func (k Keeper) DistributeRewards(ctx sdk.Context, height int64) { } // estimateBlockGasUsage creates a new distribution state for the given block height. -// Func iterates over all tracked transactions and estimates gas usage for: block, txs and contracts. +// Func iterates over all tracked transactions and estimates gas usage for each contract (on block and tx levels) merging operations. func (k Keeper) estimateBlockGasUsage(ctx sdk.Context, height int64) *blockRewardsDistributionState { metadataState := k.state.ContractMetadataState(ctx) + // Get all tracked transactions by the x/tracking module + blockGasTrackingInfo := k.trackingView.GetBlockTrackingInfo(ctx, height) + // Create a new block rewards distribution state and fill it up blockDistrState := &blockRewardsDistributionState{ - Height: height, + Height: height, + Txs: make(map[uint64]uint64, len(blockGasTrackingInfo.Txs)), + Contracts: make(map[string]*contractRewardsDistributionState, 0), } - // Get all tracked transactions by the x/tracking module - blockGasTrackingInfo := k.trackingView.GetBlockTrackingInfo(ctx, height) - blockDistrState.Txs = make([]*txRewardsDistributionState, 0, len(blockGasTrackingInfo.Txs)) - - // Fill up gas usage per transaction + // Fill up gas usage iterating over all tracked transactions and contract operations for _, txGasTrackingInfo := range blockGasTrackingInfo.Txs { - // Skip noop transaction (tx rewards will stay in the pool) - if !txGasTrackingInfo.Info.HasGasUsage() { - continue - } + // Set total gas used by the transaction + blockDistrState.Txs[txGasTrackingInfo.Info.Id] = txGasTrackingInfo.Info.TotalGas - // Estimate contract operations total gas used (could be multiple ops per contract, so we merge them) - contractDistrStatesSet := make(map[string]*contractRewardsDistributionState, len(txGasTrackingInfo.ContractOperations)) + // Estimate contract operations total gas used for this transaction for _, contractOp := range txGasTrackingInfo.ContractOperations { opGasUsed, opEligible := contractOp.GasUsed() if !opEligible { // Skip noop operation (should not happen since we're tracking an actual WASM usage) - k.Logger(ctx).Debug("Noop contract operation found", "txID", contractOp.TxId, "opID", contractOp.Id) + k.Logger(ctx).Debug("Noop contract operation found (skip)", "txID", contractOp.TxId, "opID", contractOp.Id) continue } - contractDistrState := contractDistrStatesSet[contractOp.ContractAddress] + // Create a new contract rewards distribution state + contractDistrState := blockDistrState.Contracts[contractOp.ContractAddress] if contractDistrState == nil { contractDistrState = &contractRewardsDistributionState{ ContractAddress: contractOp.MustGetContractAddress(), - GasUsed: sdk.ZeroDec(), + TxGasUsed: make(map[uint64]uint64, 0), InflationaryRewards: sdk.Coin{Amount: sdk.ZeroInt()}, // necessary to avoid nil pointer panic on Coins.Add call } if metadata, found := metadataState.GetContractMetadata(contractDistrState.ContractAddress); found { contractDistrState.Metadata = &metadata } - - contractDistrStatesSet[contractOp.ContractAddress] = contractDistrState + blockDistrState.Contracts[contractOp.ContractAddress] = contractDistrState } - contractDistrState.GasUsed = contractDistrState.GasUsed.Add(pkg.NewDecFromUint64(opGasUsed)) - } - // Create a new tx rewards distribution state and fill it up - // We sort the operations slice to prevent the consensus failure due to the order of operations - txDistState := &txRewardsDistributionState{ - TxID: txGasTrackingInfo.Info.Id, - GasUsed: pkg.NewDecFromUint64(txGasTrackingInfo.Info.TotalGas), - Contracts: make([]*contractRewardsDistributionState, 0, len(contractDistrStatesSet)), - } - for _, contractRewardsState := range contractDistrStatesSet { - txDistState.Contracts = append(txDistState.Contracts, contractRewardsState) - } - sort.Slice(txDistState.Contracts, func(i, j int) bool { - return txDistState.Contracts[i].ContractAddress.String() < txDistState.Contracts[j].ContractAddress.String() - }) + // Increase block gas usage + contractDistrState.BlockGasUsed += opGasUsed - // Append tx distr state to the block state - blockDistrState.Txs = append(blockDistrState.Txs, txDistState) + // Increase tx gas usage + txGasUsed := contractDistrState.TxGasUsed[contractOp.TxId] // 0 if not initialized + contractDistrState.TxGasUsed[contractOp.TxId] = txGasUsed + opGasUsed + } } return blockDistrState } // estimateBlockRewards update block distribution state with tracked rewards calculating reward shares per contract. -// Func iterates over all tracked transactions and estimates rewards for each contract. +// Func iterates over all tracked transactions and estimates inflation (on block level) and fee rebate (merging +// tokens for each transaction contract has operation at) rewards for each contract. func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewardsDistributionState) *blockRewardsDistributionState { txRewardsState := k.state.TxRewardsState(ctx) - // Get tracked block rewards by the x/rewards module (might not be found in case this reward is disabled) + // Fetch tracked block rewards by the x/rewards module (might not be found in case this reward is disabled) + inlfationRewardsEligible := false var blockGasLimit sdk.Dec - blockRewards, blockRewardsFound := k.state.BlockRewardsState(ctx).GetBlockRewards(blockDistrState.Height) - if blockRewardsFound { + blockRewards, found := k.state.BlockRewardsState(ctx).GetBlockRewards(blockDistrState.Height) + if found && blockRewards.HasRewards() && blockRewards.HasGasLimit() { blockGasLimit = pkg.NewDecFromUint64(blockRewards.MaxGas) - if !blockRewards.HasRewards() || !blockRewards.HasGasLimit() { - k.Logger(ctx).Debug("No block rewards found (coins are empty or gas limit is not set)", "height", blockDistrState.Height) + inlfationRewardsEligible = true + } else { + k.Logger(ctx).Debug("No inflation rewards to distribute (no record / empty coin / gas limit not set)", "height", blockDistrState.Height) + } + + // Fetch tracked transactions rewards by the x/rewards module (some might not be found in case this reward is disabled) + txsRewards := make(map[uint64]sdk.Coins, len(blockDistrState.Txs)) + for txID := range blockDistrState.Txs { + txRewards, found := txRewardsState.GetTxRewards(txID) + if found && txRewards.HasRewards() { + txsRewards[txID] = txRewards.FeeRewards + } else { + k.Logger(ctx).Debug("No tx fee rebate rewards to distribute (no record / empty coins)", "txID", txID) } } - // Estimate reward shares for each contract operation - for _, txDistrState := range blockDistrState.Txs { - // Get tracked transaction rewards by the x/rewards module (might not be found in case this reward is disabled) - txRewards, txRewardsFound := txRewardsState.GetTxRewards(txDistrState.TxID) - - for _, contractDistrState := range txDistrState.Contracts { - // Estimate contract fee rewards - if txRewardsFound && txRewards.HasRewards() { - rewardsShare := contractDistrState.GasUsed.Quo(txDistrState.GasUsed) - - rewardCoins := sdk.NewCoins() - for _, feeCoin := range txRewards.FeeRewards { - rewardCoins = rewardCoins.Add(sdk.NewCoin( - feeCoin.Denom, - feeCoin.Amount.ToDec().Mul(rewardsShare).TruncateInt(), - )) - } - contractDistrState.FeeRewards = rewardCoins + // Estimate contract rewards + for _, contractDistrState := range blockDistrState.Contracts { + // Estimate contract inflation rewards + if inlfationRewardsEligible { + gasUsed := pkg.NewDecFromUint64(contractDistrState.BlockGasUsed) + rewardsShare := gasUsed.Quo(blockGasLimit) + + contractDistrState.InflationaryRewards = sdk.NewCoin( + blockRewards.InflationRewards.Denom, + blockRewards.InflationRewards.Amount.ToDec().Mul(rewardsShare).TruncateInt(), + ) + } + + // Estimate contract tx fee rebate rewards (sum of all transactions involved) + for txID, gasUsed := range contractDistrState.TxGasUsed { + txFees, feeRewardsEligible := txsRewards[txID] + if !feeRewardsEligible { + continue } - // Estimate contract inflation rewards (only if block has rewards and gas limit is set) - if blockRewardsFound && blockRewards.HasRewards() && blockRewards.HasGasLimit() { - rewardsShare := contractDistrState.GasUsed.Quo(blockGasLimit) + gasTotal := pkg.NewDecFromUint64(blockDistrState.Txs[txID]) + rewardsShare := pkg.NewDecFromUint64(gasUsed).Quo(gasTotal) - contractDistrState.InflationaryRewards = sdk.NewCoin( - blockRewards.InflationRewards.Denom, - blockRewards.InflationRewards.Amount.ToDec().Mul(rewardsShare).TruncateInt(), - ) + for _, feeCoin := range txFees { + contractDistrState.FeeRewards = contractDistrState.FeeRewards.Add(sdk.NewCoin( + feeCoin.Denom, + feeCoin.Amount.ToDec().Mul(rewardsShare).TruncateInt(), + )) } } } @@ -160,51 +157,62 @@ func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewa } // distributeBlockRewards distributes block rewards to respective reward addresses if set (otherwise, skip) and emit events. -// Func sends rewards to the respective reward addresses (is set) and emits events. -// Leftovers caused by Int truncation or by a tx-less block (inflation rewards are tracked even -// if there were no transactions) stay in the pool. +// Leftovers caused by Int truncation or by a tx-less block (inflation rewards are tracked even if there were no transactions) +// stay in the pool. func (k Keeper) distributeBlockRewards(ctx sdk.Context, blockDistrState *blockRewardsDistributionState) { - for _, txDistrState := range blockDistrState.Txs { - for _, contractDistrState := range txDistrState.Contracts { - // Emit calculation event - types.EmitContractRewardCalculationEvent( - ctx, - contractDistrState.ContractAddress, - uint64(contractDistrState.GasUsed.TruncateInt64()), - contractDistrState.InflationaryRewards, - contractDistrState.FeeRewards, - contractDistrState.Metadata, - ) - - // Skip cases - if contractDistrState.Metadata == nil { - k.Logger(ctx).Debug("Contract rewards distribution skipped (no metadata found)", "contractAddress", contractDistrState.ContractAddress) - continue - } - if !contractDistrState.Metadata.HasRewardsAddress() { - k.Logger(ctx).Debug("Contract rewards distribution skipped (rewards address not set)", "contractAddress", contractDistrState.ContractAddress) - continue - } - rewardsAddr := contractDistrState.Metadata.MustGetRewardsAddress() - - // Distribute - rewards := sdk.NewCoins().Add(contractDistrState.FeeRewards...).Add(contractDistrState.InflationaryRewards) - if rewards.IsZero() { - k.Logger(ctx).Debug("Contract rewards distribution skipped (no rewards)", "contractAddress", contractDistrState.ContractAddress) - continue - } - - if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ContractRewardCollector, rewardsAddr, rewards); err != nil { - panic(fmt.Errorf("sending rewards (%s) to rewards address (%s) for the contract (%s): %w", contractDistrState.FeeRewards, rewardsAddr, contractDistrState.ContractAddress, err)) - } + // Convert contract distribution states to a sorted slice preventing the consensus failure due to x/bank operations order. + // Filter out contracts without: rewards, metadata or rewardsAddress. + // Emit calculation events for each contract. + contractStates := make([]*contractRewardsDistributionState, 0, len(blockDistrState.Contracts)) + for _, contractDistrState := range blockDistrState.Contracts { + // Emit calculation event + types.EmitContractRewardCalculationEvent( + ctx, + contractDistrState.ContractAddress, + contractDistrState.BlockGasUsed, + contractDistrState.InflationaryRewards, + contractDistrState.FeeRewards, + contractDistrState.Metadata, + ) + + // Filter out + if contractDistrState.FeeRewards.IsZero() && contractDistrState.InflationaryRewards.IsZero() { + k.Logger(ctx).Debug("No contract rewards to distribute (skip)", "contract", contractDistrState.ContractAddress) + continue + } + if contractDistrState.Metadata == nil { + k.Logger(ctx).Debug("Contract metadata is not set (skip)", "contract", contractDistrState.ContractAddress) + continue + } + if !contractDistrState.Metadata.HasRewardsAddress() { + k.Logger(ctx).Debug("Contract rewards address is not set (skip)", "contract", contractDistrState.ContractAddress) + continue + } - // Emit distribution event - types.EmitContractRewardDistributionEvent( - ctx, - contractDistrState.ContractAddress, - rewardsAddr, - rewards, - ) + contractStates = append(contractStates, contractDistrState) + } + sort.Slice(contractStates, func(i, j int) bool { + return contractStates[i].ContractAddress.String() < contractStates[j].ContractAddress.String() + }) + + // Distribute + for _, contractDistrState := range contractStates { + // Transfer to the rewardsAddress + rewardsAddr := contractDistrState.Metadata.MustGetRewardsAddress() + rewards := sdk.NewCoins(). + Add(contractDistrState.InflationaryRewards). + Add(contractDistrState.FeeRewards...) + + if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ContractRewardCollector, rewardsAddr, rewards); err != nil { + panic(fmt.Errorf("sending rewards (%s) to the rewards address (%s) for the contract (%s): %w", contractDistrState.FeeRewards, rewardsAddr, contractDistrState.ContractAddress, err)) } + + // Emit distribution event + types.EmitContractRewardDistributionEvent( + ctx, + contractDistrState.ContractAddress, + rewardsAddr, + rewards, + ) } } diff --git a/x/rewards/keeper/distribution_test.go b/x/rewards/keeper/distribution_test.go new file mode 100644 index 00000000..21cccad7 --- /dev/null +++ b/x/rewards/keeper/distribution_test.go @@ -0,0 +1,511 @@ +package keeper_test + +import ( + "testing" + + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + mintTypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +// TestRewardsKeeper_Distribution tests rewards distribution for a single block with different edge cases. +// This is not an E2E test, we emulate x/tracking and x/rewards Ante handler calls to create tracking entries directly. +// Ante handlers are tested independently. +func TestRewardsKeeper_Distribution(t *testing.T) { + type ( + contractInput struct { + metadataExists bool // if true, metadata is set + contractAddr sdk.AccAddress // any random address to merge operations [sdk.AccAddr] + rewardsAddr string // might be empty to skip distribution (should be a real chain address) [sdk.AccAddr] + operations []uint64 // list of gas consumptions per operation (opType is set randomly) + } + + transactionInput struct { + feeCoins string // fee coins for this transaction (might be empty to skip distribution) [sdk.Coins] + contracts []contractInput // list of contracts and their operations + } + + contractOutput struct { + rewardsAddr sdk.AccAddress // must be set since we are checking its balance [sdk.AccAddr] + rewards string // expected rewards (might be empty if no rewards are expected) [sdk.Coins] + } + + testCase struct { + name string + // inputs + blockInflationCoin string // block inflation coin (might be empty to skip distribution) [sdk.Coin] + blockGasLimit int64 // consensus parameter (might be 0 to skip inflation distribution) + txs []transactionInput // block transactions input + // expected outputs + contractsOutput []contractOutput // list of contracts and their expected rewards (might not include some contracts if they don't have metadata set) + } + ) + + // Generate empty addresses + accAddrs, _ := e2eTesting.GenAccounts(10) + contractAddrs := e2eTesting.GenContractAddresses(10) + testCases := []testCase{ + { + name: "No-op", + }, + { + name: "1 tx, 1 contract, 1 op", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Tx rewards: 1.0 (100 / 100 tx gas) = 500stake + // Inf rewards: 0.1 (100 / 1000 block gas) = 100stake + rewards: "600stake", + }, + }, + }, + { + name: "1 tx, 1 contract, 3 ops", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + 50, + 25, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Tx rewards: 1.0 (175 / 175 tx gas) = 500stake + // Inf rewards: 0.175 (175 / 1000 block gas) = 175stake + rewards: "675stake", + }, + }, + }, + { + name: "1 tx, 2 contracts with 2 ops for each", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + 50, + }, + }, + { + metadataExists: true, + contractAddr: contractAddrs[1], + rewardsAddr: accAddrs[1].String(), + operations: []uint64{ + 200, + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Tx rewards: ~0.3 (150 / 450 tx gas) = 166stake + // Inf rewards: 0.15 (150 / 1000 block gas) = 150stake + rewards: "316stake", + }, + { + rewardsAddr: accAddrs[1], + // Tx rewards: ~0.6 (300 / 450 tx gas) = 333stake + // Inf rewards: 0.3 (300 / 1000 block gas) = 300stake + rewards: "633stake", + }, + }, + }, + { + name: "2 txs with contract ops intersection (rewards from both txs)", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 200, + 250, + }, + }, + { + metadataExists: true, + contractAddr: contractAddrs[1], + rewardsAddr: accAddrs[1].String(), + operations: []uint64{ + 100, + 200, + 300, + }, + }, + }, + }, + { + feeCoins: "600stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 10, + }, + }, + { + metadataExists: true, + contractAddr: contractAddrs[1], + rewardsAddr: accAddrs[1].String(), + operations: []uint64{ + 20, + 30, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Tx 1 rewards: ~0.43 (450 / 1050 tx gas) = 214stake + // Tx 2 rewards: ~0.17 (10 / 60 tx gas) = 100stake + // Inf rewards: 0.46 (460 / 1000 block gas) = 460stake + rewards: "774stake", + }, + { + rewardsAddr: accAddrs[1], + // Tx 1 rewards: ~0.57 (600 / 1050 tx gas) = 285stake + // Tx 2 rewards: ~0.83 (50 / 60 tx gas) = 499stake + // Inf rewards: 0.65 (650 / 1000 block gas) = 650stake + rewards: "1434stake", + }, + }, + }, + { + name: "1 tx with 2 contracts (one without metadata)", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: false, + contractAddr: contractAddrs[0], + operations: []uint64{ + 100, + }, + }, + { + metadataExists: true, + contractAddr: contractAddrs[1], + rewardsAddr: accAddrs[1].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + rewards: "", + }, + { + rewardsAddr: accAddrs[1], + // Tx rewards: 0.5 (100 / 200 tx gas) = 250stake + // Inf rewards: 0.1 (100 / 1000 block gas) = 100stake + rewards: "350stake", + }, + }, + }, + { + name: "1 tx with 2 contracts (one without rewardsAddress)", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + operations: []uint64{ + 100, + }, + }, + { + metadataExists: true, + contractAddr: contractAddrs[1], + rewardsAddr: accAddrs[1].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + rewards: "", + }, + { + rewardsAddr: accAddrs[1], + // Tx rewards: 0.5 (100 / 200 tx gas) = 250stake + // Inf rewards: 0.1 (100 / 1000 block gas) = 100stake + rewards: "350stake", + }, + }, + }, + { + name: "1 tx, 1 contract, 1 op (no tx fees)", + blockInflationCoin: "1000stake", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Inf rewards: 0.1 (100 / 1000 block gas) = 100stake + rewards: "100stake", + }, + }, + }, + { + name: "1 tx, 1 contract, 1 op (no inflation)", + blockInflationCoin: "", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Tx rewards: 1.0 (100 / 100 tx gas) = 500stake + rewards: "500stake", + }, + }, + }, + { + name: "1 tx, 1 contract, 1 op (no block gas limit)", + blockInflationCoin: "1000stake", + blockGasLimit: -1, + txs: []transactionInput{ + { + feeCoins: "500stake", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + // Tx rewards: 1.0 (100 / 100 tx gas) = 500stake + rewards: "500stake", + }, + }, + }, + { + name: "1 tx, 1 contract, 1 op (no tx fee, no inflation)", + blockInflationCoin: "", + blockGasLimit: 1000, + txs: []transactionInput{ + { + feeCoins: "", + contracts: []contractInput{ + { + metadataExists: true, + contractAddr: contractAddrs[0], + rewardsAddr: accAddrs[0].String(), + operations: []uint64{ + 100, + }, + }, + }, + }, + }, + contractsOutput: []contractOutput{ + { + rewardsAddr: accAddrs[0], + rewards: "", + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create chain with block gas limit + chain := e2eTesting.NewTestChain(t, 1, + e2eTesting.WithBlockGasLimit(tc.blockGasLimit), + ) + acc := chain.GetAccount(0) + + // Set mock ContractViewer (to pass contract admin check for metadata setup) + contractViewer := newMockContractViewer() + chain.GetApp().RewardsKeeper.SetContractInfoViewer(contractViewer) + + tKeeper, rKeeper := chain.GetApp().TrackingKeeper, chain.GetApp().RewardsKeeper + ctx := chain.GetContext() + + // Setup + { + // Create transactions gas tracking and rewards tracking data for the current block + for _, tx := range tc.txs { + // Emulate x/tracking AnteHandler call + tKeeper.TrackNewTx(ctx) + + // Contracts setup + for _, contract := range tx.contracts { + // Ingest gas tracking for each contract + var gasConsumptionRecords []wasmdTypes.ContractGasRecord + for _, op := range contract.operations { + gasConsumptionRecord := wasmdTypes.ContractGasRecord{ + OperationId: GetRandomContractOperationType(), + ContractAddress: contract.contractAddr.String(), + OriginalGas: wasmdTypes.GasConsumptionInfo{ + SDKGas: op, + VMGas: 0, // to simplify testCase inputs, we don't use VMGas + }, + } + gasConsumptionRecords = append(gasConsumptionRecords, gasConsumptionRecord) + } + require.NoError(t, tKeeper.IngestGasRecord(ctx, gasConsumptionRecords)) + + // Set metadata for the contract + if contract.metadataExists { + contractViewer.AddContractAdmin(contract.contractAddr.String(), acc.Address.String()) + + metadata := rewardsTypes.ContractMetadata{ + OwnerAddress: acc.Address.String(), + RewardsAddress: contract.rewardsAddr, + } + + require.NoError(t, rKeeper.SetContractMetadata(ctx, acc.Address, contract.contractAddr, metadata)) + } + } + + // Track fee rewards + if tx.feeCoins != "" { + feeRewards, err := sdk.ParseCoinsNormalized(tx.feeCoins) + require.NoError(t, err) + + // Emulate x/rewards AnteHandler call + rKeeper.TrackFeeRebatesRewards(ctx, feeRewards) + // Mint and transfer + require.NoError(t, chain.GetApp().MintKeeper.MintCoins(ctx, feeRewards)) + require.NoError(t, chain.GetApp().BankKeeper.SendCoinsFromModuleToModule(ctx, mintTypes.ModuleName, rewardsTypes.ContractRewardCollector, feeRewards)) + } + } + + // Track inflation rewards + if tc.blockInflationCoin != "" { + inflationReward, err := sdk.ParseCoinNormalized(tc.blockInflationCoin) + require.NoError(t, err) + inflationRewards := sdk.NewCoins(inflationReward) + + // Emulate x/rewards MintKeeper call + rKeeper.TrackInflationRewards(ctx, inflationReward) + // Mint and transfer + require.NoError(t, chain.GetApp().MintKeeper.MintCoins(ctx, inflationRewards)) + require.NoError(t, chain.GetApp().BankKeeper.SendCoinsFromModuleToModule(ctx, mintTypes.ModuleName, rewardsTypes.ContractRewardCollector, inflationRewards)) + } else { + // We have to remove it since it was created by the x/mint + rKeeper.GetState().BlockRewardsState(ctx).DeleteBlockRewards(ctx.BlockHeight()) + } + } + + // Call EndBlocker, BeginBlocker to finalize x/tracking entries and distribute rewards via x/rewards + { + chain.NextBlock(0) + } + + // Assert expectations + for i, outExpected := range tc.contractsOutput { + balanceExpected, err := sdk.ParseCoinsNormalized(outExpected.rewards) + require.NoError(t, err) + + balanceReceived := chain.GetBalance(outExpected.rewardsAddr) + assert.Equal(t, balanceExpected.String(), balanceReceived.String(), "output [%d]", i) + } + }) + } +} diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index e5c71278..b028a1ae 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -153,3 +153,9 @@ func (k Keeper) UndistributedRewardsPool(ctx sdk.Context) sdk.Coins { poolAcc := k.authKeeper.GetModuleAccount(ctx, types.ContractRewardCollector) return k.bankKeeper.GetAllBalances(ctx, poolAcc.GetAddress()) } + +// SetContractInfoViewer sets the contract info view dependency. +// Only for testing purposes. +func (k *Keeper) SetContractInfoViewer(viewer ContractInfoReaderExpected) { + k.contractInfoView = viewer +} diff --git a/x/rewards/keeper/state_block_rewards.go b/x/rewards/keeper/state_block_rewards.go index 98dac5d7..99d467b8 100644 --- a/x/rewards/keeper/state_block_rewards.go +++ b/x/rewards/keeper/state_block_rewards.go @@ -44,6 +44,12 @@ func (s BlockRewardsState) GetBlockRewards(height int64) (types.BlockRewards, bo return obj, true } +// DeleteBlockRewards deletes a types.BlockRewards object. +func (s BlockRewardsState) DeleteBlockRewards(height int64) { + store := prefix.NewStore(s.stateStore, types.BlockRewardsPrefix) + store.Delete(s.buildBlockRewardsKey(height)) +} + // Import initializes state from the module genesis data. func (s BlockRewardsState) Import(objs []types.BlockRewards) { for _, obj := range objs { From 464fb1c60d55b495199ba4ebb044977cd616c841 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Sun, 31 Jul 2022 01:04:47 +0300 Subject: [PATCH 08/27] x/tracking, x/rewards: tracking data prune added --- x/rewards/keeper/distribution.go | 9 +++++++- x/rewards/keeper/keeper.go | 13 +++++------ x/rewards/keeper/state.go | 7 ++++++ x/rewards/keeper/state_tx_rewards.go | 30 ++++++++++++++++++++++++++ x/tracking/keeper/keeper.go | 5 +++++ x/tracking/keeper/state.go | 11 ++++++++++ x/tracking/keeper/state_contract_op.go | 30 ++++++++++++++++++++++++++ x/tracking/keeper/state_tx_info.go | 30 ++++++++++++++++++++++++++ 8 files changed, 128 insertions(+), 7 deletions(-) diff --git a/x/rewards/keeper/distribution.go b/x/rewards/keeper/distribution.go index 2159b497..908060aa 100644 --- a/x/rewards/keeper/distribution.go +++ b/x/rewards/keeper/distribution.go @@ -36,6 +36,7 @@ func (k Keeper) DistributeRewards(ctx sdk.Context, height int64) { blockDistrState := k.estimateBlockGasUsage(ctx, height) blockDistrState = k.estimateBlockRewards(ctx, blockDistrState) k.distributeBlockRewards(ctx, blockDistrState) + k.cleanupTracking(ctx, height) } // estimateBlockGasUsage creates a new distribution state for the given block height. @@ -44,7 +45,7 @@ func (k Keeper) estimateBlockGasUsage(ctx sdk.Context, height int64) *blockRewar metadataState := k.state.ContractMetadataState(ctx) // Get all tracked transactions by the x/tracking module - blockGasTrackingInfo := k.trackingView.GetBlockTrackingInfo(ctx, height) + blockGasTrackingInfo := k.trackingKeeper.GetBlockTrackingInfo(ctx, height) // Create a new block rewards distribution state and fill it up blockDistrState := &blockRewardsDistributionState{ @@ -216,3 +217,9 @@ func (k Keeper) distributeBlockRewards(ctx sdk.Context, blockDistrState *blockRe ) } } + +// cleanupTracking prunes all tracking data for the given block height for x/tracking and x/rewards modules. +func (k Keeper) cleanupTracking(ctx sdk.Context, height int64) { + k.trackingKeeper.RemoveBlockTrackingInfo(ctx, height) + k.state.DeleteBlockRewardsCascade(ctx, height) +} diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index b028a1ae..d7d67567 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -18,10 +18,11 @@ type ContractInfoReaderExpected interface { GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmTypes.ContractInfo } -// TrackingReaderExpected defines the interface for the x/tracking module dependency. -type TrackingReaderExpected interface { +// TrackingKeeperExpected defines the interface for the x/tracking module dependency. +type TrackingKeeperExpected interface { GetCurrentTxID(ctx sdk.Context) uint64 GetBlockTrackingInfo(ctx sdk.Context, height int64) trackingTypes.BlockTracking + RemoveBlockTrackingInfo(ctx sdk.Context, height int64) } // AuthKeeperExpected defines the interface for the x/auth module dependency. @@ -41,13 +42,13 @@ type Keeper struct { paramStore paramTypes.Subspace state State contractInfoView ContractInfoReaderExpected - trackingView TrackingReaderExpected + trackingKeeper TrackingKeeperExpected authKeeper AuthKeeperExpected bankKeeper BankKeeperExpected } // NewKeeper creates a new Keeper instance. -func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInfoReaderExpected, trackingReader TrackingReaderExpected, ak AuthKeeperExpected, bk BankKeeperExpected, ps paramTypes.Subspace) Keeper { +func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInfoReaderExpected, trackingKeeper TrackingKeeperExpected, ak AuthKeeperExpected, bk BankKeeperExpected, ps paramTypes.Subspace) Keeper { if !ps.HasKeyTable() { ps = ps.WithKeyTable(types.ParamKeyTable()) } @@ -57,7 +58,7 @@ func NewKeeper(cdc codec.Codec, key sdk.StoreKey, contractInfoReader ContractInf paramStore: ps, state: NewState(cdc, key), contractInfoView: contractInfoReader, - trackingView: trackingReader, + trackingKeeper: trackingKeeper, authKeeper: ak, bankKeeper: bk, } @@ -131,7 +132,7 @@ func (k Keeper) GetContractMetadata(ctx sdk.Context, contractAddr sdk.AccAddress // Unique transaction ID is taken from the tracking module. // CONTRACT: tracking Ante handler must be called before this module's Ante handler (tracking provides the primary key). func (k Keeper) TrackFeeRebatesRewards(ctx sdk.Context, rewards sdk.Coins) { - txID := k.trackingView.GetCurrentTxID(ctx) + txID := k.trackingKeeper.GetCurrentTxID(ctx) k.state.TxRewardsState(ctx).CreateTxRewards( txID, ctx.BlockHeight(), diff --git a/x/rewards/keeper/state.go b/x/rewards/keeper/state.go index 3e17d22a..2a2f4830 100644 --- a/x/rewards/keeper/state.go +++ b/x/rewards/keeper/state.go @@ -22,6 +22,13 @@ func NewState(cdc codec.Codec, key sdk.StoreKey) State { } } +// DeleteBlockRewardsCascade deletes all block rewards for a given height. +// Function removes BlockRewards and TxRewards objects cleaning up their indexes. +func (s State) DeleteBlockRewardsCascade(ctx sdk.Context, height int64) { + s.BlockRewardsState(ctx).DeleteBlockRewards(height) + s.TxRewardsState(ctx).deleteTxRewardsByBlock(height) +} + // ContractMetadataState returns types.ContractMetadata repository. func (s State) ContractMetadataState(ctx sdk.Context) ContractMetadataState { baseStore := ctx.KVStore(s.key) diff --git a/x/rewards/keeper/state_tx_rewards.go b/x/rewards/keeper/state_tx_rewards.go index 6a832de4..94b3e67a 100644 --- a/x/rewards/keeper/state_tx_rewards.go +++ b/x/rewards/keeper/state_tx_rewards.go @@ -87,6 +87,30 @@ func (s TxRewardsState) Export() (objs []types.TxRewards) { return } +// deleteTxRewardsByBlock deletes types.TxRewards objects by block height cleaning up the block index. +// Returns the list of deleted txIDs. +func (s TxRewardsState) deleteTxRewardsByBlock(height int64) []uint64 { + store := prefix.NewStore(s.stateStore, types.TxRewardsBlockIndexPrefix) + + iterator := sdk.KVStorePrefixIterator(store, s.buildBlockIndexPrefix(height)) + defer iterator.Close() + + var blockIndexKeys [][]byte + var removedTxIDs []uint64 + for ; iterator.Valid(); iterator.Next() { + _, txID := s.parseBlockIndexKey(iterator.Key()) + s.deleteTxRewards(txID) + + removedTxIDs = append(removedTxIDs, txID) + blockIndexKeys = append(blockIndexKeys, iterator.Key()) + } + for _, key := range blockIndexKeys { + store.Delete(key) + } + + return removedTxIDs +} + // buildTxRewardsKey returns the key used to store a types.TxRewards object. func (s TxRewardsState) buildTxRewardsKey(txID uint64) []byte { return sdk.Uint64ToBigEndian(txID) @@ -116,6 +140,12 @@ func (s TxRewardsState) getTxRewards(txID uint64) *types.TxRewards { return &obj } +// deleteTxRewards deletes a types.TxRewards object. +func (s TxRewardsState) deleteTxRewards(txID uint64) { + store := prefix.NewStore(s.stateStore, types.TxRewardsPrefix) + store.Delete(s.buildTxRewardsKey(txID)) +} + // buildBlockIndexPrefix returns the key prefix used to maintain types.TxRewards's block index. func (s TxRewardsState) buildBlockIndexPrefix(height int64) []byte { return sdk.Uint64ToBigEndian(uint64(height)) diff --git a/x/tracking/keeper/keeper.go b/x/tracking/keeper/keeper.go index 47d61451..5d45b1b8 100644 --- a/x/tracking/keeper/keeper.go +++ b/x/tracking/keeper/keeper.go @@ -91,3 +91,8 @@ func (k Keeper) GetBlockTrackingInfo(ctx sdk.Context, height int64) types.BlockT return resp } + +// RemoveBlockTrackingInfo removes gas tracking entries for the given height. +func (k Keeper) RemoveBlockTrackingInfo(ctx sdk.Context, height int64) { + k.state.DeleteTxInfosCascade(ctx, height) +} diff --git a/x/tracking/keeper/state.go b/x/tracking/keeper/state.go index aca05aac..997582ab 100644 --- a/x/tracking/keeper/state.go +++ b/x/tracking/keeper/state.go @@ -22,6 +22,17 @@ func NewState(cdc codec.Codec, key sdk.StoreKey) State { } } +// DeleteTxInfosCascade deletes all block tracking for a given height. +// Function removes TxInfo and ContractOpInfo objects cleaning up their indexes. +func (s State) DeleteTxInfosCascade(ctx sdk.Context, height int64) { + contractOpInfoState := s.ContractOpInfoState(ctx) + + txIDs := s.TxInfoState(ctx).DeleteTxInfosByBlock(height) + for _, txID := range txIDs { + contractOpInfoState.DeleteContractOpsByTxID(txID) + } +} + // TxInfoState returns types.TxInfo repository. func (s State) TxInfoState(ctx sdk.Context) TxInfoState { baseStore := ctx.KVStore(s.key) diff --git a/x/tracking/keeper/state_contract_op.go b/x/tracking/keeper/state_contract_op.go index eaaaa255..e83c8cbf 100644 --- a/x/tracking/keeper/state_contract_op.go +++ b/x/tracking/keeper/state_contract_op.go @@ -66,6 +66,30 @@ func (s ContractOpInfoState) GetContractOpInfoByTxID(txID uint64) (objs []types. return } +// DeleteContractOpsByTxID deletes all types.ContractOperationInfo objects by tx ID. +// Returns the list of deleted IDs. +func (s ContractOpInfoState) DeleteContractOpsByTxID(txID uint64) []uint64 { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoTxIndexPrefix) + + iterator := sdk.KVStorePrefixIterator(store, s.buildTxIndexPrefix(txID)) + defer iterator.Close() + + var txIndexKeys [][]byte + var removedIDs []uint64 + for ; iterator.Valid(); iterator.Next() { + _, id := s.parseTxIndexKey(iterator.Key()) + s.deleteContractOpInfo(id) + + removedIDs = append(removedIDs, id) + txIndexKeys = append(txIndexKeys, iterator.Key()) + } + for _, key := range txIndexKeys { + store.Delete(key) + } + + return removedIDs +} + // Import initializes state from the module genesis data. func (s ContractOpInfoState) Import(objs []types.ContractOperationInfo) { lastID := uint64(0) @@ -140,6 +164,12 @@ func (s ContractOpInfoState) getContractOpInfo(id uint64) *types.ContractOperati return &obj } +// deleteContractOpInfo deletes a types.ContractOperationInfo object by ID. +func (s ContractOpInfoState) deleteContractOpInfo(id uint64) { + store := prefix.NewStore(s.stateStore, types.ContractOpInfoPrefix) + store.Delete(s.buildContractOpInfoKey(id)) +} + // buildTxIndexPrefix returns the key prefix used to maintain types.ContractOperationInfo's tx index. func (s ContractOpInfoState) buildTxIndexPrefix(txID uint64) []byte { return sdk.Uint64ToBigEndian(txID) diff --git a/x/tracking/keeper/state_tx_info.go b/x/tracking/keeper/state_tx_info.go index 0a009389..aa438daa 100644 --- a/x/tracking/keeper/state_tx_info.go +++ b/x/tracking/keeper/state_tx_info.go @@ -80,6 +80,30 @@ func (s TxInfoState) GetTxInfosByBlock(height int64) (objs []types.TxInfo) { return } +// DeleteTxInfosByBlock deletes all types.TxInfo objects by block height clearing the block index. +// Returns the list of deleted IDs. +func (s TxInfoState) DeleteTxInfosByBlock(height int64) []uint64 { + store := prefix.NewStore(s.stateStore, types.TxInfoBlockIndexPrefix) + + iterator := sdk.KVStorePrefixIterator(store, s.buildBlockIndexPrefix(height)) + defer iterator.Close() + + var blockIndexKeys [][]byte + var removedIDs []uint64 + for ; iterator.Valid(); iterator.Next() { + _, id := s.parseBlockIndexKey(iterator.Key()) + s.deleteTxInfo(id) + + removedIDs = append(removedIDs, id) + blockIndexKeys = append(blockIndexKeys, iterator.Key()) + } + for _, key := range blockIndexKeys { + store.Delete(key) + } + + return removedIDs +} + // Import initializes state from the module genesis data. func (s TxInfoState) Import(objs []types.TxInfo) { lastID := uint64(0) @@ -145,6 +169,12 @@ func (s TxInfoState) getTxInfo(id uint64) *types.TxInfo { return &obj } +// deleteTxInfo deletes a types.TxInfo object by ID. +func (s TxInfoState) deleteTxInfo(id uint64) { + store := prefix.NewStore(s.stateStore, types.TxInfoPrefix) + store.Delete(s.buildTxInfoKey(id)) +} + // buildBlockIndexPrefix returns the key prefix used to maintain types.TxInfo's block index. func (s TxInfoState) buildBlockIndexPrefix(height int64) []byte { return sdk.Uint64ToBigEndian(uint64(height)) From a3da7bf26109994586d248722ae5e602aa9b1512 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Sun, 31 Jul 2022 14:43:30 +0300 Subject: [PATCH 09/27] x/rewards: mintBankKeeper test added; max inflationRewardsRation is limited (LT 1.0) as 1.0 triggers an error on x/mint BeginBlocker --- e2e/testing/chain.go | 8 + x/rewards/mintbankkeeper/keeper.go | 2 +- x/rewards/mintbankkeeper/keeper_test.go | 196 ++++++++++++++++++++++++ x/rewards/types/params.go | 4 +- 4 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 x/rewards/mintbankkeeper/keeper_test.go diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 72e6fc06..0cd2f77b 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -255,6 +255,14 @@ func (chain *TestChain) GetBalance(accAddr sdk.AccAddress) sdk.Coins { return chain.app.BankKeeper.GetAllBalances(chain.GetContext(), accAddr) } +// GetModuleBalance returns the balance of the given module. +func (chain *TestChain) GetModuleBalance(moduleName string) sdk.Coins { + ctx := chain.GetContext() + moduleAcc := chain.app.AccountKeeper.GetModuleAccount(ctx, moduleName) + + return chain.app.BankKeeper.GetAllBalances(chain.GetContext(), moduleAcc.GetAddress()) +} + // GetContext returns a context for the current block. func (chain *TestChain) GetContext() sdk.Context { ctx := chain.app.BaseApp.NewContext(false, chain.curHeader) diff --git a/x/rewards/mintbankkeeper/keeper.go b/x/rewards/mintbankkeeper/keeper.go index 570f5b06..ab2b625c 100644 --- a/x/rewards/mintbankkeeper/keeper.go +++ b/x/rewards/mintbankkeeper/keeper.go @@ -44,7 +44,7 @@ func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recip } ratio := k.rewardsKeeper.InflationRewardsRatio(ctx) - stakingRewards, dappRewards := pkg.SplitCoins(amt, ratio) + dappRewards, stakingRewards := pkg.SplitCoins(amt, ratio) // Send to the x/auth fee collector account if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, stakingRewards); err != nil { diff --git a/x/rewards/mintbankkeeper/keeper_test.go b/x/rewards/mintbankkeeper/keeper_test.go new file mode 100644 index 00000000..0551261a --- /dev/null +++ b/x/rewards/mintbankkeeper/keeper_test.go @@ -0,0 +1,196 @@ +package mintbankkeeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" + distrTypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + mintTypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/x/rewards/mintbankkeeper" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestMintBankKeeper(t *testing.T) { + type testCase struct { + name string + // Inputs + inflationRewardsRatio string // x/rewards inflation rewards ratio + blockMaxGas int64 // block max gas (consensus param) + srcModule string // source module name + dstModule string // destination module name + transferCoins string // coins to send [sdk.Coins] + // Expected outputs + errExpected bool + rewardRecordExpected bool // reward record expected to be created + srcBalanceDiffExpected string // expected source module balance diff [sdk.Coins] + dstBalanceDiffExpected string // expected destination module balance diff [sdk.Coins] + rewardsBalanceDiffExpected string // expected x/rewards module balance diff [sdk.Coins] + } + + testCases := []testCase{ + { + name: "OK: 1000stake: Mint -> FeeCollector with 0.6 ratio to Rewards", + // + inflationRewardsRatio: "0.6", + blockMaxGas: 1000, + srcModule: mintTypes.ModuleName, + dstModule: authTypes.FeeCollectorName, + transferCoins: "1000stake", + // + rewardRecordExpected: true, + srcBalanceDiffExpected: "", + dstBalanceDiffExpected: "400stake", + rewardsBalanceDiffExpected: "600stake", + }, + { + name: "OK: 45stake: Mint -> FeeCollector with 0.5 ratio to Rewards with Int truncated", + // + inflationRewardsRatio: "0.5", + blockMaxGas: 1000, + srcModule: mintTypes.ModuleName, + dstModule: authTypes.FeeCollectorName, + transferCoins: "45stake", + // + rewardRecordExpected: true, + srcBalanceDiffExpected: "", + dstBalanceDiffExpected: "23stake", + rewardsBalanceDiffExpected: "22stake", + }, + { + name: "OK: 100stake: Mint -> FeeCollector with 0.99 ratio to Rewards", + // + inflationRewardsRatio: "0.99", + blockMaxGas: 1000, + srcModule: mintTypes.ModuleName, + dstModule: authTypes.FeeCollectorName, + transferCoins: "100stake", + // + rewardRecordExpected: true, + srcBalanceDiffExpected: "", + dstBalanceDiffExpected: "1stake", + rewardsBalanceDiffExpected: "99stake", + }, + { + name: "OK: 100stake: Mint -> FeeCollector with 0.0 ratio to Rewards (no rewards)", + // + inflationRewardsRatio: "0", + blockMaxGas: 1000, + srcModule: mintTypes.ModuleName, + dstModule: authTypes.FeeCollectorName, + transferCoins: "100stake", + // + rewardRecordExpected: false, + srcBalanceDiffExpected: "", + dstBalanceDiffExpected: "100stake", + rewardsBalanceDiffExpected: "", + }, + { + name: "OK: 100stake: Mint -> FeeCollector with 0.01 ratio to Rewards (no block gas limit)", + // + inflationRewardsRatio: "0.01", + blockMaxGas: -1, + srcModule: mintTypes.ModuleName, + dstModule: authTypes.FeeCollectorName, + transferCoins: "100stake", + // + rewardRecordExpected: true, + srcBalanceDiffExpected: "", + dstBalanceDiffExpected: "99stake", + rewardsBalanceDiffExpected: "1stake", + }, + { + name: "OK: 100stake: Mint -> Distr (no x/rewards involved)", + // + inflationRewardsRatio: "0.5", + blockMaxGas: -1, + srcModule: mintTypes.ModuleName, + dstModule: distrTypes.ModuleName, + transferCoins: "100stake", + // + rewardRecordExpected: false, + srcBalanceDiffExpected: "", + dstBalanceDiffExpected: "100stake", + rewardsBalanceDiffExpected: "", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create chain + inflationRewardsRatio, err := sdk.NewDecFromStr(tc.inflationRewardsRatio) + require.NoError(t, err) + + chain := e2eTesting.NewTestChain(t, 1, + e2eTesting.WithInflationRewardsRatio(inflationRewardsRatio), + e2eTesting.WithBlockGasLimit(tc.blockMaxGas), + ) + ctx := chain.GetContext() + + // Fetch initial balances + srcBalanceBefore := chain.GetModuleBalance(tc.srcModule) + dstBalanceBefore := chain.GetModuleBalance(tc.dstModule) + rewardsBalanceBefore := chain.GetModuleBalance(rewardsTypes.ModuleName) + + // Mint funds for the source module + transferCoins, err := sdk.ParseCoinsNormalized(tc.transferCoins) + require.NoError(t, err) + + require.NoError(t, chain.GetApp().MintKeeper.MintCoins(ctx, transferCoins)) + require.NoError(t, chain.GetApp().BankKeeper.SendCoinsFromModuleToModule(ctx, mintTypes.ModuleName, tc.srcModule, transferCoins)) + + // Remove rewards records which is created automagically + chain.GetApp().RewardsKeeper.GetState().DeleteBlockRewardsCascade(ctx, ctx.BlockHeight()) + + // Transfer via keeper + k := mintbankkeeper.NewKeeper(chain.GetApp().BankKeeper, chain.GetApp().RewardsKeeper) + err = k.SendCoinsFromModuleToModule(ctx, tc.srcModule, tc.dstModule, transferCoins) + if tc.errExpected { + assert.Error(t, err) + return + } + require.NoError(t, err) + + // Check final balances + srcBalanceAfter := chain.GetModuleBalance(tc.srcModule) + dstBalanceAfter := chain.GetModuleBalance(tc.dstModule) + rewardsBalanceAfter := chain.GetModuleBalance(rewardsTypes.ModuleName) + + srcBalanceDiffReceived := srcBalanceBefore.Sub(srcBalanceAfter) // negative + dstBalanceDiffReceived := dstBalanceAfter.Sub(dstBalanceBefore) // positive + rewardsBalanceDiffReceived := rewardsBalanceAfter.Sub(rewardsBalanceBefore) // positive + + srcBalanceDiffExpected, err := sdk.ParseCoinsNormalized(tc.srcBalanceDiffExpected) + require.NoError(t, err) + dstBalanceDiffExpected, err := sdk.ParseCoinsNormalized(tc.dstBalanceDiffExpected) + require.NoError(t, err) + rewardsDiffExpected, err := sdk.ParseCoinsNormalized(tc.rewardsBalanceDiffExpected) + require.NoError(t, err) + + assert.Equal(t, srcBalanceDiffExpected.String(), srcBalanceDiffReceived.String()) + assert.Equal(t, dstBalanceDiffExpected.String(), dstBalanceDiffReceived.String()) + assert.Equal(t, rewardsDiffExpected.String(), rewardsBalanceDiffReceived.String()) + + // Check rewards record + rewardsRecordReceived, found := chain.GetApp().RewardsKeeper.GetState().BlockRewardsState(ctx).GetBlockRewards(ctx.BlockHeight()) + if !tc.rewardRecordExpected { + require.False(t, found) + return + } + require.True(t, found) + + maxGasExpected := uint64(0) + if tc.blockMaxGas > 0 { + maxGasExpected = uint64(tc.blockMaxGas) + } + + assert.Equal(t, ctx.BlockHeight(), rewardsRecordReceived.Height) + assert.Equal(t, rewardsDiffExpected.String(), rewardsRecordReceived.InflationRewards.String()) + assert.Equal(t, maxGasExpected, rewardsRecordReceived.MaxGas) + }) + } +} diff --git a/x/rewards/types/params.go b/x/rewards/types/params.go index 47a572f3..f6342b5d 100644 --- a/x/rewards/types/params.go +++ b/x/rewards/types/params.go @@ -97,8 +97,8 @@ func validateRatio(v sdk.Dec) error { if v.IsNegative() { return fmt.Errorf("must be GTE 0.0") } - if v.GT(sdk.OneDec()) { - return fmt.Errorf("must be LTE 1.0") + if v.GTE(sdk.OneDec()) { + return fmt.Errorf("must be LT 1.0") } return nil From 88d55bf1e3ec2b94122ae13fbd4970702c8a8c89 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Mon, 1 Aug 2022 13:48:06 +0300 Subject: [PATCH 10/27] Frojdi feedback changes: reading x/rewards ratio params twice removed; Ante handlers reordered; ContractMetadata has ContractAddress in it. Tests fixes --- app/ante.go | 17 +- docs/proto/proto-docs.md | 21 +- e2e/contracts/voter.wasm | Bin 366085 -> 366437 bytes e2e/gastracking_test.go | 8 +- e2e/testing/chain.go | 97 ++++--- e2e/testing/chain_ops_contract.go | 6 +- proto/archway/rewards/v1beta1/genesis.proto | 12 +- proto/archway/rewards/v1beta1/rewards.proto | 6 +- proto/archway/rewards/v1beta1/tx.proto | 4 +- x/gastracker/integration/integration_test.go | 12 +- x/rewards/ante/fee_deduction.go | 25 +- x/rewards/keeper/distribution.go | 14 +- x/rewards/keeper/distribution_test.go | 14 +- x/rewards/keeper/keeper.go | 1 + x/rewards/keeper/msg_server.go | 2 +- x/rewards/keeper/params.go | 10 - x/rewards/keeper/state_metadata.go | 13 +- x/rewards/mintbankkeeper/keeper.go | 5 +- x/rewards/types/genesis.go | 31 +-- x/rewards/types/genesis.pb.go | 276 ++----------------- x/rewards/types/metadata.go | 15 + x/rewards/types/msg.go | 11 +- x/rewards/types/rewards.pb.go | 129 ++++++--- x/rewards/types/tx.pb.go | 87 ++---- 24 files changed, 287 insertions(+), 529 deletions(-) diff --git a/app/ante.go b/app/ante.go index 36b20c29..5b97d8bf 100644 --- a/app/ante.go +++ b/app/ante.go @@ -4,15 +4,16 @@ package app import ( wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" - rewardsAnte "github.com/archway-network/archway/x/rewards/ante" - rewardsKeeper "github.com/archway-network/archway/x/rewards/keeper" - trackingAnte "github.com/archway-network/archway/x/tracking/ante" - trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/cosmos-sdk/x/auth/ante" channelkeeper "github.com/cosmos/ibc-go/v2/modules/core/04-channel/keeper" ibcante "github.com/cosmos/ibc-go/v2/modules/core/ante" + + rewardsAnte "github.com/archway-network/archway/x/rewards/ante" + rewardsKeeper "github.com/archway-network/archway/x/rewards/keeper" + trackingAnte "github.com/archway-network/archway/x/tracking/ante" + trackingKeeper "github.com/archway-network/archway/x/tracking/keeper" ) // HandlerOptions extend the SDK's AnteHandler options by requiring the IBC @@ -61,6 +62,10 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + // Custom Archway interceptor to track new transactions + trackingAnte.NewTxGasTrackingDecorator(options.TrackingKeeper), + // Custom Archway fee deduction, which splits fees between x/rewards and x/auth fee collector + rewardsAnte.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.RewardsKeeper), // SetPubKeyDecorator must be called before all signature verification decorators ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), @@ -68,10 +73,6 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewAnteDecorator(options.IBCChannelkeeper), - // Custom Archway interceptor to track new transactions - trackingAnte.NewTxGasTrackingDecorator(options.TrackingKeeper), - // Custom Archway fee deduction, which splits fees between x/rewards and x/auth fee collector - rewardsAnte.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.RewardsKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index 410ba4a1..6cdc992d 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -46,7 +46,6 @@ - [ContractRewardDistributionEvent](#archway.rewards.v1beta1.ContractRewardDistributionEvent) - [archway/rewards/v1beta1/genesis.proto](#archway/rewards/v1beta1/genesis.proto) - - [GenesisContractMetadata](#archway.rewards.v1beta1.GenesisContractMetadata) - [GenesisState](#archway.rewards.v1beta1.GenesisState) - [archway/rewards/v1beta1/query.proto](#archway/rewards/v1beta1/query.proto) @@ -480,6 +479,7 @@ ContractMetadata defines the contract rewards distribution options for a particu | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | +| `contract_address` | [string](#string) | | contract_address defines the contract address (bech32 encoded). | | `owner_address` | [string](#string) | | owner_address is the contract owner address that can modify contract reward options (bech32 encoded). That could be the contract admin or the contract itself. If owner_address is set to contract address, contract can modify the metadata on its own using WASM bindings. | | `rewards_address` | [string](#string) | | rewards_address is an address to distribute rewards to (bech32 encoded). If not set (empty), rewards are not distributed for this contract. | @@ -606,22 +606,6 @@ This event might not follow the ContractRewardCalculationEvent if the contract h - - -### GenesisContractMetadata -GenesisContractMetadata is used init ContractMetadata state via module genesis. - - -| Field | Type | Label | Description | -| ----- | ---- | ----- | ----------- | -| `contract_address` | [string](#string) | | contract_address defines the contract address. | -| `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata defines the contract metadata. | - - - - - - ### GenesisState @@ -631,7 +615,7 @@ GenesisState defines the initial state of the tracking module. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `params` | [Params](#archway.rewards.v1beta1.Params) | | params defines all the module parameters. | -| `contracts_metadata` | [GenesisContractMetadata](#archway.rewards.v1beta1.GenesisContractMetadata) | repeated | contracts_metadata defines a list of all contracts metadata. | +| `contracts_metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | repeated | contracts_metadata defines a list of all contracts metadata. | | `block_rewards` | [BlockRewards](#archway.rewards.v1beta1.BlockRewards) | repeated | block_rewards defines a list of all block rewards objects. | | `tx_rewards` | [TxRewards](#archway.rewards.v1beta1.TxRewards) | repeated | tx_rewards defines a list of all tx rewards objects. | @@ -799,7 +783,6 @@ MsgSetContractMetadata is the request for Msg.SetContractMetadata. | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | `sender_address` | [string](#string) | | sender_address is the msg sender address (bech32 encoded). | -| `contract_address` | [string](#string) | | contract_address is the target contract address (bech32 encoded). | | `metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | | metadata is the contract metadata to set / update. If metadata exists, non-empty fields will be updated. | diff --git a/e2e/contracts/voter.wasm b/e2e/contracts/voter.wasm index 10ef4f0421107cbd2fbab5c4673f880257006fbe..affe3f6bdf2476512c0e96b1543ef84591d813dd 100755 GIT binary patch delta 25811 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 WLf*T}vpSHT#bN^JZxo;(@c#fvcjp%X delta 25399 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 Mg6J;`FaY@f0412OtN;K2 diff --git a/e2e/gastracking_test.go b/e2e/gastracking_test.go index 09a82ea2..514f8932 100644 --- a/e2e/gastracking_test.go +++ b/e2e/gastracking_test.go @@ -1,14 +1,16 @@ package e2e import ( + "strconv" + "time" + voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + e2eTesting "github.com/archway-network/archway/e2e/testing" rewardsTypes "github.com/archway-network/archway/x/rewards/types" trackingTypes "github.com/archway-network/archway/x/tracking/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "strconv" - "time" ) // TestGasTracking_TxGasConsumption tries to check gas consumption by contract execution, but diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 0cd2f77b..1cc20de4 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -229,11 +229,11 @@ func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain { valSigners: valSigners, accPrivKeys: genAccPrivKeys, } - chain.beginBlock() - chain.endBlock() + chain.BeginBlock() + chain.EndBlock() // Start a new block - chain.beginBlock() + chain.BeginBlock() return &chain } @@ -308,32 +308,74 @@ func (chain *TestChain) GetApp() *app.ArchwayApp { // NextBlock starts a new block with options time shift. func (chain *TestChain) NextBlock(skipTime time.Duration) []abci.Event { - ebEvents := chain.endBlock() + ebEvents := chain.EndBlock() chain.curHeader.Time = chain.curHeader.Time.Add(skipTime) - bbEvents := chain.beginBlock() + bbEvents := chain.BeginBlock() return append(ebEvents, bbEvents...) } +// BeginBlock begins a new block. +func (chain *TestChain) BeginBlock() []abci.Event { + const blockDur = 5 * time.Second + + chain.lastHeader = chain.curHeader + + chain.curHeader.Height++ + chain.curHeader.Time = chain.curHeader.Time.Add(blockDur) + chain.curHeader.AppHash = chain.app.LastCommitID().Hash + chain.curHeader.ValidatorsHash = chain.valSet.Hash() + chain.curHeader.NextValidatorsHash = chain.valSet.Hash() + + res := chain.app.BeginBlock(abci.RequestBeginBlock{Header: chain.curHeader}) + + return res.Events +} + +// EndBlock finalizes the current block. +func (chain *TestChain) EndBlock() []abci.Event { + res := chain.app.EndBlock(abci.RequestEndBlock{Height: chain.curHeader.Height}) + chain.app.Commit() + + return res.Events +} + type SendMsgOption func(opt *sendMsgOptions) type sendMsgOptions struct { - fees sdk.Coins - gasLimit uint64 + fees sdk.Coins + gasLimit uint64 + noBlockChange bool } -func SendMsgWithFees(coins sdk.Coins) SendMsgOption { +// WithMsgFees option add fees to the transaction. +func WithMsgFees(coins sdk.Coins) SendMsgOption { return func(opt *sendMsgOptions) { opt.fees = coins } } +// WithTxGasLimit option overrides the default gas limit for the transaction. +func WithTxGasLimit(limit uint64) SendMsgOption { + return func(opt *sendMsgOptions) { + opt.gasLimit = limit + } +} + +// WithoutBlockChange option disables EndBlocker and BeginBlocker after the transaction. +func WithoutBlockChange() SendMsgOption { + return func(opt *sendMsgOptions) { + opt.noBlockChange = true + } +} + // SendMsgs sends a series of messages. func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg, opts ...SendMsgOption) (sdk.GasInfo, *sdk.Result, []abci.Event, error) { options := &sendMsgOptions{ - fees: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)), - gasLimit: 10_000_000, + fees: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)), + gasLimit: 10_000_000, + noBlockChange: false, } for _, o := range opts { @@ -369,10 +411,14 @@ func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg require.Nil(t, res) } - ebEvents := chain.endBlock() - bbEvents := chain.beginBlock() + var abciEvents []abci.Event + if !options.noBlockChange { + ebEvents := chain.EndBlock() + bbEvents := chain.BeginBlock() + abciEvents = append(ebEvents, bbEvents...) + } - return gasInfo, res, append(ebEvents, bbEvents...), err + return gasInfo, res, abciEvents, err } // ParseSDKResultData converts TX result data into a slice of Msgs. @@ -386,28 +432,3 @@ func (chain *TestChain) ParseSDKResultData(r *sdk.Result) sdk.TxMsgData { return protoResult } - -// beginBlock begins a new block. -func (chain *TestChain) beginBlock() []abci.Event { - const blockDur = 5 * time.Second - - chain.lastHeader = chain.curHeader - - chain.curHeader.Height++ - chain.curHeader.Time = chain.curHeader.Time.Add(blockDur) - chain.curHeader.AppHash = chain.app.LastCommitID().Hash - chain.curHeader.ValidatorsHash = chain.valSet.Hash() - chain.curHeader.NextValidatorsHash = chain.valSet.Hash() - - res := chain.app.BeginBlock(abci.RequestBeginBlock{Header: chain.curHeader}) - - return res.Events -} - -// endBlock finalizes the current block. -func (chain *TestChain) endBlock() []abci.Event { - res := chain.app.EndBlock(abci.RequestEndBlock{Height: chain.curHeader.Height}) - chain.app.Commit() - - return res.Events -} diff --git a/e2e/testing/chain_ops_contract.go b/e2e/testing/chain_ops_contract.go index b16c54a7..2272c9f5 100644 --- a/e2e/testing/chain_ops_contract.go +++ b/e2e/testing/chain_ops_contract.go @@ -117,10 +117,10 @@ func (chain *TestChain) GetContractMetadata(contractAddr sdk.AccAddress) rewards func (chain *TestChain) SetContractMetadata(sender Account, contractAddr sdk.AccAddress, metadata rewardsTypes.ContractMetadata) { t := chain.t + metadata.ContractAddress = contractAddr.String() txMsg := rewardsTypes.MsgSetContractMetadata{ - SenderAddress: sender.Address.String(), - ContractAddress: contractAddr.String(), - Metadata: metadata, + SenderAddress: sender.Address.String(), + Metadata: metadata, } _, _, _, err := chain.SendMsgs(sender, true, []sdk.Msg{&txMsg}) diff --git a/proto/archway/rewards/v1beta1/genesis.proto b/proto/archway/rewards/v1beta1/genesis.proto index 5cabe9f9..40f2bfda 100644 --- a/proto/archway/rewards/v1beta1/genesis.proto +++ b/proto/archway/rewards/v1beta1/genesis.proto @@ -13,7 +13,7 @@ message GenesisState { (gogoproto.nullable) = false ]; // contracts_metadata defines a list of all contracts metadata. - repeated GenesisContractMetadata contracts_metadata = 2 [ + repeated ContractMetadata contracts_metadata = 2 [ (gogoproto.nullable) = false ]; // block_rewards defines a list of all block rewards objects. @@ -25,13 +25,3 @@ message GenesisState { (gogoproto.nullable) = false ]; } - -// GenesisContractMetadata is used init ContractMetadata state via module genesis. -message GenesisContractMetadata { - // contract_address defines the contract address. - string contract_address = 1; - // metadata defines the contract metadata. - ContractMetadata metadata = 2 [ - (gogoproto.nullable) = false - ]; -} diff --git a/proto/archway/rewards/v1beta1/rewards.proto b/proto/archway/rewards/v1beta1/rewards.proto index f454f016..0e07315c 100644 --- a/proto/archway/rewards/v1beta1/rewards.proto +++ b/proto/archway/rewards/v1beta1/rewards.proto @@ -28,13 +28,15 @@ message Params { message ContractMetadata { option (gogoproto.goproto_stringer) = false; + // contract_address defines the contract address (bech32 encoded). + string contract_address = 1; // owner_address is the contract owner address that can modify contract reward options (bech32 encoded). // That could be the contract admin or the contract itself. // If owner_address is set to contract address, contract can modify the metadata on its own using WASM bindings. - string owner_address = 1; + string owner_address = 2; // rewards_address is an address to distribute rewards to (bech32 encoded). // If not set (empty), rewards are not distributed for this contract. - string rewards_address = 2; + string rewards_address = 3; } // BlockRewards defines block related rewards distribution data. diff --git a/proto/archway/rewards/v1beta1/tx.proto b/proto/archway/rewards/v1beta1/tx.proto index 3b415f85..00525648 100644 --- a/proto/archway/rewards/v1beta1/tx.proto +++ b/proto/archway/rewards/v1beta1/tx.proto @@ -17,11 +17,9 @@ service Msg { message MsgSetContractMetadata { // sender_address is the msg sender address (bech32 encoded). string sender_address = 1; - // contract_address is the target contract address (bech32 encoded). - string contract_address = 2; // metadata is the contract metadata to set / update. // If metadata exists, non-empty fields will be updated. - ContractMetadata metadata = 3 [ + ContractMetadata metadata = 2 [ (gogoproto.nullable) = false ]; } diff --git a/x/gastracker/integration/integration_test.go b/x/gastracker/integration/integration_test.go index 5386cc15..4d60dd43 100644 --- a/x/gastracker/integration/integration_test.go +++ b/x/gastracker/integration/integration_test.go @@ -2,15 +2,17 @@ package integration import ( "encoding/json" + "testing" + voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - e2eTesting "github.com/archway-network/archway/e2e/testing" - "github.com/archway-network/archway/x/gastracker" - "github.com/archway-network/archway/x/gastracker/common" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/stretchr/testify/require" - "testing" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/x/gastracker" + "github.com/archway-network/archway/x/gastracker/common" ) func TestRewardsCollection(t *testing.T) { @@ -47,7 +49,7 @@ func TestRewardsCollection(t *testing.T) { Msg: jsonMarshal(t, msg), Funds: sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), }}, - e2eTesting.SendMsgWithFees(txFees), + e2eTesting.WithMsgFees(txFees), ) require.NoError(t, err) diff --git a/x/rewards/ante/fee_deduction.go b/x/rewards/ante/fee_deduction.go index a8cf5386..7d76d5fd 100644 --- a/x/rewards/ante/fee_deduction.go +++ b/x/rewards/ante/fee_deduction.go @@ -8,13 +8,14 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/ante" authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/archway-network/archway/pkg" rewardsTypes "github.com/archway-network/archway/x/rewards/types" ) // RewardsKeeperExpected defines the expected interface for the x/rewards keeper. type RewardsKeeperExpected interface { - TxFeeRewardsEnabled(ctx sdk.Context) bool TxFeeRebateRatio(ctx sdk.Context) sdk.Dec TrackFeeRebatesRewards(ctx sdk.Context, rewards sdk.Coins) } @@ -79,7 +80,7 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo // Deduct the fees if !feeTx.GetFee().IsZero() { - if err := dfd.deductFees(ctx, deductFeesFromAcc, feeTx.GetFee()); err != nil { + if err := dfd.deductFees(ctx, tx, deductFeesFromAcc, feeTx.GetFee()); err != nil { return ctx, err } } @@ -95,15 +96,24 @@ func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bo // deductFees deducts fees from the given account if rewards calculation and distribution is enabled. // If rewards module is disabled, all the fees are sent to the fee collector account. // NOTE: this is the only logic being changed. -func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, acc authTypes.AccountI, fees sdk.Coins) error { - // TODO: we need to identify Msg type to only deduct fees for the WASM operation (not all of them) - +func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, tx sdk.Tx, acc authTypes.AccountI, fees sdk.Coins) error { if !fees.IsValid() { return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFee, "invalid fee amount: %s", fees) } - // Send everything to the fee collector account if rewards are disabled - if !dfd.rewardsKeeper.TxFeeRewardsEnabled(ctx) { + // Check if transaction has wasmd operations + hasWasmMsgs := false + for _, msg := range tx.GetMsgs() { + _, ok := msg.(*wasmdTypes.MsgExecuteContract) + if ok { + hasWasmMsgs = true + break + } + } + + // Send everything to the fee collector account if rewards are disabled or transaction is not wasm related + rebateRatio := dfd.rewardsKeeper.TxFeeRebateRatio(ctx) + if rebateRatio.IsZero() || !hasWasmMsgs { if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, fees); err != nil { return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) } @@ -111,7 +121,6 @@ func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, acc authTypes.AccountI } // Split the fees between the fee collector account and the rewards collector account - rebateRatio := dfd.rewardsKeeper.TxFeeRebateRatio(ctx) authFees, rewardsFees := pkg.SplitCoins(fees, rebateRatio) if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, authFees); err != nil { diff --git a/x/rewards/keeper/distribution.go b/x/rewards/keeper/distribution.go index 908060aa..42c585a4 100644 --- a/x/rewards/keeper/distribution.go +++ b/x/rewards/keeper/distribution.go @@ -205,7 +205,7 @@ func (k Keeper) distributeBlockRewards(ctx sdk.Context, blockDistrState *blockRe Add(contractDistrState.FeeRewards...) if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ContractRewardCollector, rewardsAddr, rewards); err != nil { - panic(fmt.Errorf("sending rewards (%s) to the rewards address (%s) for the contract (%s): %w", contractDistrState.FeeRewards, rewardsAddr, contractDistrState.ContractAddress, err)) + panic(fmt.Errorf("sending rewards (%s) to the rewards address (%s) for the contract (%s): %w", rewards, rewardsAddr, contractDistrState.ContractAddress, err)) } // Emit distribution event @@ -220,6 +220,14 @@ func (k Keeper) distributeBlockRewards(ctx sdk.Context, blockDistrState *blockRe // cleanupTracking prunes all tracking data for the given block height for x/tracking and x/rewards modules. func (k Keeper) cleanupTracking(ctx sdk.Context, height int64) { - k.trackingKeeper.RemoveBlockTrackingInfo(ctx, height) - k.state.DeleteBlockRewardsCascade(ctx, height) + // We can prune the previous block ({height}), but that makes tracking CLI queries useless as there won't be any data. + // Pruning history block also makes e2e tests possible. + // TODO: this should be replaced with a param + heightToPrune := height - 10 + if heightToPrune <= 0 { + return + } + + k.trackingKeeper.RemoveBlockTrackingInfo(ctx, heightToPrune) + k.state.DeleteBlockRewardsCascade(ctx, heightToPrune) } diff --git a/x/rewards/keeper/distribution_test.go b/x/rewards/keeper/distribution_test.go index 21cccad7..94432b1a 100644 --- a/x/rewards/keeper/distribution_test.go +++ b/x/rewards/keeper/distribution_test.go @@ -158,7 +158,7 @@ func TestRewardsKeeper_Distribution(t *testing.T) { { name: "2 txs with contract ops intersection (rewards from both txs)", blockInflationCoin: "1000stake", - blockGasLimit: 1000, + blockGasLimit: 1500, txs: []transactionInput{ { feeCoins: "500stake", @@ -212,15 +212,15 @@ func TestRewardsKeeper_Distribution(t *testing.T) { rewardsAddr: accAddrs[0], // Tx 1 rewards: ~0.43 (450 / 1050 tx gas) = 214stake // Tx 2 rewards: ~0.17 (10 / 60 tx gas) = 100stake - // Inf rewards: 0.46 (460 / 1000 block gas) = 460stake - rewards: "774stake", + // Inf rewards: ~0.30 (460 / 1500 block gas) = 306stake + rewards: "620stake", }, { rewardsAddr: accAddrs[1], // Tx 1 rewards: ~0.57 (600 / 1050 tx gas) = 285stake // Tx 2 rewards: ~0.83 (50 / 60 tx gas) = 499stake - // Inf rewards: 0.65 (650 / 1000 block gas) = 650stake - rewards: "1434stake", + // Inf rewards: ~0.43 (650 / 1500 block gas) = 433stake + rewards: "1217stake", }, }, }, @@ -471,7 +471,7 @@ func TestRewardsKeeper_Distribution(t *testing.T) { // Emulate x/rewards AnteHandler call rKeeper.TrackFeeRebatesRewards(ctx, feeRewards) // Mint and transfer - require.NoError(t, chain.GetApp().MintKeeper.MintCoins(ctx, feeRewards)) + require.NoError(t, chain.GetApp().BankKeeper.MintCoins(ctx, mintTypes.ModuleName, feeRewards)) require.NoError(t, chain.GetApp().BankKeeper.SendCoinsFromModuleToModule(ctx, mintTypes.ModuleName, rewardsTypes.ContractRewardCollector, feeRewards)) } } @@ -485,7 +485,7 @@ func TestRewardsKeeper_Distribution(t *testing.T) { // Emulate x/rewards MintKeeper call rKeeper.TrackInflationRewards(ctx, inflationReward) // Mint and transfer - require.NoError(t, chain.GetApp().MintKeeper.MintCoins(ctx, inflationRewards)) + require.NoError(t, chain.GetApp().BankKeeper.MintCoins(ctx, mintTypes.ModuleName, inflationRewards)) require.NoError(t, chain.GetApp().BankKeeper.SendCoinsFromModuleToModule(ctx, mintTypes.ModuleName, rewardsTypes.ContractRewardCollector, inflationRewards)) } else { // We have to remove it since it was created by the x/mint diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index d7d67567..27fdd738 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -96,6 +96,7 @@ func (k Keeper) SetContractMetadata(ctx sdk.Context, senderAddr, contractAddr sd // Build the updated meta metaNew := metaOld if !metaExists { + metaNew.ContractAddress = contractAddr.String() metaNew.OwnerAddress = senderAddr.String() } if metaUpdates.HasOwnerAddress() { diff --git a/x/rewards/keeper/msg_server.go b/x/rewards/keeper/msg_server.go index e4d19af2..ba533236 100644 --- a/x/rewards/keeper/msg_server.go +++ b/x/rewards/keeper/msg_server.go @@ -37,7 +37,7 @@ func (s MsgServer) SetContractMetadata(c context.Context, request *types.MsgSetC return nil, err // returning error "as is" since this should not happen due to the earlier ValidateBasic call } - contractAddr, err := sdk.AccAddressFromBech32(request.ContractAddress) + contractAddr, err := sdk.AccAddressFromBech32(request.Metadata.ContractAddress) if err != nil { return nil, err // returning error "as is" since this should not happen due to the earlier ValidateBasic call } diff --git a/x/rewards/keeper/params.go b/x/rewards/keeper/params.go index 33446316..b5518cf2 100644 --- a/x/rewards/keeper/params.go +++ b/x/rewards/keeper/params.go @@ -12,22 +12,12 @@ func (k Keeper) InflationRewardsRatio(ctx sdk.Context) (res sdk.Dec) { return } -// InflationRewardsEnabled return inflation rewards enabled flag. -func (k Keeper) InflationRewardsEnabled(ctx sdk.Context) bool { - return !k.InflationRewardsRatio(ctx).IsZero() -} - // TxFeeRebateRatio return tx fee rebate rewards params ratio. func (k Keeper) TxFeeRebateRatio(ctx sdk.Context) (res sdk.Dec) { k.paramStore.Get(ctx, types.TxFeeRebateRatioParamKey, &res) return } -// TxFeeRewardsEnabled return tx fee rewards enabled flag. -func (k Keeper) TxFeeRewardsEnabled(ctx sdk.Context) bool { - return !k.TxFeeRebateRatio(ctx).IsZero() -} - // GetParams return all module parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams( diff --git a/x/rewards/keeper/state_metadata.go b/x/rewards/keeper/state_metadata.go index c72a801a..55908faa 100644 --- a/x/rewards/keeper/state_metadata.go +++ b/x/rewards/keeper/state_metadata.go @@ -38,29 +38,24 @@ func (s ContractMetadataState) GetContractMetadata(contractAddr sdk.AccAddress) } // Import initializes state from the module genesis data. -func (s ContractMetadataState) Import(objs []types.GenesisContractMetadata) { +func (s ContractMetadataState) Import(objs []types.ContractMetadata) { for _, obj := range objs { - s.SetContractMetadata(obj.MustGetContractAddress(), obj.Metadata) + s.SetContractMetadata(obj.MustGetContractAddress(), obj) } } // Export returns the module genesis data for the state. -func (s ContractMetadataState) Export() (objs []types.GenesisContractMetadata) { +func (s ContractMetadataState) Export() (objs []types.ContractMetadata) { store := prefix.NewStore(s.stateStore, types.ContractMetadataPrefix) iterator := store.Iterator(nil, nil) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { - contractAddr := s.parseContractMetadataKey(iterator.Key()) - var obj types.ContractMetadata s.cdc.MustUnmarshal(iterator.Value(), &obj) - objs = append(objs, types.GenesisContractMetadata{ - ContractAddress: contractAddr.String(), - Metadata: obj, - }) + objs = append(objs, obj) } return diff --git a/x/rewards/mintbankkeeper/keeper.go b/x/rewards/mintbankkeeper/keeper.go index ab2b625c..24b11c46 100644 --- a/x/rewards/mintbankkeeper/keeper.go +++ b/x/rewards/mintbankkeeper/keeper.go @@ -15,7 +15,6 @@ var _ mintTypes.BankKeeper = Keeper{} // RewardsKeeperExpected defines the expected interface for the x/rewards keeper. type RewardsKeeperExpected interface { - InflationRewardsEnabled(ctx sdk.Context) bool InflationRewardsRatio(ctx sdk.Context) sdk.Dec TrackInflationRewards(ctx sdk.Context, rewards sdk.Coin) } @@ -39,11 +38,11 @@ func NewKeeper(bk mintTypes.BankKeeper, rk RewardsKeeperExpected) Keeper { func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error { // Perform the split only if the recipient is fee collector (which for instance is always the case) and // inflation rewards are enabled. - if recipientModule != authTypes.FeeCollectorName || !k.rewardsKeeper.InflationRewardsEnabled(ctx) { + ratio := k.rewardsKeeper.InflationRewardsRatio(ctx) + if recipientModule != authTypes.FeeCollectorName || ratio.IsZero() { return k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, amt) } - ratio := k.rewardsKeeper.InflationRewardsRatio(ctx) dappRewards, stakingRewards := pkg.SplitCoins(amt, ratio) // Send to the x/auth fee collector account diff --git a/x/rewards/types/genesis.go b/x/rewards/types/genesis.go index 954e316c..c8c10892 100644 --- a/x/rewards/types/genesis.go +++ b/x/rewards/types/genesis.go @@ -2,12 +2,10 @@ package types import ( "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" ) // NewGenesisState creates a new GenesisState object. -func NewGenesisState(params Params, contractsMetadata []GenesisContractMetadata, blockRewards []BlockRewards, txRewards []TxRewards) *GenesisState { +func NewGenesisState(params Params, contractsMetadata []ContractMetadata, blockRewards []BlockRewards, txRewards []TxRewards) *GenesisState { return &GenesisState{ Params: params, ContractsMetadata: contractsMetadata, @@ -20,7 +18,7 @@ func NewGenesisState(params Params, contractsMetadata []GenesisContractMetadata, func DefaultGenesisState() *GenesisState { return &GenesisState{ Params: DefaultParams(), - ContractsMetadata: []GenesisContractMetadata{}, + ContractsMetadata: []ContractMetadata{}, BlockRewards: []BlockRewards{}, TxRewards: []TxRewards{}, } @@ -34,7 +32,7 @@ func (m GenesisState) Validate() error { contractAddrSet := make(map[string]struct{}) for i, meta := range m.ContractsMetadata { - if err := meta.Validate(); err != nil { + if err := meta.Validate(true); err != nil { return fmt.Errorf("contractsMetadata [%d]: %w", i, err) } @@ -68,26 +66,3 @@ func (m GenesisState) Validate() error { return nil } - -// Validate perform object fields validation. -func (m GenesisContractMetadata) Validate() error { - if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { - return fmt.Errorf("contractAddress: %w", err) - } - if err := m.Metadata.Validate(true); err != nil { - return fmt.Errorf("metadata: %w", err) - } - - return nil -} - -// MustGetContractAddress returns the contract address parsed. -// CONTRACT: panics of error. -func (m GenesisContractMetadata) MustGetContractAddress() sdk.AccAddress { - addr, err := sdk.AccAddressFromBech32(m.ContractAddress) - if err != nil { - panic(fmt.Errorf("invalid contract address: %w", err)) - } - - return addr -} diff --git a/x/rewards/types/genesis.pb.go b/x/rewards/types/genesis.pb.go index 02bad0dc..b3cfd126 100644 --- a/x/rewards/types/genesis.pb.go +++ b/x/rewards/types/genesis.pb.go @@ -28,7 +28,7 @@ type GenesisState struct { // params defines all the module parameters. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` // contracts_metadata defines a list of all contracts metadata. - ContractsMetadata []GenesisContractMetadata `protobuf:"bytes,2,rep,name=contracts_metadata,json=contractsMetadata,proto3" json:"contracts_metadata"` + ContractsMetadata []ContractMetadata `protobuf:"bytes,2,rep,name=contracts_metadata,json=contractsMetadata,proto3" json:"contracts_metadata"` // block_rewards defines a list of all block rewards objects. BlockRewards []BlockRewards `protobuf:"bytes,3,rep,name=block_rewards,json=blockRewards,proto3" json:"block_rewards"` // tx_rewards defines a list of all tx rewards objects. @@ -75,7 +75,7 @@ func (m *GenesisState) GetParams() Params { return Params{} } -func (m *GenesisState) GetContractsMetadata() []GenesisContractMetadata { +func (m *GenesisState) GetContractsMetadata() []ContractMetadata { if m != nil { return m.ContractsMetadata } @@ -96,64 +96,8 @@ func (m *GenesisState) GetTxRewards() []TxRewards { return nil } -// GenesisContractMetadata is used init ContractMetadata state via module genesis. -type GenesisContractMetadata struct { - // contract_address defines the contract address. - ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` - // metadata defines the contract metadata. - Metadata ContractMetadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata"` -} - -func (m *GenesisContractMetadata) Reset() { *m = GenesisContractMetadata{} } -func (m *GenesisContractMetadata) String() string { return proto.CompactTextString(m) } -func (*GenesisContractMetadata) ProtoMessage() {} -func (*GenesisContractMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_cdced50517b403fe, []int{1} -} -func (m *GenesisContractMetadata) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *GenesisContractMetadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_GenesisContractMetadata.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *GenesisContractMetadata) XXX_Merge(src proto.Message) { - xxx_messageInfo_GenesisContractMetadata.Merge(m, src) -} -func (m *GenesisContractMetadata) XXX_Size() int { - return m.Size() -} -func (m *GenesisContractMetadata) XXX_DiscardUnknown() { - xxx_messageInfo_GenesisContractMetadata.DiscardUnknown(m) -} - -var xxx_messageInfo_GenesisContractMetadata proto.InternalMessageInfo - -func (m *GenesisContractMetadata) GetContractAddress() string { - if m != nil { - return m.ContractAddress - } - return "" -} - -func (m *GenesisContractMetadata) GetMetadata() ContractMetadata { - if m != nil { - return m.Metadata - } - return ContractMetadata{} -} - func init() { proto.RegisterType((*GenesisState)(nil), "archway.rewards.v1beta1.GenesisState") - proto.RegisterType((*GenesisContractMetadata)(nil), "archway.rewards.v1beta1.GenesisContractMetadata") } func init() { @@ -161,30 +105,26 @@ func init() { } var fileDescriptor_cdced50517b403fe = []byte{ - // 353 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x4e, 0xf2, 0x40, - 0x10, 0xc7, 0x5b, 0x20, 0xe4, 0x63, 0xe1, 0x8b, 0xba, 0x31, 0x81, 0x70, 0x28, 0x84, 0x84, 0x04, - 0x0e, 0xb6, 0x82, 0x67, 0x0f, 0xe2, 0x81, 0x83, 0x9a, 0x10, 0xf4, 0xe4, 0x85, 0x4c, 0xdb, 0x4d, - 0x21, 0x08, 0x4b, 0x76, 0x47, 0x81, 0xb7, 0xd0, 0xb7, 0xe2, 0x26, 0x47, 0x4f, 0xc6, 0xc0, 0x8b, - 0x18, 0xda, 0xdd, 0x06, 0x0f, 0x7b, 0x6b, 0xff, 0xfd, 0xcd, 0x6f, 0x76, 0xa7, 0x43, 0x9a, 0x20, - 0x82, 0xf1, 0x12, 0xd6, 0x9e, 0x60, 0x4b, 0x10, 0xa1, 0xf4, 0xde, 0x3a, 0x3e, 0x43, 0xe8, 0x78, - 0x11, 0x9b, 0x33, 0x39, 0x91, 0xee, 0x42, 0x70, 0xe4, 0xb4, 0xac, 0x30, 0x57, 0x61, 0xae, 0xc2, - 0xaa, 0xe7, 0x11, 0x8f, 0x78, 0xcc, 0x78, 0x87, 0xa7, 0x04, 0xaf, 0x1a, 0xad, 0xba, 0x3c, 0xc6, - 0x1a, 0x9f, 0x19, 0x52, 0xea, 0x27, 0x7d, 0x1e, 0x11, 0x90, 0xd1, 0x6b, 0x92, 0x5f, 0x80, 0x80, - 0x99, 0xac, 0xd8, 0x75, 0xbb, 0x55, 0xec, 0xd6, 0x5c, 0x43, 0x5f, 0x77, 0x10, 0x63, 0xbd, 0xdc, - 0xe6, 0xbb, 0x66, 0x0d, 0x55, 0x11, 0x65, 0x84, 0x06, 0x7c, 0x8e, 0x02, 0x02, 0x94, 0xa3, 0x19, - 0x43, 0x08, 0x01, 0xa1, 0x92, 0xa9, 0x67, 0x5b, 0xc5, 0xee, 0xa5, 0x51, 0xa5, 0x4e, 0x70, 0xab, - 0x2a, 0x1f, 0x54, 0x9d, 0x72, 0x9f, 0xa5, 0x46, 0xfd, 0x81, 0x0e, 0xc8, 0x7f, 0xff, 0x85, 0x07, - 0xd3, 0x91, 0x32, 0x55, 0xb2, 0x71, 0x87, 0xa6, 0xb1, 0x43, 0xef, 0x40, 0x0f, 0x93, 0x50, 0x69, - 0x4b, 0xfe, 0x51, 0x46, 0xfb, 0x84, 0xe0, 0x2a, 0xd5, 0xe5, 0x62, 0x5d, 0xc3, 0xa8, 0x7b, 0x5a, - 0xfd, 0x75, 0x15, 0x50, 0x07, 0x8d, 0x0f, 0x9b, 0x94, 0x0d, 0xf7, 0xa1, 0x6d, 0x72, 0xaa, 0xef, - 0x32, 0x82, 0x30, 0x14, 0x4c, 0x26, 0x63, 0x2e, 0x0c, 0x4f, 0x74, 0x7e, 0x93, 0xc4, 0xf4, 0x8e, - 0xfc, 0x3b, 0x1a, 0xdf, 0xe1, 0x4f, 0xb4, 0x8d, 0xa7, 0x31, 0xcc, 0x2d, 0x15, 0xf4, 0xee, 0x37, - 0x3b, 0xc7, 0xde, 0xee, 0x1c, 0xfb, 0x67, 0xe7, 0xd8, 0xef, 0x7b, 0xc7, 0xda, 0xee, 0x1d, 0xeb, - 0x6b, 0xef, 0x58, 0xcf, 0xdd, 0x68, 0x82, 0xe3, 0x57, 0xdf, 0x0d, 0xf8, 0xcc, 0x53, 0xfa, 0x8b, - 0x39, 0xc3, 0x25, 0x17, 0x53, 0xfd, 0xee, 0xad, 0xd2, 0x1d, 0xc2, 0xf5, 0x82, 0x49, 0x3f, 0x1f, - 0xaf, 0xce, 0xd5, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x74, 0x11, 0x3c, 0xba, 0xb9, 0x02, 0x00, - 0x00, + // 304 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x31, 0x4f, 0xc2, 0x40, + 0x14, 0xc7, 0x5b, 0x20, 0x24, 0x1e, 0x38, 0x78, 0x31, 0x91, 0x30, 0x1c, 0x84, 0x84, 0x04, 0x07, + 0xef, 0x02, 0xce, 0x2e, 0x38, 0xb0, 0x68, 0x42, 0xd0, 0xc9, 0x41, 0x72, 0x2d, 0x97, 0x42, 0x10, + 0xae, 0xb9, 0x7b, 0xda, 0xf2, 0x2d, 0xfc, 0x58, 0x1d, 0x19, 0x9d, 0x8c, 0x69, 0xbf, 0x88, 0xe1, + 0x7a, 0x6d, 0x74, 0xe8, 0x76, 0xf7, 0x7f, 0xbf, 0xff, 0xef, 0x0d, 0x0f, 0x0d, 0xb9, 0xf2, 0xd7, + 0x11, 0x3f, 0x30, 0x25, 0x22, 0xae, 0x56, 0x9a, 0x7d, 0x8c, 0x3d, 0x01, 0x7c, 0xcc, 0x02, 0xb1, + 0x17, 0x7a, 0xa3, 0x69, 0xa8, 0x24, 0x48, 0x7c, 0x65, 0x31, 0x6a, 0x31, 0x6a, 0xb1, 0xee, 0x65, + 0x20, 0x03, 0x69, 0x18, 0x76, 0x7a, 0xe5, 0x78, 0xb7, 0xd2, 0x5a, 0xd4, 0x0d, 0x36, 0x48, 0x6a, + 0xa8, 0x3d, 0xcb, 0xf7, 0x3c, 0x01, 0x07, 0x81, 0xef, 0x50, 0x33, 0xe4, 0x8a, 0xef, 0x74, 0xc7, + 0xed, 0xbb, 0xa3, 0xd6, 0xa4, 0x47, 0x2b, 0xf6, 0xd2, 0xb9, 0xc1, 0xa6, 0x8d, 0xe4, 0xbb, 0xe7, + 0x2c, 0x6c, 0x09, 0xbf, 0x22, 0xec, 0xcb, 0x3d, 0x28, 0xee, 0x83, 0x5e, 0xee, 0x04, 0xf0, 0x15, + 0x07, 0xde, 0xa9, 0xf5, 0xeb, 0xa3, 0xd6, 0xe4, 0xba, 0x52, 0x75, 0x6f, 0x2b, 0x8f, 0xb6, 0x60, + 0xa5, 0x17, 0xa5, 0xaa, 0x18, 0xe0, 0x39, 0x3a, 0xf7, 0xde, 0xa4, 0xbf, 0x5d, 0x5a, 0x45, 0xa7, + 0x6e, 0xd4, 0xc3, 0x4a, 0xf5, 0xf4, 0x44, 0x2f, 0xf2, 0xd0, 0x6a, 0xdb, 0xde, 0x9f, 0x0c, 0xcf, + 0x10, 0x82, 0xb8, 0xd4, 0x35, 0x8c, 0x6e, 0x50, 0xa9, 0x7b, 0x8e, 0xff, 0xbb, 0xce, 0xa0, 0x0c, + 0x1e, 0x92, 0x94, 0xb8, 0xc7, 0x94, 0xb8, 0x3f, 0x29, 0x71, 0x3f, 0x33, 0xe2, 0x1c, 0x33, 0xe2, + 0x7c, 0x65, 0xc4, 0x79, 0x99, 0x04, 0x1b, 0x58, 0xbf, 0x7b, 0xd4, 0x97, 0x3b, 0x66, 0xc5, 0x37, + 0x7b, 0x01, 0x91, 0x54, 0xdb, 0xe2, 0xcf, 0xe2, 0xf2, 0x50, 0x70, 0x08, 0x85, 0xf6, 0x9a, 0xe6, + 0x3e, 0xb7, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x24, 0x47, 0x7f, 0x24, 0x1e, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -262,46 +202,6 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *GenesisContractMetadata) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *GenesisContractMetadata) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *GenesisContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintGenesis(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if len(m.ContractAddress) > 0 { - i -= len(m.ContractAddress) - copy(dAtA[i:], m.ContractAddress) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.ContractAddress))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -342,21 +242,6 @@ func (m *GenesisState) Size() (n int) { return n } -func (m *GenesisContractMetadata) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.ContractAddress) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - l = m.Metadata.Size() - n += 1 + l + sovGenesis(uint64(l)) - return n -} - func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -454,7 +339,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ContractsMetadata = append(m.ContractsMetadata, GenesisContractMetadata{}) + m.ContractsMetadata = append(m.ContractsMetadata, ContractMetadata{}) if err := m.ContractsMetadata[len(m.ContractsMetadata)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } @@ -548,121 +433,6 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } -func (m *GenesisContractMetadata) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: GenesisContractMetadata: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisContractMetadata: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthGenesis - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthGenesis - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.Metadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipGenesis(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/rewards/types/metadata.go b/x/rewards/types/metadata.go index 6beec313..71f5497b 100644 --- a/x/rewards/types/metadata.go +++ b/x/rewards/types/metadata.go @@ -18,6 +18,17 @@ func (m ContractMetadata) HasRewardsAddress() bool { return m.RewardsAddress != "" } +// MustGetContractAddress returns the contract address. +// CONTRACT: panics in case of an error. +func (m ContractMetadata) MustGetContractAddress() sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(m.ContractAddress) + if err != nil { + panic(fmt.Errorf("parsing contract address: %w", err)) + } + + return addr +} + // MustGetRewardsAddress returns the rewards address. // CONTRACT: panics in case of an error. func (m ContractMetadata) MustGetRewardsAddress() sdk.AccAddress { @@ -32,6 +43,10 @@ func (m ContractMetadata) MustGetRewardsAddress() sdk.AccAddress { // Validate performs object fields validation. // genesisValidation flag perform strict validation of the genesis state (some field must be set). func (m ContractMetadata) Validate(genesisValidation bool) error { + if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { + return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid contract address") + } + if genesisValidation || m.OwnerAddress != "" { if _, err := sdk.AccAddressFromBech32(m.OwnerAddress); err != nil { return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid owner address") diff --git a/x/rewards/types/msg.go b/x/rewards/types/msg.go index d96e6453..4d0cbd8a 100644 --- a/x/rewards/types/msg.go +++ b/x/rewards/types/msg.go @@ -18,9 +18,10 @@ var ( // NewMsgSetContractMetadata creates a new MsgSetContractMetadata instance. func NewMsgSetContractMetadata(senderAddr, contractAddr sdk.AccAddress, ownerAddr, rewardsAddr *sdk.AccAddress) *MsgSetContractMetadata { msg := &MsgSetContractMetadata{ - SenderAddress: senderAddr.String(), - ContractAddress: contractAddr.String(), - Metadata: ContractMetadata{}, + SenderAddress: senderAddr.String(), + Metadata: ContractMetadata{ + ContractAddress: contractAddr.String(), + }, } if ownerAddr != nil { @@ -61,10 +62,6 @@ func (m MsgSetContractMetadata) ValidateBasic() error { return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid sender address") } - if _, err := sdk.AccAddressFromBech32(m.ContractAddress); err != nil { - return sdkErrors.Wrap(sdkErrors.ErrInvalidAddress, "invalid contract address") - } - if err := m.Metadata.Validate(false); err != nil { return err } diff --git a/x/rewards/types/rewards.pb.go b/x/rewards/types/rewards.pb.go index 6ef22f44..e1dafcbb 100644 --- a/x/rewards/types/rewards.pb.go +++ b/x/rewards/types/rewards.pb.go @@ -69,13 +69,15 @@ var xxx_messageInfo_Params proto.InternalMessageInfo // ContractMetadata defines the contract rewards distribution options for a particular contract. type ContractMetadata struct { + // contract_address defines the contract address (bech32 encoded). + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` // owner_address is the contract owner address that can modify contract reward options (bech32 encoded). // That could be the contract admin or the contract itself. // If owner_address is set to contract address, contract can modify the metadata on its own using WASM bindings. - OwnerAddress string `protobuf:"bytes,1,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` + OwnerAddress string `protobuf:"bytes,2,opt,name=owner_address,json=ownerAddress,proto3" json:"owner_address,omitempty"` // rewards_address is an address to distribute rewards to (bech32 encoded). // If not set (empty), rewards are not distributed for this contract. - RewardsAddress string `protobuf:"bytes,2,opt,name=rewards_address,json=rewardsAddress,proto3" json:"rewards_address,omitempty"` + RewardsAddress string `protobuf:"bytes,3,opt,name=rewards_address,json=rewardsAddress,proto3" json:"rewards_address,omitempty"` } func (m *ContractMetadata) Reset() { *m = ContractMetadata{} } @@ -110,6 +112,13 @@ func (m *ContractMetadata) XXX_DiscardUnknown() { var xxx_messageInfo_ContractMetadata proto.InternalMessageInfo +func (m *ContractMetadata) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + func (m *ContractMetadata) GetOwnerAddress() string { if m != nil { return m.OwnerAddress @@ -317,40 +326,41 @@ func init() { } var fileDescriptor_50f478faffe74434 = []byte{ - // 522 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x41, 0x6b, 0x13, 0x41, - 0x14, 0xc7, 0x33, 0xcd, 0x1a, 0xc9, 0xb4, 0xd5, 0xb8, 0x55, 0x53, 0x7b, 0xd8, 0x84, 0x48, 0xb5, - 0x97, 0xce, 0xd2, 0x7a, 0xf3, 0xa4, 0xa9, 0x58, 0x84, 0x0a, 0x32, 0xf4, 0x20, 0x82, 0x2c, 0x6f, - 0x77, 0x67, 0x37, 0x4b, 0xba, 0x3b, 0x65, 0x66, 0x34, 0xd3, 0x9b, 0x1f, 0x41, 0xf0, 0xe2, 0xd1, - 0x8f, 0xe1, 0x47, 0xe8, 0xb1, 0x17, 0x41, 0x3c, 0x14, 0x49, 0xbe, 0x88, 0xec, 0xec, 0x6c, 0x48, - 0xd5, 0x80, 0x78, 0x4a, 0xde, 0xcb, 0x3f, 0xbf, 0xf9, 0xbf, 0xff, 0x9b, 0xc1, 0xdb, 0x20, 0xa2, - 0xd1, 0x04, 0xce, 0x7c, 0xc1, 0x26, 0x20, 0x62, 0xe9, 0xbf, 0xdf, 0x0b, 0x99, 0x82, 0xbd, 0xba, - 0x26, 0xa7, 0x82, 0x2b, 0xee, 0x76, 0xad, 0x8c, 0xd4, 0x6d, 0x2b, 0xdb, 0xba, 0x9d, 0xf2, 0x94, - 0x1b, 0x8d, 0x5f, 0x7e, 0xab, 0xe4, 0x5b, 0x5e, 0xc4, 0x65, 0xce, 0xa5, 0x1f, 0x82, 0x64, 0x73, - 0x62, 0xc4, 0xb3, 0xa2, 0xfa, 0x7d, 0xf0, 0x0d, 0xe1, 0xd6, 0x2b, 0x10, 0x90, 0x4b, 0x37, 0xc1, - 0xdd, 0xac, 0x48, 0x4e, 0x40, 0x65, 0xbc, 0x08, 0x2c, 0x3d, 0x10, 0x65, 0xb9, 0x89, 0xfa, 0x68, - 0xa7, 0x3d, 0x24, 0xe7, 0x97, 0xbd, 0xc6, 0x8f, 0xcb, 0xde, 0x83, 0x34, 0x53, 0xa3, 0x77, 0x21, - 0x89, 0x78, 0xee, 0x5b, 0x7c, 0xf5, 0xb1, 0x2b, 0xe3, 0xb1, 0xaf, 0xce, 0x4e, 0x99, 0x24, 0xcf, - 0x58, 0x44, 0xef, 0xcc, 0x71, 0xb4, 0xa2, 0xd1, 0xb2, 0x70, 0xdf, 0xe2, 0x0d, 0xa5, 0x83, 0x84, - 0xb1, 0x40, 0xb0, 0x10, 0x14, 0xb3, 0x67, 0xac, 0xfc, 0xd7, 0x19, 0x1d, 0xa5, 0x9f, 0x33, 0x46, - 0x0d, 0xc8, 0xe0, 0x1f, 0x3b, 0x9f, 0xbf, 0xf4, 0x1a, 0x83, 0x04, 0x77, 0x0e, 0x78, 0xa1, 0x04, - 0x44, 0xea, 0x25, 0x53, 0x10, 0x83, 0x02, 0xf7, 0x3e, 0x5e, 0xe7, 0x93, 0x82, 0x89, 0x00, 0xe2, - 0x58, 0x30, 0x29, 0xab, 0xb1, 0xe8, 0x9a, 0x69, 0x3e, 0xad, 0x7a, 0xee, 0x43, 0x7c, 0xb3, 0x9e, - 0xbd, 0x96, 0x19, 0x67, 0xf4, 0x86, 0x6d, 0x5b, 0xa1, 0x3d, 0xe7, 0x13, 0xc2, 0x6b, 0xc3, 0x13, - 0x1e, 0x8d, 0xed, 0x88, 0xee, 0x5d, 0xdc, 0x1a, 0xb1, 0x2c, 0x1d, 0x29, 0x43, 0x6f, 0x52, 0x5b, - 0xb9, 0x47, 0xf8, 0xd6, 0x1f, 0xe9, 0x1a, 0xf2, 0xea, 0xfe, 0x3d, 0x52, 0x8d, 0x46, 0xca, 0x25, - 0xd5, 0xfb, 0x24, 0x07, 0x3c, 0x2b, 0x86, 0x4e, 0x19, 0x07, 0xed, 0xfc, 0x1e, 0xa4, 0xdb, 0xc5, - 0xd7, 0x73, 0xd0, 0x41, 0x0a, 0x72, 0xb3, 0xd9, 0x47, 0x3b, 0x0e, 0x6d, 0xe5, 0xa0, 0x0f, 0xa1, - 0x76, 0xf5, 0x01, 0xe1, 0xf6, 0xb1, 0xae, 0xc5, 0x1b, 0xf8, 0x9a, 0xd2, 0x41, 0x16, 0x1b, 0x47, - 0x0e, 0x75, 0x94, 0x7e, 0x11, 0x2f, 0xf8, 0x5c, 0xb9, 0xe2, 0xf3, 0x09, 0x5e, 0xad, 0x56, 0x53, - 0x39, 0x6c, 0xf6, 0x9b, 0xff, 0xe2, 0x10, 0x27, 0xe5, 0x12, 0xcc, 0x5f, 0xac, 0x85, 0xaf, 0x08, - 0xaf, 0x9b, 0x60, 0x8e, 0x05, 0x44, 0xe3, 0xac, 0x48, 0xdd, 0xd7, 0x7f, 0x4b, 0x00, 0x99, 0x04, - 0xb6, 0xc9, 0x92, 0x5b, 0x4d, 0x16, 0xb3, 0x5d, 0x9a, 0xc6, 0x21, 0xc6, 0x4a, 0x2f, 0x84, 0x5a, - 0x5a, 0x1e, 0x2c, 0x45, 0xce, 0x83, 0xb1, 0xbc, 0xb6, 0xd2, 0x57, 0xac, 0x0f, 0x8f, 0xce, 0xa7, - 0x1e, 0xba, 0x98, 0x7a, 0xe8, 0xe7, 0xd4, 0x43, 0x1f, 0x67, 0x5e, 0xe3, 0x62, 0xe6, 0x35, 0xbe, - 0xcf, 0xbc, 0xc6, 0x9b, 0xfd, 0x85, 0x5b, 0x69, 0xf1, 0xbb, 0x05, 0x53, 0x13, 0x2e, 0xc6, 0x75, - 0xed, 0xeb, 0xf9, 0x03, 0x36, 0xb7, 0x34, 0x6c, 0x99, 0x87, 0xf6, 0xe8, 0x57, 0x00, 0x00, 0x00, - 0xff, 0xff, 0x13, 0x0b, 0x1c, 0xb3, 0xe0, 0x03, 0x00, 0x00, + // 533 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0xcd, 0x6e, 0xd3, 0x40, + 0x14, 0x85, 0x33, 0x4d, 0x08, 0xca, 0xb4, 0xa5, 0xc1, 0x05, 0x02, 0x5d, 0x38, 0x55, 0x50, 0xf9, + 0x59, 0x74, 0xac, 0x96, 0x1d, 0x2b, 0x48, 0x11, 0x15, 0x52, 0x91, 0xd0, 0xa8, 0x0b, 0x84, 0x84, + 0xac, 0x1b, 0x7b, 0xe2, 0x58, 0xa9, 0x3d, 0xd5, 0x78, 0x20, 0xd3, 0x1d, 0x8f, 0x00, 0x62, 0xc3, + 0x92, 0xc7, 0xe0, 0x11, 0xba, 0xec, 0x06, 0x09, 0xb1, 0xa8, 0x50, 0xf2, 0x22, 0xc8, 0xf3, 0x63, + 0xa5, 0x40, 0x24, 0xd4, 0x55, 0x72, 0xaf, 0x8f, 0xcf, 0x7c, 0x3e, 0x77, 0x2e, 0xde, 0x02, 0x11, + 0x8d, 0x26, 0x70, 0x12, 0x08, 0x36, 0x01, 0x11, 0x17, 0xc1, 0xfb, 0x9d, 0x01, 0x93, 0xb0, 0xe3, + 0x6a, 0x72, 0x2c, 0xb8, 0xe4, 0x5e, 0xc7, 0xca, 0x88, 0x6b, 0x5b, 0xd9, 0xc6, 0x8d, 0x84, 0x27, + 0x5c, 0x6b, 0x82, 0xf2, 0x9f, 0x91, 0x6f, 0xf8, 0x11, 0x2f, 0x32, 0x5e, 0x04, 0x03, 0x28, 0x58, + 0xe5, 0x18, 0xf1, 0x34, 0x37, 0xcf, 0x7b, 0xdf, 0x11, 0x6e, 0xbe, 0x02, 0x01, 0x59, 0xe1, 0x0d, + 0x71, 0x27, 0xcd, 0x87, 0x47, 0x20, 0x53, 0x9e, 0x87, 0xd6, 0x3d, 0x14, 0x65, 0x79, 0x1b, 0x6d, + 0xa2, 0x07, 0xad, 0x3e, 0x39, 0x3d, 0xef, 0xd6, 0x7e, 0x9e, 0x77, 0xef, 0x25, 0xa9, 0x1c, 0xbd, + 0x1b, 0x90, 0x88, 0x67, 0x81, 0xb5, 0x37, 0x3f, 0xdb, 0x45, 0x3c, 0x0e, 0xe4, 0xc9, 0x31, 0x2b, + 0xc8, 0x33, 0x16, 0xd1, 0x9b, 0x95, 0x1d, 0x35, 0x6e, 0xb4, 0x2c, 0xbc, 0xb7, 0x78, 0x5d, 0xaa, + 0x70, 0xc8, 0x58, 0x28, 0xd8, 0x00, 0x24, 0xb3, 0x67, 0x2c, 0x5d, 0xea, 0x8c, 0xb6, 0x54, 0xcf, + 0x19, 0xa3, 0xda, 0x48, 0xdb, 0x3f, 0x6e, 0x7c, 0xf9, 0xda, 0xad, 0xf5, 0x3e, 0x21, 0xdc, 0xde, + 0xe3, 0xb9, 0x14, 0x10, 0xc9, 0x97, 0x4c, 0x42, 0x0c, 0x12, 0xbc, 0x87, 0xb8, 0x1d, 0xd9, 0x5e, + 0x08, 0x71, 0x2c, 0x58, 0x51, 0x98, 0x4f, 0xa3, 0x6b, 0xae, 0xff, 0xd4, 0xb4, 0xbd, 0xbb, 0x78, + 0x95, 0x4f, 0x72, 0x26, 0x2a, 0x9d, 0xc6, 0xa3, 0x2b, 0xba, 0xe9, 0x44, 0xf7, 0xf1, 0x9a, 0xcb, + 0xc9, 0xc9, 0xea, 0x5a, 0x76, 0xcd, 0xb6, 0xad, 0xd0, 0x32, 0x7d, 0x46, 0x78, 0xa5, 0x7f, 0xc4, + 0xa3, 0xb1, 0x8d, 0xc3, 0xbb, 0x85, 0x9b, 0x23, 0x96, 0x26, 0x23, 0xa9, 0x29, 0xea, 0xd4, 0x56, + 0xde, 0x01, 0xbe, 0xfe, 0xd7, 0x24, 0x34, 0xc0, 0xf2, 0xee, 0x1d, 0x62, 0x62, 0x20, 0xe5, 0x40, + 0xdd, 0xec, 0xc9, 0x1e, 0x4f, 0xf3, 0x7e, 0xa3, 0x8c, 0x8e, 0xb6, 0xff, 0x0c, 0xdd, 0xeb, 0xe0, + 0xab, 0x19, 0xa8, 0x30, 0x01, 0x43, 0xd7, 0xa0, 0xcd, 0x0c, 0xd4, 0x3e, 0x38, 0xaa, 0x0f, 0x08, + 0xb7, 0x0e, 0x95, 0x13, 0xaf, 0xe3, 0x2b, 0x52, 0x85, 0x69, 0xac, 0x89, 0x1a, 0xb4, 0x21, 0xd5, + 0x8b, 0x78, 0x8e, 0x73, 0xe9, 0x02, 0xe7, 0x13, 0xbc, 0x6c, 0xc6, 0x68, 0x08, 0xeb, 0x9b, 0xf5, + 0xff, 0x21, 0xc4, 0xc3, 0x72, 0x60, 0xfa, 0x15, 0x8b, 0xf0, 0x0d, 0xe1, 0x55, 0x1d, 0xcc, 0xa1, + 0x80, 0x68, 0x9c, 0xe6, 0x89, 0xf7, 0xfa, 0x5f, 0x09, 0x20, 0x9d, 0xc0, 0x16, 0x59, 0xb0, 0x01, + 0x64, 0x3e, 0xdb, 0x85, 0x69, 0xec, 0x63, 0x2c, 0xd5, 0x5c, 0xa8, 0x25, 0x72, 0x6f, 0xa1, 0x65, + 0x15, 0x8c, 0xf5, 0x6b, 0x49, 0x75, 0x01, 0xbd, 0x7f, 0x70, 0x3a, 0xf5, 0xd1, 0xd9, 0xd4, 0x47, + 0xbf, 0xa6, 0x3e, 0xfa, 0x38, 0xf3, 0x6b, 0x67, 0x33, 0xbf, 0xf6, 0x63, 0xe6, 0xd7, 0xde, 0xec, + 0xce, 0xdd, 0x60, 0x6b, 0xbf, 0x9d, 0x33, 0x39, 0xe1, 0x62, 0xec, 0xea, 0x40, 0x55, 0xcb, 0xae, + 0x6f, 0xf4, 0xa0, 0xa9, 0x97, 0xf2, 0xd1, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x44, 0x4b, + 0xf2, 0x0c, 0x04, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -421,13 +431,20 @@ func (m *ContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.RewardsAddress) i = encodeVarintRewards(dAtA, i, uint64(len(m.RewardsAddress))) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a } if len(m.OwnerAddress) > 0 { i -= len(m.OwnerAddress) copy(dAtA[i:], m.OwnerAddress) i = encodeVarintRewards(dAtA, i, uint64(len(m.OwnerAddress))) i-- + dAtA[i] = 0x12 + } + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintRewards(dAtA, i, uint64(len(m.ContractAddress))) + i-- dAtA[i] = 0xa } return len(dAtA) - i, nil @@ -600,6 +617,10 @@ func (m *ContractMetadata) Size() (n int) { } var l int _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovRewards(uint64(l)) + } l = len(m.OwnerAddress) if l > 0 { n += 1 + l + sovRewards(uint64(l)) @@ -820,6 +841,38 @@ func (m *ContractMetadata) Unmarshal(dAtA []byte) error { } switch fieldNum { case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRewards + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthRewards + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRewards + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field OwnerAddress", wireType) } @@ -851,7 +904,7 @@ func (m *ContractMetadata) Unmarshal(dAtA []byte) error { } m.OwnerAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field RewardsAddress", wireType) } diff --git a/x/rewards/types/tx.pb.go b/x/rewards/types/tx.pb.go index cfecef4d..31c75a51 100644 --- a/x/rewards/types/tx.pb.go +++ b/x/rewards/types/tx.pb.go @@ -32,11 +32,9 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type MsgSetContractMetadata struct { // sender_address is the msg sender address (bech32 encoded). SenderAddress string `protobuf:"bytes,1,opt,name=sender_address,json=senderAddress,proto3" json:"sender_address,omitempty"` - // contract_address is the target contract address (bech32 encoded). - ContractAddress string `protobuf:"bytes,2,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` // metadata is the contract metadata to set / update. // If metadata exists, non-empty fields will be updated. - Metadata ContractMetadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata"` + Metadata ContractMetadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata"` } func (m *MsgSetContractMetadata) Reset() { *m = MsgSetContractMetadata{} } @@ -79,13 +77,6 @@ func (m *MsgSetContractMetadata) GetSenderAddress() string { return "" } -func (m *MsgSetContractMetadata) GetContractAddress() string { - if m != nil { - return m.ContractAddress - } - return "" -} - func (m *MsgSetContractMetadata) GetMetadata() ContractMetadata { if m != nil { return m.Metadata @@ -138,26 +129,25 @@ func init() { func init() { proto.RegisterFile("archway/rewards/v1beta1/tx.proto", fileDescriptor_cda0f3b1281e62e0) } var fileDescriptor_cda0f3b1281e62e0 = []byte{ - // 303 bytes of a gzipped FileDescriptorProto + // 287 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0x2c, 0x4a, 0xce, 0x28, 0x4f, 0xac, 0xd4, 0x2f, 0x4a, 0x2d, 0x4f, 0x2c, 0x4a, 0x29, 0xd6, 0x2f, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x87, 0xaa, 0xd0, 0x83, 0xaa, 0xd0, 0x83, 0xaa, 0x90, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xab, 0xd1, 0x07, - 0xb1, 0x20, 0xca, 0xa5, 0x54, 0x71, 0x19, 0x08, 0xd3, 0x0e, 0x56, 0xa6, 0xb4, 0x9d, 0x91, 0x4b, - 0xcc, 0xb7, 0x38, 0x3d, 0x38, 0xb5, 0xc4, 0x39, 0x3f, 0xaf, 0xa4, 0x28, 0x31, 0xb9, 0xc4, 0x37, - 0xb5, 0x24, 0x31, 0x25, 0xb1, 0x24, 0x51, 0x48, 0x95, 0x8b, 0xaf, 0x38, 0x35, 0x2f, 0x25, 0xb5, - 0x28, 0x3e, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x58, 0x82, 0x51, 0x81, 0x51, 0x83, 0x33, 0x88, - 0x17, 0x22, 0xea, 0x08, 0x11, 0x14, 0xd2, 0xe4, 0x12, 0x48, 0x86, 0x6a, 0x85, 0x2b, 0x64, 0x02, - 0x2b, 0xe4, 0x87, 0x89, 0xc3, 0x94, 0x7a, 0x73, 0x71, 0xe4, 0x42, 0x4d, 0x97, 0x60, 0x56, 0x60, - 0xd4, 0xe0, 0x36, 0xd2, 0xd4, 0xc3, 0xe1, 0x2b, 0x3d, 0x74, 0xe7, 0x38, 0xb1, 0x9c, 0xb8, 0x27, - 0xcf, 0x10, 0x04, 0x37, 0x40, 0x49, 0x81, 0x4b, 0x0e, 0xbb, 0xc3, 0x83, 0x52, 0x8b, 0x0b, 0xf2, - 0xf3, 0x8a, 0x53, 0x8d, 0xda, 0x18, 0xb9, 0x98, 0x7d, 0x8b, 0xd3, 0x85, 0xea, 0xb9, 0x84, 0xb1, - 0xf9, 0x4f, 0x1f, 0xa7, 0xdd, 0xd8, 0xcd, 0x95, 0x32, 0x27, 0x51, 0x03, 0xcc, 0x21, 0x4e, 0x3e, - 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, - 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x94, 0x9e, 0x59, 0x92, 0x51, - 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x0f, 0x35, 0x5c, 0x37, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, - 0x1b, 0xc6, 0xd7, 0xaf, 0x80, 0x47, 0x61, 0x49, 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x38, 0xe6, - 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x07, 0x6d, 0x7d, 0xff, 0x33, 0x02, 0x00, 0x00, + 0xb1, 0x20, 0xca, 0xa5, 0x54, 0x71, 0x19, 0x08, 0xd3, 0x0e, 0x56, 0xa6, 0xd4, 0xc3, 0xc8, 0x25, + 0xe6, 0x5b, 0x9c, 0x1e, 0x9c, 0x5a, 0xe2, 0x9c, 0x9f, 0x57, 0x52, 0x94, 0x98, 0x5c, 0xe2, 0x9b, + 0x5a, 0x92, 0x98, 0x92, 0x58, 0x92, 0x28, 0xa4, 0xca, 0xc5, 0x57, 0x9c, 0x9a, 0x97, 0x92, 0x5a, + 0x14, 0x9f, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x2c, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x19, 0xc4, + 0x0b, 0x11, 0x75, 0x84, 0x08, 0x0a, 0x79, 0x73, 0x71, 0xe4, 0x42, 0xb5, 0x48, 0x30, 0x29, 0x30, + 0x6a, 0x70, 0x1b, 0x69, 0xea, 0xe1, 0x70, 0xaa, 0x1e, 0xba, 0x1d, 0x4e, 0x2c, 0x27, 0xee, 0xc9, + 0x33, 0x04, 0xc1, 0x0d, 0x50, 0x52, 0xe0, 0x92, 0xc3, 0xee, 0x9a, 0xa0, 0xd4, 0xe2, 0x82, 0xfc, + 0xbc, 0xe2, 0x54, 0xa3, 0x36, 0x46, 0x2e, 0x66, 0xdf, 0xe2, 0x74, 0xa1, 0x7a, 0x2e, 0x61, 0x6c, + 0x8e, 0xd6, 0xc7, 0x69, 0x37, 0x76, 0x73, 0xa5, 0xcc, 0x49, 0xd4, 0x00, 0x73, 0x88, 0x93, 0xcf, + 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, + 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x19, 0xa5, 0x67, 0x96, 0x64, 0x94, + 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x43, 0x0d, 0xd7, 0xcd, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, 0xca, + 0x86, 0xf1, 0xf5, 0x2b, 0xe0, 0xf1, 0x52, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, 0x06, 0x8e, 0x0e, + 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x64, 0xc3, 0xa1, 0x49, 0x08, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -273,14 +263,7 @@ func (m *MsgSetContractMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) i = encodeVarintTx(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - if len(m.ContractAddress) > 0 { - i -= len(m.ContractAddress) - copy(dAtA[i:], m.ContractAddress) - i = encodeVarintTx(dAtA, i, uint64(len(m.ContractAddress))) - i-- - dAtA[i] = 0x12 - } + dAtA[i] = 0x12 if len(m.SenderAddress) > 0 { i -= len(m.SenderAddress) copy(dAtA[i:], m.SenderAddress) @@ -335,10 +318,6 @@ func (m *MsgSetContractMetadata) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ContractAddress) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } l = m.Metadata.Size() n += 1 + l + sovTx(uint64(l)) return n @@ -421,38 +400,6 @@ func (m *MsgSetContractMetadata) Unmarshal(dAtA []byte) error { m.SenderAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.ContractAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) } From 13e9a528759d27539891823611b42f2bbac72208 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Mon, 1 Aug 2022 15:54:30 +0300 Subject: [PATCH 11/27] x/rewards: Ante handler tests added --- pkg/testutils/ante.go | 10 ++ pkg/testutils/msg.go | 36 ++++ pkg/testutils/tx.go | 80 +++++++++ .../testutils/wasm_op.go | 30 +--- pkg/testutils/wasmd.go | 36 ++++ x/rewards/ante/fee_deduction.go | 2 +- x/rewards/ante/fee_deduction_test.go | 170 ++++++++++++++++++ x/rewards/keeper/distribution_test.go | 5 +- x/rewards/mintbankkeeper/keeper_test.go | 11 +- 9 files changed, 338 insertions(+), 42 deletions(-) create mode 100644 pkg/testutils/ante.go create mode 100644 pkg/testutils/msg.go create mode 100644 pkg/testutils/tx.go rename x/rewards/keeper/common_test.go => pkg/testutils/wasm_op.go (52%) create mode 100644 pkg/testutils/wasmd.go create mode 100644 x/rewards/ante/fee_deduction_test.go diff --git a/pkg/testutils/ante.go b/pkg/testutils/ante.go new file mode 100644 index 00000000..c5fd2ab5 --- /dev/null +++ b/pkg/testutils/ante.go @@ -0,0 +1,10 @@ +package testutils + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// NoopAnteHandler implements the no-op AnteHandler. +func NoopAnteHandler(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + return ctx, nil +} diff --git a/pkg/testutils/msg.go b/pkg/testutils/msg.go new file mode 100644 index 00000000..4409e84b --- /dev/null +++ b/pkg/testutils/msg.go @@ -0,0 +1,36 @@ +package testutils + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.Msg = (*MockMsg)(nil) + +// MockMsg is a dummy sdk.Msg. +type MockMsg struct{} + +// NewMockMsg creates a new MockMsg. +func NewMockMsg() *MockMsg { + return &MockMsg{} +} + +// Reset implements the proto.Message interface. +func (msg MockMsg) Reset() {} + +// String implements the proto.Message interface. +func (msg MockMsg) String() string { + return "" +} + +// ProtoMessage implements the proto.Message interface. +func (msg MockMsg) ProtoMessage() {} + +// ValidateBasic implements the sdk.Msg interface. +func (msg MockMsg) ValidateBasic() error { + return nil +} + +// GetSigners implements the sdk.Msg interface. +func (msg MockMsg) GetSigners() []sdk.AccAddress { + return nil +} diff --git a/pkg/testutils/tx.go b/pkg/testutils/tx.go new file mode 100644 index 00000000..5ff42275 --- /dev/null +++ b/pkg/testutils/tx.go @@ -0,0 +1,80 @@ +package testutils + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.FeeTx = MockFeeTx{} + +// MockFeeTx is a mock implementation of sdk.FeeTx. +type MockFeeTx struct { + fees sdk.Coins + gas uint64 + msgs []sdk.Msg + feePayer sdk.AccAddress + feeGranter sdk.AccAddress +} + +type MockFeeTxOption func(tx *MockFeeTx) + +// WithMockFeeTxFees option sets the fees of the MockFeeTx. +func WithMockFeeTxFees(fees sdk.Coins) MockFeeTxOption { + return func(tx *MockFeeTx) { + tx.fees = fees + } +} + +// WithMockFeeTxMsgs option sets the msgs of the MockFeeTx. +func WithMockFeeTxMsgs(msgs ...sdk.Msg) MockFeeTxOption { + return func(tx *MockFeeTx) { + tx.msgs = msgs + } +} + +// WithMockFeeTxPayer option sets the feePayer of the MockFeeTx. +func WithMockFeeTxPayer(payer sdk.AccAddress) MockFeeTxOption { + return func(tx *MockFeeTx) { + tx.feePayer = payer + } +} + +// NewMockFeeTx creates a new MockFeeTx instance. +// CONTRACT: tx has no defaults, so it is up to a developer to set options right. +func NewMockFeeTx(opts ...MockFeeTxOption) MockFeeTx { + tx := MockFeeTx{} + for _, opt := range opts { + opt(&tx) + } + + return tx +} + +// GetMsgs implemets the sdk.Tx interface. +func (tx MockFeeTx) GetMsgs() []sdk.Msg { + return tx.msgs +} + +// ValidateBasic implemets the sdk.Tx interface. +func (tx MockFeeTx) ValidateBasic() error { + return nil +} + +// GetGas implements the sdk.FeeTx interface. +func (tx MockFeeTx) GetGas() uint64 { + return tx.gas +} + +// GetFee implements the sdk.FeeTx interface. +func (tx MockFeeTx) GetFee() sdk.Coins { + return tx.fees +} + +// FeePayer implements the sdk.FeeTx interface. +func (tx MockFeeTx) FeePayer() sdk.AccAddress { + return tx.feePayer +} + +// FeeGranter implements the sdk.FeeTx interface. +func (tx MockFeeTx) FeeGranter() sdk.AccAddress { + return tx.feeGranter +} diff --git a/x/rewards/keeper/common_test.go b/pkg/testutils/wasm_op.go similarity index 52% rename from x/rewards/keeper/common_test.go rename to pkg/testutils/wasm_op.go index ff417ef0..8add7c5b 100644 --- a/x/rewards/keeper/common_test.go +++ b/pkg/testutils/wasm_op.go @@ -1,10 +1,9 @@ -package keeper_test +package testutils import ( "math/rand" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" - sdk "github.com/cosmos/cosmos-sdk/types" ) var allContractOperationTypes = []uint64{ @@ -23,33 +22,6 @@ var allContractOperationTypes = []uint64{ wasmdTypes.ContractOperationUnknown, } -// mockContractViewer mocks x/wasmd module dependency. -type mockContractViewer struct { - contractAdminSet map[string]string // key: contractAddr, value: adminAddr -} - -func newMockContractViewer() *mockContractViewer { - return &mockContractViewer{ - contractAdminSet: make(map[string]string), - } -} - -// AddContractAdmin adds a contract admin link. -func (v *mockContractViewer) AddContractAdmin(contractAddr, adminAddr string) { - v.contractAdminSet[contractAddr] = adminAddr -} - -func (v mockContractViewer) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmdTypes.ContractInfo { - adminAddr, found := v.contractAdminSet[contractAddress.String()] - if !found { - return nil - } - - return &wasmdTypes.ContractInfo{ - Admin: adminAddr, - } -} - // GetRandomContractOperationType returns a random wasmd contract operation type. func GetRandomContractOperationType() uint64 { idx := rand.Intn(len(allContractOperationTypes)) diff --git a/pkg/testutils/wasmd.go b/pkg/testutils/wasmd.go new file mode 100644 index 00000000..114703a8 --- /dev/null +++ b/pkg/testutils/wasmd.go @@ -0,0 +1,36 @@ +package testutils + +import ( + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// MockContractViewer mocks x/wasmd module dependency. +// Mock returns a contract info if admin is set. +type MockContractViewer struct { + contractAdminSet map[string]string // key: contractAddr, value: adminAddr +} + +// NewMockContractViewer creates a new MockContractViewer instance. +func NewMockContractViewer() *MockContractViewer { + return &MockContractViewer{ + contractAdminSet: make(map[string]string), + } +} + +// AddContractAdmin adds a contract admin link. +func (v *MockContractViewer) AddContractAdmin(contractAddr, adminAddr string) { + v.contractAdminSet[contractAddr] = adminAddr +} + +// GetContractInfo returns a contract info if admin is set. +func (v MockContractViewer) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *wasmdTypes.ContractInfo { + adminAddr, found := v.contractAdminSet[contractAddress.String()] + if !found { + return nil + } + + return &wasmdTypes.ContractInfo{ + Admin: adminAddr, + } +} diff --git a/x/rewards/ante/fee_deduction.go b/x/rewards/ante/fee_deduction.go index 7d76d5fd..f7461fa8 100644 --- a/x/rewards/ante/fee_deduction.go +++ b/x/rewards/ante/fee_deduction.go @@ -121,7 +121,7 @@ func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, tx sdk.Tx, acc authTyp } // Split the fees between the fee collector account and the rewards collector account - authFees, rewardsFees := pkg.SplitCoins(fees, rebateRatio) + rewardsFees, authFees := pkg.SplitCoins(fees, rebateRatio) if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, authFees); err != nil { return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) diff --git a/x/rewards/ante/fee_deduction_test.go b/x/rewards/ante/fee_deduction_test.go new file mode 100644 index 00000000..a1bd8a50 --- /dev/null +++ b/x/rewards/ante/fee_deduction_test.go @@ -0,0 +1,170 @@ +package ante_test + +import ( + "testing" + + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authTypes "github.com/cosmos/cosmos-sdk/x/auth/types" + mintTypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg/testutils" + "github.com/archway-network/archway/x/rewards/ante" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestRewardsFeeDeductionAnteHandler(t *testing.T) { + type testCase struct { + name string + // Inputs + feeRebateRatio string // fee rebate rewards ratio (could be 0 to skip the deduction) [sdk.Dec] + feeCoins sdk.Coins // transaction fees (might be invalid) + txMsgs []sdk.Msg // transaction messages + // Output expected + errExpected bool + rewardRecordExpected bool // reward record expected to be created + feeCollectorBalanceDiffExpected string // expected FeeCollector module balance diff [sdk.Coins] + rewardsBalanceDiffExpected string // expected x/rewards module balance diff [sdk.Coins] + } + + mockWasmExecuteMsg := &wasmdTypes.MsgExecuteContract{} + + newStakeCoin := func(amt uint64) sdk.Coin { + return sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewIntFromUint64(amt)) + } + newArchCoin := func(amt uint64) sdk.Coin { + return sdk.NewCoin("uarch", sdk.NewIntFromUint64(amt)) + } + newInvalidCoin := func() sdk.Coin { + return sdk.Coin{Denom: "", Amount: sdk.OneInt()} + } + + testCases := []testCase{ + { + name: "OK: 1000stake fees with 0.5 ratio", + feeRebateRatio: "0.5", + feeCoins: sdk.Coins{newStakeCoin(1000)}, + txMsgs: []sdk.Msg{ + testutils.NewMockMsg(), + mockWasmExecuteMsg, + }, + rewardRecordExpected: true, + feeCollectorBalanceDiffExpected: "500stake", + rewardsBalanceDiffExpected: "500stake", + }, + { + name: "OK: 1000stake,500uarch fees with 0.1 ratio", + feeRebateRatio: "0.1", + feeCoins: sdk.Coins{newStakeCoin(1000), newArchCoin(500)}, + txMsgs: []sdk.Msg{ + testutils.NewMockMsg(), + mockWasmExecuteMsg, + }, + rewardRecordExpected: true, + feeCollectorBalanceDiffExpected: "900stake,450uarch", + rewardsBalanceDiffExpected: "100stake,50uarch", + }, + { + name: "OK: 1000stake fees with 0.5 ratio (no WASM msgs, rewards are skipped)", + feeRebateRatio: "0.5", + feeCoins: sdk.Coins{newStakeCoin(1000)}, + txMsgs: []sdk.Msg{ + testutils.NewMockMsg(), + }, + rewardRecordExpected: false, + feeCollectorBalanceDiffExpected: "1000stake", + rewardsBalanceDiffExpected: "", + }, + { + name: "OK: 1000stake fees with 0 ratio (rewards are skipped)", + feeRebateRatio: "0", + feeCoins: sdk.Coins{newStakeCoin(1000)}, + txMsgs: []sdk.Msg{ + testutils.NewMockMsg(), + mockWasmExecuteMsg, + }, + rewardRecordExpected: false, + feeCollectorBalanceDiffExpected: "1000stake", + rewardsBalanceDiffExpected: "", + }, + { + name: "Fail: invalid fees", + feeRebateRatio: "0.5", + feeCoins: sdk.Coins{newInvalidCoin()}, + txMsgs: []sdk.Msg{ + testutils.NewMockMsg(), + mockWasmExecuteMsg, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create chain + feeRewardsRatio, err := sdk.NewDecFromStr(tc.feeRebateRatio) + require.NoError(t, err) + + chain := e2eTesting.NewTestChain(t, 1, + e2eTesting.WithTxFeeRebatesRewardsRatio(feeRewardsRatio), + ) + acc := chain.GetAccount(0) + ctx := chain.GetContext() + + // Mint coins for account + if err := tc.feeCoins.Validate(); err == nil { + require.NoError(t, chain.GetApp().BankKeeper.MintCoins(ctx, mintTypes.ModuleName, tc.feeCoins)) + require.NoError(t, chain.GetApp().BankKeeper.SendCoinsFromModuleToAccount(ctx, mintTypes.ModuleName, acc.Address, tc.feeCoins)) + } + + // Fetch initial balances + feeCollectorBalanceBefore := chain.GetModuleBalance(authTypes.FeeCollectorName) + rewardsBalanceBefore := chain.GetModuleBalance(rewardsTypes.ModuleName) + + // Build transaction + tx := testutils.NewMockFeeTx( + testutils.WithMockFeeTxFees(tc.feeCoins), + testutils.WithMockFeeTxPayer(acc.Address), + testutils.WithMockFeeTxMsgs(tc.txMsgs...), + ) + + // Call the deduction Ante handler manually + anteHandler := ante.NewDeductFeeDecorator(chain.GetApp().AccountKeeper, chain.GetApp().BankKeeper, chain.GetApp().FeeGrantKeeper, chain.GetApp().RewardsKeeper) + _, err = anteHandler.AnteHandle(ctx, tx, false, testutils.NoopAnteHandler) + if tc.errExpected { + require.Error(t, err) + return + } + require.NoError(t, err) + + // Check final balances + feeCollectorBalanceAfter := chain.GetModuleBalance(authTypes.FeeCollectorName) + rewardsBalanceAfter := chain.GetModuleBalance(rewardsTypes.ModuleName) + + feeCollectorBalanceDiffReceived := feeCollectorBalanceAfter.Sub(feeCollectorBalanceBefore) // positive + rewardsBalanceDiffReceived := rewardsBalanceAfter.Sub(rewardsBalanceBefore) // positive + + feeCollectorBalanceDiffExpected, err := sdk.ParseCoinsNormalized(tc.feeCollectorBalanceDiffExpected) + require.NoError(t, err) + rewardsBalanceDiffExpected, err := sdk.ParseCoinsNormalized(tc.rewardsBalanceDiffExpected) + require.NoError(t, err) + + assert.Equal(t, feeCollectorBalanceDiffExpected.String(), feeCollectorBalanceDiffReceived.String()) + assert.Equal(t, rewardsBalanceDiffExpected.String(), rewardsBalanceDiffReceived.String()) + + // Check rewards record + if tc.rewardRecordExpected { + txID := chain.GetApp().TrackingKeeper.GetCurrentTxID(ctx) + rewardsRecordsReceived, found := chain.GetApp().RewardsKeeper.GetState().TxRewardsState(ctx).GetTxRewards(txID) + require.True(t, found) + + assert.Equal(t, txID, rewardsRecordsReceived.TxId) + assert.Equal(t, ctx.BlockHeight(), rewardsRecordsReceived.Height) + assert.ElementsMatch(t, rewardsBalanceDiffExpected, rewardsRecordsReceived.FeeRewards) + } + }) + } +} diff --git a/x/rewards/keeper/distribution_test.go b/x/rewards/keeper/distribution_test.go index 94432b1a..67ebb828 100644 --- a/x/rewards/keeper/distribution_test.go +++ b/x/rewards/keeper/distribution_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg/testutils" rewardsTypes "github.com/archway-network/archway/x/rewards/types" ) @@ -420,7 +421,7 @@ func TestRewardsKeeper_Distribution(t *testing.T) { acc := chain.GetAccount(0) // Set mock ContractViewer (to pass contract admin check for metadata setup) - contractViewer := newMockContractViewer() + contractViewer := testutils.NewMockContractViewer() chain.GetApp().RewardsKeeper.SetContractInfoViewer(contractViewer) tKeeper, rKeeper := chain.GetApp().TrackingKeeper, chain.GetApp().RewardsKeeper @@ -439,7 +440,7 @@ func TestRewardsKeeper_Distribution(t *testing.T) { var gasConsumptionRecords []wasmdTypes.ContractGasRecord for _, op := range contract.operations { gasConsumptionRecord := wasmdTypes.ContractGasRecord{ - OperationId: GetRandomContractOperationType(), + OperationId: testutils.GetRandomContractOperationType(), ContractAddress: contract.contractAddr.String(), OriginalGas: wasmdTypes.GasConsumptionInfo{ SDKGas: op, diff --git a/x/rewards/mintbankkeeper/keeper_test.go b/x/rewards/mintbankkeeper/keeper_test.go index 0551261a..0c1a7a04 100644 --- a/x/rewards/mintbankkeeper/keeper_test.go +++ b/x/rewards/mintbankkeeper/keeper_test.go @@ -27,7 +27,6 @@ func TestMintBankKeeper(t *testing.T) { // Expected outputs errExpected bool rewardRecordExpected bool // reward record expected to be created - srcBalanceDiffExpected string // expected source module balance diff [sdk.Coins] dstBalanceDiffExpected string // expected destination module balance diff [sdk.Coins] rewardsBalanceDiffExpected string // expected x/rewards module balance diff [sdk.Coins] } @@ -43,7 +42,6 @@ func TestMintBankKeeper(t *testing.T) { transferCoins: "1000stake", // rewardRecordExpected: true, - srcBalanceDiffExpected: "", dstBalanceDiffExpected: "400stake", rewardsBalanceDiffExpected: "600stake", }, @@ -57,7 +55,6 @@ func TestMintBankKeeper(t *testing.T) { transferCoins: "45stake", // rewardRecordExpected: true, - srcBalanceDiffExpected: "", dstBalanceDiffExpected: "23stake", rewardsBalanceDiffExpected: "22stake", }, @@ -71,7 +68,6 @@ func TestMintBankKeeper(t *testing.T) { transferCoins: "100stake", // rewardRecordExpected: true, - srcBalanceDiffExpected: "", dstBalanceDiffExpected: "1stake", rewardsBalanceDiffExpected: "99stake", }, @@ -85,7 +81,6 @@ func TestMintBankKeeper(t *testing.T) { transferCoins: "100stake", // rewardRecordExpected: false, - srcBalanceDiffExpected: "", dstBalanceDiffExpected: "100stake", rewardsBalanceDiffExpected: "", }, @@ -99,7 +94,6 @@ func TestMintBankKeeper(t *testing.T) { transferCoins: "100stake", // rewardRecordExpected: true, - srcBalanceDiffExpected: "", dstBalanceDiffExpected: "99stake", rewardsBalanceDiffExpected: "1stake", }, @@ -113,7 +107,6 @@ func TestMintBankKeeper(t *testing.T) { transferCoins: "100stake", // rewardRecordExpected: false, - srcBalanceDiffExpected: "", dstBalanceDiffExpected: "100stake", rewardsBalanceDiffExpected: "", }, @@ -164,14 +157,12 @@ func TestMintBankKeeper(t *testing.T) { dstBalanceDiffReceived := dstBalanceAfter.Sub(dstBalanceBefore) // positive rewardsBalanceDiffReceived := rewardsBalanceAfter.Sub(rewardsBalanceBefore) // positive - srcBalanceDiffExpected, err := sdk.ParseCoinsNormalized(tc.srcBalanceDiffExpected) - require.NoError(t, err) dstBalanceDiffExpected, err := sdk.ParseCoinsNormalized(tc.dstBalanceDiffExpected) require.NoError(t, err) rewardsDiffExpected, err := sdk.ParseCoinsNormalized(tc.rewardsBalanceDiffExpected) require.NoError(t, err) - assert.Equal(t, srcBalanceDiffExpected.String(), srcBalanceDiffReceived.String()) + assert.True(t, srcBalanceDiffReceived.IsZero()) assert.Equal(t, dstBalanceDiffExpected.String(), dstBalanceDiffReceived.String()) assert.Equal(t, rewardsDiffExpected.String(), rewardsBalanceDiffReceived.String()) From f3f3e6f376fc92e54b0c6db86d729ef9c6122a99 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Mon, 1 Aug 2022 16:13:19 +0300 Subject: [PATCH 12/27] x/rewards: SetMetadata tests added --- pkg/testutils/wasm_op.go | 26 ++++++++++++ x/rewards/keeper/common_test.go | 23 ++++++++++ x/rewards/keeper/keeper_test.go | 72 ++++++++++++++++++++++++++++++++ x/tracking/keeper/common_test.go | 25 ----------- x/tracking/keeper/state_test.go | 21 +++++++++- 5 files changed, 141 insertions(+), 26 deletions(-) create mode 100644 x/rewards/keeper/common_test.go create mode 100644 x/rewards/keeper/keeper_test.go diff --git a/pkg/testutils/wasm_op.go b/pkg/testutils/wasm_op.go index 8add7c5b..1a27dd9d 100644 --- a/pkg/testutils/wasm_op.go +++ b/pkg/testutils/wasm_op.go @@ -4,6 +4,8 @@ import ( "math/rand" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + + treckingTypes "github.com/archway-network/archway/x/tracking/types" ) var allContractOperationTypes = []uint64{ @@ -27,3 +29,27 @@ func GetRandomContractOperationType() uint64 { idx := rand.Intn(len(allContractOperationTypes)) return allContractOperationTypes[idx] } + +// ContractOperationToWASM converts x/tracking contract operation to wasmd type. +func ContractOperationToWASM(opType treckingTypes.ContractOperation) uint64 { + switch opType { + case treckingTypes.ContractOperation_CONTRACT_OPERATION_INSTANTIATION: + return wasmdTypes.ContractOperationInstantiate + case treckingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION: + return wasmdTypes.ContractOperationExecute + case treckingTypes.ContractOperation_CONTRACT_OPERATION_QUERY: + return wasmdTypes.ContractOperationQuery + case treckingTypes.ContractOperation_CONTRACT_OPERATION_MIGRATE: + return wasmdTypes.ContractOperationMigrate + case treckingTypes.ContractOperation_CONTRACT_OPERATION_IBC: + return wasmdTypes.ContractOperationIbcPacketReceive + case treckingTypes.ContractOperation_CONTRACT_OPERATION_SUDO: + return wasmdTypes.ContractOperationSudo + case treckingTypes.ContractOperation_CONTRACT_OPERATION_REPLY: + return wasmdTypes.ContractOperationReply + case treckingTypes.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED: + fallthrough + default: + return wasmdTypes.ContractOperationUnknown + } +} diff --git a/x/rewards/keeper/common_test.go b/x/rewards/keeper/common_test.go new file mode 100644 index 00000000..57028637 --- /dev/null +++ b/x/rewards/keeper/common_test.go @@ -0,0 +1,23 @@ +package keeper_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + e2eTesting "github.com/archway-network/archway/e2e/testing" +) + +type KeeperTestSuite struct { + suite.Suite + + chain *e2eTesting.TestChain +} + +func (s *KeeperTestSuite) SetupTest() { + s.chain = e2eTesting.NewTestChain(s.T(), 1) +} + +func TestRewardsKeeper(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/rewards/keeper/keeper_test.go b/x/rewards/keeper/keeper_test.go new file mode 100644 index 00000000..b52262a0 --- /dev/null +++ b/x/rewards/keeper/keeper_test.go @@ -0,0 +1,72 @@ +package keeper_test + +import ( + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg/testutils" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func (s KeeperTestSuite) TestSetContractMetadata() { + ctx, keeper := s.chain.GetContext(), s.chain.GetApp().RewardsKeeper + contractAdminAcc, otherAcc := s.chain.GetAccount(0), s.chain.GetAccount(1) + + contractViewer := testutils.NewMockContractViewer() + keeper.SetContractInfoViewer(contractViewer) + + contractAddr := e2eTesting.GenContractAddresses(1)[0] + + s.Run("Fail: non-existing contract", func() { + err := keeper.SetContractMetadata(ctx, otherAcc.Address, contractAddr, rewardsTypes.ContractMetadata{}) + s.Assert().ErrorIs(err, rewardsTypes.ErrContractNotFound) + }) + + // Set contract admin + contractViewer.AddContractAdmin(contractAddr.String(), contractAdminAcc.Address.String()) + + s.Run("Fail: not a contract admin", func() { + err := keeper.SetContractMetadata(ctx, otherAcc.Address, contractAddr, rewardsTypes.ContractMetadata{}) + s.Assert().ErrorIs(err, rewardsTypes.ErrUnauthorized) + }) + + var metaCurrent rewardsTypes.ContractMetadata + s.Run("OK: create", func() { + metaCurrent.ContractAddress = contractAddr.String() + metaCurrent.OwnerAddress = contractAdminAcc.Address.String() + + err := keeper.SetContractMetadata(ctx, contractAdminAcc.Address, contractAddr, metaCurrent) + s.Require().NoError(err) + + metaReceived := keeper.GetContractMetadata(ctx, contractAddr) + s.Require().NotNil(metaReceived) + s.Assert().Equal(metaCurrent, *metaReceived) + }) + + s.Run("OK: set RewardsAddr", func() { + metaCurrent.RewardsAddress = otherAcc.Address.String() + + err := keeper.SetContractMetadata(ctx, contractAdminAcc.Address, contractAddr, metaCurrent) + s.Require().NoError(err) + + metaReceived := keeper.GetContractMetadata(ctx, contractAddr) + s.Require().NotNil(metaReceived) + s.Assert().Equal(metaCurrent, *metaReceived) + }) + + s.Run("OK: update OwnerAddr (change ownership)", func() { + metaCurrent.OwnerAddress = otherAcc.Address.String() + + err := keeper.SetContractMetadata(ctx, contractAdminAcc.Address, contractAddr, metaCurrent) + s.Require().NoError(err) + + metaReceived := keeper.GetContractMetadata(ctx, contractAddr) + s.Require().NotNil(metaReceived) + s.Assert().Equal(metaCurrent, *metaReceived) + }) + + s.Run("Fail: try to regain ownership", func() { + metaCurrent.OwnerAddress = contractAdminAcc.Address.String() + + err := keeper.SetContractMetadata(ctx, contractAdminAcc.Address, contractAddr, metaCurrent) + s.Require().ErrorIs(err, rewardsTypes.ErrUnauthorized) + }) +} diff --git a/x/tracking/keeper/common_test.go b/x/tracking/keeper/common_test.go index 6c6805c0..b4597a80 100644 --- a/x/tracking/keeper/common_test.go +++ b/x/tracking/keeper/common_test.go @@ -3,11 +3,9 @@ package keeper_test import ( "testing" - wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/stretchr/testify/suite" e2eTesting "github.com/archway-network/archway/e2e/testing" - "github.com/archway-network/archway/x/tracking/types" ) type KeeperTestSuite struct { @@ -23,26 +21,3 @@ func (s *KeeperTestSuite) SetupTest() { func TestTrackingKeeper(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } - -func ContractOperationToWASM(opType types.ContractOperation) uint64 { - switch opType { - case types.ContractOperation_CONTRACT_OPERATION_INSTANTIATION: - return wasmTypes.ContractOperationInstantiate - case types.ContractOperation_CONTRACT_OPERATION_EXECUTION: - return wasmTypes.ContractOperationExecute - case types.ContractOperation_CONTRACT_OPERATION_QUERY: - return wasmTypes.ContractOperationQuery - case types.ContractOperation_CONTRACT_OPERATION_MIGRATE: - return wasmTypes.ContractOperationMigrate - case types.ContractOperation_CONTRACT_OPERATION_IBC: - return wasmTypes.ContractOperationIbcPacketReceive - case types.ContractOperation_CONTRACT_OPERATION_SUDO: - return wasmTypes.ContractOperationSudo - case types.ContractOperation_CONTRACT_OPERATION_REPLY: - return wasmTypes.ContractOperationReply - case types.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED: - fallthrough - default: - return wasmTypes.ContractOperationUnknown - } -} diff --git a/x/tracking/keeper/state_test.go b/x/tracking/keeper/state_test.go index 3e905aaf..e21b09ec 100644 --- a/x/tracking/keeper/state_test.go +++ b/x/tracking/keeper/state_test.go @@ -3,6 +3,7 @@ package keeper_test import ( wasmTypes "github.com/CosmWasm/wasmd/x/wasm/types" + "github.com/archway-network/archway/pkg/testutils" "github.com/archway-network/archway/x/tracking/types" ) @@ -162,7 +163,7 @@ func (s *KeeperTestSuite) TestStates() { records = append( records, wasmTypes.ContractGasRecord{ - OperationId: ContractOperationToWASM(op.OperationType), + OperationId: testutils.ContractOperationToWASM(op.OperationType), ContractAddress: op.ContractAddress, OriginalGas: wasmTypes.GasConsumptionInfo{ VMGas: keeper.WasmGasRegister.ToWasmVMGas(op.VmGas), @@ -236,4 +237,22 @@ func (s *KeeperTestSuite) TestStates() { s.Assert().ElementsMatch(opsExpected, opsReceived, "ContractOpInfoByTxID (%d): wrong value", txID) } }) + + // Check records removal + s.Run("Check records removal for the 1st block", func() { + keeper.GetState().DeleteTxInfosCascade(ctx, startBlock+1) + + block1Txs := keeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(startBlock + 1) + s.Assert().Empty(block1Txs) + + block2Txs := keeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(startBlock + 2) + s.Assert().Len(block2Txs, 2) + }) + + s.Run("Check records removal for the 2nd block", func() { + keeper.GetState().DeleteTxInfosCascade(ctx, startBlock+2) + + block2Txs := keeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(startBlock + 2) + s.Assert().Empty(block2Txs) + }) } From 57d14a7859b32e5a8f22ea24a969211a85a97f17 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Mon, 1 Aug 2022 18:52:08 +0300 Subject: [PATCH 13/27] x/rewards, x/tracking: basic validation tests added --- pkg/coin.go | 31 ++++ pkg/testutils/wasm_op.go | 54 +++++-- x/rewards/types/genesis.go | 3 + x/rewards/types/genesis_test.go | 145 +++++++++++++++++ x/rewards/types/metadata_test.go | 82 ++++++++++ x/rewards/types/msg_test.go | 66 ++++++++ x/rewards/types/params_test.go | 71 ++++++++ x/rewards/types/rewards.go | 24 ++- x/rewards/types/rewards_test.go | 142 ++++++++++++++++ x/tracking/keeper/genesis_test.go | 9 +- x/tracking/keeper/state_test.go | 2 +- x/tracking/types/genesis_test.go | 260 ++++++++++++++++++++++++++++++ x/tracking/types/tracking.go | 4 + 13 files changed, 865 insertions(+), 28 deletions(-) create mode 100644 pkg/coin.go create mode 100644 x/rewards/types/genesis_test.go create mode 100644 x/rewards/types/metadata_test.go create mode 100644 x/rewards/types/msg_test.go create mode 100644 x/rewards/types/params_test.go create mode 100644 x/rewards/types/rewards_test.go create mode 100644 x/tracking/types/genesis_test.go diff --git a/pkg/coin.go b/pkg/coin.go new file mode 100644 index 00000000..37e0521c --- /dev/null +++ b/pkg/coin.go @@ -0,0 +1,31 @@ +package pkg + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// CoinIsZero checks if sdk.Coin is set (not panics in case Amount is nil). +func CoinIsZero(coin sdk.Coin) bool { + if coin.Amount.IsNil() { + return true + } + + return coin.IsZero() +} + +// ValidateCoin performs a stricter validation of sdk.Coin comparing to the SDK version. +func ValidateCoin(coin sdk.Coin) error { + if err := sdk.ValidateDenom(coin.Denom); err != nil { + return fmt.Errorf("denom: %w", err) + } + if coin.Amount.IsNil() { + return fmt.Errorf("amount: nil") + } + if coin.IsNegative() { + return fmt.Errorf("amount: is negative") + } + + return nil +} diff --git a/pkg/testutils/wasm_op.go b/pkg/testutils/wasm_op.go index 1a27dd9d..dcf2f714 100644 --- a/pkg/testutils/wasm_op.go +++ b/pkg/testutils/wasm_op.go @@ -5,7 +5,7 @@ import ( wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" - treckingTypes "github.com/archway-network/archway/x/tracking/types" + trackingTypes "github.com/archway-network/archway/x/tracking/types" ) var allContractOperationTypes = []uint64{ @@ -30,26 +30,58 @@ func GetRandomContractOperationType() uint64 { return allContractOperationTypes[idx] } -// ContractOperationToWASM converts x/tracking contract operation to wasmd type. -func ContractOperationToWASM(opType treckingTypes.ContractOperation) uint64 { +// RewardsContractOperationToWASM converts x/tracking contract operation to wasmd type. +func RewardsContractOperationToWASM(opType trackingTypes.ContractOperation) uint64 { switch opType { - case treckingTypes.ContractOperation_CONTRACT_OPERATION_INSTANTIATION: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_INSTANTIATION: return wasmdTypes.ContractOperationInstantiate - case treckingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION: return wasmdTypes.ContractOperationExecute - case treckingTypes.ContractOperation_CONTRACT_OPERATION_QUERY: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_QUERY: return wasmdTypes.ContractOperationQuery - case treckingTypes.ContractOperation_CONTRACT_OPERATION_MIGRATE: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_MIGRATE: return wasmdTypes.ContractOperationMigrate - case treckingTypes.ContractOperation_CONTRACT_OPERATION_IBC: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_IBC: return wasmdTypes.ContractOperationIbcPacketReceive - case treckingTypes.ContractOperation_CONTRACT_OPERATION_SUDO: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_SUDO: return wasmdTypes.ContractOperationSudo - case treckingTypes.ContractOperation_CONTRACT_OPERATION_REPLY: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_REPLY: return wasmdTypes.ContractOperationReply - case treckingTypes.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED: + case trackingTypes.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED: fallthrough default: return wasmdTypes.ContractOperationUnknown } } + +// WASMContractOperationToRewards converts wasmd operation type to x/tracking type. +func WASMContractOperationToRewards(opType uint64) trackingTypes.ContractOperation { + switch opType { + case wasmdTypes.ContractOperationQuery: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_QUERY + case wasmdTypes.ContractOperationInstantiate: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_INSTANTIATION + case wasmdTypes.ContractOperationExecute: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION + case wasmdTypes.ContractOperationMigrate: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_MIGRATE + case wasmdTypes.ContractOperationSudo: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_SUDO + case wasmdTypes.ContractOperationReply: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_REPLY + case wasmdTypes.ContractOperationIbcPacketTimeout: + fallthrough + case wasmdTypes.ContractOperationIbcPacketAck: + fallthrough + case wasmdTypes.ContractOperationIbcPacketReceive: + fallthrough + case wasmdTypes.ContractOperationIbcChannelClose: + fallthrough + case wasmdTypes.ContractOperationIbcChannelOpen: + fallthrough + case wasmdTypes.ContractOperationIbcChannelConnect: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_IBC + default: + return trackingTypes.ContractOperation_CONTRACT_OPERATION_UNSPECIFIED + } +} diff --git a/x/rewards/types/genesis.go b/x/rewards/types/genesis.go index c8c10892..75902d84 100644 --- a/x/rewards/types/genesis.go +++ b/x/rewards/types/genesis.go @@ -58,6 +58,9 @@ func (m GenesisState) Validate() error { if err := txRewards.Validate(); err != nil { return fmt.Errorf("txRewards [%d]: %w", i, err) } + if _, ok := blockRewardsHeightSet[txRewards.Height]; !ok { + return fmt.Errorf("txRewards [%d]: height not found: %d", i, txRewards.Height) + } if _, ok := txRewardsIdSet[txRewards.TxId]; ok { return fmt.Errorf("txRewards [%d]: duplicated txId: %d", i, txRewards.TxId) } diff --git a/x/rewards/types/genesis_test.go b/x/rewards/types/genesis_test.go new file mode 100644 index 00000000..a10d5c4e --- /dev/null +++ b/x/rewards/types/genesis_test.go @@ -0,0 +1,145 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestRewardsGenesisStateValidate(t *testing.T) { + type testCase struct { + name string + genesisState rewardsTypes.GenesisState + errExpected bool + } + + accAddrs, _ := e2eTesting.GenAccounts(1) + accAddr := accAddrs[0] + + contractAddr := e2eTesting.GenContractAddresses(1)[0] + + testCases := []testCase{ + { + name: "OK: empty", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + }, + }, + { + name: "OK", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + ContractsMetadata: []rewardsTypes.ContractMetadata{ + {ContractAddress: contractAddr.String(), OwnerAddress: accAddr.String()}, + }, + BlockRewards: []rewardsTypes.BlockRewards{ + {Height: 1}, + }, + TxRewards: []rewardsTypes.TxRewards{ + {TxId: 1, Height: 1}, + }, + }, + }, + { + name: "Fail: invalid Params", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.Params{ + InflationRewardsRatio: sdk.NewDecWithPrec(15, 0), + TxFeeRebateRatio: sdk.NewDecWithPrec(5, 2), + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid ContractsMetadata: ownerAddress not set", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + ContractsMetadata: []rewardsTypes.ContractMetadata{ + {ContractAddress: contractAddr.String()}, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid ContractsMetadata: duplicates", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + ContractsMetadata: []rewardsTypes.ContractMetadata{ + {ContractAddress: contractAddr.String(), OwnerAddress: accAddr.String()}, + {ContractAddress: contractAddr.String(), OwnerAddress: accAddr.String()}, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid BlockRewards", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + BlockRewards: []rewardsTypes.BlockRewards{ + {Height: -1}, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid BlockRewards: duplicates", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + BlockRewards: []rewardsTypes.BlockRewards{ + {Height: 1}, + {Height: 1}, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid TxRewards", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + TxRewards: []rewardsTypes.TxRewards{ + {TxId: 0}, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid TxRewards: duplicates", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + BlockRewards: []rewardsTypes.BlockRewards{ + {Height: 1}, + }, + TxRewards: []rewardsTypes.TxRewards{ + {TxId: 1}, + {TxId: 1}, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid TxRewards: non-existing block rewards", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + TxRewards: []rewardsTypes.TxRewards{ + {TxId: 1, Height: 1}, + }, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.genesisState.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/rewards/types/metadata_test.go b/x/rewards/types/metadata_test.go new file mode 100644 index 00000000..a8078e60 --- /dev/null +++ b/x/rewards/types/metadata_test.go @@ -0,0 +1,82 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestContractMetadataValidate(t *testing.T) { + type testCase struct { + name string + meta rewardsTypes.ContractMetadata + isGenesisValidation bool + errExpected bool + } + + accAddrs, _ := e2eTesting.GenAccounts(1) + accAddr := accAddrs[0] + + contractAddr := e2eTesting.GenContractAddresses(1)[0] + + testCases := []testCase{ + { + name: "OK: empty", + meta: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + }, + }, + { + name: "OK: with OwnerAddress", + meta: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + OwnerAddress: accAddr.String(), + }, + }, + { + name: "OK: with RewardsAddress", + meta: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + RewardsAddress: accAddr.String(), + }, + }, + { + name: "Fail: invalid ContractAddress", + meta: rewardsTypes.ContractMetadata{ + ContractAddress: "invalid", + }, + errExpected: true, + }, + { + name: "Fail: invalid RewardsAddress", + meta: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + RewardsAddress: "invalid", + }, + errExpected: true, + }, + { + name: "Fail: empty OwnerAddress with genesis validation", + meta: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + }, + isGenesisValidation: true, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.meta.Validate(tc.isGenesisValidation) + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } + +} diff --git a/x/rewards/types/msg_test.go b/x/rewards/types/msg_test.go new file mode 100644 index 00000000..39d0eea3 --- /dev/null +++ b/x/rewards/types/msg_test.go @@ -0,0 +1,66 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestMsgSetContractMetadataValidateBasic(t *testing.T) { + type testCase struct { + name string + msg rewardsTypes.MsgSetContractMetadata + errExpected bool + } + + accAddrs, _ := e2eTesting.GenAccounts(1) + accAddr := accAddrs[0] + + contractAddr := e2eTesting.GenContractAddresses(1)[0] + + testCases := []testCase{ + { + name: "OK", + msg: rewardsTypes.MsgSetContractMetadata{ + SenderAddress: accAddr.String(), + Metadata: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + }, + }, + }, + { + name: "Fail: invalid SenderAddress", + msg: rewardsTypes.MsgSetContractMetadata{ + SenderAddress: "invalid", + Metadata: rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid Metadata", + msg: rewardsTypes.MsgSetContractMetadata{ + SenderAddress: accAddr.String(), + Metadata: rewardsTypes.ContractMetadata{ + ContractAddress: "invalid", + }, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/rewards/types/params_test.go b/x/rewards/types/params_test.go new file mode 100644 index 00000000..43fb3265 --- /dev/null +++ b/x/rewards/types/params_test.go @@ -0,0 +1,71 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestRewardsParamsValidate(t *testing.T) { + type testCase struct { + name string + params rewardsTypes.Params + errExpected bool + } + + testCases := []testCase{ + { + name: "OK", + params: rewardsTypes.Params{ + InflationRewardsRatio: sdk.NewDecWithPrec(2, 2), + TxFeeRebateRatio: sdk.NewDecWithPrec(5, 2), + }, + }, + { + name: "Fail: InflationRewardsRatio: negative", + params: rewardsTypes.Params{ + InflationRewardsRatio: sdk.NewDecWithPrec(-2, 2), + TxFeeRebateRatio: sdk.NewDecWithPrec(5, 2), + }, + errExpected: true, + }, + { + name: "Fail: InflationRewardsRatio: equal to 1.0", + params: rewardsTypes.Params{ + InflationRewardsRatio: sdk.NewDecWithPrec(1, 0), + TxFeeRebateRatio: sdk.NewDecWithPrec(5, 2), + }, + errExpected: true, + }, + { + name: "Fail: TxFeeRebateRatio: negative", + params: rewardsTypes.Params{ + InflationRewardsRatio: sdk.NewDecWithPrec(2, 2), + TxFeeRebateRatio: sdk.NewDecWithPrec(-1, 2), + }, + errExpected: true, + }, + { + name: "Fail: TxFeeRebateRatio: equal to 1.0", + params: rewardsTypes.Params{ + InflationRewardsRatio: sdk.NewDecWithPrec(2, 2), + TxFeeRebateRatio: sdk.NewDecWithPrec(1, 0), + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.params.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/rewards/types/rewards.go b/x/rewards/types/rewards.go index 0bc8292c..0ea2e9ea 100644 --- a/x/rewards/types/rewards.go +++ b/x/rewards/types/rewards.go @@ -5,6 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "sigs.k8s.io/yaml" + + "github.com/archway-network/archway/pkg" ) // HasRewards returns true if the block rewards have been set. @@ -23,18 +25,11 @@ func (m BlockRewards) Validate() error { return fmt.Errorf("height: must be GTE 0") } - if m.InflationRewards.Denom != "" { - if err := sdk.ValidateDenom(m.InflationRewards.Denom); err != nil { - return fmt.Errorf("inflationRewards: denom: %w", err) + if !pkg.CoinIsZero(m.InflationRewards) { + if err := pkg.ValidateCoin(m.InflationRewards); err != nil { + return fmt.Errorf("inflationRewards: %w", err) } } - if m.InflationRewards.Amount.IsNegative() { - return fmt.Errorf("inflationRewards: amount: is negative") - } - - if m.MaxGas <= 0 { - return fmt.Errorf("maxGas: must be GT 0") - } return nil } @@ -61,11 +56,12 @@ func (m TxRewards) Validate() error { } for i, coin := range m.FeeRewards { - if err := sdk.ValidateDenom(coin.Denom); err != nil { - return fmt.Errorf("feeRewards [%d]: denom: %w", i, err) + if pkg.CoinIsZero(coin) { + return fmt.Errorf("feeRewards [%d]: must be non-zero", i) } - if coin.Amount.IsNegative() { - return fmt.Errorf("feeRewards [%d]: amount: is negative", i) + + if err := pkg.ValidateCoin(coin); err != nil { + return fmt.Errorf("feeRewards [%d]: %w", i, err) } } diff --git a/x/rewards/types/rewards_test.go b/x/rewards/types/rewards_test.go new file mode 100644 index 00000000..118413bb --- /dev/null +++ b/x/rewards/types/rewards_test.go @@ -0,0 +1,142 @@ +package types_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func TestBlockRewardsValidate(t *testing.T) { + type testCase struct { + name string + record rewardsTypes.BlockRewards + errExpected bool + } + + testCases := []testCase{ + { + name: "OK", + record: rewardsTypes.BlockRewards{ + Height: 1, + InflationRewards: sdk.Coin{Denom: "uatom", Amount: sdk.OneInt()}, + }, + }, + { + name: "OK: no rewards", + record: rewardsTypes.BlockRewards{ + Height: 1, + }, + }, + { + name: "Fail: invalid Height", + record: rewardsTypes.BlockRewards{ + Height: -1, + InflationRewards: sdk.Coin{Denom: "uatom", Amount: sdk.OneInt()}, + }, + errExpected: true, + }, + { + name: "Fail: invalid InflationRewards denom", + record: rewardsTypes.BlockRewards{ + Height: 1, + InflationRewards: sdk.Coin{Denom: "123invalid", Amount: sdk.OneInt()}, + }, + errExpected: true, + }, + { + name: "Fail: invalid InflationRewards amount (negative)", + record: rewardsTypes.BlockRewards{ + Height: 1, + InflationRewards: sdk.Coin{Denom: "uatom", Amount: sdk.NewInt(-1)}, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.record.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestTxRewardsValidate(t *testing.T) { + type testCase struct { + name string + record rewardsTypes.TxRewards + errExpected bool + } + + testCases := []testCase{ + { + name: "OK", + record: rewardsTypes.TxRewards{ + TxId: 1, + Height: 1, + FeeRewards: sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())), + }, + }, + { + name: "OK: no rewards", + record: rewardsTypes.TxRewards{ + TxId: 1, + Height: 1, + }, + }, + { + name: "Fail: invalid TxId", + record: rewardsTypes.TxRewards{ + TxId: 0, + Height: 1, + FeeRewards: sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())), + }, + errExpected: true, + }, + { + name: "Fail: invalid Height", + record: rewardsTypes.TxRewards{ + TxId: 1, + Height: -1, + FeeRewards: sdk.NewCoins(sdk.NewCoin("uatom", sdk.OneInt())), + }, + errExpected: true, + }, + { + name: "Fail: invalid FeeRewards (empty coin)", + record: rewardsTypes.TxRewards{ + TxId: 1, + Height: -1, + FeeRewards: sdk.NewCoins(), + }, + errExpected: true, + }, + { + name: "Fail: invalid FeeRewards (invalid coin)", + record: rewardsTypes.TxRewards{ + TxId: 1, + Height: -1, + FeeRewards: []sdk.Coin{{Denom: "123invalid", Amount: sdk.OneInt()}}, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.record.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/tracking/keeper/genesis_test.go b/x/tracking/keeper/genesis_test.go index 539db6d3..ba0b31a1 100644 --- a/x/tracking/keeper/genesis_test.go +++ b/x/tracking/keeper/genesis_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "math/rand" + "github.com/archway-network/archway/pkg/testutils" "github.com/archway-network/archway/x/tracking/types" ) @@ -13,8 +14,10 @@ func (s *KeeperTestSuite) TestGenesisExport() { operationsToExecute := 100 for i := 0; i < operationsToExecute; i++ { + opType := testutils.WASMContractOperationToRewards(testutils.GetRandomContractOperationType()) + keeper.TrackNewTx(ctx) - keeper.TrackNewContractOperation(ctx, chain.GetAccount(rand.Intn(5)).Address, types.ContractOperation(rand.Int31n(8)-1), 1, 1) + keeper.TrackNewContractOperation(ctx, chain.GetAccount(rand.Intn(5)).Address, opType, 1, 1) } genesis := keeper.ExportGenesis(ctx) @@ -31,12 +34,14 @@ func (s *KeeperTestSuite) TestGenesisImport() { // Ids must be greater than 0 for i := 1; i <= operationsToExecute; i++ { + opType := testutils.WASMContractOperationToRewards(testutils.GetRandomContractOperationType()) + txInfo := types.TxInfo{uint64(i), 0, 2} contractOperation := types.ContractOperationInfo{ txInfo.Id, txInfo.Id, chain.GetAccount(rand.Intn(5)).Address.String(), - types.ContractOperation(rand.Int31n(8) - 1), + opType, 1, 1, } diff --git a/x/tracking/keeper/state_test.go b/x/tracking/keeper/state_test.go index e21b09ec..63547160 100644 --- a/x/tracking/keeper/state_test.go +++ b/x/tracking/keeper/state_test.go @@ -163,7 +163,7 @@ func (s *KeeperTestSuite) TestStates() { records = append( records, wasmTypes.ContractGasRecord{ - OperationId: testutils.ContractOperationToWASM(op.OperationType), + OperationId: testutils.RewardsContractOperationToWASM(op.OperationType), ContractAddress: op.ContractAddress, OriginalGas: wasmTypes.GasConsumptionInfo{ VMGas: keeper.WasmGasRegister.ToWasmVMGas(op.VmGas), diff --git a/x/tracking/types/genesis_test.go b/x/tracking/types/genesis_test.go new file mode 100644 index 00000000..40167f12 --- /dev/null +++ b/x/tracking/types/genesis_test.go @@ -0,0 +1,260 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + trackingTypes "github.com/archway-network/archway/x/tracking/types" +) + +func TestTrackingGenesisStateValidation(t *testing.T) { + type testCase struct { + name string + genesis trackingTypes.GenesisState + errExpected bool + } + + contractAddrs := e2eTesting.GenContractAddresses(2) + contractAddr1, contractAddr2 := contractAddrs[0], contractAddrs[1] + + testCases := []testCase{ + { + name: "OK: empty", + genesis: trackingTypes.GenesisState{}, + }, + { + name: "OK: non-empty", + genesis: trackingTypes.GenesisState{ + TxInfos: []trackingTypes.TxInfo{ + { + Id: 1, + }, + }, + ContractOpInfos: []trackingTypes.ContractOperationInfo{ + { + Id: 1, + TxId: 1, + ContractAddress: contractAddr1.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, + }, + { + Id: 2, + TxId: 1, + ContractAddress: contractAddr2.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, + }, + }, + }, + }, + { + name: "Fail: invalid TxInfos", + genesis: trackingTypes.GenesisState{ + TxInfos: []trackingTypes.TxInfo{ + { + Id: 0, + }, + }, + }, + errExpected: true, + }, + { + name: "Fail: invalid ContractOperationInfos", + genesis: trackingTypes.GenesisState{ + TxInfos: []trackingTypes.TxInfo{ + { + Id: 1, + }, + }, + ContractOpInfos: []trackingTypes.ContractOperationInfo{ + { + Id: 0, + }, + }, + }, + errExpected: true, + }, + { + name: "Fail: duplicated TxInfo", + genesis: trackingTypes.GenesisState{ + TxInfos: []trackingTypes.TxInfo{ + { + Id: 1, + }, + { + Id: 1, + }, + }, + }, + errExpected: true, + }, + { + name: "Fail: duplicated ContractOperationInfos", + genesis: trackingTypes.GenesisState{ + TxInfos: []trackingTypes.TxInfo{ + { + Id: 1, + }, + }, + ContractOpInfos: []trackingTypes.ContractOperationInfo{ + { + Id: 1, + TxId: 1, + ContractAddress: contractAddr1.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, + }, + { + Id: 1, + TxId: 1, + ContractAddress: contractAddr2.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, + }, + }, + }, + errExpected: true, + }, + { + name: "Fail: unmatched TxID", + genesis: trackingTypes.GenesisState{ + TxInfos: []trackingTypes.TxInfo{ + { + Id: 1, + }, + }, + ContractOpInfos: []trackingTypes.ContractOperationInfo{ + { + Id: 1, + TxId: 2, + ContractAddress: contractAddr1.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, + }, + }, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.genesis.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestTrackingTxInfoValidate(t *testing.T) { + type testCase struct { + name string + txInfo trackingTypes.TxInfo + errExpected bool + } + + testCases := []testCase{ + { + name: "OK", + txInfo: trackingTypes.TxInfo{ + Id: 1, + Height: 1, + TotalGas: 100, + }, + }, + { + name: "Fail: invalid ID", + txInfo: trackingTypes.TxInfo{ + Id: 0, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.txInfo.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestTrackingContractOperationInfoValidate(t *testing.T) { + type testCase struct { + name string + opInfo trackingTypes.ContractOperationInfo + errExpected bool + } + + contractAddr := e2eTesting.GenContractAddresses(1)[0] + + testCases := []testCase{ + { + name: "OK", + opInfo: trackingTypes.ContractOperationInfo{ + Id: 1, + TxId: 1, + ContractAddress: contractAddr.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_SUDO, + VmGas: 100, + SdkGas: 50, + }, + }, + { + name: "Fail: invalid ID", + opInfo: trackingTypes.ContractOperationInfo{ + Id: 0, + TxId: 1, + ContractAddress: contractAddr.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_SUDO, + }, + errExpected: true, + }, + { + name: "Fail: invalid TxID", + opInfo: trackingTypes.ContractOperationInfo{ + Id: 1, + TxId: 0, + ContractAddress: contractAddr.String(), + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_SUDO, + }, + errExpected: true, + }, + { + name: "Fail: invalid ContractAddress", + opInfo: trackingTypes.ContractOperationInfo{ + Id: 1, + TxId: 1, + ContractAddress: "invalid", + OperationType: trackingTypes.ContractOperation_CONTRACT_OPERATION_SUDO, + }, + errExpected: true, + }, + { + name: "Fail: invalid OperationType", + opInfo: trackingTypes.ContractOperationInfo{ + Id: 1, + TxId: 1, + ContractAddress: contractAddr.String(), + OperationType: 100, + }, + errExpected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := tc.opInfo.Validate() + if tc.errExpected { + assert.Error(t, err) + return + } + assert.NoError(t, err) + }) + } +} diff --git a/x/tracking/types/tracking.go b/x/tracking/types/tracking.go index 32e7c83a..ef8595b5 100644 --- a/x/tracking/types/tracking.go +++ b/x/tracking/types/tracking.go @@ -58,6 +58,10 @@ func (m ContractOperationInfo) Validate() error { return fmt.Errorf("contractAddress: %s", err.Error()) } + if _, found := ContractOperation_name[int32(m.OperationType)]; !found { + return fmt.Errorf("operationType: unknown type") + } + return nil } From eeb4ff67ff7a7eae9e408cf4b8b2f3b8319f0f12 Mon Sep 17 00:00:00 2001 From: edjroz Date: Mon, 1 Aug 2022 20:34:40 +0000 Subject: [PATCH 14/27] fix go dependencies --- go.sum | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/go.sum b/go.sum index 6fd7ad4f..ebf1a65b 100644 --- a/go.sum +++ b/go.sum @@ -88,7 +88,6 @@ github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220729111547-079232ac0432 h1:51VJ/Rwt github.com/CosmWasm/cosmwasm-go v0.5.1-0.20220729111547-079232ac0432/go.mod h1:qCTzr8cQYwoYdA9AT4azEVbiYGjULS1nrUgw6YScXks= github.com/CosmWasm/tinyjson v0.9.0 h1:sPjgikATp5W0vD/v/Qz99uQ6G/lh/SuK0Wfskqua4Co= github.com/CosmWasm/tinyjson v0.9.0/go.mod h1:5+7QnSKrkIWnpIdhUT2t2EYzXnII3/3MlM0oDsBSbc8= -github.com/CosmWasm/wasmvm v1.0.0-rc.0 h1:YI0ytwQZewPhSNxlqsrZ3/bVKTYXmrR1bfVapleCXWk= github.com/CosmWasm/wasmvm v1.0.0-rc.0/go.mod h1:ei0xpvomwSdONsxDuONzV7bL1jSET1M8brEx0FCXc+A= github.com/CosmWasm/wasmvm v1.0.0 h1:NRmnHe3xXsKn2uEcB1F5Ha323JVAhON+BI6L177dlKc= github.com/CosmWasm/wasmvm v1.0.0/go.mod h1:ei0xpvomwSdONsxDuONzV7bL1jSET1M8brEx0FCXc+A= @@ -310,10 +309,12 @@ github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -1345,7 +1346,7 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 7f9cf685e7e53e0ec6e149eca25098bbe49d4d50 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Tue, 2 Aug 2022 15:03:49 +0300 Subject: [PATCH 15/27] dontcover.sh added to prepend DONTCOVER for proto-gen files. x/rewards, x/tracking: state tests added. E2E tests: Sudo test enabled (after the wasmd upgrade), Stargate query test disabled (removed by the wasmvm developers). --- Makefile | 2 + app/ante.go | 2 +- e2e/voter_test.go | 13 +-- scripts/dontcover.sh | 17 +++ x/rewards/keeper/genesis_test.go | 96 +++++++++++++++ x/rewards/keeper/state_test.go | 194 +++++++++++++++++++++++++++++++ x/rewards/types/events.pb.go | 1 + x/rewards/types/genesis.pb.go | 1 + x/rewards/types/query.pb.go | 1 + x/rewards/types/query.pb.gw.go | 1 + x/rewards/types/rewards.pb.go | 1 + x/rewards/types/tx.pb.go | 1 + x/tracking/ante/tracking.go | 5 - x/tracking/ante/tracking_test.go | 25 ++++ x/tracking/keeper/state_test.go | 36 +++++- x/tracking/types/genesis.pb.go | 1 + x/tracking/types/query.pb.go | 1 + x/tracking/types/query.pb.gw.go | 1 + x/tracking/types/tracking.pb.go | 1 + 19 files changed, 382 insertions(+), 18 deletions(-) create mode 100755 scripts/dontcover.sh create mode 100644 x/rewards/keeper/genesis_test.go create mode 100644 x/rewards/keeper/state_test.go create mode 100644 x/tracking/ante/tracking_test.go diff --git a/Makefile b/Makefile index a14e15a9..a1683607 100644 --- a/Makefile +++ b/Makefile @@ -171,6 +171,8 @@ proto-all: proto-format proto-lint proto-gen proto-gen: @echo "Generating Protobuf files" $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(PROTO_BUILDER_IMAGE) sh ./scripts/protocgen.sh + ./scripts/dontcover.sh ./x/tracking + ./scripts/dontcover.sh ./x/rewards proto-format: @echo "Formatting Protobuf files" diff --git a/app/ante.go b/app/ante.go index d6d442ba..d07f4f6f 100644 --- a/app/ante.go +++ b/app/ante.go @@ -76,7 +76,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), - ibcante.NewAnteDecorator(options.IBCChannelkeeper), + ibcante.NewAnteDecorator(options.IBCKeeper), } return sdk.ChainAnteDecorators(anteDecorators...), nil diff --git a/e2e/voter_test.go b/e2e/voter_test.go index 80ff979c..b8bd368f 100644 --- a/e2e/voter_test.go +++ b/e2e/voter_test.go @@ -18,8 +18,9 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" - e2eTesting "github.com/archway-network/archway/e2e/testing" channelTypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" + + e2eTesting "github.com/archway-network/archway/e2e/testing" ) const ( @@ -88,11 +89,6 @@ func (s *E2ETestSuite) TestVoter_ExecuteQueryAndReply() { // - api.HumanAddress: called by querying contract Params (OwnerAddr); // - and api.CanonicalAddress: called by instantiate to convert OwnerAddr (string) to canonical address (bytes); func (s *E2ETestSuite) TestVoter_Sudo() { - // x/wasmd/types/codec.go: - // registry.RegisterImplementations() call: - // "&SudoContractProposal{}" should be added - s.T().Skip("Current wasmd dependency doesn't have SudoContractProposal type registered (fixed in 1.0.0, skip for now)") - chain := s.chainA acc := chain.GetAccount(0) contractAddr := s.VoterUploadAndInstantiate(chain, acc) @@ -768,8 +764,9 @@ func (s *E2ETestSuite) TestVoter_WASMBindingsMetadataQuery() { } getAndCmpMetas := func(metaExp rewardsTypes.ContractMetadata) { - metaRcvStargate := s.VoterGetMetadata(chain, contractAddr, true, true) - cmpMetas(metaExp, metaRcvStargate) + // wasmvm v1.0.0 (wasmd for us) has disabled the Stargate query, so we skip this case + //metaRcvStargate := s.VoterGetMetadata(chain, contractAddr, true, true) + //cmpMetas(metaExp, metaRcvStargate) metaRcvCustom := s.VoterGetMetadata(chain, contractAddr, false, true) cmpMetas(metaExp, metaRcvCustom) diff --git a/scripts/dontcover.sh b/scripts/dontcover.sh new file mode 100755 index 00000000..db8d9698 --- /dev/null +++ b/scripts/dontcover.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -eo pipefail + +# Check input +target_dir="$1" +if [ -z "${target_dir}" ]; then + echo "Usage: $0 [target_dir]" + exit 1 +fi + +# Add DONTCOVER +echo "Prepending '// DONTCOVER' to proto-generated files:" +find "${target_dir}" -type f -name '*.pb.go' -o -iname '*.pb.gw.go' | while read fname; do + echo "${fname}" + echo -e "// DONTCOVER\n$(cat ${fname})" > "${fname}" +done diff --git a/x/rewards/keeper/genesis_test.go b/x/rewards/keeper/genesis_test.go new file mode 100644 index 00000000..d7e5d229 --- /dev/null +++ b/x/rewards/keeper/genesis_test.go @@ -0,0 +1,96 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/x/rewards/types" +) + +// TestGenesisImportExport check genesis import/export. +// Test updates the initial state with new records and checks that they were merged. +func (s KeeperTestSuite) TestGenesisImportExport() { + ctx, keeper := s.chain.GetContext(), s.chain.GetApp().RewardsKeeper + + contractAddrs := e2eTesting.GenContractAddresses(2) + accAddrs, _ := e2eTesting.GenAccounts(2) + + var genesisStateInitial types.GenesisState + s.Run("Check export of the initial genesis", func() { + genesisState := keeper.ExportGenesis(ctx) + s.Require().NotNil(genesisState) + + s.Assert().Equal(types.DefaultParams(), genesisState.Params) + s.Assert().Empty(genesisState.ContractsMetadata) + s.Assert().NotEmpty(genesisState.BlockRewards) // height is 2 so we have some inflation rewards already + s.Assert().Empty(genesisState.TxRewards) + + genesisStateInitial = *genesisState + }) + + newParams := types.NewParams( + sdk.NewDecWithPrec(99, 2), + sdk.NewDecWithPrec(98, 2), + ) + + newMetadata := []types.ContractMetadata{ + { + ContractAddress: contractAddrs[0].String(), + OwnerAddress: accAddrs[0].String(), + }, + { + ContractAddress: contractAddrs[1].String(), + OwnerAddress: accAddrs[1].String(), + RewardsAddress: accAddrs[1].String(), + }, + } + + newBlockRewards := []types.BlockRewards{ + { + Height: 100, + InflationRewards: sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}, + MaxGas: 1000, + }, + { + Height: 200, + InflationRewards: sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(200)}, + MaxGas: 2000, + }, + } + + newTxRewards := []types.TxRewards{ + { + TxId: 110, + Height: 100, + FeeRewards: []sdk.Coin{ + {Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(150)}, + }, + }, + { + TxId: 210, + Height: 200, + FeeRewards: []sdk.Coin{ + {Denom: "uarch", Amount: sdk.NewInt(250)}, + }, + }, + } + + genesisStateImported := types.NewGenesisState(newParams, newMetadata, newBlockRewards, newTxRewards) + s.Run("Check import of an updated genesis", func() { + keeper.InitGenesis(ctx, genesisStateImported) + + genesisStateExpected := types.GenesisState{ + Params: newParams, + ContractsMetadata: append(genesisStateInitial.ContractsMetadata, newMetadata...), + BlockRewards: append(genesisStateInitial.BlockRewards, newBlockRewards...), + TxRewards: append(genesisStateInitial.TxRewards, newTxRewards...), + } + + genesisStateReceived := keeper.ExportGenesis(ctx) + s.Require().NotNil(genesisStateReceived) + s.Assert().Equal(genesisStateExpected.Params, genesisStateReceived.Params) + s.Assert().ElementsMatch(genesisStateExpected.ContractsMetadata, genesisStateReceived.ContractsMetadata) + s.Assert().ElementsMatch(genesisStateExpected.BlockRewards, genesisStateReceived.BlockRewards) + s.Assert().ElementsMatch(genesisStateExpected.TxRewards, genesisStateReceived.TxRewards) + }) +} diff --git a/x/rewards/keeper/state_test.go b/x/rewards/keeper/state_test.go new file mode 100644 index 00000000..84b1e0a3 --- /dev/null +++ b/x/rewards/keeper/state_test.go @@ -0,0 +1,194 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/x/rewards/types" +) + +// TestStates tests ContractMetadata, BlockRewards and TxRewards state storages. +// Test append multiple objects for different blocks to make sure there are no namespace +// collisions (prefixed store keys) and state indexes work as expected. +// Final test stage is the cascade delete of reward objects. +func (s *KeeperTestSuite) TestStates() { + type testBlockData struct { + BlockRewards types.BlockRewards + TxRewards []types.TxRewards + } + + type testData struct { + Metadata []types.ContractMetadata + Blocks []testBlockData + } + + chain := s.chain + ctx, keeper := chain.GetContext(), chain.GetApp().RewardsKeeper + metaState, blockState, txState := keeper.GetState().ContractMetadataState(ctx), keeper.GetState().BlockRewardsState(ctx), keeper.GetState().TxRewardsState(ctx) + + // Fixtures + startBlock := ctx.BlockHeight() + contractAddrs := e2eTesting.GenContractAddresses(3) + accAddrs, _ := e2eTesting.GenAccounts(3) + coin1 := sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)} + coin2 := sdk.Coin{Denom: "uarch", Amount: sdk.NewInt(200)} + + testDataExpected := testData{ + Metadata: []types.ContractMetadata{ + // Metadata 1 + { + ContractAddress: contractAddrs[0].String(), + OwnerAddress: accAddrs[0].String(), + }, + // Metadata 2 + { + ContractAddress: contractAddrs[1].String(), + OwnerAddress: accAddrs[1].String(), + RewardsAddress: accAddrs[2].String(), + }, + }, + Blocks: []testBlockData{ + // Block 1 (no gas, no rewards) + { + BlockRewards: types.BlockRewards{ + Height: startBlock, + }, + TxRewards: []types.TxRewards{ + // Tx 1 (no rewards) + { + TxId: 1, + Height: startBlock, + }, + // Tx 2 + { + TxId: 2, + Height: startBlock, + FeeRewards: []sdk.Coin{coin1}, + }, + }, + }, + // Block 2 + { + BlockRewards: types.BlockRewards{ + Height: startBlock + 1, + InflationRewards: sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(100)}, + MaxGas: 1000, + }, + TxRewards: []types.TxRewards{ + // Tx 3 + { + TxId: 3, + Height: startBlock + 1, + FeeRewards: []sdk.Coin{coin1, coin2}, + }, + }, + }, + }, + } + + // Upload fixtures + for _, metadata := range testDataExpected.Metadata { + metaState.SetContractMetadata(metadata.MustGetContractAddress(), metadata) + } + for _, blockData := range testDataExpected.Blocks { + blockRewards := blockData.BlockRewards + blockState.CreateBlockRewards(blockRewards.Height, blockRewards.InflationRewards, blockRewards.MaxGas) + + for _, txRewards := range blockData.TxRewards { + txState.CreateTxRewards(txRewards.TxId, txRewards.Height, txRewards.FeeRewards) + } + } + + // Check non-existing records + s.Run("Check non-existing metadata record", func() { + _, metaFound := metaState.GetContractMetadata(contractAddrs[2]) + s.Assert().False(metaFound) + }) + s.Run("Check non-existing BlockRewards and TxRewards records", func() { + _, blockRewardsFound := blockState.GetBlockRewards(startBlock + 10) + s.Assert().False(blockRewardsFound) + + _, txRewardsFound := txState.GetTxRewards(10) + s.Assert().False(txRewardsFound) + }) + + // Check that the states are as expected + s.Run("Check objects one by one", func() { + for _, metadataExpected := range testDataExpected.Metadata { + metaReceived, found := metaState.GetContractMetadata(metadataExpected.MustGetContractAddress()) + s.Require().True(found) + s.Assert().Equal(metadataExpected, metaReceived) + } + + for i, blockData := range testDataExpected.Blocks { + blockRewardsExpected := blockData.BlockRewards + blockRewardsReceived, found := blockState.GetBlockRewards(blockRewardsExpected.Height) + s.Require().True(found, "BlockRewards [%d]: not found", i) + + // Modify the expected coin because proto.Unmarshal creates a coin with zero amount (not nil) + if blockRewardsExpected.InflationRewards.Amount.IsNil() { + blockRewardsExpected.InflationRewards.Amount = sdk.ZeroInt() + } + s.Assert().Equal(blockRewardsExpected, blockRewardsReceived, "BlockRewards [%d]: wrong value", i) + + for j, txRewardsExpected := range blockData.TxRewards { + txRewardsReceived, found := txState.GetTxRewards(txRewardsExpected.TxId) + s.Require().True(found, "TxRewards [%d][%d]: not found", i, j) + s.Assert().Equal(txRewardsExpected, txRewardsReceived, "TxRewards [%d][%d]: wrong value", i, j) + } + } + }) + + // Check TxRewards search via block index + s.Run("Check TxRewards block index", func() { + // 1st block + { + height := testDataExpected.Blocks[0].BlockRewards.Height + txRewardsExpected := testDataExpected.Blocks[0].TxRewards + + txRewardsReceived := txState.GetTxRewardsByBlock(height) + s.Assert().ElementsMatch(txRewardsExpected, txRewardsReceived, "TxRewardsByBlock (%d): wrong value", height) + } + + // 2nd block + { + height := testDataExpected.Blocks[1].BlockRewards.Height + txRewardsExpected := testDataExpected.Blocks[1].TxRewards + + txRewardsReceived := txState.GetTxRewardsByBlock(height) + s.Assert().ElementsMatch(txRewardsExpected, txRewardsReceived, "TxRewardsByBlock (%d): wrong value", height) + } + }) + + // Check rewards removal + s.Run("Check rewards removal for the 1st block", func() { + height1, height2 := testDataExpected.Blocks[0].BlockRewards.Height, testDataExpected.Blocks[1].BlockRewards.Height + txs2 := testDataExpected.Blocks[1].TxRewards + + keeper.GetState().DeleteBlockRewardsCascade(ctx, height1) + + block1Txs := txState.GetTxRewardsByBlock(height1) + s.Assert().Empty(block1Txs) + + block2Txs := txState.GetTxRewardsByBlock(height2) + s.Assert().Len(block2Txs, len(txs2)) + + _, block1Found := blockState.GetBlockRewards(height1) + s.Assert().False(block1Found) + + _, block2Found := blockState.GetBlockRewards(height2) + s.Assert().True(block2Found) + }) + + s.Run("Check rewards removal for the 2nd block", func() { + height2 := testDataExpected.Blocks[1].BlockRewards.Height + + keeper.GetState().DeleteBlockRewardsCascade(ctx, height2) + + block2Txs := txState.GetTxRewardsByBlock(height2) + s.Assert().Empty(block2Txs) + + _, block2Found := blockState.GetBlockRewards(height2) + s.Assert().False(block2Found) + }) +} diff --git a/x/rewards/types/events.pb.go b/x/rewards/types/events.pb.go index 7dd6adc1..57755255 100644 --- a/x/rewards/types/events.pb.go +++ b/x/rewards/types/events.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/rewards/v1beta1/events.proto diff --git a/x/rewards/types/genesis.pb.go b/x/rewards/types/genesis.pb.go index b3cfd126..301c62e1 100644 --- a/x/rewards/types/genesis.pb.go +++ b/x/rewards/types/genesis.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/rewards/v1beta1/genesis.proto diff --git a/x/rewards/types/query.pb.go b/x/rewards/types/query.pb.go index 3168d2f7..b0e75b3c 100644 --- a/x/rewards/types/query.pb.go +++ b/x/rewards/types/query.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/rewards/v1beta1/query.proto diff --git a/x/rewards/types/query.pb.gw.go b/x/rewards/types/query.pb.gw.go index 3048376c..c7c26fb0 100644 --- a/x/rewards/types/query.pb.gw.go +++ b/x/rewards/types/query.pb.gw.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. // source: archway/rewards/v1beta1/query.proto diff --git a/x/rewards/types/rewards.pb.go b/x/rewards/types/rewards.pb.go index e1dafcbb..aeb9499b 100644 --- a/x/rewards/types/rewards.pb.go +++ b/x/rewards/types/rewards.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/rewards/v1beta1/rewards.proto diff --git a/x/rewards/types/tx.pb.go b/x/rewards/types/tx.pb.go index 31c75a51..082bb0cf 100644 --- a/x/rewards/types/tx.pb.go +++ b/x/rewards/types/tx.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/rewards/v1beta1/tx.proto diff --git a/x/tracking/ante/tracking.go b/x/tracking/ante/tracking.go index 1934b86a..2e461bba 100644 --- a/x/tracking/ante/tracking.go +++ b/x/tracking/ante/tracking.go @@ -18,11 +18,6 @@ type TxGasTrackingDecorator struct { // AnteHandle implements the AnteDecorator interface. func (d TxGasTrackingDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - // TODO: commented out because we need to have x/tracking and x/rewards in sync. - //if ctx.BlockHeight() <= 1 { - // return next(ctx, tx, simulate) - //} - d.keeper.TrackNewTx(ctx) return next(ctx, tx, simulate) diff --git a/x/tracking/ante/tracking_test.go b/x/tracking/ante/tracking_test.go new file mode 100644 index 00000000..046737b3 --- /dev/null +++ b/x/tracking/ante/tracking_test.go @@ -0,0 +1,25 @@ +package ante_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg/testutils" + "github.com/archway-network/archway/x/tracking/ante" +) + +func TestTrackingAnteHandler(t *testing.T) { + chain := e2eTesting.NewTestChain(t, 1) + ctx, keeper := chain.GetContext(), chain.GetApp().TrackingKeeper + + anteHandler := ante.NewTxGasTrackingDecorator(keeper) + for i := uint64(1); i < 10; i++ { + _, err := anteHandler.AnteHandle(ctx, nil, false, testutils.NoopAnteHandler) + require.NoError(t, err) + + assert.Equal(t, i, keeper.GetCurrentTxID(ctx)) + } +} diff --git a/x/tracking/keeper/state_test.go b/x/tracking/keeper/state_test.go index 63547160..6c1d12a4 100644 --- a/x/tracking/keeper/state_test.go +++ b/x/tracking/keeper/state_test.go @@ -10,6 +10,7 @@ import ( // TestStates tests TxInfo and ContractOperationInfo state storages. // Test append multiple objects for different blocks to make sure there are no namespace // collisions (prefixed store keys) and state indexes work as expected. +// Final test stage is the cascade delete of all objects. func (s *KeeperTestSuite) TestStates() { type testData struct { Tx types.TxInfo @@ -21,6 +22,7 @@ func (s *KeeperTestSuite) TestStates() { // Fixtures startBlock := ctx.BlockHeight() + testDataExpected := []testData{ // Block 1, Tx 1: 3 ops { @@ -154,8 +156,9 @@ func (s *KeeperTestSuite) TestStates() { block = ctx.BlockHeight() } - // Start tracking a new Tx (emulate Ante handler) + // Start tracking a new Tx (emulate Ante handler) and check TxID sequence is correct keeper.TrackNewTx(ctx) + s.Require().Equal(data.Tx.Id, keeper.GetState().TxInfoState(ctx).GetCurrentTxID()) // Ingest contract operations records := make([]wasmTypes.ContractGasRecord, 0, len(data.Ops)) @@ -176,6 +179,15 @@ func (s *KeeperTestSuite) TestStates() { } keeper.FinalizeBlockTxTracking(ctx) + // Check non-existing records + s.Run("Check non-existing state records", func() { + _, txFound := keeper.GetState().TxInfoState(ctx).GetTxInfo(10) + s.Assert().False(txFound) + + _, opFound := keeper.GetState().ContractOpInfoState(ctx).GetContractOpInfo(100) + s.Assert().False(opFound) + }) + // Check that the states are as expected s.Run("Check objects one by one", func() { opState := keeper.GetState().ContractOpInfoState(ctx) @@ -240,19 +252,35 @@ func (s *KeeperTestSuite) TestStates() { // Check records removal s.Run("Check records removal for the 1st block", func() { + txState := keeper.GetState().TxInfoState(ctx) + keeper.GetState().DeleteTxInfosCascade(ctx, startBlock+1) - block1Txs := keeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(startBlock + 1) + block1Txs := txState.GetTxInfosByBlock(startBlock + 1) s.Assert().Empty(block1Txs) - block2Txs := keeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(startBlock + 2) + block2Txs := txState.GetTxInfosByBlock(startBlock + 2) s.Assert().Len(block2Txs, 2) + + _, tx1Found := txState.GetTxInfo(testDataExpected[0].Tx.Id) + s.Assert().False(tx1Found) + + _, tx2Found := txState.GetTxInfo(testDataExpected[1].Tx.Id) + s.Assert().False(tx2Found) }) s.Run("Check records removal for the 2nd block", func() { + txState := keeper.GetState().TxInfoState(ctx) + keeper.GetState().DeleteTxInfosCascade(ctx, startBlock+2) - block2Txs := keeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(startBlock + 2) + block2Txs := txState.GetTxInfosByBlock(startBlock + 2) s.Assert().Empty(block2Txs) + + _, tx3Found := txState.GetTxInfo(testDataExpected[2].Tx.Id) + s.Assert().False(tx3Found) + + _, tx4Found := txState.GetTxInfo(testDataExpected[3].Tx.Id) + s.Assert().False(tx4Found) }) } diff --git a/x/tracking/types/genesis.pb.go b/x/tracking/types/genesis.pb.go index b57dc389..95281f5f 100644 --- a/x/tracking/types/genesis.pb.go +++ b/x/tracking/types/genesis.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/tracking/v1beta1/genesis.proto diff --git a/x/tracking/types/query.pb.go b/x/tracking/types/query.pb.go index 1d96fb32..6abbfea3 100644 --- a/x/tracking/types/query.pb.go +++ b/x/tracking/types/query.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/tracking/v1beta1/query.proto diff --git a/x/tracking/types/query.pb.gw.go b/x/tracking/types/query.pb.gw.go index 08b57475..52255e47 100644 --- a/x/tracking/types/query.pb.gw.go +++ b/x/tracking/types/query.pb.gw.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. // source: archway/tracking/v1beta1/query.proto diff --git a/x/tracking/types/tracking.pb.go b/x/tracking/types/tracking.pb.go index 1a1659bd..a6224cf3 100644 --- a/x/tracking/types/tracking.pb.go +++ b/x/tracking/types/tracking.pb.go @@ -1,3 +1,4 @@ +// DONTCOVER // Code generated by protoc-gen-gogo. DO NOT EDIT. // source: archway/tracking/v1beta1/tracking.proto From e849565ac316b9630e8cd5070cb6458b6aa20b10 Mon Sep 17 00:00:00 2001 From: edjroz Date: Tue, 2 Aug 2022 14:28:07 +0000 Subject: [PATCH 16/27] add codecov config --- codecov.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..5a5d89b2 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,13 @@ +coverage: + status: + project: + default: + target: 70 + threshold: 1% + + patch: + default: false +ignore: + - "**/*.pb.go" + - "third_party" + - "vendor" From a525728ade2837ccf965e32ed3cd5780d71ac4c6 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Tue, 2 Aug 2022 18:13:48 +0300 Subject: [PATCH 17/27] Big integration test added --- e2e/gastracking_test.go | 267 ++++++++++++++++--- e2e/testing/chain.go | 10 +- e2e/testing/chain_options.go | 15 ++ e2e/testing/common.go | 9 +- x/gastracker/integration/integration_test.go | 3 +- 5 files changed, 260 insertions(+), 44 deletions(-) diff --git a/e2e/gastracking_test.go b/e2e/gastracking_test.go index 514f8932..382b453b 100644 --- a/e2e/gastracking_test.go +++ b/e2e/gastracking_test.go @@ -1,37 +1,112 @@ package e2e import ( + "encoding/json" "strconv" "time" voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg" rewardsTypes "github.com/archway-network/archway/x/rewards/types" trackingTypes "github.com/archway-network/archway/x/tracking/types" ) -// TestGasTracking_TxGasConsumption tries to check gas consumption by contract execution, but -// since we can't (or I don't know how) check the real gas consumption by WASM only, it is kind of useless. -// TODO: modify the Voter (or create an other contract) with a pure "Execute" call without bank involvement. -func (s *E2ETestSuite) TestGasTracking_TxGasConsumption() { - chain := s.chainA +// TestGasTrackingAndRewardsDistribution tests the whole x/tracking + x/rewards chain: +// * sets contract metadata and check an emitted event; +// * sends WASM Execute event; +// * checks x/tracking records created; +// * checks x/rewards records created; +// * checks x/rewards events emitted; +// * checks rewards address receives distributed rewards; +func (s *E2ETestSuite) TestGasTrackingAndRewardsDistribution() { + txFeeRebateRewardsRatio := sdk.NewDecWithPrec(5, 1) + inflationRewardsRatio := sdk.NewDecWithPrec(5, 1) + blockGasLimit := int64(10_000_000) - acc := chain.GetAccount(0) - contractAddr := s.VoterUploadAndInstantiate(chain, acc) + // Setup (create new chain here with custom params) + chain := e2eTesting.NewTestChain(s.T(), 1, + e2eTesting.WithTxFeeRebatesRewardsRatio(txFeeRebateRewardsRatio), + e2eTesting.WithInflationRewardsRatio(inflationRewardsRatio), + e2eTesting.WithBlockGasLimit(blockGasLimit), + // Artificially increase the minted inflation coin to get some rewards for the contract (otherwise contractOp gas / blockGasLimit ratio will be 0) + e2eTesting.WithMintParams( + sdk.NewDecWithPrec(8, 1), + sdk.NewDecWithPrec(8, 1), + 1, + ), + ) + trackingKeeper, rewardsKeeper := chain.GetApp().TrackingKeeper, chain.GetApp().RewardsKeeper - // Set metadata to get rewards + senderAcc := chain.GetAccount(0) + contractAddr := s.VoterUploadAndInstantiate(chain, senderAcc) + accAddrs, _ := e2eTesting.GenAccounts(1) // an empty account + + // Inputs + txFees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000))) + rewardsAddr := accAddrs[0] + + // Collected values + var abciEvents []abci.Event // all ABCI events from Tx execution, BeginBlocker and EndBlockers + var txID uint64 // tracked Tx ID + var txGasUsed, txGasTracked uint64 // tx gas tracking + + // Expected values (set below) + contractMetadataExpected := rewardsTypes.ContractMetadata{ + ContractAddress: contractAddr.String(), + OwnerAddress: senderAcc.Address.String(), + RewardsAddress: rewardsAddr.String(), + } + var contractTxRewardsExpected sdk.Coins // contract tx fee rebate rewards expected + var contractInflationRewardsExpected sdk.Coin // contract inflation rewards expected + var contractTotalRewardsExpected sdk.Coins // contract tx + inflation rewards expected + var blockInflationRewardsExpected sdk.Coin // block rewards expected + + // Set metadata and fetch ABCI events { - chain.SetContractMetadata(acc, contractAddr, rewardsTypes.ContractMetadata{ - OwnerAddress: acc.Address.String(), - RewardsAddress: acc.Address.String(), - }) + msg := rewardsTypes.NewMsgSetContractMetadata(senderAcc.Address, contractAddr, &senderAcc.Address, &rewardsAddr) + _, _, events, _ := chain.SendMsgs(senderAcc, true, []sdk.Msg{msg}) + + abciEvents = append(abciEvents, events...) } - // Send Tx manually to get Tx results - var txGasUsed uint64 + // Check x/rewards metadata set event + s.Run("Check metadata set event", func() { + eventContractAddr := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractMetadataSetEvent", + "contract_address", + ) + eventMetadataBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractMetadataSetEvent", + "metadata", + ) + + var metadataReceived rewardsTypes.ContractMetadata + s.Require().NoError(json.Unmarshal([]byte(eventMetadataBz), &metadataReceived)) + + s.Assert().Equal(contractAddr.String(), eventContractAddr) + s.Assert().Equal(contractMetadataExpected, metadataReceived) + }) + + // Estimate block rewards (inflation portion that should be distributed over contracts) + // This should be done before the actual Tx to get Minter values for the Tx's block + { + ctx := chain.GetContext() + + mintKeeper := chain.GetApp().MintKeeper + mintParams := mintKeeper.GetParams(ctx) + + mintedCoin := chain.GetApp().MintKeeper.GetMinter(ctx).BlockProvision(mintParams) + inflationRewards, _ := pkg.SplitCoins(sdk.NewCoins(mintedCoin), inflationRewardsRatio) + s.Require().Len(inflationRewards, 1) + blockInflationRewardsExpected = inflationRewards[0] + } + + // Send contract Execute Tx with fees, fetch ABCI events and Tx gas used { req := voterTypes.MsgExecute{ NewVoting: &voterTypes.NewVotingRequest{ @@ -44,7 +119,7 @@ func (s *E2ETestSuite) TestGasTracking_TxGasConsumption() { s.Require().NoError(err) msg := wasmdTypes.MsgExecuteContract{ - Sender: acc.Address.String(), + Sender: senderAcc.Address.String(), Contract: contractAddr.String(), Msg: reqBz, Funds: sdk.NewCoins(sdk.Coin{ @@ -52,38 +127,158 @@ func (s *E2ETestSuite) TestGasTracking_TxGasConsumption() { Amount: sdk.NewIntFromUint64(DefNewVotingCostAmt), }), } + gasInfo, _, events, _ := chain.SendMsgs(senderAcc, true, []sdk.Msg{&msg}, + e2eTesting.WithMsgFees(txFees...), + ) - gasInfo, _, events, _ := chain.SendMsgs(acc, true, []sdk.Msg{&msg}) txGasUsed = gasInfo.GasUsed - - // TODO: add proper event checks - calcEventContractAddr, err := strconv.Unquote( - e2eTesting.GetStringEventAttribute(events, - "archway.rewards.v1beta1.ContractRewardCalculationEvent", - "contract_address", - ), - ) - s.Require().NoError(err) - s.Assert().Equal(contractAddr.String(), calcEventContractAddr) + abciEvents = append(abciEvents, events...) } - // Get gas tracking data - var trackedGas uint64 - { + // Check x/tracking Tx and ContractOps records + s.Run("Check gas tracked records", func() { ctx := chain.GetContext() + txInfoState := trackingKeeper.GetState().TxInfoState(ctx) + contractOpState := trackingKeeper.GetState().ContractOpInfoState(ctx) - txInfos := chain.GetApp().TrackingKeeper.GetState().TxInfoState(ctx).GetTxInfosByBlock(ctx.BlockHeight() - 1) + // TxInfo + txInfos := txInfoState.GetTxInfosByBlock(ctx.BlockHeight() - 1) s.Require().Len(txInfos, 1) + s.Assert().NotEmpty(txInfos[0].Id) + s.Assert().EqualValues(ctx.BlockHeight()-1, txInfos[0].Height) + s.Assert().NotEmpty(txInfos[0].TotalGas) + + txID = txInfos[0].Id + txGasTracked = txInfos[0].TotalGas - contractOps := chain.GetApp().TrackingKeeper.GetState().ContractOpInfoState(ctx).GetContractOpInfoByTxID(txInfos[0].Id) + // Contract operations + contractOps := contractOpState.GetContractOpInfoByTxID(txInfos[0].Id) s.Require().Len(contractOps, 1) + s.Assert().NotEmpty(contractOps[0].Id) + s.Assert().Equal(txInfos[0].Id, contractOps[0].TxId) + s.Assert().Equal(contractAddr.String(), contractOps[0].ContractAddress) s.Assert().Equal(trackingTypes.ContractOperation_CONTRACT_OPERATION_EXECUTION, contractOps[0].OperationType) - s.Assert().Equal(contractOps[0].VmGas+contractOps[0].SdkGas, txInfos[0].TotalGas) + s.Assert().NotEmpty(contractOps[0].VmGas) + s.Assert().NotEmpty(contractOps[0].SdkGas) + + contractGasTracked := contractOps[0].VmGas + contractOps[0].SdkGas + + // Assert gas consumptions + s.Assert().Equal(txGasTracked, contractGasTracked) + s.Assert().LessOrEqual(txGasTracked, txGasUsed) + }) + + // Estimate contract rewards + // This should be done after the actual Tx to get gas tracking data + { + // Contract fee rewards + txFeeRewards, _ := pkg.SplitCoins(txFees, txFeeRebateRewardsRatio) + contractTxRewardsExpected = txFeeRewards - trackedGas = txInfos[0].TotalGas + // Contract inflation rewards + contractToBlockGasRatio := sdk.NewDec(int64(txGasTracked)).Quo(sdk.NewDec(blockGasLimit)) + contractInflationRewardsExpected = sdk.Coin{ + Denom: blockInflationRewardsExpected.Denom, + Amount: blockInflationRewardsExpected.Amount.ToDec().Mul(contractToBlockGasRatio).TruncateInt(), + } + + // Total + contractTotalRewardsExpected = contractTxRewardsExpected.Add(contractInflationRewardsExpected) } - s.Assert().NotEmpty(trackedGas) - s.Assert().Less(trackedGas, txGasUsed) - s.T().Log("Gas consumption:", trackedGas, ">", txGasUsed) + // Check x/rewards Tx record + s.Run("Check tx fee rebate rewards records", func() { + ctx := chain.GetContext() + txRewardsState := rewardsKeeper.GetState().TxRewardsState(ctx) + + txRewards := txRewardsState.GetTxRewardsByBlock(ctx.BlockHeight() - 1) + s.Require().Len(txRewards, 1) + s.Assert().Equal(txID, txRewards[0].TxId) + s.Assert().Equal(ctx.BlockHeight()-1, txRewards[0].Height) + s.Assert().Equal(contractTxRewardsExpected.String(), sdk.NewCoins(txRewards[0].FeeRewards...).String()) + }) + + // Check x/rewards Block record + s.Run("Check block rewards record", func() { + ctx := chain.GetContext() + blockRewardsState := rewardsKeeper.GetState().BlockRewardsState(ctx) + + blockRewards, found := blockRewardsState.GetBlockRewards(ctx.BlockHeight() - 1) + s.Require().True(found) + s.Assert().Equal(ctx.BlockHeight()-1, blockRewards.Height) + s.Assert().Equal(blockInflationRewardsExpected.String(), blockRewards.InflationRewards.String()) + s.Assert().EqualValues(blockGasLimit, blockRewards.MaxGas) + }) + + // Check x/rewards calculation event + s.Run("Check calculation event", func() { + eventContractAddr := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "contract_address", + ) + eventGasConsumedBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "gas_consumed", + ) + eventInflationRewardsBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "inflation_rewards", + ) + eventFeeRebateRewardsBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "fee_rebate_rewards", + ) + eventMetadataBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "metadata", + ) + + gasConsumedReceived, err := strconv.ParseUint(eventGasConsumedBz, 10, 64) + s.Require().NoError(err) + + var inflationRewardsReceived sdk.Coin + s.Require().NoError(json.Unmarshal([]byte(eventInflationRewardsBz), &inflationRewardsReceived)) + + var feeRebateRewardsReceived sdk.Coins + s.Require().NoError(json.Unmarshal([]byte(eventFeeRebateRewardsBz), &feeRebateRewardsReceived)) + s.Require().NoError(err) + + var metadataReceived rewardsTypes.ContractMetadata + s.Require().NoError(json.Unmarshal([]byte(eventMetadataBz), &metadataReceived)) + + s.Assert().Equal(contractAddr.String(), eventContractAddr) + s.Assert().Equal(txGasTracked, gasConsumedReceived) + s.Assert().Equal(contractInflationRewardsExpected.String(), inflationRewardsReceived.String()) + s.Assert().Equal(contractTxRewardsExpected.String(), feeRebateRewardsReceived.String()) + s.Assert().Equal(contractMetadataExpected, metadataReceived) + }) + + // Check x/rewards distribution event + s.Run("Check distribution event", func() { + eventContractAddr := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardDistributionEvent", + "contract_address", + ) + eventRewardsAddr := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardDistributionEvent", + "reward_address", + ) + eventRewardsBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardDistributionEvent", + "rewards", + ) + + var rewardsReceived sdk.Coins + s.Require().NoError(json.Unmarshal([]byte(eventRewardsBz), &rewardsReceived)) + + s.Assert().Equal(contractAddr.String(), eventContractAddr) + s.Assert().Equal(contractMetadataExpected.RewardsAddress, eventRewardsAddr) + s.Assert().Equal(contractTotalRewardsExpected.String(), rewardsReceived.String()) + }) + + // Check rewards address balance + s.Run("Check funds transferred", func() { + accCoins := chain.GetBalance(rewardsAddr) + s.Assert().Equal(contractTotalRewardsExpected.String(), accCoins.String()) + }) } diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 0f296e37..1e0f2fd4 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -350,7 +350,7 @@ type sendMsgOptions struct { } // WithMsgFees option add fees to the transaction. -func WithMsgFees(coins sdk.Coins) SendMsgOption { +func WithMsgFees(coins ...sdk.Coin) SendMsgOption { return func(opt *sendMsgOptions) { opt.fees = coins } @@ -383,6 +383,7 @@ func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg } t := chain.t + var abciEvents []abci.Event // Get the sender account senderAccI := chain.app.AccountKeeper.GetAccount(chain.GetContext(), senderAcc.Address) @@ -410,12 +411,11 @@ func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg require.Error(t, err) require.Nil(t, res) } + abciEvents = append(abciEvents, res.Events...) - var abciEvents []abci.Event if !options.noBlockChange { - ebEvents := chain.EndBlock() - bbEvents := chain.BeginBlock() - abciEvents = append(ebEvents, bbEvents...) + abciEvents = append(abciEvents, chain.EndBlock()...) + abciEvents = append(abciEvents, chain.BeginBlock()...) } return gasInfo, res, abciEvents, err diff --git a/e2e/testing/chain_options.go b/e2e/testing/chain_options.go index 44cc6a04..7ecc566f 100644 --- a/e2e/testing/chain_options.go +++ b/e2e/testing/chain_options.go @@ -3,6 +3,7 @@ package e2eTesting import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + mintTypes "github.com/cosmos/cosmos-sdk/x/mint/types" abci "github.com/tendermint/tendermint/abci/types" "github.com/archway-network/archway/app" @@ -55,3 +56,17 @@ func WithTxFeeRebatesRewardsRatio(ratio sdk.Dec) TestChainGenesisOption { genesis[rewardsTypes.ModuleName] = cdc.MustMarshalJSON(&rewardsGenesis) } } + +// WithMintParams sets x/mint inflation calculation parameters. +func WithMintParams(inflationMin, inflationMax sdk.Dec, blocksPerYear uint64) TestChainGenesisOption { + return func(cdc codec.Codec, genesis app.GenesisState) { + var mintGenesis mintTypes.GenesisState + cdc.MustUnmarshalJSON(genesis[mintTypes.ModuleName], &mintGenesis) + + mintGenesis.Params.InflationMin = inflationMin + mintGenesis.Params.InflationMax = inflationMax + mintGenesis.Params.BlocksPerYear = blocksPerYear + + genesis[mintTypes.ModuleName] = cdc.MustMarshalJSON(&mintGenesis) + } +} diff --git a/e2e/testing/common.go b/e2e/testing/common.go index d82fd998..f9383f07 100644 --- a/e2e/testing/common.go +++ b/e2e/testing/common.go @@ -1,6 +1,8 @@ package e2eTesting import ( + "strconv" + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" @@ -20,7 +22,12 @@ func GetStringEventAttribute(events []abci.Event, eventType, attrKey string) str continue } - return string(attr.Value) + attrValue := string(attr.Value) + if valueUnquoted, err := strconv.Unquote(string(attr.Value)); err == nil { + attrValue = valueUnquoted + } + + return attrValue } } diff --git a/x/gastracker/integration/integration_test.go b/x/gastracker/integration/integration_test.go index 4d60dd43..2c206035 100644 --- a/x/gastracker/integration/integration_test.go +++ b/x/gastracker/integration/integration_test.go @@ -43,7 +43,7 @@ func TestRewardsCollection(t *testing.T) { }, } txFees := sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)) - _, _, err = chain.SendMsgs(chain.GetAccount(0), true, []sdk.Msg{&wasmtypes.MsgExecuteContract{ + chain.SendMsgs(chain.GetAccount(0), true, []sdk.Msg{&wasmtypes.MsgExecuteContract{ Sender: chain.GetAccount(0).Address.String(), Contract: contractAddr.String(), Msg: jsonMarshal(t, msg), @@ -51,7 +51,6 @@ func TestRewardsCollection(t *testing.T) { }}, e2eTesting.WithMsgFees(txFees), ) - require.NoError(t, err) balance := chain.GetBalance(authtypes.NewModuleAddress(gastracker.ModuleName)) totalInflation = sdk.NewCoin( From 89ef3787a2de1115b85b4ffa2e62d6f83f86d169 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Tue, 2 Aug 2022 18:18:18 +0300 Subject: [PATCH 18/27] Test chain fix --- e2e/testing/chain.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index 1e0f2fd4..d525b2f2 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -411,7 +411,9 @@ func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg require.Error(t, err) require.Nil(t, res) } - abciEvents = append(abciEvents, res.Events...) + if res != nil { + abciEvents = append(abciEvents, res.Events...) + } if !options.noBlockChange { abciEvents = append(abciEvents, chain.EndBlock()...) From db607bbc1ce1b9d77283986560a17ddc74b7d4cf Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Tue, 2 Aug 2022 18:28:03 +0300 Subject: [PATCH 19/27] Parth PR feedback changes --- x/rewards/ante/fee_deduction.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/x/rewards/ante/fee_deduction.go b/x/rewards/ante/fee_deduction.go index f7461fa8..20a89586 100644 --- a/x/rewards/ante/fee_deduction.go +++ b/x/rewards/ante/fee_deduction.go @@ -104,8 +104,12 @@ func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, tx sdk.Tx, acc authTyp // Check if transaction has wasmd operations hasWasmMsgs := false for _, msg := range tx.GetMsgs() { - _, ok := msg.(*wasmdTypes.MsgExecuteContract) - if ok { + // We can use switch here, but breaking the for loop from switch is less readable + if _, ok := msg.(*wasmdTypes.MsgExecuteContract); ok { + hasWasmMsgs = true + break + } + if _, ok := msg.(*wasmdTypes.MsgMigrateContract); ok { hasWasmMsgs = true break } From fcb015b4a8a7c9d562ae1f6afcce6c70112eb2df Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Tue, 2 Aug 2022 19:31:16 +0300 Subject: [PATCH 20/27] Coins split logic changed: doesn't return invalid sdk.Coins if one of the stacks is empty; ModuleToModule checks for empty coins added --- pkg/coins.go | 10 +++++----- pkg/coins_test.go | 13 +++++++++++++ x/rewards/ante/fee_deduction.go | 12 ++++++++---- x/rewards/mintbankkeeper/keeper.go | 12 ++++++++---- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/pkg/coins.go b/pkg/coins.go index 79689306..0de23b05 100644 --- a/pkg/coins.go +++ b/pkg/coins.go @@ -5,18 +5,18 @@ import sdk "github.com/cosmos/cosmos-sdk/types" // SplitCoins splits coins in a proportion defined by the ratio. // CONTRACT: inputs must be valid. func SplitCoins(coins sdk.Coins, ratio sdk.Dec) (stack1, stack2 sdk.Coins) { - stack1 = make([]sdk.Coin, len(coins)) - stack2 = make([]sdk.Coin, len(coins)) + stack1 = sdk.NewCoins() + stack2 = sdk.NewCoins() - for i, coin := range coins { + for _, coin := range coins { stack1Coin := sdk.Coin{ Denom: coin.Denom, Amount: coin.Amount.ToDec().Mul(ratio).TruncateInt(), } stack2Coin := coin.Sub(stack1Coin) - stack1[i] = stack1Coin - stack2[i] = stack2Coin + stack1 = stack1.Add(stack1Coin) + stack2 = stack2.Add(stack2Coin) } return diff --git a/pkg/coins_test.go b/pkg/coins_test.go index 9a7793c7..3e88ae37 100644 --- a/pkg/coins_test.go +++ b/pkg/coins_test.go @@ -42,6 +42,12 @@ func TestSplitCoins(t *testing.T) { stack1Expected: "3uatom,5ubtc", stack2Expected: "10uatom,15ubtc", }, + { + coins: "13uatom,20ubtc", + ratio: "1.0", + stack1Expected: "13uatom,20ubtc", + stack2Expected: "", + }, } for _, tc := range testCases { @@ -59,6 +65,13 @@ func TestSplitCoins(t *testing.T) { require.NoError(t, err) stack1Received, stack2Received := SplitCoins(coins, ratio) + if tc.stack1Expected == "" { + assert.True(t, stack1Received.Empty()) + } + if tc.stack2Expected == "" { + assert.True(t, stack2Received.Empty()) + } + assert.ElementsMatch(t, stack1Expected, stack1Received) assert.ElementsMatch(t, stack2Expected, stack2Received) }) diff --git a/x/rewards/ante/fee_deduction.go b/x/rewards/ante/fee_deduction.go index 20a89586..dcc11f0e 100644 --- a/x/rewards/ante/fee_deduction.go +++ b/x/rewards/ante/fee_deduction.go @@ -127,12 +127,16 @@ func (dfd DeductFeeDecorator) deductFees(ctx sdk.Context, tx sdk.Tx, acc authTyp // Split the fees between the fee collector account and the rewards collector account rewardsFees, authFees := pkg.SplitCoins(fees, rebateRatio) - if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, authFees); err != nil { - return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + if !authFees.Empty() { + if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), authTypes.FeeCollectorName, authFees); err != nil { + return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + } } - if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), rewardsTypes.ContractRewardCollector, rewardsFees); err != nil { - return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + if !rewardsFees.Empty() { + if err := dfd.bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), rewardsTypes.ContractRewardCollector, rewardsFees); err != nil { + return sdkErrors.Wrapf(sdkErrors.ErrInsufficientFunds, err.Error()) + } } // Track transaction fee rewards diff --git a/x/rewards/mintbankkeeper/keeper.go b/x/rewards/mintbankkeeper/keeper.go index 24b11c46..55cdb6dc 100644 --- a/x/rewards/mintbankkeeper/keeper.go +++ b/x/rewards/mintbankkeeper/keeper.go @@ -46,13 +46,17 @@ func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recip dappRewards, stakingRewards := pkg.SplitCoins(amt, ratio) // Send to the x/auth fee collector account - if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, stakingRewards); err != nil { - return err + if !stakingRewards.Empty() { + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, recipientModule, stakingRewards); err != nil { + return err + } } // Send to the x/rewards account - if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, rewardsTypes.ContractRewardCollector, dappRewards); err != nil { - return err + if !dappRewards.Empty() { + if err := k.bankKeeper.SendCoinsFromModuleToModule(ctx, senderModule, rewardsTypes.ContractRewardCollector, dappRewards); err != nil { + return err + } } // Check that only one coin has been minted From cdc40f6a3d55f7629294702775946da0448f3648 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Tue, 2 Aug 2022 22:00:53 +0300 Subject: [PATCH 21/27] Tx fees vs rewards demo test added --- e2e/gastracking_test.go | 1 - e2e/txfees_test.go | 129 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 e2e/txfees_test.go diff --git a/e2e/gastracking_test.go b/e2e/gastracking_test.go index 382b453b..5d6b658b 100644 --- a/e2e/gastracking_test.go +++ b/e2e/gastracking_test.go @@ -241,7 +241,6 @@ func (s *E2ETestSuite) TestGasTrackingAndRewardsDistribution() { var feeRebateRewardsReceived sdk.Coins s.Require().NoError(json.Unmarshal([]byte(eventFeeRebateRewardsBz), &feeRebateRewardsReceived)) - s.Require().NoError(err) var metadataReceived rewardsTypes.ContractMetadata s.Require().NoError(json.Unmarshal([]byte(eventMetadataBz), &metadataReceived)) diff --git a/e2e/txfees_test.go b/e2e/txfees_test.go new file mode 100644 index 00000000..e28efbd2 --- /dev/null +++ b/e2e/txfees_test.go @@ -0,0 +1,129 @@ +package e2e + +import ( + "encoding/json" + "fmt" + "time" + + voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" + wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + abci "github.com/tendermint/tendermint/abci/types" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + rewardsTypes "github.com/archway-network/archway/x/rewards/types" +) + +func (s *E2ETestSuite) TestTxFees() { + // Create a custom chain with fixed inflation (10%) and 10M block gas limit + chain := e2eTesting.NewTestChain(s.T(), 1, + e2eTesting.WithBlockGasLimit(10_000_000), + e2eTesting.WithMintParams( + sdk.NewDecWithPrec(1, 1), // 10% + sdk.NewDecWithPrec(1, 1), // 10% + uint64(60*60*8766/5), // standard calculation + ), + ) + + senderAcc := chain.GetAccount(0) + contractAddr := s.VoterUploadAndInstantiate(chain, senderAcc) + accAddrs, _ := e2eTesting.GenAccounts(1) // an empty account + rewardsAddr := accAddrs[0] + + // Set metadata + chain.SetContractMetadata(senderAcc, contractAddr, rewardsTypes.ContractMetadata{ + OwnerAddress: senderAcc.Address.String(), + RewardsAddress: rewardsAddr.String(), + }) + + txFee := sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()) + rewardsAccPrevBalance := chain.GetBalance(rewardsAddr) + for i := 0; i < 10; i++ { + // Send Tx + var abciEvents []abci.Event + var txGasUsed uint64 + { + req := voterTypes.MsgExecute{ + NewVoting: &voterTypes.NewVotingRequest{ + Name: "Test", + VoteOptions: []string{"Yes", "No"}, + Duration: uint64(time.Minute), + }, + } + reqBz, err := req.MarshalJSON() + s.Require().NoError(err) + + msg := wasmdTypes.MsgExecuteContract{ + Sender: senderAcc.Address.String(), + Contract: contractAddr.String(), + Msg: reqBz, + Funds: sdk.NewCoins(sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewIntFromUint64(DefNewVotingCostAmt)}), + } + gasUsed, _, events, _ := chain.SendMsgs(senderAcc, true, []sdk.Msg{&msg}, + e2eTesting.WithMsgFees(txFee), + ) + + abciEvents, txGasUsed = events, gasUsed.GasUsed + } + + // Get gas tracked for this Tx + var txGasTracked uint64 + { + ctx := chain.GetContext() + txInfosState := chain.GetApp().TrackingKeeper.GetState().TxInfoState(ctx) + + txInfos := txInfosState.GetTxInfosByBlock(ctx.BlockHeight() - 1) + s.Require().Len(txInfos, 1) + txGasTracked = txInfos[0].TotalGas + } + + // Get block rewards for prev. block + var blockRewards sdk.Coin + { + ctx := chain.GetContext() + blockRewardsState := chain.GetApp().RewardsKeeper.GetState().BlockRewardsState(ctx) + + blockRewardsInfo, found := blockRewardsState.GetBlockRewards(ctx.BlockHeight() - 1) + s.Require().True(found) + + blockRewards = blockRewardsInfo.InflationRewards + } + + // Get rewards for this Tx + var inflationRewards sdk.Coin + var feeRebateRewards sdk.Coins + { + eventInflationRewardsBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "inflation_rewards", + ) + eventFeeRebateRewardsBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.ContractRewardCalculationEvent", + "fee_rebate_rewards", + ) + + s.Require().NoError(json.Unmarshal([]byte(eventInflationRewardsBz), &inflationRewards)) + s.Require().NoError(json.Unmarshal([]byte(eventFeeRebateRewardsBz), &feeRebateRewards)) + } + + // Get rewards address balance diff + var rewardsAddrBalanceDiff sdk.Coins + { + curBalance := chain.GetBalance(rewardsAddr) + rewardsAddrBalanceDiff = curBalance.Sub(rewardsAccPrevBalance) + rewardsAccPrevBalance = curBalance + + s.Require().Equal(rewardsAddrBalanceDiff.String(), feeRebateRewards.Add(inflationRewards).String()) + } + + // Output + fmt.Printf("TxID %d (gas %d / %d): \t%s fees (%s infl rewards) -> \t%s rewards taken (%s + %s)\n", + i, txGasTracked, txGasUsed, + txFee.String(), blockRewards.String(), rewardsAddrBalanceDiff.String(), + feeRebateRewards.String(), inflationRewards.String(), + ) + + // Increase next TxFees + txFee.Amount = txFee.Amount.AddRaw(1) + } +} From 63dbcd37f8f9421a0b147b16a1399602ba3bb618 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Wed, 3 Aug 2022 16:59:01 +0300 Subject: [PATCH 22/27] Minimum consensus fee added --- app/ante.go | 8 +- docs/proto/proto-docs.md | 17 ++ e2e/gastracking_test.go | 6 +- e2e/testing/chain.go | 116 ++++++---- e2e/testing/chain_options.go | 48 ++++ e2e/testing/common.go | 34 +++ e2e/txfees_test.go | 130 +++++++++-- e2e/voter_test.go | 3 +- pkg/coin.go | 24 ++ pkg/testutils/tx.go | 7 + proto/archway/rewards/v1beta1/events.proto | 8 + proto/archway/rewards/v1beta1/genesis.proto | 5 + x/gastracker/integration/integration_test.go | 2 +- x/rewards/ante/fee_deduction.go | 12 +- x/rewards/ante/min_cons_fee.go | 63 +++++ x/rewards/ante/min_cons_fee_test.go | 92 ++++++++ x/rewards/keeper/distribution.go | 4 +- x/rewards/keeper/genesis.go | 8 + x/rewards/keeper/genesis_test.go | 6 +- x/rewards/keeper/keeper.go | 58 +++++ x/rewards/keeper/state.go | 10 + x/rewards/keeper/state_minconsfee.go | 37 +++ x/rewards/mintbankkeeper/keeper.go | 3 + x/rewards/mintbankkeeper/keeper_test.go | 19 ++ x/rewards/types/events.go | 9 + x/rewards/types/events.pb.go | 232 ++++++++++++++++--- x/rewards/types/genesis.go | 14 +- x/rewards/types/genesis.pb.go | 97 ++++++-- x/rewards/types/genesis_test.go | 12 + x/rewards/types/keys.go | 11 + 30 files changed, 973 insertions(+), 122 deletions(-) create mode 100644 x/rewards/ante/min_cons_fee.go create mode 100644 x/rewards/ante/min_cons_fee_test.go create mode 100644 x/rewards/keeper/state_minconsfee.go diff --git a/app/ante.go b/app/ante.go index d07f4f6f..c6035388 100644 --- a/app/ante.go +++ b/app/ante.go @@ -57,8 +57,10 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { } anteDecorators := []sdk.AnteDecorator{ - ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first - wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), // after setup context to enforce limits early + // Outermost AnteDecorator (SetUpContext must be called first) + ante.NewSetUpContextDecorator(), + // After setup context to enforce limits early + wasmkeeper.NewLimitSimulationGasDecorator(options.WasmConfig.SimulationGasLimit), wasmkeeper.NewCountTXDecorator(options.TXCounterStoreKey), ante.NewRejectExtensionOptionsDecorator(), ante.NewMempoolFeeDecorator(), @@ -66,6 +68,8 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewTxTimeoutHeightDecorator(), ante.NewValidateMemoDecorator(options.AccountKeeper), ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + // Custom Archway minimum fee checker + rewardsAnte.NewMinFeeDecorator(options.RewardsKeeper), // Custom Archway interceptor to track new transactions trackingAnte.NewTxGasTrackingDecorator(options.TrackingKeeper), // Custom Archway fee deduction, which splits fees between x/rewards and x/auth fee collector diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index 6cdc992d..b54cc310 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -44,6 +44,7 @@ - [ContractMetadataSetEvent](#archway.rewards.v1beta1.ContractMetadataSetEvent) - [ContractRewardCalculationEvent](#archway.rewards.v1beta1.ContractRewardCalculationEvent) - [ContractRewardDistributionEvent](#archway.rewards.v1beta1.ContractRewardDistributionEvent) + - [MinConsensusFeeSetEvent](#archway.rewards.v1beta1.MinConsensusFeeSetEvent) - [archway/rewards/v1beta1/genesis.proto](#archway/rewards/v1beta1/genesis.proto) - [GenesisState](#archway.rewards.v1beta1.GenesisState) @@ -589,6 +590,21 @@ This event might not follow the ContractRewardCalculationEvent if the contract h + + + +### MinConsensusFeeSetEvent +MinConsensusFeeSetEvent is emitted when the minimum consensus fee is updated. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `fee` | [cosmos.base.v1beta1.DecCoin](#cosmos.base.v1beta1.DecCoin) | | fee defines the updated minimum gas unit price. | + + + + + @@ -618,6 +634,7 @@ GenesisState defines the initial state of the tracking module. | `contracts_metadata` | [ContractMetadata](#archway.rewards.v1beta1.ContractMetadata) | repeated | contracts_metadata defines a list of all contracts metadata. | | `block_rewards` | [BlockRewards](#archway.rewards.v1beta1.BlockRewards) | repeated | block_rewards defines a list of all block rewards objects. | | `tx_rewards` | [TxRewards](#archway.rewards.v1beta1.TxRewards) | repeated | tx_rewards defines a list of all tx rewards objects. | +| `min_consensus_fee` | [cosmos.base.v1beta1.DecCoin](#cosmos.base.v1beta1.DecCoin) | | min_consensus_fee defines the minimum gas unit price. | diff --git a/e2e/gastracking_test.go b/e2e/gastracking_test.go index 5d6b658b..cdcf5904 100644 --- a/e2e/gastracking_test.go +++ b/e2e/gastracking_test.go @@ -37,8 +37,10 @@ func (s *E2ETestSuite) TestGasTrackingAndRewardsDistribution() { e2eTesting.WithMintParams( sdk.NewDecWithPrec(8, 1), sdk.NewDecWithPrec(8, 1), - 1, + 1000000, ), + // Set default Tx fee for non-manual transaction like Upload / Instantiate + e2eTesting.WithDefaultFeeAmount("10000"), ) trackingKeeper, rewardsKeeper := chain.GetApp().TrackingKeeper, chain.GetApp().RewardsKeeper @@ -47,7 +49,7 @@ func (s *E2ETestSuite) TestGasTrackingAndRewardsDistribution() { accAddrs, _ := e2eTesting.GenAccounts(1) // an empty account // Inputs - txFees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1000))) + txFees := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10000))) rewardsAddr := accAddrs[0] // Collected values diff --git a/e2e/testing/chain.go b/e2e/testing/chain.go index d525b2f2..94feffd7 100644 --- a/e2e/testing/chain.go +++ b/e2e/testing/chain.go @@ -39,6 +39,7 @@ import ( type TestChain struct { t *testing.T + cfg chainConfig app *app.ArchwayApp // main application lastHeader tmProto.Header // header for the last committed block curHeader tmProto.Header // header for the current block @@ -72,12 +73,7 @@ func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain { } // Define chain config - chainCfg := chainConfig{ - ValidatorsNum: 1, - GenAccountsNum: 5, - GenBalanceAmount: "1000000000", - BondAmount: "1000000", - } + chainCfg := defaultChainConfig() for _, opt := range chainCfgOpts { opt(&chainCfg) } @@ -86,8 +82,10 @@ func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain { encCfg := app.MakeEncodingConfig() // Pick your poison here =) - //logger := log.TestingLogger() logger := log.NewNopLogger() + if chainCfg.LoggerEnabled { + logger = log.TestingLogger() + } archApp := app.NewArchwayApp( logger, @@ -175,16 +173,20 @@ func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain { bondedPoolCoins := sdk.NewCoins() balances := make([]bankTypes.Balance, 0, chainCfg.GenAccountsNum) for i := 0; i < chainCfg.GenAccountsNum; i++ { + accGenCoins := genCoins + // Lower genesis balance for validator account + if i < chainCfg.ValidatorsNum { + accGenCoins = accGenCoins.Sub(bondCoins) + bondedPoolCoins = bondedPoolCoins.Add(bondCoins...) + } + balances = append(balances, bankTypes.Balance{ Address: genAccs[i].GetAddress().String(), - Coins: genCoins, + Coins: accGenCoins, }) totalSupply = totalSupply.Add(genCoins...) } - for i := 0; i < chainCfg.ValidatorsNum; i++ { - bondedPoolCoins = bondedPoolCoins.Add(bondCoins...) - totalSupply = totalSupply.Add(bondCoins...) - } + balances = append(balances, bankTypes.Balance{ Address: authTypes.NewModuleAddress(stakingTypes.BondedPoolName).String(), Coins: bondedPoolCoins, @@ -219,6 +221,7 @@ func NewTestChain(t *testing.T, chainIdx int, opts ...interface{}) *TestChain { // Create a chain and finalize the 1st block chain := TestChain{ t: t, + cfg: chainCfg, app: archApp, curHeader: tmProto.Header{ ChainID: chainIDPrefix + strconv.Itoa(chainIdx), @@ -341,13 +344,15 @@ func (chain *TestChain) EndBlock() []abci.Event { return res.Events } -type SendMsgOption func(opt *sendMsgOptions) +type ( + SendMsgOption func(opt *sendMsgOptions) -type sendMsgOptions struct { - fees sdk.Coins - gasLimit uint64 - noBlockChange bool -} + sendMsgOptions struct { + fees sdk.Coins + gasLimit uint64 + noBlockChange bool + } +) // WithMsgFees option add fees to the transaction. func WithMsgFees(coins ...sdk.Coin) SendMsgOption { @@ -370,20 +375,36 @@ func WithoutBlockChange() SendMsgOption { } } -// SendMsgs sends a series of messages. +// SendMsgs sends a series of messages, checks for tx failure and starts a new block. func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg, opts ...SendMsgOption) (sdk.GasInfo, *sdk.Result, []abci.Event, error) { - options := &sendMsgOptions{ - fees: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)), - gasLimit: 10_000_000, - noBlockChange: false, + var abciEvents []abci.Event + + t := chain.t + + gasInfo, res, err := chain.SendMsgsRaw(senderAcc, msgs, opts...) + if expPass { + require.NoError(t, err) + require.NotNil(t, res) + } else { + require.Error(t, err) + require.Nil(t, res) + } + if res != nil { + abciEvents = append(abciEvents, res.Events...) } - for _, o := range opts { - o(options) + if !chain.buildSendMsgOptions(opts...).noBlockChange { + abciEvents = append(abciEvents, chain.EndBlock()...) + abciEvents = append(abciEvents, chain.BeginBlock()...) } + return gasInfo, res, abciEvents, err +} + +// SendMsgsRaw sends a series of messages. +func (chain *TestChain) SendMsgsRaw(senderAcc Account, msgs []sdk.Msg, opts ...SendMsgOption) (sdk.GasInfo, *sdk.Result, error) { t := chain.t - var abciEvents []abci.Event + options := chain.buildSendMsgOptions(opts...) // Get the sender account senderAccI := chain.app.AccountKeeper.GetAccount(chain.GetContext(), senderAcc.Address) @@ -403,24 +424,7 @@ func (chain *TestChain) SendMsgs(senderAcc Account, expPass bool, msgs []sdk.Msg require.NoError(t, err) // Send the Tx - gasInfo, res, err := chain.app.Deliver(chain.txConfig.TxEncoder(), tx) - if expPass { - require.NoError(t, err) - require.NotNil(t, res) - } else { - require.Error(t, err) - require.Nil(t, res) - } - if res != nil { - abciEvents = append(abciEvents, res.Events...) - } - - if !options.noBlockChange { - abciEvents = append(abciEvents, chain.EndBlock()...) - abciEvents = append(abciEvents, chain.BeginBlock()...) - } - - return gasInfo, res, abciEvents, err + return chain.app.Deliver(chain.txConfig.TxEncoder(), tx) } // ParseSDKResultData converts TX result data into a slice of Msgs. @@ -434,3 +438,27 @@ func (chain *TestChain) ParseSDKResultData(r *sdk.Result) sdk.TxMsgData { return protoResult } + +// GetDefaultTxFee returns the default transaction fee (that one is used if SendMsgs has no other options). +func (chain *TestChain) GetDefaultTxFee() sdk.Coins { + t := chain.t + + feeAmt, ok := sdk.NewIntFromString(chain.cfg.DefaultFeeAmt) + require.True(t, ok) + + return sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, feeAmt)) +} + +func (chain *TestChain) buildSendMsgOptions(opts ...SendMsgOption) sendMsgOptions { + options := sendMsgOptions{ + fees: chain.GetDefaultTxFee(), + gasLimit: 10_000_000, + noBlockChange: false, + } + + for _, o := range opts { + o(&options) + } + + return options +} diff --git a/e2e/testing/chain_options.go b/e2e/testing/chain_options.go index 7ecc566f..54809646 100644 --- a/e2e/testing/chain_options.go +++ b/e2e/testing/chain_options.go @@ -16,6 +16,8 @@ type chainConfig struct { GenAccountsNum int GenBalanceAmount string BondAmount string + LoggerEnabled bool + DefaultFeeAmt string } type ( @@ -26,6 +28,52 @@ type ( TestChainConsensusParamsOption func(params *abci.ConsensusParams) ) +// defaultChainConfig builds chain default config. +func defaultChainConfig() chainConfig { + return chainConfig{ + ValidatorsNum: 1, + GenAccountsNum: 5, + GenBalanceAmount: "1000000000", + BondAmount: "1000000", + DefaultFeeAmt: "100", + } +} + +// WithGenAccounts sets the number of genesis accounts +func WithGenAccounts(num int) TestChainConfigOption { + return func(cfg *chainConfig) { + cfg.GenAccountsNum = num + } +} + +// WithGenDefaultCoinBalance sets the genesis account balance for the default token (stake). +func WithGenDefaultCoinBalance(amount string) TestChainConfigOption { + return func(cfg *chainConfig) { + cfg.GenBalanceAmount = amount + } +} + +// WithDefaultFeeAmount sets the default fee amount which is used for sending Msgs with no fee specified. +func WithDefaultFeeAmount(amount string) TestChainConfigOption { + return func(cfg *chainConfig) { + cfg.DefaultFeeAmt = amount + } +} + +// WithBondAmount sets the amount of coins to bond for each validator. +func WithBondAmount(amount string) TestChainConfigOption { + return func(cfg *chainConfig) { + cfg.BondAmount = amount + } +} + +// WithLogger enables the app console logger. +func WithLogger() TestChainConfigOption { + return func(cfg *chainConfig) { + cfg.LoggerEnabled = true + } +} + // WithBlockGasLimit sets the block gas limit (not set by default). func WithBlockGasLimit(gasLimit int64) TestChainConsensusParamsOption { return func(params *abci.ConsensusParams) { diff --git a/e2e/testing/common.go b/e2e/testing/common.go index f9383f07..d926dd36 100644 --- a/e2e/testing/common.go +++ b/e2e/testing/common.go @@ -1,7 +1,9 @@ package e2eTesting import ( + "fmt" "strconv" + "strings" wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -60,3 +62,35 @@ func GenContractAddresses(num uint) []sdk.AccAddress { return addrs } + +// HumanizeCoins returns the sdk.Coins string representation with a number of decimals specified. +// 1123000stake -> 1.123stake with 6 decimals (3 numbers after the dot is hardcoded). +func HumanizeCoins(decimals uint8, coins ...sdk.Coin) string { + baseDec := sdk.NewDecWithPrec(1, int64(decimals)) + + strs := make([]string, 0, len(coins)) + for _, coin := range coins { + amtDec := coin.Amount.ToDec().Mul(baseDec) + amtFloat, _ := amtDec.Float64() + + strs = append(strs, fmt.Sprintf("%.03f%s", amtFloat, coin.Denom)) + } + + return strings.Join(strs, ",") +} + +// HumanizeDecCoins returns the sdk.DecCoins string representation. +// 1000.123456789stake -> 1.123456stake with 3 decimals (6 numbers after the dot is hardcoded). +func HumanizeDecCoins(decimals uint8, coins ...sdk.DecCoin) string { + baseDec := sdk.NewDecWithPrec(1, int64(decimals)) + + strs := make([]string, 0, len(coins)) + for _, coin := range coins { + amtDec := coin.Amount.Mul(baseDec) + amtFloat, _ := amtDec.Float64() + + strs = append(strs, fmt.Sprintf("%.06f%s", amtFloat, coin.Denom)) + } + + return strings.Join(strs, ",") +} diff --git a/e2e/txfees_test.go b/e2e/txfees_test.go index e28efbd2..c25c6315 100644 --- a/e2e/txfees_test.go +++ b/e2e/txfees_test.go @@ -8,23 +8,65 @@ import ( voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" wasmdTypes "github.com/CosmWasm/wasmd/x/wasm/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" abci "github.com/tendermint/tendermint/abci/types" e2eTesting "github.com/archway-network/archway/e2e/testing" rewardsTypes "github.com/archway-network/archway/x/rewards/types" ) +// TestTxFees ensures that a transaction fees paid are less than rewards received. +// Test configures a chain based on the Archway mainnet parameters. func (s *E2ETestSuite) TestTxFees() { + const ( + txGasLimit = 200_000 + txFeeAmtIncrement = 1000 + ) + + coinsToStr := func(coins ...sdk.Coin) string { + return fmt.Sprintf("%12s", e2eTesting.HumanizeCoins(6, coins...)) + } + + minConfFeeToStr := func(coin sdk.DecCoin) string { + if coin.IsZero() { + return "-" + } + return fmt.Sprintf("%8s", e2eTesting.HumanizeDecCoins(0, coin)) + } + // Create a custom chain with fixed inflation (10%) and 10M block gas limit chain := e2eTesting.NewTestChain(s.T(), 1, - e2eTesting.WithBlockGasLimit(10_000_000), + // Set 1B total supply (10^9 * 10^6) (Archway mainnet param) + e2eTesting.WithGenAccounts(1), + e2eTesting.WithGenDefaultCoinBalance("1000000000000000"), + // Set bonded ratio to 30% + e2eTesting.WithBondAmount("300000000000000"), + // Override the default Tx fee + e2eTesting.WithDefaultFeeAmount("10000000"), + // Set block gas limit (Archway mainnet param) + e2eTesting.WithBlockGasLimit(100_000_000), + // x/rewards distribution params + e2eTesting.WithTxFeeRebatesRewardsRatio(sdk.NewDecWithPrec(5, 1)), // 50 % (Archway mainnet param) + e2eTesting.WithInflationRewardsRatio(sdk.NewDecWithPrec(2, 1)), // 20 % (Archway mainnet param) + // Set constant inflation rate e2eTesting.WithMintParams( - sdk.NewDecWithPrec(1, 1), // 10% - sdk.NewDecWithPrec(1, 1), // 10% - uint64(60*60*8766/5), // standard calculation + sdk.NewDecWithPrec(10, 2), // 10% (Archway mainnet param) + sdk.NewDecWithPrec(10, 2), // 10% (Archway mainnet param) + uint64(60*60*8766/1), //1 seconds block time (Archway mainnet param) ), ) + // Check total supply + { + ctx := chain.GetContext() + + totalSupplyMaxAmtExpected, ok := sdk.NewIntFromString("1000000050000000") // small gap for minted coins for 2 blocks + s.Require().True(ok) + + totalSupplyReceived := chain.GetApp().BankKeeper.GetSupply(ctx, sdk.DefaultBondDenom) + s.Require().True(totalSupplyReceived.Amount.LTE(totalSupplyMaxAmtExpected), "total supply", totalSupplyReceived.String()) + } + senderAcc := chain.GetAccount(0) contractAddr := s.VoterUploadAndInstantiate(chain, senderAcc) accAddrs, _ := e2eTesting.GenAccounts(1) // an empty account @@ -36,11 +78,48 @@ func (s *E2ETestSuite) TestTxFees() { RewardsAddress: rewardsAddr.String(), }) - txFee := sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()) + // Get minted inflation amount + { + ctx := chain.GetContext() + + mintParams := chain.GetApp().MintKeeper.GetParams(ctx) + mintedCoin := chain.GetApp().MintKeeper.GetMinter(ctx).BlockProvision(mintParams) + s.T().Logf("x/mint minted amount per block: %s", coinsToStr(mintedCoin)) + } + + var abciEvents []abci.Event + txFee := sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewInt(0)} // this one gonna increase rewardsAccPrevBalance := chain.GetBalance(rewardsAddr) - for i := 0; i < 10; i++ { + + // Generate transactions and check fees (some txs might fail with InsufficientFee error) + for i := 0; i < 100; i++ { + // Increase next TxFees + txFee.Amount = txFee.Amount.AddRaw(txFeeAmtIncrement) + + // Get min consensus fee for the current block and check the update event + minConsensusFee := sdk.DecCoin{Amount: sdk.ZeroDec()} + { + ctx := chain.GetContext() + + if fee := chain.GetApp().RewardsKeeper.GetMinConsensusFee(ctx); fee != nil { + minConsensusFee = *fee + + // Check the event from the previous BeginBlocker + if len(abciEvents) > 0 { + eventFeeBz := e2eTesting.GetStringEventAttribute(abciEvents, + "archway.rewards.v1beta1.MinConsensusFeeSetEvent", + "fee", + ) + + var eventFee sdk.DecCoin + s.Require().NoError(json.Unmarshal([]byte(eventFeeBz), &eventFee)) + + s.Require().Equal(minConsensusFee.String(), eventFee.String()) + } + } + } + // Send Tx - var abciEvents []abci.Event var txGasUsed uint64 { req := voterTypes.MsgExecute{ @@ -59,13 +138,31 @@ func (s *E2ETestSuite) TestTxFees() { Msg: reqBz, Funds: sdk.NewCoins(sdk.Coin{Denom: sdk.DefaultBondDenom, Amount: sdk.NewIntFromUint64(DefNewVotingCostAmt)}), } - gasUsed, _, events, _ := chain.SendMsgs(senderAcc, true, []sdk.Msg{&msg}, + + gasUsed, res, err := chain.SendMsgsRaw(senderAcc, []sdk.Msg{&msg}, e2eTesting.WithMsgFees(txFee), + e2eTesting.WithTxGasLimit(txGasLimit), ) + if err != nil { + s.Require().ErrorIs(err, sdkErrors.ErrInsufficientFee) + + s.T().Logf("TxID %03d: %s fees (%s minConsFee): insufficient fees: %v", + i, + coinsToStr(txFee), minConfFeeToStr(minConsensusFee), + err, + ) + + // Skip the block to avoid "out of gas" for this one + abciEvents = chain.NextBlock(0) + continue + } - abciEvents, txGasUsed = events, gasUsed.GasUsed + abciEvents, txGasUsed = res.Events, gasUsed.GasUsed } + // Start a new block to get rewards and tracking for the previous one + abciEvents = append(abciEvents, chain.NextBlock(0)...) + // Get gas tracked for this Tx var txGasTracked uint64 { @@ -117,13 +214,16 @@ func (s *E2ETestSuite) TestTxFees() { } // Output - fmt.Printf("TxID %d (gas %d / %d): \t%s fees (%s infl rewards) -> \t%s rewards taken (%s + %s)\n", - i, txGasTracked, txGasUsed, - txFee.String(), blockRewards.String(), rewardsAddrBalanceDiff.String(), - feeRebateRewards.String(), inflationRewards.String(), + s.T().Logf("TxID %03d (gas %06d / %06d / %06d): %s fees (%s inflRewards, %s minConsFee) -> %s rewards taken (%s + %s)", + i, txGasTracked, txGasUsed, txGasLimit, + coinsToStr(txFee), + coinsToStr(blockRewards), minConfFeeToStr(minConsensusFee), + coinsToStr(rewardsAddrBalanceDiff...), coinsToStr(feeRebateRewards...), coinsToStr(inflationRewards), ) - // Increase next TxFees - txFee.Amount = txFee.Amount.AddRaw(1) + // Check rewards are lower than the fee paid + { + s.Assert().True(rewardsAddrBalanceDiff.IsAllLT(sdk.Coins{txFee})) + } } } diff --git a/e2e/voter_test.go b/e2e/voter_test.go index b8bd368f..10238db7 100644 --- a/e2e/voter_test.go +++ b/e2e/voter_test.go @@ -76,7 +76,8 @@ func (s *E2ETestSuite) TestVoter_ExecuteQueryAndReply() { s.Assert().EqualValues(contractCoinsExp, releasedCoinsRcv) acc1BalanceAfter := chain.GetBalance(acc1.Address) - s.Assert().EqualValues(acc1BalanceBefore.Add(contractCoinsExp...), acc1BalanceAfter) + acc1BalanceExpected := acc1BalanceBefore.Add(contractCoinsExp...).Sub(chain.GetDefaultTxFee()) + s.Assert().EqualValues(acc1BalanceExpected.String(), acc1BalanceAfter.String()) releaseStats := s.VoterGetReleaseStats(chain, contractAddr) s.Assert().EqualValues(1, releaseStats.Count) diff --git a/pkg/coin.go b/pkg/coin.go index 37e0521c..61276bad 100644 --- a/pkg/coin.go +++ b/pkg/coin.go @@ -15,6 +15,15 @@ func CoinIsZero(coin sdk.Coin) bool { return coin.IsZero() } +// DecCoinIsZero checks if sdk.DecCoin is set (not panics in case Amount is nil). +func DecCoinIsZero(coin sdk.DecCoin) bool { + if coin.Amount.IsNil() { + return true + } + + return coin.IsZero() +} + // ValidateCoin performs a stricter validation of sdk.Coin comparing to the SDK version. func ValidateCoin(coin sdk.Coin) error { if err := sdk.ValidateDenom(coin.Denom); err != nil { @@ -29,3 +38,18 @@ func ValidateCoin(coin sdk.Coin) error { return nil } + +// ValidateDecCoin performs a stricter validation of sdk.DecCoin comparing to the SDK version. +func ValidateDecCoin(coin sdk.DecCoin) error { + if err := sdk.ValidateDenom(coin.Denom); err != nil { + return fmt.Errorf("denom: %w", err) + } + if coin.Amount.IsNil() { + return fmt.Errorf("amount: nil") + } + if coin.IsNegative() { + return fmt.Errorf("amount: is negative") + } + + return nil +} diff --git a/pkg/testutils/tx.go b/pkg/testutils/tx.go index 5ff42275..7ac5dbcf 100644 --- a/pkg/testutils/tx.go +++ b/pkg/testutils/tx.go @@ -38,6 +38,13 @@ func WithMockFeeTxPayer(payer sdk.AccAddress) MockFeeTxOption { } } +// WithMockFeeTxGas option sets the gas limit of the MockFeeTx. +func WithMockFeeTxGas(gas uint64) MockFeeTxOption { + return func(tx *MockFeeTx) { + tx.gas = gas + } +} + // NewMockFeeTx creates a new MockFeeTx instance. // CONTRACT: tx has no defaults, so it is up to a developer to set options right. func NewMockFeeTx(opts ...MockFeeTxOption) MockFeeTx { diff --git a/proto/archway/rewards/v1beta1/events.proto b/proto/archway/rewards/v1beta1/events.proto index 8fd037f3..b399b901 100644 --- a/proto/archway/rewards/v1beta1/events.proto +++ b/proto/archway/rewards/v1beta1/events.proto @@ -47,3 +47,11 @@ message ContractRewardDistributionEvent { (gogoproto.nullable) = false ]; } + +// MinConsensusFeeSetEvent is emitted when the minimum consensus fee is updated. +message MinConsensusFeeSetEvent { + // fee defines the updated minimum gas unit price. + cosmos.base.v1beta1.DecCoin fee = 1 [ + (gogoproto.nullable) = false + ]; +} diff --git a/proto/archway/rewards/v1beta1/genesis.proto b/proto/archway/rewards/v1beta1/genesis.proto index 40f2bfda..504c5b4c 100644 --- a/proto/archway/rewards/v1beta1/genesis.proto +++ b/proto/archway/rewards/v1beta1/genesis.proto @@ -4,6 +4,7 @@ package archway.rewards.v1beta1; option go_package = "github.com/archway-network/archway/x/rewards/types"; import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; import "archway/rewards/v1beta1/rewards.proto"; // GenesisState defines the initial state of the tracking module. @@ -24,4 +25,8 @@ message GenesisState { repeated TxRewards tx_rewards = 4 [ (gogoproto.nullable) = false ]; + // min_consensus_fee defines the minimum gas unit price. + cosmos.base.v1beta1.DecCoin min_consensus_fee = 5 [ + (gogoproto.nullable) = false + ]; } diff --git a/x/gastracker/integration/integration_test.go b/x/gastracker/integration/integration_test.go index 2c206035..b69db7fc 100644 --- a/x/gastracker/integration/integration_test.go +++ b/x/gastracker/integration/integration_test.go @@ -49,7 +49,7 @@ func TestRewardsCollection(t *testing.T) { Msg: jsonMarshal(t, msg), Funds: sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), }}, - e2eTesting.WithMsgFees(txFees), + e2eTesting.WithMsgFees(txFees...), ) balance := chain.GetBalance(authtypes.NewModuleAddress(gastracker.ModuleName)) diff --git a/x/rewards/ante/fee_deduction.go b/x/rewards/ante/fee_deduction.go index dcc11f0e..60d752ca 100644 --- a/x/rewards/ante/fee_deduction.go +++ b/x/rewards/ante/fee_deduction.go @@ -14,8 +14,10 @@ import ( rewardsTypes "github.com/archway-network/archway/x/rewards/types" ) -// RewardsKeeperExpected defines the expected interface for the x/rewards keeper. -type RewardsKeeperExpected interface { +var _ sdk.AnteDecorator = DeductFeeDecorator{} + +// TxFeeRewardsKeeperExpected defines the expected interface for the x/rewards keeper. +type TxFeeRewardsKeeperExpected interface { TxFeeRebateRatio(ctx sdk.Context) sdk.Dec TrackFeeRebatesRewards(ctx sdk.Context, rewards sdk.Coins) } @@ -28,11 +30,11 @@ type DeductFeeDecorator struct { ak ante.AccountKeeper bankKeeper authTypes.BankKeeper feegrantKeeper ante.FeegrantKeeper - rewardsKeeper RewardsKeeperExpected + rewardsKeeper TxFeeRewardsKeeperExpected } // NewDeductFeeDecorator returns a new DeductFeeDecorator instance. -func NewDeductFeeDecorator(ak ante.AccountKeeper, bk authTypes.BankKeeper, fk ante.FeegrantKeeper, rk RewardsKeeperExpected) DeductFeeDecorator { +func NewDeductFeeDecorator(ak ante.AccountKeeper, bk authTypes.BankKeeper, fk ante.FeegrantKeeper, rk TxFeeRewardsKeeperExpected) DeductFeeDecorator { return DeductFeeDecorator{ ak: ak, bankKeeper: bk, @@ -41,7 +43,7 @@ func NewDeductFeeDecorator(ak ante.AccountKeeper, bk authTypes.BankKeeper, fk an } } -// AnteHandle implements the ante.AnteHandler interface. +// AnteHandle implements the ante.AnteDecorator interface. func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { feeTx, ok := tx.(sdk.FeeTx) if !ok { diff --git a/x/rewards/ante/min_cons_fee.go b/x/rewards/ante/min_cons_fee.go new file mode 100644 index 00000000..47cec011 --- /dev/null +++ b/x/rewards/ante/min_cons_fee.go @@ -0,0 +1,63 @@ +package ante + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/archway-network/archway/pkg" +) + +// MinConsensusFeeReaderExpected defines the expected interface for the x/rewards keeper. +type MinConsensusFeeReaderExpected interface { + GetMinConsensusFee(ctx sdk.Context) *sdk.DecCoin +} + +// MinFeeDecorator rejects transaction if its fees are less than minimum fees defined by the x/rewards module. +// Estimation is done using the minimum consensus fee value which is the minimum gas unit price. +// The minimum consensus fee value is defined by block dApp rewards and rewards distribution parameters. +// CONTRACT: Tx must implement FeeTx interface to use MinFeeDecorator. +type MinFeeDecorator struct { + rewardsKeeper MinConsensusFeeReaderExpected +} + +// NewMinFeeDecorator returns a new MinFeeDecorator instance. +func NewMinFeeDecorator(rk MinConsensusFeeReaderExpected) MinFeeDecorator { + return MinFeeDecorator{ + rewardsKeeper: rk, + } +} + +// AnteHandle implements the ante.AnteDecorator interface. +func (mfd MinFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + feeTx, ok := tx.(sdk.FeeTx) + if !ok { + return ctx, sdkErrors.Wrap(sdkErrors.ErrTxDecode, "Tx must be a FeeTx") + } + + // Skip the check if min gas unit price is not defined (not yet set or is zero) + gasUnitPrice := mfd.rewardsKeeper.GetMinConsensusFee(ctx) + if gasUnitPrice == nil || gasUnitPrice.IsZero() { + return next(ctx, tx, simulate) + } + + // Estimate the minimum fee expected + // We use RoundInt here since minimum fee must be GTE calculated amount + txFees := feeTx.GetFee() + + txGasLimit := pkg.NewDecFromUint64(feeTx.GetGas()) + if txGasLimit.IsZero() { + return ctx, sdkErrors.Wrap(sdkErrors.ErrInvalidRequest, "tx gas limit is not set") + } + + minFeeExpected := sdk.Coin{ + Denom: gasUnitPrice.Denom, + Amount: gasUnitPrice.Amount.Mul(txGasLimit).RoundInt(), + } + + // Check (skip if the expected amount is zero) + if minFeeExpected.Amount.IsZero() || txFees.IsAnyGTE(sdk.Coins{minFeeExpected}) { + return next(ctx, tx, simulate) + } + + return ctx, sdkErrors.Wrapf(sdkErrors.ErrInsufficientFee, "tx fee %s is less than min fee: %s", txFees, minFeeExpected) +} diff --git a/x/rewards/ante/min_cons_fee_test.go b/x/rewards/ante/min_cons_fee_test.go new file mode 100644 index 00000000..cd779897 --- /dev/null +++ b/x/rewards/ante/min_cons_fee_test.go @@ -0,0 +1,92 @@ +package ante_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg/testutils" + "github.com/archway-network/archway/x/rewards/ante" +) + +func TestRewardsMinFeeAnteHandler(t *testing.T) { + type testCase struct { + name string + // Inputs + txFees string // transaction fees [sdk.Coins] + txGasLimit uint64 // transaction gas limit + minConsFee string // min consensus fee [sdk.DecCoin] + // Output expected + errExpected error // concrete error expected (or nil if no error expected) + } + + testCases := []testCase{ + { + name: "OK: 200stake fee > 100stake min fee", + txFees: "200stake", + txGasLimit: 1000, + minConsFee: "0.1stake", + }, + { + name: "OK: 100stake fee == 100stake min fee", + txFees: "100stake", + txGasLimit: 1000, + minConsFee: "0.1stake", + }, + { + name: "Fail: 99stake fee < 100stake min fee", + txFees: "99stake", + txGasLimit: 1000, + minConsFee: "0.1stake", + errExpected: sdkErrors.ErrInsufficientFee, + }, + { + name: "OK: min consensus fee is zero", + txFees: "100stake", + txGasLimit: 1000, + minConsFee: "0stake", + }, + { + name: "OK: expected fee is too low (zero)", + txFees: "1stake", + txGasLimit: 1000, + minConsFee: "0.000000000001stake", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Create chain + chain := e2eTesting.NewTestChain(t, 1) + ctx := chain.GetContext() + + // Set min consensus fee + minConsFee, err := sdk.ParseDecCoin(tc.minConsFee) + require.NoError(t, err) + + chain.GetApp().RewardsKeeper.GetState().MinConsensusFee(ctx).SetFee(minConsFee) + + // Build transaction + txFees, err := sdk.ParseCoinsNormalized(tc.txFees) + require.NoError(t, err) + + tx := testutils.NewMockFeeTx( + testutils.WithMockFeeTxFees(txFees), + testutils.WithMockFeeTxGas(tc.txGasLimit), + ) + + // Call the Ante handler manually + anteHandler := ante.NewMinFeeDecorator(chain.GetApp().RewardsKeeper) + _, err = anteHandler.AnteHandle(ctx, tx, false, testutils.NoopAnteHandler) + if tc.errExpected != nil { + assert.ErrorIs(t, err, tc.errExpected) + return + } + require.NoError(t, err) + }) + } +} diff --git a/x/rewards/keeper/distribution.go b/x/rewards/keeper/distribution.go index 42c585a4..a621d64c 100644 --- a/x/rewards/keeper/distribution.go +++ b/x/rewards/keeper/distribution.go @@ -102,10 +102,8 @@ func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewa // Fetch tracked block rewards by the x/rewards module (might not be found in case this reward is disabled) inlfationRewardsEligible := false - var blockGasLimit sdk.Dec blockRewards, found := k.state.BlockRewardsState(ctx).GetBlockRewards(blockDistrState.Height) if found && blockRewards.HasRewards() && blockRewards.HasGasLimit() { - blockGasLimit = pkg.NewDecFromUint64(blockRewards.MaxGas) inlfationRewardsEligible = true } else { k.Logger(ctx).Debug("No inflation rewards to distribute (no record / empty coin / gas limit not set)", "height", blockDistrState.Height) @@ -127,7 +125,7 @@ func (k Keeper) estimateBlockRewards(ctx sdk.Context, blockDistrState *blockRewa // Estimate contract inflation rewards if inlfationRewardsEligible { gasUsed := pkg.NewDecFromUint64(contractDistrState.BlockGasUsed) - rewardsShare := gasUsed.Quo(blockGasLimit) + rewardsShare := gasUsed.Quo(pkg.NewDecFromUint64(blockRewards.MaxGas)) contractDistrState.InflationaryRewards = sdk.NewCoin( blockRewards.InflationRewards.Denom, diff --git a/x/rewards/keeper/genesis.go b/x/rewards/keeper/genesis.go index 343472df..5f6c98ec 100644 --- a/x/rewards/keeper/genesis.go +++ b/x/rewards/keeper/genesis.go @@ -3,16 +3,20 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/archway-network/archway/pkg" "github.com/archway-network/archway/x/rewards/types" ) // ExportGenesis exports the module genesis for the current block. func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + minConsFee, _ := k.state.MinConsensusFee(ctx).GetFee() // default sdk.Coin value is ok + return types.NewGenesisState( k.GetParams(ctx), k.state.ContractMetadataState(ctx).Export(), k.state.BlockRewardsState(ctx).Export(), k.state.TxRewardsState(ctx).Export(), + minConsFee, ) } @@ -22,4 +26,8 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *types.GenesisState) { k.state.ContractMetadataState(ctx).Import(state.ContractsMetadata) k.state.BlockRewardsState(ctx).Import(state.BlockRewards) k.state.TxRewardsState(ctx).Import(state.TxRewards) + + if !pkg.DecCoinIsZero(state.MinConsensusFee) { + k.state.MinConsensusFee(ctx).SetFee(state.MinConsensusFee) + } } diff --git a/x/rewards/keeper/genesis_test.go b/x/rewards/keeper/genesis_test.go index d7e5d229..975cd1ab 100644 --- a/x/rewards/keeper/genesis_test.go +++ b/x/rewards/keeper/genesis_test.go @@ -75,7 +75,9 @@ func (s KeeperTestSuite) TestGenesisImportExport() { }, } - genesisStateImported := types.NewGenesisState(newParams, newMetadata, newBlockRewards, newTxRewards) + newMinConsFee := sdk.NewDecCoin("uarch", sdk.NewInt(100)) + + genesisStateImported := types.NewGenesisState(newParams, newMetadata, newBlockRewards, newTxRewards, newMinConsFee) s.Run("Check import of an updated genesis", func() { keeper.InitGenesis(ctx, genesisStateImported) @@ -84,6 +86,7 @@ func (s KeeperTestSuite) TestGenesisImportExport() { ContractsMetadata: append(genesisStateInitial.ContractsMetadata, newMetadata...), BlockRewards: append(genesisStateInitial.BlockRewards, newBlockRewards...), TxRewards: append(genesisStateInitial.TxRewards, newTxRewards...), + MinConsensusFee: newMinConsFee, } genesisStateReceived := keeper.ExportGenesis(ctx) @@ -92,5 +95,6 @@ func (s KeeperTestSuite) TestGenesisImportExport() { s.Assert().ElementsMatch(genesisStateExpected.ContractsMetadata, genesisStateReceived.ContractsMetadata) s.Assert().ElementsMatch(genesisStateExpected.BlockRewards, genesisStateReceived.BlockRewards) s.Assert().ElementsMatch(genesisStateExpected.TxRewards, genesisStateReceived.TxRewards) + s.Assert().Equal(genesisStateExpected.MinConsensusFee.String(), genesisStateReceived.MinConsensusFee.String()) }) } diff --git a/x/rewards/keeper/keeper.go b/x/rewards/keeper/keeper.go index 27fdd738..38494f5c 100644 --- a/x/rewards/keeper/keeper.go +++ b/x/rewards/keeper/keeper.go @@ -9,6 +9,7 @@ import ( paramTypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/tendermint/tendermint/libs/log" + "github.com/archway-network/archway/pkg" "github.com/archway-network/archway/x/rewards/types" trackingTypes "github.com/archway-network/archway/x/tracking/types" ) @@ -150,6 +151,52 @@ func (k Keeper) TrackInflationRewards(ctx sdk.Context, rewards sdk.Coin) { ) } +// UpdateMinConsensusFee calculates and updates the minimum consensus fee if eligible emitting an event. +func (k Keeper) UpdateMinConsensusFee(ctx sdk.Context, inflationRewards sdk.Coin) { + // Prepare and verify inputs + if inflationRewards.IsZero() { + k.Logger(ctx).Info("Minimum consensus fee update skipped: inflation rewards are zero") + return + } + inflationRewardsAmt := inflationRewards.Amount.ToDec() + + blockGasLimit := pkg.NewDecFromUint64(ctx.BlockGasMeter().Limit()) + if blockGasLimit.IsZero() { + k.Logger(ctx).Info("Minimum consensus fee update skipped: block gas limit is not set") + return + } + + txFeeRebateRatio := k.TxFeeRebateRatio(ctx) + + // Calculate + feeAmt := calculateMinConsensusFeeAmt(inflationRewardsAmt, blockGasLimit, txFeeRebateRatio) + if feeAmt.IsZero() { + k.Logger(ctx).Info("Minimum consensus fee update skipped: calculated amount is zero") + return + } + feeCoin := sdk.DecCoin{ + Denom: inflationRewards.Denom, + Amount: feeAmt, + } + + // Set and emit event + k.state.MinConsensusFee(ctx).SetFee(feeCoin) + k.Logger(ctx).Info("Minimum consensus fee update", "fee", feeCoin) + + types.EmitMinConsensusFeeSetEvent(ctx, feeCoin) +} + +// GetMinConsensusFee returns the minimum consensus fee. +// Fee defines the minimum gas unit price for a transaction to be included in a block. +func (k Keeper) GetMinConsensusFee(ctx sdk.Context) *sdk.DecCoin { + fee, found := k.state.MinConsensusFee(ctx).GetFee() + if !found { + return nil + } + + return &fee +} + // UndistributedRewardsPool returns the current undistributed rewards leftovers. func (k Keeper) UndistributedRewardsPool(ctx sdk.Context) sdk.Coins { poolAcc := k.authKeeper.GetModuleAccount(ctx, types.ContractRewardCollector) @@ -161,3 +208,14 @@ func (k Keeper) UndistributedRewardsPool(ctx sdk.Context) sdk.Coins { func (k *Keeper) SetContractInfoViewer(viewer ContractInfoReaderExpected) { k.contractInfoView = viewer } + +// calculateMinConsensusFee calculates the minimum consensus fee amount using the formula: +// -1 * ( BlockRewards / ( GasLimit * (TxFeeRatio - 1) ) ) +// A simplified expression is used, original from specs: -1 * ( BlockRewards / ( GasLimit * TxFeeRatio - GasLimit ) ) +func calculateMinConsensusFeeAmt(blockRewards, gasLimit, txFeeRatio sdk.Dec) sdk.Dec { + return blockRewards.Quo( + gasLimit.Mul( + txFeeRatio.Sub(sdk.OneDec()), + ), + ).Neg() +} diff --git a/x/rewards/keeper/state.go b/x/rewards/keeper/state.go index 2a2f4830..a14c2c9b 100644 --- a/x/rewards/keeper/state.go +++ b/x/rewards/keeper/state.go @@ -59,6 +59,16 @@ func (s State) TxRewardsState(ctx sdk.Context) TxRewardsState { } } +// MinConsensusFee returns the Minimum Consensus Fee repository. +func (s State) MinConsensusFee(ctx sdk.Context) MinConsFeeState { + baseStore := ctx.KVStore(s.key) + return MinConsFeeState{ + stateStore: prefix.NewStore(baseStore, types.MinConsFeeStatePrefix), + cdc: s.cdc, + ctx: ctx, + } +} + // GetState returns the module storage state. // Only for testing purposes. func (k Keeper) GetState() State { diff --git a/x/rewards/keeper/state_minconsfee.go b/x/rewards/keeper/state_minconsfee.go new file mode 100644 index 00000000..c7127d04 --- /dev/null +++ b/x/rewards/keeper/state_minconsfee.go @@ -0,0 +1,37 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + storeTypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/x/rewards/types" +) + +// MinConsFeeState provides access to the Minimum Consensus Fee object storage operations. +type MinConsFeeState struct { + stateStore storeTypes.KVStore + cdc codec.Codec + ctx sdk.Context +} + +// SetFee creates or modifies the fee coin. +func (s MinConsFeeState) SetFee(feeCoin sdk.DecCoin) { + s.stateStore.Set( + types.MinConsFeeKey, + s.cdc.MustMarshal(&feeCoin), + ) +} + +// GetFee returns the fee coin if exists. +func (s MinConsFeeState) GetFee() (sdk.DecCoin, bool) { + coinBz := s.stateStore.Get(types.MinConsFeeKey) + if coinBz == nil { + return sdk.DecCoin{}, false + } + + var coin sdk.DecCoin + s.cdc.MustUnmarshal(coinBz, &coin) + + return coin, true +} diff --git a/x/rewards/mintbankkeeper/keeper.go b/x/rewards/mintbankkeeper/keeper.go index 55cdb6dc..c344900e 100644 --- a/x/rewards/mintbankkeeper/keeper.go +++ b/x/rewards/mintbankkeeper/keeper.go @@ -17,6 +17,7 @@ var _ mintTypes.BankKeeper = Keeper{} type RewardsKeeperExpected interface { InflationRewardsRatio(ctx sdk.Context) sdk.Dec TrackInflationRewards(ctx sdk.Context, rewards sdk.Coin) + UpdateMinConsensusFee(ctx sdk.Context, inflationRewards sdk.Coin) } // Keeper is the x/bank keeper decorator that is used by the x/mint module. @@ -66,6 +67,8 @@ func (k Keeper) SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recip // Track inflation rewards k.rewardsKeeper.TrackInflationRewards(ctx, dappRewards[0]) + // Update the minimum consensus fee + k.rewardsKeeper.UpdateMinConsensusFee(ctx, dappRewards[0]) return nil } diff --git a/x/rewards/mintbankkeeper/keeper_test.go b/x/rewards/mintbankkeeper/keeper_test.go index 0c1a7a04..74d5a261 100644 --- a/x/rewards/mintbankkeeper/keeper_test.go +++ b/x/rewards/mintbankkeeper/keeper_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" e2eTesting "github.com/archway-network/archway/e2e/testing" + "github.com/archway-network/archway/pkg" "github.com/archway-network/archway/x/rewards/mintbankkeeper" rewardsTypes "github.com/archway-network/archway/x/rewards/types" ) @@ -182,6 +183,24 @@ func TestMintBankKeeper(t *testing.T) { assert.Equal(t, ctx.BlockHeight(), rewardsRecordReceived.Height) assert.Equal(t, rewardsDiffExpected.String(), rewardsRecordReceived.InflationRewards.String()) assert.Equal(t, maxGasExpected, rewardsRecordReceived.MaxGas) + + // Check minimum consensus fee record + minConsFeeReceived, minConfFeeFound := chain.GetApp().RewardsKeeper.GetState().MinConsensusFee(ctx).GetFee() + if maxGasExpected == 0 || rewardsDiffExpected.IsZero() { + assert.False(t, minConfFeeFound) + } else { + require.True(t, minConfFeeFound) + + minConsFeeExpected := sdk.DecCoin{ + Denom: sdk.DefaultBondDenom, + Amount: rewardsDiffExpected[0].Amount.ToDec().Quo( + pkg.NewDecFromUint64(maxGasExpected).Mul( + chain.GetApp().RewardsKeeper.TxFeeRebateRatio(ctx).Sub(sdk.OneDec()), + ), + ).Neg(), + } + assert.Equal(t, minConsFeeExpected.String(), minConsFeeReceived.String()) + } }) } } diff --git a/x/rewards/types/events.go b/x/rewards/types/events.go index eaacf2d1..2171e1e6 100644 --- a/x/rewards/types/events.go +++ b/x/rewards/types/events.go @@ -39,3 +39,12 @@ func EmitContractRewardDistributionEvent(ctx sdk.Context, contractAddr, rewardAd panic(fmt.Errorf("sending ContractRewardDistributionEvent event: %w", err)) } } + +func EmitMinConsensusFeeSetEvent(ctx sdk.Context, fee sdk.DecCoin) { + err := ctx.EventManager().EmitTypedEvent(&MinConsensusFeeSetEvent{ + Fee: fee, + }) + if err != nil { + panic(fmt.Errorf("sending MinConsensusFeeSetEvent event: %w", err)) + } +} diff --git a/x/rewards/types/events.pb.go b/x/rewards/types/events.pb.go index 57755255..7add3086 100644 --- a/x/rewards/types/events.pb.go +++ b/x/rewards/types/events.pb.go @@ -227,10 +227,57 @@ func (m *ContractRewardDistributionEvent) GetRewards() []types.Coin { return nil } +// MinConsensusFeeSetEvent is emitted when the minimum consensus fee is updated. +type MinConsensusFeeSetEvent struct { + // fee defines the updated minimum gas unit price. + Fee types.DecCoin `protobuf:"bytes,1,opt,name=fee,proto3" json:"fee"` +} + +func (m *MinConsensusFeeSetEvent) Reset() { *m = MinConsensusFeeSetEvent{} } +func (m *MinConsensusFeeSetEvent) String() string { return proto.CompactTextString(m) } +func (*MinConsensusFeeSetEvent) ProtoMessage() {} +func (*MinConsensusFeeSetEvent) Descriptor() ([]byte, []int) { + return fileDescriptor_ad2689b4f7dc3cd8, []int{3} +} +func (m *MinConsensusFeeSetEvent) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MinConsensusFeeSetEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MinConsensusFeeSetEvent.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MinConsensusFeeSetEvent) XXX_Merge(src proto.Message) { + xxx_messageInfo_MinConsensusFeeSetEvent.Merge(m, src) +} +func (m *MinConsensusFeeSetEvent) XXX_Size() int { + return m.Size() +} +func (m *MinConsensusFeeSetEvent) XXX_DiscardUnknown() { + xxx_messageInfo_MinConsensusFeeSetEvent.DiscardUnknown(m) +} + +var xxx_messageInfo_MinConsensusFeeSetEvent proto.InternalMessageInfo + +func (m *MinConsensusFeeSetEvent) GetFee() types.DecCoin { + if m != nil { + return m.Fee + } + return types.DecCoin{} +} + func init() { proto.RegisterType((*ContractMetadataSetEvent)(nil), "archway.rewards.v1beta1.ContractMetadataSetEvent") proto.RegisterType((*ContractRewardCalculationEvent)(nil), "archway.rewards.v1beta1.ContractRewardCalculationEvent") proto.RegisterType((*ContractRewardDistributionEvent)(nil), "archway.rewards.v1beta1.ContractRewardDistributionEvent") + proto.RegisterType((*MinConsensusFeeSetEvent)(nil), "archway.rewards.v1beta1.MinConsensusFeeSetEvent") } func init() { @@ -238,34 +285,36 @@ func init() { } var fileDescriptor_ad2689b4f7dc3cd8 = []byte{ - // 423 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xbd, 0x69, 0xf8, 0xb7, 0xe5, 0x4f, 0xb1, 0x90, 0x30, 0x3d, 0x6c, 0x43, 0x45, 0xa5, - 0xf6, 0xc0, 0x5a, 0x2d, 0x27, 0x8e, 0x34, 0xf4, 0x44, 0x72, 0x31, 0x37, 0x2e, 0xd6, 0x7a, 0x3d, - 0x71, 0x2c, 0xe2, 0xdd, 0x68, 0x77, 0x9d, 0x90, 0xb7, 0x40, 0x3c, 0x08, 0xcf, 0x91, 0x63, 0xc4, - 0x89, 0x13, 0x42, 0xc9, 0x8b, 0xa0, 0xac, 0xd7, 0x26, 0x20, 0x45, 0x4a, 0x7a, 0xb3, 0x67, 0x7f, - 0xf3, 0xcd, 0x37, 0x9f, 0x06, 0xbf, 0x62, 0x8a, 0x0f, 0xa7, 0x6c, 0x16, 0x2a, 0x98, 0x32, 0x95, - 0xea, 0x70, 0x72, 0x99, 0x80, 0x61, 0x97, 0x21, 0x4c, 0x40, 0x18, 0x4d, 0xc7, 0x4a, 0x1a, 0xe9, - 0x3f, 0x77, 0x14, 0x75, 0x14, 0x75, 0xd4, 0xf1, 0xb3, 0x4c, 0x66, 0xd2, 0x32, 0xe1, 0xfa, 0xab, - 0xc2, 0x8f, 0x09, 0x97, 0xba, 0x90, 0x3a, 0x4c, 0x98, 0x86, 0x46, 0x90, 0xcb, 0x5c, 0xb8, 0xf7, - 0xb3, 0x6d, 0x43, 0x6b, 0x79, 0x8b, 0x9d, 0x7e, 0x43, 0x38, 0xe8, 0x4a, 0x61, 0x14, 0xe3, 0xa6, - 0x0f, 0x86, 0xa5, 0xcc, 0xb0, 0x8f, 0x60, 0x6e, 0xd6, 0xce, 0xfc, 0x0b, 0x7c, 0xc4, 0xdd, 0x5b, - 0xcc, 0xd2, 0x54, 0x81, 0xd6, 0x01, 0xea, 0xa0, 0xf3, 0x07, 0xd1, 0x93, 0xba, 0xfe, 0xae, 0x2a, - 0xfb, 0x1f, 0xf0, 0xfd, 0xc2, 0xb5, 0x07, 0xad, 0x0e, 0x3a, 0x3f, 0xbc, 0xba, 0xa0, 0x5b, 0x16, - 0xa2, 0xff, 0xcf, 0xbb, 0x6e, 0xcf, 0x7f, 0x9d, 0x78, 0x51, 0x23, 0x70, 0xfa, 0xa3, 0x85, 0x49, - 0x0d, 0x45, 0xb6, 0xb9, 0xcb, 0x46, 0xbc, 0x1c, 0x31, 0x93, 0x4b, 0xb1, 0xb7, 0xb5, 0x97, 0xf8, - 0x61, 0xc6, 0x74, 0xcc, 0xa5, 0xd0, 0x65, 0x01, 0xa9, 0xb5, 0xd7, 0x8e, 0x0e, 0x33, 0xa6, 0xbb, - 0xae, 0xe4, 0xf7, 0xf0, 0xd3, 0x5c, 0x0c, 0x2a, 0xfd, 0xd8, 0xd9, 0x0d, 0x0e, 0xec, 0x1a, 0x2f, - 0x68, 0x15, 0x34, 0x5d, 0x07, 0xbd, 0xb1, 0x42, 0x2e, 0x9c, 0xed, 0xa3, 0xa6, 0xb3, 0xb2, 0xaa, - 0xfd, 0x3e, 0xf6, 0x07, 0x00, 0xb1, 0x82, 0x84, 0x19, 0x68, 0xe4, 0xda, 0x9d, 0x83, 0x9d, 0xe4, - 0x06, 0x00, 0x91, 0xed, 0xac, 0xe5, 0x6e, 0x36, 0xa2, 0xbd, 0xb3, 0x67, 0xb4, 0x1b, 0xa1, 0x7e, - 0x47, 0xf8, 0xe4, 0xdf, 0x50, 0xdf, 0xe7, 0xda, 0xa8, 0x3c, 0x29, 0x6f, 0x95, 0xea, 0x19, 0x7e, - 0x5c, 0x0d, 0x6f, 0xc0, 0x96, 0x05, 0x1f, 0x55, 0xd5, 0x1a, 0x7b, 0x8b, 0xef, 0xfd, 0xcd, 0x73, - 0xa7, 0x00, 0x6a, 0xfe, 0xba, 0x37, 0x5f, 0x12, 0xb4, 0x58, 0x12, 0xf4, 0x7b, 0x49, 0xd0, 0xd7, - 0x15, 0xf1, 0x16, 0x2b, 0xe2, 0xfd, 0x5c, 0x11, 0xef, 0xd3, 0x55, 0x96, 0x9b, 0x61, 0x99, 0x50, - 0x2e, 0x8b, 0xd0, 0x25, 0xf1, 0x5a, 0x80, 0x99, 0x4a, 0xf5, 0xb9, 0xfe, 0x0f, 0xbf, 0x34, 0x87, - 0x6f, 0x66, 0x63, 0xd0, 0xc9, 0x5d, 0x7b, 0xef, 0x6f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x78, - 0x80, 0xef, 0x41, 0x8d, 0x03, 0x00, 0x00, + // 459 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x93, 0x4f, 0x6f, 0xd3, 0x30, + 0x18, 0xc6, 0xeb, 0xb6, 0xfc, 0x73, 0xf9, 0x33, 0x22, 0xa4, 0x95, 0x09, 0x79, 0xa5, 0x62, 0xd2, + 0x76, 0xc0, 0xd1, 0x0a, 0x17, 0x8e, 0xac, 0x1b, 0x17, 0x56, 0x21, 0x85, 0x1b, 0x97, 0xca, 0x71, + 0xde, 0x64, 0x16, 0x8b, 0x3d, 0xd9, 0xce, 0xca, 0xbe, 0x05, 0xe2, 0x83, 0xf0, 0x39, 0x76, 0x9c, + 0x38, 0x71, 0x42, 0xa8, 0xfd, 0x22, 0x28, 0x8e, 0x13, 0x02, 0x62, 0xd2, 0xc6, 0x2d, 0x79, 0xfd, + 0x7b, 0x9f, 0xf7, 0x79, 0x9f, 0xc4, 0xf8, 0x19, 0xd3, 0xfc, 0x68, 0xc1, 0xce, 0x42, 0x0d, 0x0b, + 0xa6, 0x13, 0x13, 0x9e, 0xee, 0xc6, 0x60, 0xd9, 0x6e, 0x08, 0xa7, 0x20, 0xad, 0xa1, 0x27, 0x5a, + 0x59, 0x15, 0xac, 0x7b, 0x8a, 0x7a, 0x8a, 0x7a, 0x6a, 0xe3, 0x51, 0xa6, 0x32, 0xe5, 0x98, 0xb0, + 0x7c, 0xaa, 0xf0, 0x0d, 0xc2, 0x95, 0xc9, 0x95, 0x09, 0x63, 0x66, 0xa0, 0x11, 0xe4, 0x4a, 0x48, + 0x7f, 0xbe, 0x75, 0xd9, 0xd0, 0x5a, 0xde, 0x61, 0xe3, 0x2f, 0x08, 0x0f, 0xa7, 0x4a, 0x5a, 0xcd, + 0xb8, 0x9d, 0x81, 0x65, 0x09, 0xb3, 0xec, 0x3d, 0xd8, 0x83, 0xd2, 0x59, 0xb0, 0x83, 0xd7, 0xb8, + 0x3f, 0x9b, 0xb3, 0x24, 0xd1, 0x60, 0xcc, 0x10, 0x8d, 0xd0, 0xf6, 0x9d, 0xe8, 0x41, 0x5d, 0x7f, + 0x5d, 0x95, 0x83, 0xb7, 0xf8, 0x76, 0xee, 0xdb, 0x87, 0xdd, 0x11, 0xda, 0x1e, 0x4c, 0x76, 0xe8, + 0x25, 0x0b, 0xd1, 0xbf, 0xe7, 0xed, 0xf5, 0xcf, 0x7f, 0x6c, 0x76, 0xa2, 0x46, 0x60, 0xfc, 0xad, + 0x8b, 0x49, 0x0d, 0x45, 0xae, 0x79, 0xca, 0x8e, 0x79, 0x71, 0xcc, 0xac, 0x50, 0xf2, 0xda, 0xd6, + 0x9e, 0xe2, 0xbb, 0x19, 0x33, 0x73, 0xae, 0xa4, 0x29, 0x72, 0x48, 0x9c, 0xbd, 0x7e, 0x34, 0xc8, + 0x98, 0x99, 0xfa, 0x52, 0x70, 0x88, 0x1f, 0x0a, 0x99, 0x56, 0xfa, 0x73, 0x6f, 0x77, 0xd8, 0x73, + 0x6b, 0x3c, 0xa6, 0x55, 0xd0, 0xb4, 0x0c, 0xba, 0xb5, 0x82, 0x90, 0xde, 0xf6, 0x5a, 0xd3, 0x59, + 0x59, 0x35, 0xc1, 0x0c, 0x07, 0x29, 0xc0, 0x5c, 0x43, 0xcc, 0x2c, 0x34, 0x72, 0xfd, 0x51, 0xef, + 0x4a, 0x72, 0x29, 0x40, 0xe4, 0x3a, 0x6b, 0xb9, 0x83, 0x56, 0xb4, 0x37, 0xae, 0x19, 0x6d, 0x2b, + 0xd4, 0xaf, 0x08, 0x6f, 0xfe, 0x19, 0xea, 0xbe, 0x30, 0x56, 0x8b, 0xb8, 0xf8, 0xaf, 0x54, 0xb7, + 0xf0, 0xfd, 0x6a, 0x78, 0x03, 0x76, 0x1d, 0x78, 0xaf, 0xaa, 0xd6, 0xd8, 0x2b, 0x7c, 0xeb, 0x77, + 0x9e, 0x57, 0x0a, 0xa0, 0xe6, 0xc7, 0xef, 0xf0, 0xfa, 0x4c, 0xc8, 0xf2, 0x1b, 0x81, 0x34, 0x85, + 0x79, 0x03, 0xd0, 0xfc, 0x98, 0x2f, 0x71, 0x2f, 0x05, 0x70, 0xd6, 0x06, 0x93, 0x27, 0xff, 0x54, + 0xdc, 0x07, 0xde, 0x12, 0x2d, 0xf1, 0xbd, 0xc3, 0xf3, 0x25, 0x41, 0x17, 0x4b, 0x82, 0x7e, 0x2e, + 0x09, 0xfa, 0xbc, 0x22, 0x9d, 0x8b, 0x15, 0xe9, 0x7c, 0x5f, 0x91, 0xce, 0x87, 0x49, 0x26, 0xec, + 0x51, 0x11, 0x53, 0xae, 0xf2, 0xd0, 0x47, 0xfb, 0x5c, 0x82, 0x5d, 0x28, 0xfd, 0xb1, 0x7e, 0x0f, + 0x3f, 0x35, 0x37, 0xc9, 0x9e, 0x9d, 0x80, 0x89, 0x6f, 0xba, 0x0b, 0xf4, 0xe2, 0x57, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x0b, 0x3c, 0xcf, 0xe3, 0xde, 0x03, 0x00, 0x00, } func (m *ContractMetadataSetEvent) Marshal() (dAtA []byte, err error) { @@ -430,6 +479,39 @@ func (m *ContractRewardDistributionEvent) MarshalToSizedBuffer(dAtA []byte) (int return len(dAtA) - i, nil } +func (m *MinConsensusFeeSetEvent) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MinConsensusFeeSetEvent) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MinConsensusFeeSetEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Fee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { offset -= sovEvents(v) base := offset @@ -507,6 +589,17 @@ func (m *ContractRewardDistributionEvent) Size() (n int) { return n } +func (m *MinConsensusFeeSetEvent) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Fee.Size() + n += 1 + l + sovEvents(uint64(l)) + return n +} + func sovEvents(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -980,6 +1073,89 @@ func (m *ContractRewardDistributionEvent) Unmarshal(dAtA []byte) error { } return nil } +func (m *MinConsensusFeeSetEvent) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MinConsensusFeeSetEvent: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MinConsensusFeeSetEvent: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Fee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Fee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipEvents(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/rewards/types/genesis.go b/x/rewards/types/genesis.go index 75902d84..da1d68fd 100644 --- a/x/rewards/types/genesis.go +++ b/x/rewards/types/genesis.go @@ -2,15 +2,20 @@ package types import ( "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/archway-network/archway/pkg" ) // NewGenesisState creates a new GenesisState object. -func NewGenesisState(params Params, contractsMetadata []ContractMetadata, blockRewards []BlockRewards, txRewards []TxRewards) *GenesisState { +func NewGenesisState(params Params, contractsMetadata []ContractMetadata, blockRewards []BlockRewards, txRewards []TxRewards, minConsFee sdk.DecCoin) *GenesisState { return &GenesisState{ Params: params, ContractsMetadata: contractsMetadata, BlockRewards: blockRewards, TxRewards: txRewards, + MinConsensusFee: minConsFee, } } @@ -21,6 +26,7 @@ func DefaultGenesisState() *GenesisState { ContractsMetadata: []ContractMetadata{}, BlockRewards: []BlockRewards{}, TxRewards: []TxRewards{}, + MinConsensusFee: sdk.DecCoin{}, } } @@ -67,5 +73,11 @@ func (m GenesisState) Validate() error { txRewardsIdSet[txRewards.TxId] = struct{}{} } + if !pkg.DecCoinIsZero(m.MinConsensusFee) { + if err := pkg.ValidateDecCoin(m.MinConsensusFee); err != nil { + return fmt.Errorf("minConsensusFee: %w", err) + } + } + return nil } diff --git a/x/rewards/types/genesis.pb.go b/x/rewards/types/genesis.pb.go index 301c62e1..313cc28a 100644 --- a/x/rewards/types/genesis.pb.go +++ b/x/rewards/types/genesis.pb.go @@ -6,6 +6,7 @@ package types import ( fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" @@ -34,6 +35,8 @@ type GenesisState struct { BlockRewards []BlockRewards `protobuf:"bytes,3,rep,name=block_rewards,json=blockRewards,proto3" json:"block_rewards"` // tx_rewards defines a list of all tx rewards objects. TxRewards []TxRewards `protobuf:"bytes,4,rep,name=tx_rewards,json=txRewards,proto3" json:"tx_rewards"` + // min_consensus_fee defines the minimum gas unit price. + MinConsensusFee types.DecCoin `protobuf:"bytes,5,opt,name=min_consensus_fee,json=minConsensusFee,proto3" json:"min_consensus_fee"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -97,6 +100,13 @@ func (m *GenesisState) GetTxRewards() []TxRewards { return nil } +func (m *GenesisState) GetMinConsensusFee() types.DecCoin { + if m != nil { + return m.MinConsensusFee + } + return types.DecCoin{} +} + func init() { proto.RegisterType((*GenesisState)(nil), "archway.rewards.v1beta1.GenesisState") } @@ -106,26 +116,30 @@ func init() { } var fileDescriptor_cdced50517b403fe = []byte{ - // 304 bytes of a gzipped FileDescriptorProto + // 365 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x31, 0x4f, 0xc2, 0x40, - 0x14, 0xc7, 0x5b, 0x20, 0x24, 0x1e, 0x38, 0x78, 0x31, 0x91, 0x30, 0x1c, 0x84, 0x84, 0x04, 0x07, - 0xef, 0x02, 0xce, 0x2e, 0x38, 0xb0, 0x68, 0x42, 0xd0, 0xc9, 0x41, 0x72, 0x2d, 0x97, 0x42, 0x10, - 0xae, 0xb9, 0x7b, 0xda, 0xf2, 0x2d, 0xfc, 0x58, 0x1d, 0x19, 0x9d, 0x8c, 0x69, 0xbf, 0x88, 0xe1, - 0x7a, 0x6d, 0x74, 0xe8, 0x76, 0xf7, 0x7f, 0xbf, 0xff, 0xef, 0x0d, 0x0f, 0x0d, 0xb9, 0xf2, 0xd7, - 0x11, 0x3f, 0x30, 0x25, 0x22, 0xae, 0x56, 0x9a, 0x7d, 0x8c, 0x3d, 0x01, 0x7c, 0xcc, 0x02, 0xb1, - 0x17, 0x7a, 0xa3, 0x69, 0xa8, 0x24, 0x48, 0x7c, 0x65, 0x31, 0x6a, 0x31, 0x6a, 0xb1, 0xee, 0x65, - 0x20, 0x03, 0x69, 0x18, 0x76, 0x7a, 0xe5, 0x78, 0xb7, 0xd2, 0x5a, 0xd4, 0x0d, 0x36, 0x48, 0x6a, - 0xa8, 0x3d, 0xcb, 0xf7, 0x3c, 0x01, 0x07, 0x81, 0xef, 0x50, 0x33, 0xe4, 0x8a, 0xef, 0x74, 0xc7, - 0xed, 0xbb, 0xa3, 0xd6, 0xa4, 0x47, 0x2b, 0xf6, 0xd2, 0xb9, 0xc1, 0xa6, 0x8d, 0xe4, 0xbb, 0xe7, - 0x2c, 0x6c, 0x09, 0xbf, 0x22, 0xec, 0xcb, 0x3d, 0x28, 0xee, 0x83, 0x5e, 0xee, 0x04, 0xf0, 0x15, - 0x07, 0xde, 0xa9, 0xf5, 0xeb, 0xa3, 0xd6, 0xe4, 0xba, 0x52, 0x75, 0x6f, 0x2b, 0x8f, 0xb6, 0x60, - 0xa5, 0x17, 0xa5, 0xaa, 0x18, 0xe0, 0x39, 0x3a, 0xf7, 0xde, 0xa4, 0xbf, 0x5d, 0x5a, 0x45, 0xa7, - 0x6e, 0xd4, 0xc3, 0x4a, 0xf5, 0xf4, 0x44, 0x2f, 0xf2, 0xd0, 0x6a, 0xdb, 0xde, 0x9f, 0x0c, 0xcf, - 0x10, 0x82, 0xb8, 0xd4, 0x35, 0x8c, 0x6e, 0x50, 0xa9, 0x7b, 0x8e, 0xff, 0xbb, 0xce, 0xa0, 0x0c, - 0x1e, 0x92, 0x94, 0xb8, 0xc7, 0x94, 0xb8, 0x3f, 0x29, 0x71, 0x3f, 0x33, 0xe2, 0x1c, 0x33, 0xe2, - 0x7c, 0x65, 0xc4, 0x79, 0x99, 0x04, 0x1b, 0x58, 0xbf, 0x7b, 0xd4, 0x97, 0x3b, 0x66, 0xc5, 0x37, - 0x7b, 0x01, 0x91, 0x54, 0xdb, 0xe2, 0xcf, 0xe2, 0xf2, 0x50, 0x70, 0x08, 0x85, 0xf6, 0x9a, 0xe6, - 0x3e, 0xb7, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x24, 0x47, 0x7f, 0x24, 0x1e, 0x02, 0x00, 0x00, + 0x14, 0xc7, 0x5b, 0x41, 0x12, 0x0f, 0x8c, 0xa1, 0x31, 0xb1, 0x21, 0xa6, 0x10, 0x12, 0x12, 0x1c, + 0xbc, 0x06, 0x9c, 0x5d, 0xc0, 0xc8, 0xa2, 0x86, 0xa0, 0x93, 0x83, 0xcd, 0xf5, 0x78, 0x96, 0x06, + 0x7b, 0x47, 0x7a, 0x87, 0xc0, 0xb7, 0x70, 0xf4, 0x23, 0x31, 0x32, 0x3a, 0x19, 0x03, 0x5f, 0xc4, + 0x70, 0xbd, 0x36, 0x3a, 0x74, 0x6b, 0xdf, 0xfb, 0xfd, 0x7f, 0x7d, 0xe9, 0x1f, 0xb5, 0x48, 0x4c, + 0x27, 0x0b, 0xb2, 0x72, 0x63, 0x58, 0x90, 0x78, 0x2c, 0xdc, 0xf7, 0x8e, 0x0f, 0x92, 0x74, 0xdc, + 0x00, 0x18, 0x88, 0x50, 0xe0, 0x59, 0xcc, 0x25, 0xb7, 0xce, 0x34, 0x86, 0x35, 0x86, 0x35, 0x56, + 0x3b, 0x0d, 0x78, 0xc0, 0x15, 0xe3, 0xee, 0x9f, 0x12, 0xbc, 0xe6, 0x50, 0x2e, 0x22, 0x2e, 0x5c, + 0x9f, 0x08, 0xc8, 0x8c, 0x94, 0x87, 0x4c, 0xef, 0x73, 0xbf, 0x9a, 0xea, 0x15, 0xd6, 0xfc, 0x2c, + 0xa0, 0xca, 0x20, 0xb9, 0xe3, 0x51, 0x12, 0x09, 0xd6, 0x35, 0x2a, 0xcd, 0x48, 0x4c, 0x22, 0x61, + 0x9b, 0x0d, 0xb3, 0x5d, 0xee, 0xd6, 0x71, 0xce, 0x5d, 0x78, 0xa8, 0xb0, 0x5e, 0x71, 0xfd, 0x5d, + 0x37, 0x46, 0x3a, 0x64, 0xbd, 0x20, 0x8b, 0x72, 0x26, 0x63, 0x42, 0xa5, 0xf0, 0x22, 0x90, 0x64, + 0x4c, 0x24, 0xb1, 0x0f, 0x1a, 0x85, 0x76, 0xb9, 0x7b, 0x91, 0xab, 0xea, 0xeb, 0xc8, 0xbd, 0x0e, + 0x68, 0x69, 0x35, 0x53, 0xa5, 0x0b, 0x6b, 0x88, 0x8e, 0xfd, 0x37, 0x4e, 0xa7, 0x9e, 0x56, 0xd8, + 0x05, 0xa5, 0x6e, 0xe5, 0xaa, 0x7b, 0x7b, 0x7a, 0x94, 0x0c, 0xb5, 0xb6, 0xe2, 0xff, 0x99, 0x59, + 0x03, 0x84, 0xe4, 0x32, 0xd3, 0x15, 0x95, 0xae, 0x99, 0xab, 0x7b, 0x5a, 0xfe, 0x77, 0x1d, 0xc9, + 0x74, 0x60, 0x3d, 0xa0, 0x6a, 0x14, 0x32, 0x8f, 0x72, 0x26, 0x80, 0x89, 0xb9, 0xf0, 0x5e, 0x01, + 0xec, 0x43, 0xf5, 0x13, 0xcf, 0x71, 0xd2, 0x16, 0xde, 0xb7, 0x95, 0xb9, 0x6e, 0x80, 0xf6, 0x79, + 0xc8, 0xb4, 0xe9, 0x24, 0x0a, 0x59, 0x3f, 0xcd, 0xde, 0x02, 0xf4, 0xee, 0xd6, 0x5b, 0xc7, 0xdc, + 0x6c, 0x1d, 0xf3, 0x67, 0xeb, 0x98, 0x1f, 0x3b, 0xc7, 0xd8, 0xec, 0x1c, 0xe3, 0x6b, 0xe7, 0x18, + 0xcf, 0xdd, 0x20, 0x94, 0x93, 0xb9, 0x8f, 0x29, 0x8f, 0x5c, 0x7d, 0xe8, 0x25, 0x03, 0xb9, 0xe0, + 0xf1, 0x34, 0x7d, 0x77, 0x97, 0x59, 0xf1, 0x72, 0x35, 0x03, 0xe1, 0x97, 0x54, 0xdf, 0x57, 0xbf, + 0x01, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x6e, 0x70, 0x62, 0x8e, 0x02, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -148,6 +162,16 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.MinConsensusFee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a if len(m.TxRewards) > 0 { for iNdEx := len(m.TxRewards) - 1; iNdEx >= 0; iNdEx-- { { @@ -240,6 +264,8 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + l = m.MinConsensusFee.Size() + n += 1 + l + sovGenesis(uint64(l)) return n } @@ -413,6 +439,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinConsensusFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinConsensusFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/rewards/types/genesis_test.go b/x/rewards/types/genesis_test.go index a10d5c4e..7eb51c61 100644 --- a/x/rewards/types/genesis_test.go +++ b/x/rewards/types/genesis_test.go @@ -42,6 +42,7 @@ func TestRewardsGenesisStateValidate(t *testing.T) { TxRewards: []rewardsTypes.TxRewards{ {TxId: 1, Height: 1}, }, + MinConsensusFee: sdk.NewDecCoin(sdk.DefaultBondDenom, sdk.OneInt()), }, }, { @@ -130,6 +131,17 @@ func TestRewardsGenesisStateValidate(t *testing.T) { }, errExpected: true, }, + { + name: "Fail: invalid MinConsensusFee", + genesisState: rewardsTypes.GenesisState{ + Params: rewardsTypes.DefaultParams(), + MinConsensusFee: sdk.DecCoin{ + Denom: sdk.DefaultBondDenom, + Amount: sdk.NewDec(-1), + }, + }, + errExpected: true, + }, } for _, tc := range testCases { diff --git a/x/rewards/types/keys.go b/x/rewards/types/keys.go index 56cb74c6..0e8e08b8 100644 --- a/x/rewards/types/keys.go +++ b/x/rewards/types/keys.go @@ -51,3 +51,14 @@ var ( // Value: None TxRewardsBlockIndexPrefix = []byte{0x01} ) + +// Minimum consensus fee store state keys. +var ( + // MinConsFeeStatePrefix defines the state global prefix. + MinConsFeeStatePrefix = []byte{0x03} + + // MinConsFeeKey defines the key for storing MinConsFee coin. + // Key: MinConsFeeStatePrefix | MinConsFeeKey + // Value: sdk.Coin + MinConsFeeKey = []byte{0x00} +) From 60be0450ca8aacf94aba933c71c12033d541cba8 Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Wed, 3 Aug 2022 19:22:16 +0300 Subject: [PATCH 23/27] x/rewards: estimate tx fees query added --- docs/proto/proto-docs.md | 34 ++ pkg/cli_args.go | 11 + proto/archway/rewards/v1beta1/query.proto | 25 ++ x/rewards/client/cli/query.go | 34 ++ x/rewards/keeper/grpc_query.go | 22 + x/rewards/types/query.pb.go | 507 ++++++++++++++++++++-- x/rewards/types/query.pb.gw.go | 80 ++++ 7 files changed, 676 insertions(+), 37 deletions(-) diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index b54cc310..6a72c2e0 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -54,6 +54,8 @@ - [QueryBlockRewardsTrackingResponse](#archway.rewards.v1beta1.QueryBlockRewardsTrackingResponse) - [QueryContractMetadataRequest](#archway.rewards.v1beta1.QueryContractMetadataRequest) - [QueryContractMetadataResponse](#archway.rewards.v1beta1.QueryContractMetadataResponse) + - [QueryEstimateTxFeesRequest](#archway.rewards.v1beta1.QueryEstimateTxFeesRequest) + - [QueryEstimateTxFeesResponse](#archway.rewards.v1beta1.QueryEstimateTxFeesResponse) - [QueryParamsRequest](#archway.rewards.v1beta1.QueryParamsRequest) - [QueryParamsResponse](#archway.rewards.v1beta1.QueryParamsResponse) - [QueryRewardsPoolRequest](#archway.rewards.v1beta1.QueryRewardsPoolRequest) @@ -712,6 +714,37 @@ QueryContractMetadataResponse is the response for Query.ContractMetadata. + + +### QueryEstimateTxFeesRequest +QueryEstimateTxFeesRequest is the request for Query.EstimateTxFees. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `gas_limit` | [uint64](#uint64) | | gas_limit is the transaction gas limit. | + + + + + + + + +### QueryEstimateTxFeesResponse +QueryEstimateTxFeesResponse is the response for Query.EstimateTxFees. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `gas_unit_price` | [cosmos.base.v1beta1.DecCoin](#cosmos.base.v1beta1.DecCoin) | | gas_unit_price defines the minimum transaction fee per gas unit. | +| `estimated_fee` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | | estimated_fee is the estimated transaction fee for a given gas limit. | + + + + + + ### QueryParamsRequest @@ -779,6 +812,7 @@ Query service for the tracking module. | `ContractMetadata` | [QueryContractMetadataRequest](#archway.rewards.v1beta1.QueryContractMetadataRequest) | [QueryContractMetadataResponse](#archway.rewards.v1beta1.QueryContractMetadataResponse) | ContractMetadata returns the contract rewards parameters (metadata). | GET|/archway/rewards/v1/contract_metadata| | `BlockRewardsTracking` | [QueryBlockRewardsTrackingRequest](#archway.rewards.v1beta1.QueryBlockRewardsTrackingRequest) | [QueryBlockRewardsTrackingResponse](#archway.rewards.v1beta1.QueryBlockRewardsTrackingResponse) | BlockRewardsTracking returns block rewards tracking for the current block. | GET|/archway/rewards/v1/block_rewards_tracking| | `RewardsPool` | [QueryRewardsPoolRequest](#archway.rewards.v1beta1.QueryRewardsPoolRequest) | [QueryRewardsPoolResponse](#archway.rewards.v1beta1.QueryRewardsPoolResponse) | RewardsPool returns the current undistributed rewards pool funds. | GET|/archway/rewards/v1/rewards_pool| +| `EstimateTxFees` | [QueryEstimateTxFeesRequest](#archway.rewards.v1beta1.QueryEstimateTxFeesRequest) | [QueryEstimateTxFeesResponse](#archway.rewards.v1beta1.QueryEstimateTxFeesResponse) | EstimateTxFees returns the estimated transaction fees for the given transaction gas limit using the minimum consensus fee value for the current block. | GET|/archway/rewards/v1/estimate_tx_fees| diff --git a/pkg/cli_args.go b/pkg/cli_args.go index 211fba41..2d41a0ae 100644 --- a/pkg/cli_args.go +++ b/pkg/cli_args.go @@ -2,6 +2,7 @@ package pkg import ( "fmt" + "strconv" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -15,3 +16,13 @@ func ParseAccAddressArg(argName, argValue string) (sdk.AccAddress, error) { return addr, nil } + +// ParseUint64Arg is a helper function to parse uint64 CLI argument. +func ParseUint64Arg(argName, argValue string) (uint64, error) { + v, err := strconv.ParseUint(argValue, 10, 64) + if err != nil { + return 0, fmt.Errorf("parsing %s argument: invalid uint64 value: %w", argName, err) + } + + return v, nil +} diff --git a/proto/archway/rewards/v1beta1/query.proto b/proto/archway/rewards/v1beta1/query.proto index 0692e8dc..c4115f95 100644 --- a/proto/archway/rewards/v1beta1/query.proto +++ b/proto/archway/rewards/v1beta1/query.proto @@ -29,6 +29,12 @@ service Query { rpc RewardsPool(QueryRewardsPoolRequest) returns (QueryRewardsPoolResponse) { option (google.api.http).get = "/archway/rewards/v1/rewards_pool"; } + + // EstimateTxFees returns the estimated transaction fees for the given transaction + // gas limit using the minimum consensus fee value for the current block. + rpc EstimateTxFees(QueryEstimateTxFeesRequest) returns (QueryEstimateTxFeesResponse) { + option (google.api.http).get = "/archway/rewards/v1/estimate_tx_fees"; + } } // QueryParamsRequest is the request for Query.Params. @@ -73,3 +79,22 @@ message QueryRewardsPoolResponse { (gogoproto.nullable) = false ]; } + +// QueryEstimateTxFeesRequest is the request for Query.EstimateTxFees. +message QueryEstimateTxFeesRequest { + // gas_limit is the transaction gas limit. + uint64 gas_limit = 1; +} + +// QueryEstimateTxFeesResponse is the response for Query.EstimateTxFees. +message QueryEstimateTxFeesResponse { + // gas_unit_price defines the minimum transaction fee per gas unit. + cosmos.base.v1beta1.DecCoin gas_unit_price = 1 [ + (gogoproto.nullable) = false + ]; + + // estimated_fee is the estimated transaction fee for a given gas limit. + cosmos.base.v1beta1.Coin estimated_fee = 2 [ + (gogoproto.nullable) = false + ]; +} diff --git a/x/rewards/client/cli/query.go b/x/rewards/client/cli/query.go index 1517a74b..36f57437 100644 --- a/x/rewards/client/cli/query.go +++ b/x/rewards/client/cli/query.go @@ -23,6 +23,7 @@ func GetQueryCmd() *cobra.Command { getQueryBlockRewardsTrackingCmd(), getQueryContractMetadataCmd(), getQueryUndistributedPoolFundsCmd(), + getQueryEstimateTxFeesCmd(), ) return cmd @@ -138,3 +139,36 @@ func getQueryUndistributedPoolFundsCmd() *cobra.Command { return cmd } + +func getQueryEstimateTxFeesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "estimate-fees [gas-limit]", + Args: cobra.ExactArgs(1), + Short: "Query transaction fees estimation for a give gas limit", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + gasLimit, err := pkg.ParseUint64Arg("gas-limit", args[0]) + if err != nil { + return err + } + + res, err := queryClient.EstimateTxFees(cmd.Context(), &types.QueryEstimateTxFeesRequest{ + GasLimit: gasLimit, + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/rewards/keeper/grpc_query.go b/x/rewards/keeper/grpc_query.go index 7110c841..a8e5fe2b 100644 --- a/x/rewards/keeper/grpc_query.go +++ b/x/rewards/keeper/grpc_query.go @@ -95,3 +95,25 @@ func (s *QueryServer) RewardsPool(c context.Context, request *types.QueryRewards Funds: s.keeper.UndistributedRewardsPool(ctx), }, nil } + +// EstimateTxFees implements the types.QueryServer interface. +func (s *QueryServer) EstimateTxFees(c context.Context, request *types.QueryEstimateTxFeesRequest) (*types.QueryEstimateTxFeesResponse, error) { + if request == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(c) + + minConsFee := s.keeper.GetMinConsensusFee(ctx) + if minConsFee == nil { + return nil, status.Errorf(codes.NotFound, "min consensus fee: not found") + } + + return &types.QueryEstimateTxFeesResponse{ + GasUnitPrice: *minConsFee, + EstimatedFee: sdk.Coin{ + Denom: minConsFee.Denom, + Amount: minConsFee.Amount.MulInt64(int64(request.GasLimit)).RoundInt(), + }, + }, nil +} diff --git a/x/rewards/types/query.pb.go b/x/rewards/types/query.pb.go index b0e75b3c..a653e0f8 100644 --- a/x/rewards/types/query.pb.go +++ b/x/rewards/types/query.pb.go @@ -368,6 +368,107 @@ func (m *QueryRewardsPoolResponse) GetFunds() []types.Coin { return nil } +// QueryEstimateTxFeesRequest is the request for Query.EstimateTxFees. +type QueryEstimateTxFeesRequest struct { + // gas_limit is the transaction gas limit. + GasLimit uint64 `protobuf:"varint,1,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"` +} + +func (m *QueryEstimateTxFeesRequest) Reset() { *m = QueryEstimateTxFeesRequest{} } +func (m *QueryEstimateTxFeesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryEstimateTxFeesRequest) ProtoMessage() {} +func (*QueryEstimateTxFeesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{8} +} +func (m *QueryEstimateTxFeesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryEstimateTxFeesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryEstimateTxFeesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryEstimateTxFeesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryEstimateTxFeesRequest.Merge(m, src) +} +func (m *QueryEstimateTxFeesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryEstimateTxFeesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryEstimateTxFeesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryEstimateTxFeesRequest proto.InternalMessageInfo + +func (m *QueryEstimateTxFeesRequest) GetGasLimit() uint64 { + if m != nil { + return m.GasLimit + } + return 0 +} + +// QueryEstimateTxFeesResponse is the response for Query.EstimateTxFees. +type QueryEstimateTxFeesResponse struct { + // gas_unit_price defines the minimum transaction fee per gas unit. + GasUnitPrice types.DecCoin `protobuf:"bytes,1,opt,name=gas_unit_price,json=gasUnitPrice,proto3" json:"gas_unit_price"` + // estimated_fee is the estimated transaction fee for a given gas limit. + EstimatedFee types.Coin `protobuf:"bytes,2,opt,name=estimated_fee,json=estimatedFee,proto3" json:"estimated_fee"` +} + +func (m *QueryEstimateTxFeesResponse) Reset() { *m = QueryEstimateTxFeesResponse{} } +func (m *QueryEstimateTxFeesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryEstimateTxFeesResponse) ProtoMessage() {} +func (*QueryEstimateTxFeesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_078e0e66cc6cb70d, []int{9} +} +func (m *QueryEstimateTxFeesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryEstimateTxFeesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryEstimateTxFeesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryEstimateTxFeesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryEstimateTxFeesResponse.Merge(m, src) +} +func (m *QueryEstimateTxFeesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryEstimateTxFeesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryEstimateTxFeesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryEstimateTxFeesResponse proto.InternalMessageInfo + +func (m *QueryEstimateTxFeesResponse) GetGasUnitPrice() types.DecCoin { + if m != nil { + return m.GasUnitPrice + } + return types.DecCoin{} +} + +func (m *QueryEstimateTxFeesResponse) GetEstimatedFee() types.Coin { + if m != nil { + return m.EstimatedFee + } + return types.Coin{} +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "archway.rewards.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "archway.rewards.v1beta1.QueryParamsResponse") @@ -377,6 +478,8 @@ func init() { proto.RegisterType((*QueryBlockRewardsTrackingResponse)(nil), "archway.rewards.v1beta1.QueryBlockRewardsTrackingResponse") proto.RegisterType((*QueryRewardsPoolRequest)(nil), "archway.rewards.v1beta1.QueryRewardsPoolRequest") proto.RegisterType((*QueryRewardsPoolResponse)(nil), "archway.rewards.v1beta1.QueryRewardsPoolResponse") + proto.RegisterType((*QueryEstimateTxFeesRequest)(nil), "archway.rewards.v1beta1.QueryEstimateTxFeesRequest") + proto.RegisterType((*QueryEstimateTxFeesResponse)(nil), "archway.rewards.v1beta1.QueryEstimateTxFeesResponse") } func init() { @@ -384,43 +487,52 @@ func init() { } var fileDescriptor_078e0e66cc6cb70d = []byte{ - // 572 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xb1, 0x6f, 0xd3, 0x40, - 0x14, 0xc6, 0x63, 0x20, 0x11, 0x5c, 0x06, 0xaa, 0x23, 0x52, 0x5b, 0x2b, 0xb8, 0xc1, 0xa8, 0x90, - 0x42, 0x6b, 0x93, 0xa0, 0x22, 0x81, 0xc4, 0x40, 0x98, 0x10, 0x20, 0xb5, 0x51, 0x27, 0x96, 0xe8, - 0xe2, 0x1c, 0xae, 0x95, 0xc4, 0xcf, 0xf5, 0x5d, 0x08, 0x59, 0x59, 0x58, 0x91, 0x58, 0xd9, 0x59, - 0xf9, 0x17, 0xd8, 0x3a, 0x56, 0x62, 0x61, 0x42, 0x28, 0xe1, 0x0f, 0x41, 0xb9, 0x7b, 0x17, 0x95, - 0x26, 0x8e, 0x68, 0xb7, 0xea, 0xbd, 0xef, 0x7d, 0xdf, 0xaf, 0xe7, 0x4f, 0x21, 0xb7, 0x59, 0x1a, - 0x1c, 0x0e, 0xd9, 0xc8, 0x4f, 0xf9, 0x90, 0xa5, 0x1d, 0xe1, 0xbf, 0xab, 0xb5, 0xb9, 0x64, 0x35, - 0xff, 0x68, 0xc0, 0xd3, 0x91, 0x97, 0xa4, 0x20, 0x81, 0xae, 0xa2, 0xc8, 0x43, 0x91, 0x87, 0x22, - 0xbb, 0x14, 0x42, 0x08, 0x4a, 0xe3, 0x4f, 0xff, 0xd2, 0x72, 0xbb, 0x1c, 0x02, 0x84, 0x3d, 0xee, - 0xb3, 0x24, 0xf2, 0x59, 0x1c, 0x83, 0x64, 0x32, 0x82, 0x58, 0xe0, 0xd6, 0x09, 0x40, 0xf4, 0x41, - 0xf8, 0x6d, 0x26, 0xf8, 0x2c, 0x2d, 0x80, 0x28, 0xc6, 0xfd, 0x66, 0x16, 0x91, 0x09, 0x57, 0x32, - 0xb7, 0x44, 0xe8, 0xfe, 0x14, 0x71, 0x8f, 0xa5, 0xac, 0x2f, 0x9a, 0xfc, 0x68, 0xc0, 0x85, 0x74, - 0x0f, 0xc8, 0x8d, 0x7f, 0xa6, 0x22, 0x81, 0x58, 0x70, 0xfa, 0x94, 0x14, 0x12, 0x35, 0x59, 0xb3, - 0x2a, 0x56, 0xb5, 0x58, 0xdf, 0xf0, 0x32, 0xfe, 0x23, 0x4f, 0x1f, 0x36, 0xae, 0x1c, 0xff, 0xda, - 0xc8, 0x35, 0xf1, 0xc8, 0x7d, 0x41, 0xca, 0xca, 0xf5, 0x39, 0xc4, 0x32, 0x65, 0x81, 0x7c, 0xcd, - 0x25, 0xeb, 0x30, 0xc9, 0x30, 0x95, 0x6e, 0x91, 0x95, 0x00, 0x57, 0x2d, 0xd6, 0xe9, 0xa4, 0x5c, - 0xe8, 0xa0, 0x6b, 0xcd, 0xeb, 0x66, 0xfe, 0x4c, 0x8f, 0xdd, 0x1e, 0xb9, 0x99, 0x61, 0x85, 0xa8, - 0x2f, 0xc9, 0xd5, 0x3e, 0xce, 0x10, 0x76, 0x2b, 0x13, 0xf6, 0xac, 0x09, 0x62, 0xcf, 0x0c, 0x5c, - 0x97, 0x54, 0x54, 0x5a, 0xa3, 0x07, 0x41, 0xb7, 0xa9, 0xaf, 0x0f, 0x52, 0x16, 0x74, 0xa3, 0x38, - 0x34, 0x4f, 0x16, 0x92, 0x5b, 0x4b, 0x34, 0x48, 0xd5, 0x20, 0xf9, 0xf6, 0x74, 0x8f, 0x48, 0x77, - 0x32, 0x91, 0x94, 0x8b, 0x39, 0x47, 0x1e, 0x7d, 0xea, 0xae, 0x93, 0x55, 0x15, 0x84, 0x19, 0x7b, - 0x00, 0x3d, 0xc3, 0xb0, 0x4f, 0xd6, 0xe6, 0x57, 0x18, 0xbd, 0x4b, 0xf2, 0x6f, 0x07, 0x71, 0x67, - 0xfa, 0xa2, 0x97, 0xab, 0xc5, 0xfa, 0xba, 0xa7, 0xfb, 0xe3, 0x4d, 0xfb, 0x73, 0xea, 0x25, 0xa2, - 0xd8, 0xa4, 0x29, 0x75, 0xfd, 0x6b, 0x9e, 0xe4, 0x95, 0x27, 0xfd, 0x68, 0x91, 0x82, 0xfe, 0xac, - 0xf4, 0x7e, 0x26, 0xf7, 0x7c, 0x97, 0xec, 0xed, 0xff, 0x13, 0x6b, 0x4c, 0xd7, 0xfd, 0xf0, 0xe3, - 0xcf, 0xe7, 0x4b, 0x65, 0x6a, 0xfb, 0xf3, 0xfd, 0xf5, 0x75, 0x8f, 0xe8, 0x37, 0x8b, 0xac, 0x9c, - 0xfd, 0x66, 0x74, 0x77, 0x79, 0x4c, 0x46, 0xe7, 0xec, 0x47, 0xe7, 0x3d, 0x43, 0xce, 0x1d, 0xc5, - 0x79, 0x97, 0x6e, 0x2e, 0xe2, 0x9c, 0xb5, 0xd8, 0x34, 0x88, 0x7e, 0xb7, 0x48, 0x69, 0x51, 0x33, - 0xe8, 0xe3, 0xe5, 0xf9, 0x4b, 0x1a, 0x67, 0x3f, 0xb9, 0xc8, 0x29, 0xe2, 0xd7, 0x15, 0xfe, 0x36, - 0xbd, 0xb7, 0x08, 0x5f, 0xf5, 0xac, 0x85, 0x83, 0x96, 0x34, 0xa8, 0x5f, 0x2c, 0x52, 0x3c, 0xd5, - 0x2c, 0xfa, 0x60, 0x79, 0xfe, 0x7c, 0x3f, 0xed, 0xda, 0x39, 0x2e, 0x10, 0xb4, 0xaa, 0x40, 0x5d, - 0x5a, 0x59, 0x04, 0x6a, 0x10, 0x13, 0x80, 0x5e, 0xe3, 0xd5, 0xf1, 0xd8, 0xb1, 0x4e, 0xc6, 0x8e, - 0xf5, 0x7b, 0xec, 0x58, 0x9f, 0x26, 0x4e, 0xee, 0x64, 0xe2, 0xe4, 0x7e, 0x4e, 0x9c, 0xdc, 0x9b, - 0x7a, 0x18, 0xc9, 0xc3, 0x41, 0xdb, 0x0b, 0xa0, 0x6f, 0x5c, 0x76, 0x62, 0x2e, 0x87, 0x90, 0x76, - 0x67, 0xae, 0xef, 0x67, 0xbe, 0x72, 0x94, 0x70, 0xd1, 0x2e, 0xa8, 0x9f, 0xc7, 0x87, 0x7f, 0x03, - 0x00, 0x00, 0xff, 0xff, 0x55, 0x73, 0x38, 0x81, 0xd9, 0x05, 0x00, 0x00, + // 711 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x95, 0x41, 0x4f, 0x13, 0x5b, + 0x14, 0xc7, 0x3b, 0x3c, 0x68, 0xe0, 0xc0, 0xe3, 0x91, 0xfb, 0x48, 0x80, 0xa1, 0x6f, 0xe0, 0x8d, + 0x82, 0xa0, 0x30, 0x23, 0x45, 0x4c, 0x30, 0x71, 0x61, 0x45, 0xa2, 0x11, 0x13, 0x68, 0x70, 0xe3, + 0x66, 0x72, 0x3b, 0xbd, 0x0c, 0x13, 0xda, 0xb9, 0xc3, 0xdc, 0x5b, 0x81, 0xad, 0x1b, 0xb7, 0x26, + 0x6e, 0xfd, 0x02, 0x2e, 0x4c, 0xfc, 0x0a, 0xee, 0x58, 0x92, 0xb0, 0x71, 0x65, 0x0c, 0xf8, 0x41, + 0xcc, 0xdc, 0x39, 0xd3, 0x00, 0x9d, 0xa9, 0xe2, 0xae, 0x3d, 0xf7, 0xfc, 0xcf, 0xff, 0x77, 0x6f, + 0xcf, 0x3f, 0x85, 0x1b, 0x34, 0x72, 0x77, 0x0f, 0xe8, 0x91, 0x1d, 0xb1, 0x03, 0x1a, 0xd5, 0x85, + 0xfd, 0x7a, 0xa9, 0xc6, 0x24, 0x5d, 0xb2, 0xf7, 0x5b, 0x2c, 0x3a, 0xb2, 0xc2, 0x88, 0x4b, 0x4e, + 0xc6, 0xb0, 0xc9, 0xc2, 0x26, 0x0b, 0x9b, 0xf4, 0x51, 0x8f, 0x7b, 0x5c, 0xf5, 0xd8, 0xf1, 0xa7, + 0xa4, 0x5d, 0x2f, 0x79, 0x9c, 0x7b, 0x0d, 0x66, 0xd3, 0xd0, 0xb7, 0x69, 0x10, 0x70, 0x49, 0xa5, + 0xcf, 0x03, 0x81, 0xa7, 0x86, 0xcb, 0x45, 0x93, 0x0b, 0xbb, 0x46, 0x05, 0x6b, 0xbb, 0xb9, 0xdc, + 0x0f, 0xf0, 0x7c, 0x26, 0x8f, 0x28, 0x35, 0x57, 0x6d, 0xe6, 0x28, 0x90, 0xad, 0x18, 0x71, 0x93, + 0x46, 0xb4, 0x29, 0xaa, 0x6c, 0xbf, 0xc5, 0x84, 0x34, 0xb7, 0xe1, 0xdf, 0x4b, 0x55, 0x11, 0xf2, + 0x40, 0x30, 0xf2, 0x10, 0x8a, 0xa1, 0xaa, 0x8c, 0x6b, 0xd3, 0xda, 0xdc, 0x60, 0x79, 0xca, 0xca, + 0xb9, 0x91, 0x95, 0x08, 0x2b, 0xbd, 0xc7, 0xdf, 0xa6, 0x0a, 0x55, 0x14, 0x99, 0xcf, 0xa0, 0xa4, + 0xa6, 0x3e, 0xe6, 0x81, 0x8c, 0xa8, 0x2b, 0x5f, 0x30, 0x49, 0xeb, 0x54, 0x52, 0x74, 0x25, 0xf3, + 0x30, 0xe2, 0xe2, 0x91, 0x43, 0xeb, 0xf5, 0x88, 0x89, 0xc4, 0x68, 0xa0, 0xfa, 0x4f, 0x5a, 0x7f, + 0x94, 0x94, 0xcd, 0x06, 0xfc, 0x97, 0x33, 0x0a, 0x51, 0x9f, 0x43, 0x7f, 0x13, 0x6b, 0x08, 0x3b, + 0x9f, 0x0b, 0x7b, 0x75, 0x08, 0x62, 0xb7, 0x07, 0x98, 0x26, 0x4c, 0x2b, 0xb7, 0x4a, 0x83, 0xbb, + 0x7b, 0xd5, 0x44, 0xbd, 0x1d, 0x51, 0x77, 0xcf, 0x0f, 0xbc, 0xf4, 0xc9, 0x3c, 0xf8, 0xbf, 0x4b, + 0x0f, 0x52, 0x55, 0xa0, 0xaf, 0x16, 0x9f, 0x23, 0xd2, 0x6c, 0x2e, 0x92, 0x9a, 0x92, 0xca, 0x91, + 0x27, 0x91, 0x9a, 0x13, 0x30, 0xa6, 0x8c, 0xd0, 0x63, 0x93, 0xf3, 0x46, 0xca, 0xb0, 0x05, 0xe3, + 0x9d, 0x47, 0x68, 0xbd, 0x02, 0x7d, 0x3b, 0xad, 0xa0, 0x1e, 0xbf, 0xe8, 0x5f, 0x73, 0x83, 0xe5, + 0x09, 0x2b, 0xd9, 0x1f, 0x2b, 0xde, 0x9f, 0x0b, 0x2f, 0xe1, 0x07, 0xa9, 0x9b, 0xea, 0x36, 0x57, + 0x41, 0x57, 0x23, 0x9f, 0x08, 0xe9, 0x37, 0xa9, 0x64, 0xdb, 0x87, 0xeb, 0x8c, 0xa5, 0x7b, 0x42, + 0x26, 0x61, 0xc0, 0xa3, 0xc2, 0x69, 0xf8, 0x4d, 0x5f, 0xaa, 0x3b, 0xf5, 0x56, 0xfb, 0x3d, 0x2a, + 0x36, 0xe2, 0xef, 0xe6, 0x27, 0x0d, 0x26, 0x33, 0xb5, 0x48, 0xf4, 0x14, 0x86, 0x63, 0x71, 0x2b, + 0xf0, 0xa5, 0x13, 0x46, 0xbe, 0xcb, 0xf0, 0x55, 0x4a, 0x99, 0x68, 0x6b, 0xcc, 0xbd, 0x40, 0x37, + 0xe4, 0x51, 0xf1, 0x32, 0xf0, 0xe5, 0x66, 0xac, 0x23, 0x6b, 0xf0, 0x37, 0x43, 0x8f, 0xba, 0xb3, + 0xc3, 0xd8, 0x78, 0x8f, 0x1a, 0xf4, 0xcb, 0x3b, 0x0e, 0xb5, 0x55, 0xeb, 0x8c, 0x95, 0x4f, 0x8b, + 0xd0, 0xa7, 0x78, 0xc9, 0x5b, 0x0d, 0x8a, 0xc9, 0x06, 0x93, 0x3b, 0xb9, 0x3f, 0x51, 0x67, 0x6c, + 0xf4, 0x85, 0xdf, 0x6b, 0x4e, 0xee, 0x6f, 0x9a, 0x6f, 0x4e, 0x7f, 0xbc, 0xef, 0x29, 0x11, 0xdd, + 0xee, 0x8c, 0xaa, 0x9d, 0x44, 0x86, 0x7c, 0xd6, 0x60, 0xe4, 0xea, 0x7a, 0x92, 0x95, 0xee, 0x36, + 0x39, 0xf1, 0xd2, 0xef, 0x5f, 0x57, 0x86, 0x9c, 0x8b, 0x8a, 0xf3, 0x16, 0x99, 0xc9, 0xe2, 0x6c, + 0x07, 0x36, 0x0d, 0x0b, 0xf9, 0xa2, 0xc1, 0x68, 0x56, 0x08, 0xc8, 0x6a, 0x77, 0xff, 0x2e, 0xe1, + 0xd2, 0x1f, 0xfc, 0x89, 0x14, 0xf1, 0xcb, 0x0a, 0x7f, 0x81, 0xdc, 0xce, 0xc2, 0x57, 0x91, 0x72, + 0xb0, 0xe0, 0xc8, 0x14, 0xf5, 0x83, 0x06, 0x83, 0x17, 0x42, 0x44, 0xee, 0x76, 0xf7, 0xef, 0x8c, + 0xa2, 0xbe, 0x74, 0x0d, 0x05, 0x82, 0xce, 0x29, 0x50, 0x93, 0x4c, 0x67, 0x81, 0xa6, 0x88, 0x61, + 0x8c, 0xf3, 0x51, 0x83, 0xe1, 0xcb, 0xa1, 0x22, 0xcb, 0xdd, 0xfd, 0x32, 0xe3, 0xab, 0xdf, 0xbb, + 0x9e, 0x08, 0x39, 0x17, 0x14, 0xe7, 0x2c, 0xb9, 0x99, 0xc5, 0x99, 0x26, 0xca, 0x91, 0x87, 0x71, + 0x12, 0x45, 0x65, 0xe3, 0xf8, 0xcc, 0xd0, 0x4e, 0xce, 0x0c, 0xed, 0xfb, 0x99, 0xa1, 0xbd, 0x3b, + 0x37, 0x0a, 0x27, 0xe7, 0x46, 0xe1, 0xeb, 0xb9, 0x51, 0x78, 0x55, 0xf6, 0x7c, 0xb9, 0xdb, 0xaa, + 0x59, 0x2e, 0x6f, 0xa6, 0x93, 0x16, 0x03, 0x26, 0x0f, 0x78, 0xb4, 0xd7, 0x9e, 0x7c, 0xd8, 0x9e, + 0x2d, 0x8f, 0x42, 0x26, 0x6a, 0x45, 0xf5, 0xaf, 0xb5, 0xfc, 0x33, 0x00, 0x00, 0xff, 0xff, 0xf0, + 0xd7, 0xcc, 0xcb, 0x70, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -443,6 +555,9 @@ type QueryClient interface { BlockRewardsTracking(ctx context.Context, in *QueryBlockRewardsTrackingRequest, opts ...grpc.CallOption) (*QueryBlockRewardsTrackingResponse, error) // RewardsPool returns the current undistributed rewards pool funds. RewardsPool(ctx context.Context, in *QueryRewardsPoolRequest, opts ...grpc.CallOption) (*QueryRewardsPoolResponse, error) + // EstimateTxFees returns the estimated transaction fees for the given transaction + // gas limit using the minimum consensus fee value for the current block. + EstimateTxFees(ctx context.Context, in *QueryEstimateTxFeesRequest, opts ...grpc.CallOption) (*QueryEstimateTxFeesResponse, error) } type queryClient struct { @@ -489,6 +604,15 @@ func (c *queryClient) RewardsPool(ctx context.Context, in *QueryRewardsPoolReque return out, nil } +func (c *queryClient) EstimateTxFees(ctx context.Context, in *QueryEstimateTxFeesRequest, opts ...grpc.CallOption) (*QueryEstimateTxFeesResponse, error) { + out := new(QueryEstimateTxFeesResponse) + err := c.cc.Invoke(ctx, "/archway.rewards.v1beta1.Query/EstimateTxFees", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Params returns module parameters. @@ -499,6 +623,9 @@ type QueryServer interface { BlockRewardsTracking(context.Context, *QueryBlockRewardsTrackingRequest) (*QueryBlockRewardsTrackingResponse, error) // RewardsPool returns the current undistributed rewards pool funds. RewardsPool(context.Context, *QueryRewardsPoolRequest) (*QueryRewardsPoolResponse, error) + // EstimateTxFees returns the estimated transaction fees for the given transaction + // gas limit using the minimum consensus fee value for the current block. + EstimateTxFees(context.Context, *QueryEstimateTxFeesRequest) (*QueryEstimateTxFeesResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -517,6 +644,9 @@ func (*UnimplementedQueryServer) BlockRewardsTracking(ctx context.Context, req * func (*UnimplementedQueryServer) RewardsPool(ctx context.Context, req *QueryRewardsPoolRequest) (*QueryRewardsPoolResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RewardsPool not implemented") } +func (*UnimplementedQueryServer) EstimateTxFees(ctx context.Context, req *QueryEstimateTxFeesRequest) (*QueryEstimateTxFeesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method EstimateTxFees not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -594,6 +724,24 @@ func _Query_RewardsPool_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Query_EstimateTxFees_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryEstimateTxFeesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).EstimateTxFees(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/archway.rewards.v1beta1.Query/EstimateTxFees", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).EstimateTxFees(ctx, req.(*QueryEstimateTxFeesRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "archway.rewards.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -614,6 +762,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "RewardsPool", Handler: _Query_RewardsPool_Handler, }, + { + MethodName: "EstimateTxFees", + Handler: _Query_EstimateTxFees_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "archway/rewards/v1beta1/query.proto", @@ -854,6 +1006,77 @@ func (m *QueryRewardsPoolResponse) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } +func (m *QueryEstimateTxFeesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryEstimateTxFeesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryEstimateTxFeesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.GasLimit != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.GasLimit)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryEstimateTxFeesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryEstimateTxFeesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryEstimateTxFeesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.EstimatedFee.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.GasUnitPrice.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -953,6 +1176,31 @@ func (m *QueryRewardsPoolResponse) Size() (n int) { return n } +func (m *QueryEstimateTxFeesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.GasLimit != 0 { + n += 1 + sovQuery(uint64(m.GasLimit)) + } + return n +} + +func (m *QueryEstimateTxFeesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.GasUnitPrice.Size() + n += 1 + l + sovQuery(uint64(l)) + l = m.EstimatedFee.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1524,6 +1772,191 @@ func (m *QueryRewardsPoolResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryEstimateTxFeesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryEstimateTxFeesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryEstimateTxFeesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType) + } + m.GasLimit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.GasLimit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryEstimateTxFeesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryEstimateTxFeesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryEstimateTxFeesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GasUnitPrice", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GasUnitPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EstimatedFee", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.EstimatedFee.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/rewards/types/query.pb.gw.go b/x/rewards/types/query.pb.gw.go index c7c26fb0..34d87631 100644 --- a/x/rewards/types/query.pb.gw.go +++ b/x/rewards/types/query.pb.gw.go @@ -122,6 +122,42 @@ func local_request_Query_RewardsPool_0(ctx context.Context, marshaler runtime.Ma } +var ( + filter_Query_EstimateTxFees_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_EstimateTxFees_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryEstimateTxFeesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_EstimateTxFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.EstimateTxFees(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_EstimateTxFees_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryEstimateTxFeesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_EstimateTxFees_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.EstimateTxFees(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -208,6 +244,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_EstimateTxFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_EstimateTxFees_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_EstimateTxFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -329,6 +385,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_EstimateTxFees_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_EstimateTxFees_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_EstimateTxFees_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -340,6 +416,8 @@ var ( pattern_Query_BlockRewardsTracking_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "block_rewards_tracking"}, "", runtime.AssumeColonVerbOpt(true))) pattern_Query_RewardsPool_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "rewards_pool"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_Query_EstimateTxFees_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"archway", "rewards", "v1", "estimate_tx_fees"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -350,4 +428,6 @@ var ( forward_Query_BlockRewardsTracking_0 = runtime.ForwardResponseMessage forward_Query_RewardsPool_0 = runtime.ForwardResponseMessage + + forward_Query_EstimateTxFees_0 = runtime.ForwardResponseMessage ) From 51784e8689799938d180ca58b3773d13eb0dedfd Mon Sep 17 00:00:00 2001 From: Mikhail Kornilov Date: Wed, 3 Aug 2022 21:44:19 +0300 Subject: [PATCH 24/27] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Eduardo Díaz --- x/rewards/client/cli/query.go | 2 +- x/rewards/client/cli/tx.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/rewards/client/cli/query.go b/x/rewards/client/cli/query.go index 36f57437..95a83122 100644 --- a/x/rewards/client/cli/query.go +++ b/x/rewards/client/cli/query.go @@ -13,7 +13,7 @@ import ( func GetQueryCmd() *cobra.Command { cmd := &cobra.Command{ Use: types.ModuleName, - Short: "Querying commands for the tracking module", + Short: "Querying commands for the rewards module", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, diff --git a/x/rewards/client/cli/tx.go b/x/rewards/client/cli/tx.go index 03700584..9de0cf91 100644 --- a/x/rewards/client/cli/tx.go +++ b/x/rewards/client/cli/tx.go @@ -14,7 +14,7 @@ import ( func GetTxCmd() *cobra.Command { cmd := &cobra.Command{ Use: types.ModuleName, - Short: "Querying commands for the rewards module", + Short: "Transaction commands for the rewards module", DisableFlagParsing: true, SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, From ad68719b5ccf05b61264e41ddd1130e437f6b008 Mon Sep 17 00:00:00 2001 From: edjroz Date: Tue, 9 Aug 2022 14:08:40 +0000 Subject: [PATCH 25/27] remove legacy gastracker integration test --- x/gastracker/integration/integration_test.go | 163 ++++++++++--------- 1 file changed, 82 insertions(+), 81 deletions(-) diff --git a/x/gastracker/integration/integration_test.go b/x/gastracker/integration/integration_test.go index b69db7fc..60e80e79 100644 --- a/x/gastracker/integration/integration_test.go +++ b/x/gastracker/integration/integration_test.go @@ -1,83 +1,84 @@ package integration -import ( - "encoding/json" - "testing" - - voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" - wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/stretchr/testify/require" - - e2eTesting "github.com/archway-network/archway/e2e/testing" - "github.com/archway-network/archway/x/gastracker" - "github.com/archway-network/archway/x/gastracker/common" -) - -func TestRewardsCollection(t *testing.T) { - chain := e2eTesting.NewTestChain(t, 1) - // TODO: this test can be done better but for the sake of simplicity lets keep it like this for now - const blocks int64 = 2 - var inflation = sdk.NewInt64Coin("stake", 103) - - params, err := gastracker.NewQueryClient(chain.Client()).Params(chain.GetContext().Context(), &gastracker.QueryParamsRequest{}) - require.NoError(t, err) - - totalInflation := sdk.NewCoin( - inflation.Denom, (inflation.Amount.ToDec().Mul(params.Params.DappInflationRewardsRatio)).MulInt64(blocks).TruncateInt().SubRaw(1)) // we're subbing a meaningless residual due to loss of precision - - gasTrackerBalance := chain.GetBalance(authtypes.NewModuleAddress(gastracker.ModuleName)) - require.Equal(t, - gasTrackerBalance.String(), - sdk.NewCoins(totalInflation).String(), - ) - - contractAddr := uploadAndInstantiateContract(chain) - - msg := &voterTypes.MsgExecute{ - NewVoting: &voterTypes.NewVotingRequest{ - Name: "hello", - VoteOptions: []string{"idk"}, - Duration: 100, - }, - } - txFees := sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)) - chain.SendMsgs(chain.GetAccount(0), true, []sdk.Msg{&wasmtypes.MsgExecuteContract{ - Sender: chain.GetAccount(0).Address.String(), - Contract: contractAddr.String(), - Msg: jsonMarshal(t, msg), - Funds: sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), - }}, - e2eTesting.WithMsgFees(txFees...), - ) - - balance := chain.GetBalance(authtypes.NewModuleAddress(gastracker.ModuleName)) - totalInflation = sdk.NewCoin( - inflation.Denom, (inflation.Amount.ToDec().Mul(params.Params.DappInflationRewardsRatio)).MulInt64(5).TruncateInt().SubRaw(3)) // we're subbing a meaningless residual due to loss of precision - - _, dappRewardFees := common.SplitCoins(params.Params.DappTxFeeRebateRatio, txFees) - require.Equal(t, - dappRewardFees, - balance.Sub(sdk.NewCoins(totalInflation)), // remove inflation - ) -} - -func uploadAndInstantiateContract(chain *e2eTesting.TestChain) sdk.AccAddress { - owner := chain.GetAccount(0) - id := chain.UploadContract(owner, "../../../e2e/contracts/voter.wasm", wasmtypes.DefaultUploadAccess) - addr, _ := chain.InstantiateContract(owner, id, "", "voter", nil, voterTypes.MsgInstantiate{Params: voterTypes.Params{ - OwnerAddr: owner.Address.String(), - NewVotingCost: "100stake", - VoteCost: "100stake", - IBCSendTimeout: 10_000_000, - }}) - - return addr -} - -func jsonMarshal(t *testing.T, msg interface{}) []byte { - b, err := json.Marshal(msg) - require.NoError(t, err) - return b -} +// +//import ( +// "encoding/json" +// "testing" +// +// voterTypes "github.com/CosmWasm/cosmwasm-go/example/voter/src/types" +// wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" +// sdk "github.com/cosmos/cosmos-sdk/types" +// authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +// "github.com/stretchr/testify/require" +// +// e2eTesting "github.com/archway-network/archway/e2e/testing" +// "github.com/archway-network/archway/x/gastracker" +// "github.com/archway-network/archway/x/gastracker/common" +//) +// +//func TestRewardsCollection(t *testing.T) { +// chain := e2eTesting.NewTestChain(t, 1) +// // TODO: this test can be done better but for the sake of simplicity lets keep it like this for now +// const blocks int64 = 2 +// var inflation = sdk.NewInt64Coin("stake", 103) +// +// params, err := gastracker.NewQueryClient(chain.Client()).Params(chain.GetContext().Context(), &gastracker.QueryParamsRequest{}) +// require.NoError(t, err) +// +// totalInflation := sdk.NewCoin( +// inflation.Denom, (inflation.Amount.ToDec().Mul(params.Params.DappInflationRewardsRatio)).MulInt64(blocks).TruncateInt().SubRaw(1)) // we're subbing a meaningless residual due to loss of precision +// +// gasTrackerBalance := chain.GetBalance(authtypes.NewModuleAddress(gastracker.ModuleName)) +// require.Equal(t, +// gasTrackerBalance.String(), +// sdk.NewCoins(totalInflation).String(), +// ) +// +// contractAddr := uploadAndInstantiateContract(chain) +// +// msg := &voterTypes.MsgExecute{ +// NewVoting: &voterTypes.NewVotingRequest{ +// Name: "hello", +// VoteOptions: []string{"idk"}, +// Duration: 100, +// }, +// } +// txFees := sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)) +// chain.SendMsgs(chain.GetAccount(0), true, []sdk.Msg{&wasmtypes.MsgExecuteContract{ +// Sender: chain.GetAccount(0).Address.String(), +// Contract: contractAddr.String(), +// Msg: jsonMarshal(t, msg), +// Funds: sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), +// }}, +// e2eTesting.WithMsgFees(txFees...), +// ) +// +// balance := chain.GetBalance(authtypes.NewModuleAddress(gastracker.ModuleName)) +// totalInflation = sdk.NewCoin( +// inflation.Denom, (inflation.Amount.ToDec().Mul(params.Params.DappInflationRewardsRatio)).MulInt64(5).TruncateInt().SubRaw(3)) // we're subbing a meaningless residual due to loss of precision +// +// _, dappRewardFees := common.SplitCoins(params.Params.DappTxFeeRebateRatio, txFees) +// require.Equal(t, +// dappRewardFees, +// balance.Sub(sdk.NewCoins(totalInflation)), // remove inflation +// ) +//} +// +//func uploadAndInstantiateContract(chain *e2eTesting.TestChain) sdk.AccAddress { +// owner := chain.GetAccount(0) +// id := chain.UploadContract(owner, "../../../e2e/contracts/voter.wasm", wasmtypes.DefaultUploadAccess) +// addr, _ := chain.InstantiateContract(owner, id, "", "voter", nil, voterTypes.MsgInstantiate{Params: voterTypes.Params{ +// OwnerAddr: owner.Address.String(), +// NewVotingCost: "100stake", +// VoteCost: "100stake", +// IBCSendTimeout: 10_000_000, +// }}) +// +// return addr +//} +// +//func jsonMarshal(t *testing.T, msg interface{}) []byte { +// b, err := json.Marshal(msg) +// require.NoError(t, err) +// return b +//} From 6c1e3cd11fb668e4732295a8b3fa6106c98dc7e8 Mon Sep 17 00:00:00 2001 From: edjroz Date: Tue, 9 Aug 2022 14:16:58 +0000 Subject: [PATCH 26/27] add legacy gastracker to code coverage ignore --- codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/codecov.yml b/codecov.yml index 5a5d89b2..f93881ff 100644 --- a/codecov.yml +++ b/codecov.yml @@ -11,3 +11,4 @@ ignore: - "**/*.pb.go" - "third_party" - "vendor" + - "x/gastracker" From b1fc0784208d752d91da3ec989ef312537398e73 Mon Sep 17 00:00:00 2001 From: edjroz Date: Tue, 9 Aug 2022 14:34:26 +0000 Subject: [PATCH 27/27] add pg.gw.go files to ignroe coverage --- codecov.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/codecov.yml b/codecov.yml index f93881ff..bead7fa6 100644 --- a/codecov.yml +++ b/codecov.yml @@ -9,6 +9,7 @@ coverage: default: false ignore: - "**/*.pb.go" + - "**/*.pb.gw.go" - "third_party" - "vendor" - "x/gastracker"