diff --git a/Dockerfile.builder b/Dockerfile.builder index ded10401f..9e9c084dd 100644 --- a/Dockerfile.builder +++ b/Dockerfile.builder @@ -14,7 +14,7 @@ ARG GIT_COMMIT ARG BUILD_TAGS ARG ENABLED_PROPOSALS -ENV GOTOOLCHAIN go1.22.6 +ENV GOTOOLCHAIN go1.22.9 RUN apk add --no-cache \ ca-certificates \ diff --git a/app/app.go b/app/app.go index 8d5fab53e..1da8f2343 100644 --- a/app/app.go +++ b/app/app.go @@ -10,7 +10,11 @@ import ( "path/filepath" "time" + v502 "github.com/neutron-org/neutron/v5/app/upgrades/v5.0.2" dynamicfeestypes "github.com/neutron-org/neutron/v5/x/dynamicfees/types" + stateverifier "github.com/neutron-org/neutron/v5/x/state-verifier" + svkeeper "github.com/neutron-org/neutron/v5/x/state-verifier/keeper" + stateverifiertypes "github.com/neutron-org/neutron/v5/x/state-verifier/types" "github.com/skip-mev/feemarket/x/feemarket" feemarketkeeper "github.com/skip-mev/feemarket/x/feemarket/keeper" @@ -228,6 +232,7 @@ const ( var ( Upgrades = []upgrades.Upgrade{ v500.Upgrade, + v502.Upgrade, } // DefaultNodeHome default home directories for the application daemon @@ -392,6 +397,8 @@ type App struct { InterchainTxsKeeper interchaintxskeeper.Keeper ContractManagerKeeper contractmanagermodulekeeper.Keeper + StateVerifierKeeper *svkeeper.Keeper + ConsensusParamsKeeper consensusparamkeeper.Keeper WasmKeeper wasmkeeper.Keeper @@ -487,7 +494,7 @@ func New( interchainqueriesmoduletypes.StoreKey, contractmanagermoduletypes.StoreKey, interchaintxstypes.StoreKey, wasmtypes.StoreKey, feetypes.StoreKey, feeburnertypes.StoreKey, adminmoduletypes.StoreKey, ccvconsumertypes.StoreKey, tokenfactorytypes.StoreKey, pfmtypes.StoreKey, crontypes.StoreKey, ibcratelimittypes.ModuleName, ibchookstypes.StoreKey, consensusparamtypes.StoreKey, crisistypes.StoreKey, dextypes.StoreKey, auctiontypes.StoreKey, - oracletypes.StoreKey, marketmaptypes.StoreKey, feemarkettypes.StoreKey, dynamicfeestypes.StoreKey, globalfeetypes.StoreKey, + oracletypes.StoreKey, marketmaptypes.StoreKey, feemarkettypes.StoreKey, dynamicfeestypes.StoreKey, globalfeetypes.StoreKey, stateverifiertypes.StoreKey, ) tkeys := storetypes.NewTransientStoreKeys(paramstypes.TStoreKey, dextypes.TStoreKey) memKeys := storetypes.NewMemoryStoreKeys(capabilitytypes.MemStoreKey, feetypes.MemStoreKey) @@ -651,6 +658,8 @@ func New( app.GlobalFeeKeeper = globalfeekeeper.NewKeeper(appCodec, keys[globalfeetypes.StoreKey], authtypes.NewModuleAddress(adminmoduletypes.ModuleName).String()) + app.StateVerifierKeeper = svkeeper.NewKeeper(appCodec, keys[stateverifiertypes.StoreKey], runtime.ProvideCometInfoService(), runtime.ProvideHeaderInfoService(nil), authtypes.NewModuleAddress(adminmoduletypes.ModuleName).String()) + // Create evidence Keeper for to register the IBC light client misbehaviour evidence route evidenceKeeper := evidencekeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), &app.ConsumerKeeper, app.SlashingKeeper, @@ -929,6 +938,7 @@ func New( consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), // always be last to make sure that it checks for all invariants and not only part of them crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), + stateverifier.NewAppModule(appCodec, app.StateVerifierKeeper), ) app.mm.SetOrderPreBlockers( @@ -974,6 +984,7 @@ func New( feemarkettypes.ModuleName, dextypes.ModuleName, consensusparamtypes.ModuleName, + stateverifiertypes.ModuleName, ) app.mm.SetOrderEndBlockers( @@ -1011,6 +1022,7 @@ func New( feemarkettypes.ModuleName, dextypes.ModuleName, consensusparamtypes.ModuleName, + stateverifiertypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -1054,6 +1066,7 @@ func New( dextypes.ModuleName, dynamicfeestypes.ModuleName, consensusparamtypes.ModuleName, + stateverifiertypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) diff --git a/app/upgrades/v5.0.2/constants.go b/app/upgrades/v5.0.2/constants.go new file mode 100644 index 000000000..fca497bfd --- /dev/null +++ b/app/upgrades/v5.0.2/constants.go @@ -0,0 +1,18 @@ +package v502 + +import ( + storetypes "cosmossdk.io/store/types" + + "github.com/neutron-org/neutron/v5/app/upgrades" +) + +const ( + // UpgradeName defines the on-chain upgrade name. + UpgradeName = "v5.0.2" +) + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: storetypes.StoreUpgrades{}, +} diff --git a/app/upgrades/v5.0.2/upgrades.go b/app/upgrades/v5.0.2/upgrades.go new file mode 100644 index 000000000..a783821b4 --- /dev/null +++ b/app/upgrades/v5.0.2/upgrades.go @@ -0,0 +1,35 @@ +package v502 + +import ( + "context" + "fmt" + + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/neutron-org/neutron/v5/app/upgrades" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + _ *upgrades.UpgradeKeepers, + _ upgrades.StoreKeys, + _ codec.Codec, +) upgradetypes.UpgradeHandler { + return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx := sdk.UnwrapSDKContext(c) + + ctx.Logger().Info("Starting module migrations...") + + vm, err := mm.RunMigrations(ctx, configurator, vm) + if err != nil { + return vm, err + } + + ctx.Logger().Info(fmt.Sprintf("Migration {%s} applied", UpgradeName)) + return vm, nil + } +} diff --git a/app/upgrades/v5.0.2/upgrades_test.go b/app/upgrades/v5.0.2/upgrades_test.go new file mode 100644 index 000000000..a9062c5ea --- /dev/null +++ b/app/upgrades/v5.0.2/upgrades_test.go @@ -0,0 +1,37 @@ +package v502_test + +import ( + "testing" + + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + + v502 "github.com/neutron-org/neutron/v5/app/upgrades/v5.0.2" + "github.com/neutron-org/neutron/v5/testutil" +) + +type UpgradeTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(UpgradeTestSuite)) +} + +func (suite *UpgradeTestSuite) SetupTest() { + suite.IBCConnectionTestSuite.SetupTest() +} + +func (suite *UpgradeTestSuite) TestOracleUpgrade() { + app := suite.GetNeutronZoneApp(suite.ChainA) + ctx := suite.ChainA.GetContext().WithChainID("neutron-1") + t := suite.T() + + upgrade := upgradetypes.Plan{ + Name: v502.UpgradeName, + Info: "some text here", + Height: 100, + } + require.NoError(t, app.UpgradeKeeper.ApplyUpgrade(ctx, upgrade)) +} diff --git a/docs/static/swagger.yaml b/docs/static/swagger.yaml index c1c094a97..b31dea7db 100644 --- a/docs/static/swagger.yaml +++ b/docs/static/swagger.yaml @@ -19635,6 +19635,11 @@ definitions: type: array type: object type: object + neutron.state_verifier.v1.QueryVerifyStateValuesResponse: + properties: + valid: + type: boolean + type: object osmosis.tokenfactory.Params: description: Params defines the parameters for the tokenfactory module. properties: @@ -45443,6 +45448,47 @@ paths: type: object tags: - Query + /neutron/state-verifier/verify_state_values: + get: + operationId: VerifyStateValues + parameters: + - format: uint64 + in: query + name: height + required: false + type: string + responses: + '200': + description: A successful response. + schema: + properties: + valid: + type: boolean + type: object + default: + description: An unexpected error response. + schema: + properties: + code: + format: int32 + type: integer + details: + items: + properties: + type_url: + type: string + value: + format: byte + type: string + type: object + type: array + error: + type: string + message: + type: string + type: object + tags: + - Query /osmosis/tokenfactory/v1beta1/denoms/factory/{creator}/{subdenom}/authority_metadata: get: operationId: DenomAuthorityMetadata diff --git a/go.mod b/go.mod index fad2e48c0..366f9fe5b 100644 --- a/go.mod +++ b/go.mod @@ -1,53 +1,55 @@ module github.com/neutron-org/neutron/v5 -go 1.22.6 +go 1.22.7 + +toolchain go1.22.9 require ( cosmossdk.io/client/v2 v2.0.0-beta.4 cosmossdk.io/core v0.11.1 cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.4.1 - cosmossdk.io/math v1.3.0 - cosmossdk.io/store v1.1.0 + cosmossdk.io/math v1.4.0 + cosmossdk.io/store v1.1.1 cosmossdk.io/x/evidence v0.1.1 cosmossdk.io/x/feegrant v0.1.1 cosmossdk.io/x/tx v0.13.5 cosmossdk.io/x/upgrade v0.1.4 github.com/CosmWasm/wasmd v0.53.0 github.com/CosmWasm/wasmvm/v2 v2.1.3 - github.com/cometbft/cometbft v0.38.11 + github.com/cometbft/cometbft v0.38.15 github.com/cosmos/admin-module/v2 v2.0.0-20240430142959-8b3328d1b1a2 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 - github.com/cosmos/cosmos-sdk v0.50.9 + github.com/cosmos/cosmos-sdk v0.50.10 github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2 github.com/cosmos/ibc-go/modules/capability v1.0.1 - github.com/cosmos/ibc-go/v8 v8.5.1 + github.com/cosmos/ibc-go/v8 v8.5.2 github.com/cosmos/ics23/go v0.11.0 - github.com/cosmos/interchain-security/v5 v5.1.1 + github.com/cosmos/interchain-security/v5 v5.2.0 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.4 github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 github.com/hashicorp/go-metrics v0.5.3 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.20.5 github.com/rs/zerolog v1.33.0 github.com/skip-mev/block-sdk/v2 v2.1.5 github.com/skip-mev/feemarket v1.1.1 - github.com/skip-mev/slinky v1.0.12 + github.com/skip-mev/slinky v1.0.13 github.com/spf13/cast v1.7.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 - google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 + google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 google.golang.org/grpc v1.67.1 - google.golang.org/protobuf v1.35.1 + google.golang.org/protobuf v1.35.2 gopkg.in/yaml.v2 v2.4.0 ) @@ -73,7 +75,7 @@ require ( github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect github.com/bits-and-blooms/bitset v1.13.0 // indirect github.com/btcsuite/btcd v0.22.0-beta // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect @@ -84,7 +86,7 @@ require ( github.com/cockroachdb/pebble v1.1.1 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cometbft/cometbft-db v0.12.0 // indirect + github.com/cometbft/cometbft-db v0.14.1 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect @@ -92,7 +94,7 @@ require ( github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v4 v4.2.0 // indirect github.com/dgraph-io/ristretto v0.1.1 // indirect @@ -115,7 +117,7 @@ require ( github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -156,7 +158,7 @@ require ( github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/minio/highwayhash v1.0.2 // indirect + github.com/minio/highwayhash v1.0.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -167,17 +169,17 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/oxyno-zeta/gomock-extra-matcher v1.2.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect + github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/common v0.60.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.8.3 // indirect + github.com/rs/cors v1.11.1 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shamaton/msgpack/v2 v2.2.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect @@ -198,17 +200,17 @@ require ( go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.186.0 // indirect google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect @@ -220,10 +222,11 @@ require ( replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 github.com/CosmWasm/wasmd => github.com/neutron-org/wasmd v0.53.0-neutron + github.com/btcsuite/btcd/btcec/v2 => github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/cometbft/cometbft => github.com/neutron-org/cometbft v0.0.0-20241111105801-a7fe160b0b62 github.com/cometbft/cometbft-db => github.com/sotnikov-s/cometbft-db v0.12.0-no-leveldb-compression github.com/cosmos/admin-module/v2 => github.com/neutron-org/admin-module/v2 v2.0.2 - github.com/cosmos/cosmos-sdk => github.com/neutron-org/cosmos-sdk v0.50.9-neutron.0.20240924163649-207f347e9c53 + github.com/cosmos/cosmos-sdk => github.com/neutron-org/cosmos-sdk v0.50.10-neutron // explicitely replace iavl to v1.2.0 cause sometimes go mod tidy uses not right version github.com/cosmos/iavl => github.com/cosmos/iavl v1.2.0 github.com/cosmos/interchain-security/v5 => github.com/cosmos/interchain-security/v5 v5.0.0-20240802125602-fa1e09444aae diff --git a/go.sum b/go.sum index cb2b3955e..960264cc3 100644 --- a/go.sum +++ b/go.sum @@ -200,10 +200,10 @@ cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= cosmossdk.io/log v1.4.1 h1:wKdjfDRbDyZRuWa8M+9nuvpVYxrEOwbD/CA8hvhU8QM= cosmossdk.io/log v1.4.1/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= -cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= -cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= -cosmossdk.io/store v1.1.0 h1:LnKwgYMc9BInn9PhpTFEQVbL9UK475G2H911CGGnWHk= -cosmossdk.io/store v1.1.0/go.mod h1:oZfW/4Fc/zYqu3JmQcQdUJ3fqu5vnYTn3LZFFy8P8ng= +cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= +cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= +cosmossdk.io/store v1.1.1 h1:NA3PioJtWDVU7cHHeyvdva5J/ggyLDkyH0hGHl2804Y= +cosmossdk.io/store v1.1.1/go.mod h1:8DwVTz83/2PSI366FERGbWSH7hL6sB7HbYp8bqksNwM= cosmossdk.io/x/circuit v0.1.1 h1:KPJCnLChWrxD4jLwUiuQaf5mFD/1m7Omyo7oooefBVQ= cosmossdk.io/x/circuit v0.1.1/go.mod h1:B6f/urRuQH8gjt4eLIXfZJucrbreuYrKh5CSjaOxr+Q= cosmossdk.io/x/evidence v0.1.1 h1:Ks+BLTa3uftFpElLTDp9L76t2b58htjVbSZ86aoK/E4= @@ -373,8 +373,8 @@ github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0 github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd/go.mod h1:JWfpWVKJKiKtd53/KbRoKfxWl8FsT2GPcNezTOk0o5Q= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v8 v8.5.1 h1:3JleEMKBjRKa3FeTKt4fjg22za/qygLBo7mDkoYTNBs= -github.com/cosmos/ibc-go/v8 v8.5.1/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= +github.com/cosmos/ibc-go/v8 v8.5.2 h1:27s9oeD2AxLQF3e9BQsYt9doONyZ7FwZi/qkBv6Sdks= +github.com/cosmos/ibc-go/v8 v8.5.2/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/interchain-security/v5 v5.0.0-20240802125602-fa1e09444aae h1:/EWV9qryltapge0v4ctvl2jV3Nne5nsbd+GYblj/jWA= @@ -396,8 +396,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= @@ -561,8 +561,8 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXi github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -654,8 +654,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= @@ -804,8 +804,8 @@ github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= -github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= +github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -845,8 +845,8 @@ github.com/neutron-org/admin-module/v2 v2.0.2 h1:XDDFWjvkVBKRf3lBFCazT1zAXZ3dHX8 github.com/neutron-org/admin-module/v2 v2.0.2/go.mod h1:RfOyabXsdJ5btcOKyKPZDYiZhtuKFubbJMOb8EJZtvA= github.com/neutron-org/cometbft v0.0.0-20241111105801-a7fe160b0b62 h1:erXDgRxrEtWScO9i8ZYjr0cnjxTJ0BT+WrUsRMbMVSU= github.com/neutron-org/cometbft v0.0.0-20241111105801-a7fe160b0b62/go.mod h1:jHPx9vQpWzPHEAiYI/7EDKaB1NXhK6o3SArrrY8ExKc= -github.com/neutron-org/cosmos-sdk v0.50.9-neutron.0.20240924163649-207f347e9c53 h1:7FJOHOt9F0oea0b5jrn090u/zn7+LdBmT6ZDmrJtTqs= -github.com/neutron-org/cosmos-sdk v0.50.9-neutron.0.20240924163649-207f347e9c53/go.mod h1:TMH6wpoYBcg7Cp5BEg8fneLr+8XloNQkf2MRNF9V6JE= +github.com/neutron-org/cosmos-sdk v0.50.10-neutron h1:1q8P0l29Mm22m8wUstKlCZpKScJOa5bFFqkO/RbHL5w= +github.com/neutron-org/cosmos-sdk v0.50.10-neutron/go.mod h1:6Eesrx3ZE7vxBZWpK++30H+Uc7Q4ahQWCL7JKU/LEdU= github.com/neutron-org/wasmd v0.53.0-neutron h1:Dv1VP1+QjYeb6RMo03sxw0Pe42JU0MPxefwNaG22KVs= github.com/neutron-org/wasmd v0.53.0-neutron/go.mod h1:FJl/aWjdpGof3usAMFQpDe07Rkx77PUzp0cygFMOvtw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= @@ -899,9 +899,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= -github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= -github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= +github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= @@ -938,8 +937,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc= +github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -954,8 +953,8 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= +github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= @@ -967,8 +966,8 @@ github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgY github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= -github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= +github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g3L/Y= github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= @@ -985,8 +984,8 @@ github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610 h1:4JlsiRVt github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610/go.mod h1:kB8gFZX07CyJnw8q9iEZijI3qJTIe1K/Y++P5VGkrcg= github.com/skip-mev/feemarket v1.1.1 h1:L34K7N2J6o635kzNYRAvQ93+hAFtSiJ2t03jmaNx0zw= github.com/skip-mev/feemarket v1.1.1/go.mod h1:DUa6djUsTeMOrbrcIZqWSVxU9IZNCXp96ruaojyBNpc= -github.com/skip-mev/slinky v1.0.12 h1:qmZHB6c5fgDhO/pv67YcZc2M25t3gZcceVmJtA9zjOo= -github.com/skip-mev/slinky v1.0.12/go.mod h1:8mxMdQ8MY8QAxgxLvUKTfDwX6XCAUeqZwkU/r+ZsELU= +github.com/skip-mev/slinky v1.0.13 h1:Ym+xqrhq1kJzyyJICGc2gB43+EETGy72sumZUU1wCt8= +github.com/skip-mev/slinky v1.0.13/go.mod h1:OgOJivOCJQqjGefvoe/kzszCJKgK/hrXluoPiGJHTwU= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1124,8 +1123,8 @@ golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1227,8 +1226,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1254,8 +1253,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1281,7 +1280,6 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1367,13 +1365,14 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1384,8 +1383,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1631,10 +1630,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1694,8 +1693,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/proto/neutron/state_verifier/v1/genesis.proto b/proto/neutron/state_verifier/v1/genesis.proto new file mode 100644 index 000000000..d6ef33a7b --- /dev/null +++ b/proto/neutron/state_verifier/v1/genesis.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package neutron.state_verifier.v1; + +import "ibc/lightclients/tendermint/v1/tendermint.proto"; + +option go_package = "github.com/neutron-org/neutron/v5/x/state-verifier/types"; + +// ConsensusState describes a "light" consensus state of Neutron at a particular height +message ConsensusState { + int64 height = 1; + ibc.lightclients.tendermint.v1.ConsensusState cs = 2; +} + +message GenesisState { + repeated ConsensusState states = 1; +} diff --git a/proto/neutron/state_verifier/v1/query.proto b/proto/neutron/state_verifier/v1/query.proto new file mode 100644 index 000000000..8f86bf5e6 --- /dev/null +++ b/proto/neutron/state_verifier/v1/query.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; +package neutron.state_verifier.v1; + +import "google/api/annotations.proto"; +import "neutron/interchainqueries/tx.proto"; + +option go_package = "github.com/neutron-org/neutron/v5/x/state-verifier/types"; + +service Query { + rpc VerifyStateValues(QueryVerifyStateValuesRequest) returns (QueryVerifyStateValuesResponse) { + option (google.api.http).get = "/neutron/state-verifier/verify_state_values"; + } +} + +// QueryVerifyStateValuesRequest describes a structure to verify storage values from Neutron state from a particular height in the past +message QueryVerifyStateValuesRequest { + uint64 height = 1; + repeated neutron.interchainqueries.StorageValue storage_values = 2; +} + +message QueryVerifyStateValuesResponse { + bool valid = 1; +} diff --git a/testutil/test_helpers.go b/testutil/test_helpers.go index de7cb00ba..12b6ede56 100644 --- a/testutil/test_helpers.go +++ b/testutil/test_helpers.go @@ -288,6 +288,16 @@ func (suite *IBCConnectionTestSuite) FundAcc(acc sdk.AccAddress, amounts sdk.Coi suite.Require().NoError(err) } +// FundModuleAcc funds target modules with specified amount. +func (suite *IBCConnectionTestSuite) FundModuleAcc(moduleName string, amounts sdk.Coins) { + bankKeeper := suite.GetNeutronZoneApp(suite.ChainA).BankKeeper + err := bankKeeper.MintCoins(suite.ChainA.GetContext(), tokenfactorytypes.ModuleName, amounts) + suite.Require().NoError(err) + + err = bankKeeper.SendCoinsFromModuleToModule(suite.ChainA.GetContext(), tokenfactorytypes.ModuleName, moduleName, amounts) + suite.Require().NoError(err) +} + // update CCV path with correct info func SetupCCVPath(path *ibctesting.Path, suite *IBCConnectionTestSuite) { // - set provider endpoint's clientID diff --git a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto new file mode 100644 index 000000000..7dec438f1 --- /dev/null +++ b/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto @@ -0,0 +1,101 @@ +syntax = "proto3"; + +package ibc.lightclients.tendermint.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint;tendermint"; + +import "tendermint/types/validator.proto"; +import "tendermint/types/types.proto"; +import "cosmos/ics23/v1/proofs.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "ibc/core/client/v1/client.proto"; +import "ibc/core/commitment/v1/commitment.proto"; +import "gogoproto/gogo.proto"; + +// ClientState from Tendermint tracks the current validator set, latest height, +// and a possible frozen height. +message ClientState { + option (gogoproto.goproto_getters) = false; + + string chain_id = 1; + Fraction trust_level = 2 [(gogoproto.nullable) = false]; + // duration of the period since the LastestTimestamp during which the + // submitted headers are valid for upgrade + google.protobuf.Duration trusting_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + // duration of the staking unbonding period + google.protobuf.Duration unbonding_period = 4 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + // defines how much new (untrusted) header's Time can drift into the future. + google.protobuf.Duration max_clock_drift = 5 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + // Block height when the client was frozen due to a misbehaviour + ibc.core.client.v1.Height frozen_height = 6 [(gogoproto.nullable) = false]; + // Latest height the client was updated to + ibc.core.client.v1.Height latest_height = 7 [(gogoproto.nullable) = false]; + + // Proof specifications used in verifying counterparty state + repeated cosmos.ics23.v1.ProofSpec proof_specs = 8; + + // Path at which next upgraded client will be committed. + // Each element corresponds to the key for a single CommitmentProof in the + // chained proof. NOTE: ClientState must stored under + // `{upgradePath}/{upgradeHeight}/clientState` ConsensusState must be stored + // under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using + // the default upgrade module, upgrade_path should be []string{"upgrade", + // "upgradedIBCState"}` + repeated string upgrade_path = 9; + + // allow_update_after_expiry is deprecated + bool allow_update_after_expiry = 10 [deprecated = true]; + // allow_update_after_misbehaviour is deprecated + bool allow_update_after_misbehaviour = 11 [deprecated = true]; +} + +// ConsensusState defines the consensus state from Tendermint. +message ConsensusState { + option (gogoproto.goproto_getters) = false; + + // timestamp that corresponds to the block height in which the ConsensusState + // was stored. + google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + // commitment root (i.e app hash) + ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; + bytes next_validators_hash = 3 [(gogoproto.casttype) = "github.com/cometbft/cometbft/libs/bytes.HexBytes"]; +} + +// Misbehaviour is a wrapper over two conflicting Headers +// that implements Misbehaviour interface expected by ICS-02 +message Misbehaviour { + option (gogoproto.goproto_getters) = false; + + // ClientID is deprecated + string client_id = 1 [deprecated = true]; + Header header_1 = 2 [(gogoproto.customname) = "Header1"]; + Header header_2 = 3 [(gogoproto.customname) = "Header2"]; +} + +// Header defines the Tendermint client consensus Header. +// It encapsulates all the information necessary to update from a trusted +// Tendermint ConsensusState. The inclusion of TrustedHeight and +// TrustedValidators allows this update to process correctly, so long as the +// ConsensusState for the TrustedHeight exists, this removes race conditions +// among relayers The SignedHeader and ValidatorSet are the new untrusted update +// fields for the client. The TrustedHeight is the height of a stored +// ConsensusState on the client that will be used to verify the new untrusted +// header. The Trusted ConsensusState must be within the unbonding period of +// current time in order to correctly verify, and the TrustedValidators must +// hash to TrustedConsensusState.NextValidatorsHash since that is the last +// trusted validator set at the TrustedHeight. +message Header { + .tendermint.types.SignedHeader signed_header = 1 [(gogoproto.embed) = true]; + + .tendermint.types.ValidatorSet validator_set = 2; + ibc.core.client.v1.Height trusted_height = 3 [(gogoproto.nullable) = false]; + .tendermint.types.ValidatorSet trusted_validators = 4; +} + +// Fraction defines the protobuf message type for tmmath.Fraction that only +// supports positive values. +message Fraction { + uint64 numerator = 1; + uint64 denominator = 2; +} \ No newline at end of file diff --git a/utils/storageverification/errors.go b/utils/storageverification/errors.go new file mode 100644 index 000000000..80386c10a --- /dev/null +++ b/utils/storageverification/errors.go @@ -0,0 +1,11 @@ +package storageverification + +import "cosmossdk.io/errors" + +const StateVerificationCodespace = "state_verification" + +var ( + ErrInvalidType = errors.Register(StateVerificationCodespace, 1, "invalid type") + ErrInvalidStorageValue = errors.Register(StateVerificationCodespace, 2, "failed to check storage value") + ErrInvalidProof = errors.Register(StateVerificationCodespace, 3, "merkle proof is invalid") +) diff --git a/utils/storageverification/verify.go b/utils/storageverification/verify.go new file mode 100644 index 000000000..a17d14bce --- /dev/null +++ b/utils/storageverification/verify.go @@ -0,0 +1,50 @@ +package storageverification + +import ( + "cosmossdk.io/errors" + ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ics23 "github.com/cosmos/ics23/go" + + "github.com/neutron-org/neutron/v5/x/interchainqueries/types" +) + +type VerifyCallback func(index int) error + +// VerifyStorageValues verifies stValues slice against proof using proofSpecs +// A caller can provide verifyCallback method that will be called for each storage value from the slice with an index of the value in the slice +// to do any additional user-defined checks of storage values +func VerifyStorageValues(stValues []*types.StorageValue, root exported.Root, proofSpecs []*ics23.ProofSpec, verifyCallback VerifyCallback) error { + for index, value := range stValues { + proof, err := ibccommitmenttypes.ConvertProofs(value.Proof) + if err != nil { + return errors.Wrapf(ErrInvalidType, "failed to convert crypto.ProofOps to MerkleProof: %v", err) + } + + if verifyCallback != nil { + if err := verifyCallback(index); err != nil { + return errors.Wrapf(ErrInvalidStorageValue, err.Error()) + } + } + + path := ibccommitmenttypes.NewMerklePath(value.StoragePrefix, string(value.Key)) + // identify what kind proofs (non-existence proof always has *ics23.CommitmentProof_Nonexist as the first item) we got + // and call corresponding method to verify it + switch proof.GetProofs()[0].GetProof().(type) { + // we can get non-existence proof if someone queried some key which is not exists in the storage on remote chain + case *ics23.CommitmentProof_Nonexist: + if err := proof.VerifyNonMembership(proofSpecs, root, path); err != nil { + return errors.Wrapf(ErrInvalidProof, "failed to verify proof: %v", err) + } + value.Value = nil + case *ics23.CommitmentProof_Exist: + if err := proof.VerifyMembership(proofSpecs, root, path, value.Value); err != nil { + return errors.Wrapf(ErrInvalidProof, "failed to verify proof: %v", err) + } + default: + return errors.Wrapf(ErrInvalidProof, "unknown proof type %T", proof.GetProofs()[0].GetProof()) + } + } + + return nil +} diff --git a/wasmbinding/bindings/query.go b/wasmbinding/bindings/query.go index 9b60fe070..884f0d273 100644 --- a/wasmbinding/bindings/query.go +++ b/wasmbinding/bindings/query.go @@ -107,7 +107,7 @@ type RegisteredQuery struct { ID uint64 `json:"id"` // The address that registered the query. Owner string `json:"owner"` - // The KV-storage keys for which we want to get values from remote chain + // The KV-storage keys for which we want to get values from the remote chain Keys []*types.KVKey `json:"keys"` // The filter for transaction search ICQ TransactionsFilter string `json:"transactions_filter"` @@ -115,15 +115,15 @@ type RegisteredQuery struct { QueryType string `json:"query_type"` // The IBC connection ID for getting ConsensusState to verify proofs. ConnectionID string `json:"connection_id"` - // Parameter that defines how often the query must be updated. + // A parameter that defines how often the query must be updated. UpdatePeriod uint64 `json:"update_period"` // The local chain last block height when the query result was updated. LastSubmittedResultLocalHeight uint64 `json:"last_submitted_result_local_height"` // The remote chain last block height when the query result was updated. LastSubmittedResultRemoteHeight *ibcclienttypes.Height `json:"last_submitted_result_remote_height,omitempty"` - // Amount of coins deposited for the query. + // The amount of coins deposited for the query. Deposit sdktypes.Coins `json:"deposit"` - // Timeout before query becomes available for everybody to remove. + // The timeout before the query becomes available for everybody to remove. SubmitTimeout uint64 `json:"submit_timeout"` // The local chain height when the query was registered. RegisteredAtHeight uint64 `json:"registered_at_height"` diff --git a/wasmbinding/stargate_allowlist.go b/wasmbinding/stargate_allowlist.go index 1364c94a4..00702a2b1 100644 --- a/wasmbinding/stargate_allowlist.go +++ b/wasmbinding/stargate_allowlist.go @@ -13,13 +13,13 @@ import ( marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" oracletypes "github.com/skip-mev/slinky/x/oracle/types" - dynamicfeestypes "github.com/neutron-org/neutron/v5/x/dynamicfees/types" - crontypes "github.com/neutron-org/neutron/v5/x/cron/types" dextypes "github.com/neutron-org/neutron/v5/x/dex/types" + dynamicfeestypes "github.com/neutron-org/neutron/v5/x/dynamicfees/types" feeburnertypes "github.com/neutron-org/neutron/v5/x/feeburner/types" interchainqueriestypes "github.com/neutron-org/neutron/v5/x/interchainqueries/types" interchaintxstypes "github.com/neutron-org/neutron/v5/x/interchaintxs/types" + stateverifiertypes "github.com/neutron-org/neutron/v5/x/state-verifier/types" tokenfactorytypes "github.com/neutron-org/neutron/v5/x/tokenfactory/types" ) @@ -118,5 +118,8 @@ func AcceptedStargateQueries() wasmkeeper.AcceptedQueries { // dynamicfees "neutron.dynamicfees.v1.Query/Params": &dynamicfeestypes.QueryParamsResponse{}, + + // state verifier + "/neutron.state_verifier.v1.Query/VerifyStateValues": &stateverifiertypes.QueryVerifyStateValuesResponse{}, } } diff --git a/x/dex/keeper/msg_server_test.go b/x/dex/keeper/msg_server_test.go index 5fb64f8d6..adc1efedf 100644 --- a/x/dex/keeper/msg_server_test.go +++ b/x/dex/keeper/msg_server_test.go @@ -7,6 +7,7 @@ import ( "time" abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/baseapp" "github.com/stretchr/testify/require" sdkmath "cosmossdk.io/math" @@ -1520,6 +1521,11 @@ func (s *DexTestSuite) nextBlockWithTime(blockTime time.Time) { func (s *DexTestSuite) beginBlockWithTime(blockTime time.Time) { s.Ctx = s.Ctx.WithBlockTime(blockTime) + // fill in empty CometBFT info just to avoid nil pointer panics (we don't care about validity of the info in these tests) + s.Ctx = s.Ctx.WithCometInfo(baseapp.NewBlockInfo(nil, nil, nil, abci.CommitInfo{ + Round: 0, + Votes: nil, + })) _, err := s.App.BeginBlocker(s.Ctx) s.NoError(err) } diff --git a/x/interchainqueries/keeper/keeper_test.go b/x/interchainqueries/keeper/keeper_test.go index 9ac2b5228..fafb48f77 100644 --- a/x/interchainqueries/keeper/keeper_test.go +++ b/x/interchainqueries/keeper/keeper_test.go @@ -989,7 +989,7 @@ func (suite *KeeperTestSuite) TestSubmitInterchainQueryResult() { }, } }, - iqtypes.ErrInvalidType, + iqtypes.ErrInvalidSubmittedResult, }, { "non-registered key in KV result", @@ -1239,7 +1239,7 @@ func (suite *KeeperTestSuite) TestSubmitInterchainQueryResult() { }, } }, - iqtypes.ErrInvalidProof, + iqtypes.ErrInvalidSubmittedResult, }, { "query result height is too old", diff --git a/x/interchainqueries/keeper/msg_server.go b/x/interchainqueries/keeper/msg_server.go index 50f30fa97..f92811f29 100644 --- a/x/interchainqueries/keeper/msg_server.go +++ b/x/interchainqueries/keeper/msg_server.go @@ -15,9 +15,8 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" - ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - ics23 "github.com/cosmos/ics23/go" + "github.com/neutron-org/neutron/v5/utils/storageverification" "github.com/neutron-org/neutron/v5/x/interchainqueries/types" ) @@ -235,43 +234,18 @@ func (m msgServer) SubmitQueryResult(goCtx context.Context, msg *types.MsgSubmit return nil, err } - for index, result := range msg.Result.KvResults { - proof, err := ibccommitmenttypes.ConvertProofs(result.Proof) - if err != nil { - ctx.Logger().Debug("SubmitQueryResult: failed to ConvertProofs", - "error", err, "query", query, "message", msg) - return nil, errors.Wrapf(types.ErrInvalidType, "failed to convert crypto.ProofOps to MerkleProof: %v", err) + if err := storageverification.VerifyStorageValues(msg.Result.KvResults, consensusState.GetRoot(), clientState.ProofSpecs, func(index int) error { + if !bytes.Equal(msg.Result.KvResults[index].Key, query.Keys[index].Key) { + return errors.Wrapf(types.ErrInvalidSubmittedResult, "KV key from result is not equal to registered query key: %v != %v", msg.Result.KvResults[index].Key, query.Keys[index].Key) } - if !bytes.Equal(result.Key, query.Keys[index].Key) { - return nil, errors.Wrapf(types.ErrInvalidSubmittedResult, "KV key from result is not equal to registered query key: %v != %v", result.Key, query.Keys[index].Key) + if msg.Result.KvResults[index].StoragePrefix != query.Keys[index].Path { + return errors.Wrapf(types.ErrInvalidSubmittedResult, "KV path from result is not equal to registered query storage prefix: %v != %v", msg.Result.KvResults[index].StoragePrefix, query.Keys[index].Path) } - if result.StoragePrefix != query.Keys[index].Path { - return nil, errors.Wrapf(types.ErrInvalidSubmittedResult, "KV path from result is not equal to registered query storage prefix: %v != %v", result.StoragePrefix, query.Keys[index].Path) - } - - path := ibccommitmenttypes.NewMerklePath(result.StoragePrefix, string(result.Key)) - // identify what kind proofs (non-existence proof always has *ics23.CommitmentProof_Nonexist as the first item) we got - // and call corresponding method to verify it - switch proof.GetProofs()[0].GetProof().(type) { - // we can get non-existence proof if someone queried some key which is not exists in the storage on remote chain - case *ics23.CommitmentProof_Nonexist: - if err := proof.VerifyNonMembership(clientState.ProofSpecs, consensusState.GetRoot(), path); err != nil { - ctx.Logger().Debug("SubmitQueryResult: failed to VerifyNonMembership", - "error", err, "query", query, "message", msg, "path", path) - return nil, errors.Wrapf(types.ErrInvalidProof, "failed to verify proof: %v", err) - } - result.Value = nil - case *ics23.CommitmentProof_Exist: - if err := proof.VerifyMembership(clientState.ProofSpecs, consensusState.GetRoot(), path, result.Value); err != nil { - ctx.Logger().Debug("SubmitQueryResult: failed to VerifyMembership", - "error", err, "query", query, "message", msg, "path", path) - return nil, errors.Wrapf(types.ErrInvalidProof, "failed to verify proof: %v", err) - } - default: - return nil, errors.Wrapf(types.ErrInvalidProof, "unknown proof type %T", proof.GetProofs()[0].GetProof()) - } + return nil + }); err != nil { + return nil, errors.Wrapf(types.ErrInvalidSubmittedResult, "failed to verify submitted result: %v", err) } if err = m.saveKVQueryResult(ctx, query, msg.Result); err != nil { diff --git a/x/state-verifier/README.md b/x/state-verifier/README.md new file mode 100644 index 000000000..88214dcc4 --- /dev/null +++ b/x/state-verifier/README.md @@ -0,0 +1,33 @@ +# Overview + +The State Verifier module allows to verify that some `storage values` were indeed present on a particular `block height` in the chain. + +The idea is the similar how Neutron's KV ICQ works: each `StorageValue` in Cosmos SDK is stored in [KV-IAVL storage](https://github.com/cosmos/iavl). +And to be more precise it's stored in a structure called [`MerkleTree`](https://github.com/cosmos/cosmos-sdk/blob/ae77f0080a724b159233bd9b289b2e91c0de21b5/docs/interfaces/lite/specification.md). +The tree allows to compose `Proof` for `key` and `value` pairs that can prove two things using `RootHash` of the tree: +* `key` and `value` are present in the tree; +* `key` is not present in the tree. + +Cosmos blockchain's storage is stored as a different tree for each block. +That means we can prove that a particular `KV` pair is really present (or not present) in the storage at a particular block height. + +See [Neutron's ICQ relayer implementation](https://github.com/neutron-org/neutron-query-relayer/blob/4542045ab24d2735890e70d4dc525677d5f30c8a/internal/proof/proof_impl/get_storage_values.go#L11) if you want to know how to query KV-proofs + +# Implementation + +### BeginBlocker +In each block the module's `BeginBlocker` is being called, and it saves `ConsensusState` of the current block height in the storage to use it for verification of storage values later: + +```go +consensusState := tendermint.ConsensusState{ + Timestamp: ctx.BlockTime(), // current block time + Root: ibccommitmenttypes.NewMerkleRoot(headerInfo.AppHash), // .AppHash for the previous block + NextValidatorsHash: cometInfo.GetValidatorsHash(), // hash of the validator set for the next block +} +``` + +For verification only `.Root` (`header.AppHash`) is used, but it's good to save all the values just in case and do not leave them empty. + +### VerifyStateValues query +The main query of the module that accepts slice of `[]StorageValue` structures and `blockHeight` on which those `StorageValues` are present. +The module verifies the values and returns an error if values cannot be verified `{valid: true}` structure if values are valid. \ No newline at end of file diff --git a/x/state-verifier/genesis.go b/x/state-verifier/genesis.go new file mode 100644 index 000000000..0a73afffb --- /dev/null +++ b/x/state-verifier/genesis.go @@ -0,0 +1,32 @@ +package stateverifier + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/neutron-org/neutron/v5/x/state-verifier/keeper" + "github.com/neutron-org/neutron/v5/x/state-verifier/types" +) + +// InitGenesis initializes the module's state from a provided genesis state. +func InitGenesis(ctx sdk.Context, k *keeper.Keeper, genState types.GenesisState) { + // this line is used by starport scaffolding # genesis/module/init + for _, state := range genState.States { + if err := k.WriteConsensusState(ctx, state.Height, *state.Cs); err != nil { + panic(err) + } + } +} + +// ExportGenesis returns the module's exported genesis +func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *types.GenesisState { + genesis := types.DefaultGenesis() + + allCs, err := k.GetAllConsensusStates(ctx) + if err != nil { + panic(err) + } + + genesis.States = append(genesis.States, allCs...) + + return genesis +} diff --git a/x/state-verifier/genesis_test.go b/x/state-verifier/genesis_test.go new file mode 100644 index 000000000..1fc461e69 --- /dev/null +++ b/x/state-verifier/genesis_test.go @@ -0,0 +1,67 @@ +package stateverifier_test + +import ( + "testing" + "time" + + ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + "github.com/stretchr/testify/suite" + + "github.com/neutron-org/neutron/v5/testutil/apptesting" + stateverifier "github.com/neutron-org/neutron/v5/x/state-verifier" + "github.com/neutron-org/neutron/v5/x/state-verifier/types" +) + +type GenesisTestSuite struct { + apptesting.KeeperTestHelper +} + +func TestGenesisTestSuite(t *testing.T) { + suite.Run(t, new(GenesisTestSuite)) +} + +func (suite *GenesisTestSuite) SetupTest() { + suite.Setup() +} + +func (suite *GenesisTestSuite) TestInitExportGenesis() { + states := []*types.ConsensusState{ + { + Height: 1, + Cs: &tendermint.ConsensusState{ + Timestamp: time.Now().UTC(), + Root: ibccommitmenttypes.MerkleRoot{Hash: []byte("MerkleRoot")}, + NextValidatorsHash: []byte("qqqqqqqqq"), + }, + }, + { + Height: 2, + Cs: &tendermint.ConsensusState{ + Timestamp: time.Now().UTC(), + Root: ibccommitmenttypes.MerkleRoot{Hash: []byte("oafpaosfsdf")}, + NextValidatorsHash: []byte("sdfsdfsdf"), + }, + }, + { + Height: 3, + Cs: &tendermint.ConsensusState{ + Timestamp: time.Now().UTC(), + Root: ibccommitmenttypes.MerkleRoot{Hash: []byte("okjdfhjsdfsdf")}, + NextValidatorsHash: []byte("irhweiriweyrwe"), + }, + }, + } + suite.SetupTest() + k := suite.App.StateVerifierKeeper + + initialGenesis := types.GenesisState{ + States: states, + } + + stateverifier.InitGenesis(suite.Ctx, k, initialGenesis) + + exportedGenesis := stateverifier.ExportGenesis(suite.Ctx, k) + + suite.Require().EqualValues(initialGenesis, *exportedGenesis) +} diff --git a/x/state-verifier/keeper/keeper.go b/x/state-verifier/keeper/keeper.go new file mode 100644 index 000000000..187b9a40a --- /dev/null +++ b/x/state-verifier/keeper/keeper.go @@ -0,0 +1,131 @@ +package keeper + +import ( + "fmt" + + "cosmossdk.io/core/comet" + "cosmossdk.io/core/header" + "cosmossdk.io/errors" + "cosmossdk.io/log" + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + + "github.com/neutron-org/neutron/v5/utils/storageverification" + icqtypes "github.com/neutron-org/neutron/v5/x/interchainqueries/types" + "github.com/neutron-org/neutron/v5/x/state-verifier/types" +) + +type ( + Keeper struct { + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + cometInfo comet.BlockInfoService + headerInfo header.Service + authority string + } +) + +func NewKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + cometInfo comet.BlockInfoService, + headerInfo header.Service, + authority string, +) *Keeper { + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + authority: authority, + headerInfo: headerInfo, + cometInfo: cometInfo, + } +} + +func (k *Keeper) GetAuthority() string { + return k.authority +} + +func (k *Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// SaveConsensusState extracts info about the current header from the context, composes ConsensusState structure with that info +// and saves the structure to the state +func (k *Keeper) SaveConsensusState(ctx sdk.Context) error { + headerInfo := k.headerInfo.GetHeaderInfo(ctx) + cometInfo := k.cometInfo.GetCometBlockInfo(ctx) + + cs := tendermint.ConsensusState{ + Timestamp: ctx.BlockTime(), + Root: ibccommitmenttypes.NewMerkleRoot(headerInfo.AppHash), + NextValidatorsHash: cometInfo.GetValidatorsHash(), + } + + return k.WriteConsensusState(ctx, ctx.BlockHeight(), cs) +} + +// WriteConsensusState writes ConsensusState structure and corresponding height into the storage +func (k *Keeper) WriteConsensusState(ctx sdk.Context, height int64, cs tendermint.ConsensusState) error { + store := ctx.KVStore(k.storeKey) + key := types.GetConsensusStateKey(height) + + csBz, err := k.cdc.Marshal(&cs) + if err != nil { + return errors.Wrapf(sdkerrors.ErrJSONMarshal, err.Error()) + } + + store.Set(key, csBz) + + return nil +} + +// Verify verifies that provided `values` are actually present on Neutron blockchain at `blockHeight` +func (k *Keeper) Verify(ctx sdk.Context, blockHeight int64, values []*icqtypes.StorageValue) error { + store := ctx.KVStore(k.storeKey) + + // we need to use consensus state from the next height (N + 1), cause that consensus state contains .AppHash (Merkle Root) of the state for `blockHeight` (N) + csBz := store.Get(types.GetConsensusStateKey(blockHeight + 1)) + if csBz == nil { + return errors.Wrap(sdkerrors.ErrKeyNotFound, fmt.Sprintf("consensus state for block %d not found", blockHeight)) + } + + var cs tendermint.ConsensusState + if err := k.cdc.Unmarshal(csBz, &cs); err != nil { + return errors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + + if err := storageverification.VerifyStorageValues(values, cs.Root, ibccommitmenttypes.GetSDKSpecs(), nil); err != nil { + return errors.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) + } + + return nil +} + +// GetAllConsensusStates returns ALL consensus states that are present in the storage +// Pagination is not needed here because the method is used to export state to genesis +func (k *Keeper) GetAllConsensusStates(ctx sdk.Context) ([]*types.ConsensusState, error) { + var ( + store = prefix.NewStore(ctx.KVStore(k.storeKey), types.ConsensusStateKey) + states []*types.ConsensusState + ) + + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + cs := tendermint.ConsensusState{} + k.cdc.MustUnmarshal(iterator.Value(), &cs) + height := int64(sdk.BigEndianToUint64(iterator.Key())) + states = append(states, &types.ConsensusState{ + Height: height, + Cs: &cs, + }) + } + + return states, nil +} diff --git a/x/state-verifier/keeper/keeper_test.go b/x/state-verifier/keeper/keeper_test.go new file mode 100644 index 000000000..d6c052d2e --- /dev/null +++ b/x/state-verifier/keeper/keeper_test.go @@ -0,0 +1,182 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "cosmossdk.io/math" + wasmKeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/proto/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" + ibctypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibchost "github.com/cosmos/ibc-go/v8/modules/core/exported" + "github.com/stretchr/testify/suite" + + "github.com/neutron-org/neutron/v5/app/params" + "github.com/neutron-org/neutron/v5/testutil" + iqtypes "github.com/neutron-org/neutron/v5/x/interchainqueries/types" +) + +var reflectContractPath = "../../../wasmbinding/testdata/reflect.wasm" + +type KeeperTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func (suite *KeeperTestSuite) TestVerifyValue() { + tests := []struct { + name string + malleate func(sender string, ctx sdk.Context) ([]*iqtypes.StorageValue, int64, error) + }{ + { + name: "valid KV storage proof", + malleate: func(sender string, ctx sdk.Context) ([]*iqtypes.StorageValue, int64, error) { + clientKey := host.FullClientStateKey(suite.Path.EndpointA.ClientID) + + resp, err := suite.ChainA.App.Query(ctx, &types.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibchost.StoreKey), + Height: suite.ChainA.LastHeader.Header.Height - 1, + Data: clientKey, + Prove: true, + }) + suite.Require().NoError(err) + + return []*iqtypes.StorageValue{{ + Key: resp.Key, + Proof: resp.ProofOps, + Value: resp.Value, + StoragePrefix: ibchost.StoreKey, + }}, resp.Height, nil + }, + }, + { + name: "empty KV storage proof", + malleate: func(sender string, ctx sdk.Context) ([]*iqtypes.StorageValue, int64, error) { + clientKey := host.FullClientStateKey(suite.Path.EndpointA.ClientID) + + resp, err := suite.ChainA.App.Query(ctx, &types.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibchost.StoreKey), + Height: suite.ChainA.LastHeader.Header.Height - 1, + Data: clientKey, + Prove: true, + }) + suite.Require().NoError(err) + + return []*iqtypes.StorageValue{{ + Key: resp.Key, + Proof: nil, + Value: resp.Value, + StoragePrefix: ibchost.StoreKey, + }}, resp.Height, ibctypes.ErrInvalidMerkleProof + }, + }, + { + name: "invalid KV storage proof", + malleate: func(sender string, ctx sdk.Context) ([]*iqtypes.StorageValue, int64, error) { + clientKey := host.FullClientStateKey(suite.Path.EndpointA.ClientID) + + resp, err := suite.ChainA.App.Query(ctx, &types.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibchost.StoreKey), + Height: suite.ChainA.LastHeader.Header.Height - 1, + Data: clientKey, + Prove: true, + }) + suite.Require().NoError(err) + + return []*iqtypes.StorageValue{{ + Key: resp.Key, + Proof: &crypto.ProofOps{Ops: []crypto.ProofOp{{Type: "dasfsdf", Key: []byte("sffgsdf"), Data: []byte("sfdsdfs")}}}, + Value: resp.Value, + StoragePrefix: ibchost.StoreKey, + }}, resp.Height, ibctypes.ErrInvalidMerkleProof + }, + }, + { + name: "invalid height for proof", + malleate: func(sender string, ctx sdk.Context) ([]*iqtypes.StorageValue, int64, error) { + clientKey := host.FullClientStateKey(suite.Path.EndpointA.ClientID) + + resp, err := suite.ChainA.App.Query(ctx, &types.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibchost.StoreKey), + Height: suite.ChainA.LastHeader.Header.Height - 1, + Data: clientKey, + Prove: true, + }) + suite.Require().NoError(err) + + return []*iqtypes.StorageValue{{ + Key: resp.Key, + Proof: resp.ProofOps, + Value: resp.Value, + StoragePrefix: ibchost.StoreKey, + }}, resp.Height - 2, fmt.Errorf("Please ensure proof was submitted with correct proofHeight and to the correct chain.") //nolint:revive + }, + }, + { + name: "invalid storage prefix", + malleate: func(sender string, ctx sdk.Context) ([]*iqtypes.StorageValue, int64, error) { + clientKey := host.FullClientStateKey(suite.Path.EndpointA.ClientID) + + resp, err := suite.ChainA.App.Query(ctx, &types.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibchost.StoreKey), + Height: suite.ChainA.LastHeader.Header.Height - 1, + Data: clientKey, + Prove: true, + }) + suite.Require().NoError(err) + + return []*iqtypes.StorageValue{{ + Key: resp.Key, + Proof: resp.ProofOps, + Value: resp.Value, + StoragePrefix: "kekekek", + }}, resp.Height, fmt.Errorf("Please ensure the path and value are both correct.") //nolint:revive + }, + }, + } + + for i, tc := range tests { + tt := tc + suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tt.name, i+1, len(tests)), func() { + suite.SetupTest() + + var ( + ctx = suite.ChainA.GetContext() + contractOwner = wasmKeeper.RandomAccountAddress(suite.T()) + ) + + // Store code and instantiate reflect contract. + codeID := suite.StoreTestCode(ctx, contractOwner, reflectContractPath) + contractAddress := suite.InstantiateTestContract(ctx, contractOwner, codeID) + suite.Require().NotEmpty(contractAddress) + + err := testutil.SetupICAPath(suite.Path, contractAddress.String()) + suite.Require().NoError(err) + + // Top up contract address with native coins for deposit + senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() + suite.TopUpWallet(ctx, senderAddress, contractAddress) + + stValues, height, expectedError := tt.malleate(contractAddress.String(), ctx) + + if expectedError != nil { + suite.Require().ErrorContains(suite.GetNeutronZoneApp(suite.ChainA).StateVerifierKeeper.Verify(ctx, height, stValues), expectedError.Error()) + } else { + suite.Require().NoError(suite.GetNeutronZoneApp(suite.ChainA).StateVerifierKeeper.Verify(ctx, height, stValues)) + } + }) + } +} + +func (suite *KeeperTestSuite) TopUpWallet(ctx sdk.Context, sender, contractAddress sdk.AccAddress) { + coinsAmnt := sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(int64(1_000_000)))) + bankKeeper := suite.GetNeutronZoneApp(suite.ChainA).BankKeeper + err := bankKeeper.SendCoins(ctx, sender, contractAddress, coinsAmnt) + suite.Require().NoError(err) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/state-verifier/keeper/query.go b/x/state-verifier/keeper/query.go new file mode 100644 index 000000000..a21e8f804 --- /dev/null +++ b/x/state-verifier/keeper/query.go @@ -0,0 +1,18 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/neutron-org/neutron/v5/x/state-verifier/types" +) + +// VerifyStateValues implements `VerifyStateValues` gRPC query to verify storage values +func (k *Keeper) VerifyStateValues(ctx context.Context, request *types.QueryVerifyStateValuesRequest) (*types.QueryVerifyStateValuesResponse, error) { + if err := k.Verify(sdk.UnwrapSDKContext(ctx), int64(request.Height), request.StorageValues); err != nil { + return nil, err + } + + return &types.QueryVerifyStateValuesResponse{Valid: true}, nil +} diff --git a/x/state-verifier/module.go b/x/state-verifier/module.go new file mode 100644 index 000000000..6cb0e965f --- /dev/null +++ b/x/state-verifier/module.go @@ -0,0 +1,157 @@ +package stateverifier + +import ( + "context" + "encoding/json" + "fmt" + + "cosmossdk.io/core/appmodule" + + "github.com/gorilla/mux" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/cometbft/cometbft/abci/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/neutron-org/neutron/v5/x/state-verifier/keeper" + "github.com/neutron-org/neutron/v5/x/state-verifier/types" +) + +var ( + _ appmodule.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface that defines the independent methods a Cosmos SDK module needs to implement. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func (a AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) { +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the name of the module as a string +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the amino codec for the module, which is used to marshal and unmarshal structs to/from []byte in order to persist them in the module's KVStore +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers a module's interface types and their concrete implementations as proto.Message +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns a default GenesisState for the module, marshalled to json.RawMessage. The default GenesisState need to be defined by the module developer and is primarily used for testing +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err != nil { + panic(err) + } +} + +// Do not expose any CLI commands for this module + +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return &cobra.Command{} +} + +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return &cobra.Command{} +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- +var _ appmodule.AppModule = AppModule{} + +// AppModule implements the AppModule interface that defines the inter-dependent methods that modules need to implement +type AppModule struct { + AppModuleBasic + + keeper *keeper.Keeper +} + +func NewAppModule( + cdc codec.Codec, + keeper *keeper.Keeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() { // marker +} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() { // marker +} + +// RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) + // types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) +} + +// RegisterInvariants registers the invariants of the module. If an invariant deviates from its predicted value, the InvariantRegistry triggers appropriate logic (most often the chain will be halted) +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the module's genesis initialization. It returns no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion is a sequence number for state-breaking change of the module. It should be incremented on each consensus-breaking change introduced by the module. To avoid wrong/empty versions, the initial version should be set to 1 +func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } + +// BeginBlock contains the logic that is automatically triggered at the beginning of each block +func (am AppModule) BeginBlock(ctx context.Context) error { + return am.keeper.SaveConsensusState(sdk.UnwrapSDKContext(ctx)) +} diff --git a/x/state-verifier/types/codec.go b/x/state-verifier/types/codec.go new file mode 100644 index 000000000..847679bb4 --- /dev/null +++ b/x/state-verifier/types/codec.go @@ -0,0 +1,16 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func RegisterCodec(_ *codec.LegacyAmino) { +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + ) +} diff --git a/x/state-verifier/types/constants.go b/x/state-verifier/types/constants.go new file mode 100644 index 000000000..6bad94d03 --- /dev/null +++ b/x/state-verifier/types/constants.go @@ -0,0 +1,3 @@ +package types + +const ConsensusVersion = 1 diff --git a/x/state-verifier/types/genesis.go b/x/state-verifier/types/genesis.go new file mode 100644 index 000000000..315d5df0a --- /dev/null +++ b/x/state-verifier/types/genesis.go @@ -0,0 +1,12 @@ +package types + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{} +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + return nil +} diff --git a/x/state-verifier/types/genesis.pb.go b/x/state-verifier/types/genesis.pb.go new file mode 100644 index 000000000..75bb7cf35 --- /dev/null +++ b/x/state-verifier/types/genesis.pb.go @@ -0,0 +1,551 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: neutron/state_verifier/v1/genesis.proto + +package types + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + _07_tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + 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 + +// ConsensusState describes a "light" consensus state of Neutron at a particular height +type ConsensusState struct { + Height int64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + Cs *_07_tendermint.ConsensusState `protobuf:"bytes,2,opt,name=cs,proto3" json:"cs,omitempty"` +} + +func (m *ConsensusState) Reset() { *m = ConsensusState{} } +func (m *ConsensusState) String() string { return proto.CompactTextString(m) } +func (*ConsensusState) ProtoMessage() {} +func (*ConsensusState) Descriptor() ([]byte, []int) { + return fileDescriptor_12c2ac447c18f7c3, []int{0} +} +func (m *ConsensusState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsensusState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsensusState.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 *ConsensusState) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsensusState.Merge(m, src) +} +func (m *ConsensusState) XXX_Size() int { + return m.Size() +} +func (m *ConsensusState) XXX_DiscardUnknown() { + xxx_messageInfo_ConsensusState.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsensusState proto.InternalMessageInfo + +func (m *ConsensusState) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *ConsensusState) GetCs() *_07_tendermint.ConsensusState { + if m != nil { + return m.Cs + } + return nil +} + +type GenesisState struct { + States []*ConsensusState `protobuf:"bytes,1,rep,name=states,proto3" json:"states,omitempty"` +} + +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_12c2ac447c18f7c3, []int{1} +} +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) GetStates() []*ConsensusState { + if m != nil { + return m.States + } + return nil +} + +func init() { + proto.RegisterType((*ConsensusState)(nil), "neutron.state_verifier.v1.ConsensusState") + proto.RegisterType((*GenesisState)(nil), "neutron.state_verifier.v1.GenesisState") +} + +func init() { + proto.RegisterFile("neutron/state_verifier/v1/genesis.proto", fileDescriptor_12c2ac447c18f7c3) +} + +var fileDescriptor_12c2ac447c18f7c3 = []byte{ + // 274 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0xd0, 0xb1, 0x4e, 0xc3, 0x30, + 0x10, 0x06, 0xe0, 0x3a, 0x95, 0x32, 0xb8, 0x88, 0x21, 0x03, 0x0a, 0x0c, 0x56, 0xd4, 0x85, 0x30, + 0xd4, 0x56, 0x8a, 0x90, 0x98, 0x90, 0x80, 0x81, 0x99, 0xb0, 0xb1, 0x20, 0x62, 0x8e, 0xc4, 0x52, + 0x6b, 0x57, 0x3e, 0xc7, 0x82, 0xb7, 0xe0, 0xb1, 0x18, 0x3b, 0x32, 0xa2, 0xe4, 0x45, 0x50, 0x9a, + 0x00, 0x2d, 0x12, 0x9b, 0x4f, 0x3a, 0x7f, 0x77, 0xf7, 0xd3, 0x63, 0x0d, 0xb5, 0xb3, 0x46, 0x0b, + 0x74, 0x8f, 0x0e, 0x1e, 0x3c, 0x58, 0xf5, 0xac, 0xc0, 0x0a, 0x9f, 0x89, 0x12, 0x34, 0xa0, 0x42, + 0xbe, 0xb2, 0xc6, 0x99, 0xe8, 0x70, 0x68, 0xe4, 0xbb, 0x8d, 0xdc, 0x67, 0x47, 0x42, 0x15, 0x52, + 0x2c, 0x54, 0x59, 0x39, 0xb9, 0x50, 0xa0, 0x1d, 0x0a, 0x07, 0xfa, 0x09, 0xec, 0x52, 0x69, 0xd7, + 0x41, 0xbf, 0x55, 0x6f, 0x4d, 0x2b, 0xba, 0x7f, 0x6d, 0x34, 0x82, 0xc6, 0x1a, 0xef, 0x3a, 0x2e, + 0x3a, 0xa0, 0x61, 0x05, 0x9d, 0x10, 0x93, 0x84, 0xa4, 0xe3, 0x7c, 0xa8, 0xa2, 0x0b, 0x1a, 0x48, + 0x8c, 0x83, 0x84, 0xa4, 0x93, 0x39, 0xe7, 0xaa, 0x90, 0x7c, 0x7b, 0x0e, 0xdf, 0x92, 0x7d, 0xc6, + 0x77, 0xcd, 0x3c, 0x90, 0x38, 0xbd, 0xa5, 0x7b, 0x37, 0xfd, 0x19, 0xfd, 0x9c, 0x4b, 0x1a, 0x6e, + 0xf6, 0xc7, 0x98, 0x24, 0xe3, 0x74, 0x32, 0x3f, 0xe1, 0xff, 0x9e, 0xf5, 0x97, 0x1b, 0x3e, 0x5e, + 0xe5, 0xef, 0x0d, 0x23, 0xeb, 0x86, 0x91, 0xcf, 0x86, 0x91, 0xb7, 0x96, 0x8d, 0xd6, 0x2d, 0x1b, + 0x7d, 0xb4, 0x6c, 0x74, 0x7f, 0x5e, 0x2a, 0x57, 0xd5, 0x05, 0x97, 0x66, 0x29, 0x06, 0x76, 0x66, + 0x6c, 0xf9, 0xfd, 0x16, 0xfe, 0x4c, 0xbc, 0xf4, 0x39, 0xcf, 0x7e, 0x72, 0x76, 0xaf, 0x2b, 0xc0, + 0x22, 0xdc, 0xe4, 0x72, 0xfa, 0x15, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xbb, 0x34, 0x4c, 0x8e, 0x01, + 0x00, 0x00, +} + +func (m *ConsensusState) 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 *ConsensusState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsensusState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Cs != nil { + { + size, err := m.Cs.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.Height != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +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.States) > 0 { + for iNdEx := len(m.States) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.States[iNdEx].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 *ConsensusState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovGenesis(uint64(m.Height)) + } + if m.Cs != nil { + l = m.Cs.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.States) > 0 { + for _, e := range m.States { + 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 *ConsensusState) 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: ConsensusState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsensusState: 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 ErrIntOverflowGenesis + } + 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 Cs", 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 m.Cs == nil { + m.Cs = &_07_tendermint.ConsensusState{} + } + if err := m.Cs.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 *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 States", 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.States = append(m.States, &ConsensusState{}) + if err := m.States[len(m.States)-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/state-verifier/types/keys.go b/x/state-verifier/types/keys.go new file mode 100644 index 000000000..fbe933b08 --- /dev/null +++ b/x/state-verifier/types/keys.go @@ -0,0 +1,23 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // ModuleName defines the module name + ModuleName = "state-verifier" + + // StoreKey defines the primary module store key + StoreKey = ModuleName +) + +const ( + prefixConsensusStateKey = iota + 1 +) + +var ConsensusStateKey = []byte{prefixConsensusStateKey} + +func GetConsensusStateKey(height int64) []byte { + return append(ConsensusStateKey, types.Uint64ToBigEndian(uint64(height))...) +} diff --git a/x/state-verifier/types/query.pb.go b/x/state-verifier/types/query.pb.go new file mode 100644 index 000000000..a4c48ea58 --- /dev/null +++ b/x/state-verifier/types/query.pb.go @@ -0,0 +1,623 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: neutron/state_verifier/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + types "github.com/neutron-org/neutron/v5/x/interchainqueries/types" + _ "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 + +// QueryVerifyStateValuesRequest describes a structure to verify storage values from Neutron state from a particular height in the past +type QueryVerifyStateValuesRequest struct { + Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` + StorageValues []*types.StorageValue `protobuf:"bytes,2,rep,name=storage_values,json=storageValues,proto3" json:"storage_values,omitempty"` +} + +func (m *QueryVerifyStateValuesRequest) Reset() { *m = QueryVerifyStateValuesRequest{} } +func (m *QueryVerifyStateValuesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryVerifyStateValuesRequest) ProtoMessage() {} +func (*QueryVerifyStateValuesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_57fce5d311842a25, []int{0} +} +func (m *QueryVerifyStateValuesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVerifyStateValuesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVerifyStateValuesRequest.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 *QueryVerifyStateValuesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVerifyStateValuesRequest.Merge(m, src) +} +func (m *QueryVerifyStateValuesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryVerifyStateValuesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVerifyStateValuesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVerifyStateValuesRequest proto.InternalMessageInfo + +func (m *QueryVerifyStateValuesRequest) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *QueryVerifyStateValuesRequest) GetStorageValues() []*types.StorageValue { + if m != nil { + return m.StorageValues + } + return nil +} + +type QueryVerifyStateValuesResponse struct { + Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"` +} + +func (m *QueryVerifyStateValuesResponse) Reset() { *m = QueryVerifyStateValuesResponse{} } +func (m *QueryVerifyStateValuesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryVerifyStateValuesResponse) ProtoMessage() {} +func (*QueryVerifyStateValuesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_57fce5d311842a25, []int{1} +} +func (m *QueryVerifyStateValuesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVerifyStateValuesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVerifyStateValuesResponse.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 *QueryVerifyStateValuesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVerifyStateValuesResponse.Merge(m, src) +} +func (m *QueryVerifyStateValuesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryVerifyStateValuesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVerifyStateValuesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVerifyStateValuesResponse proto.InternalMessageInfo + +func (m *QueryVerifyStateValuesResponse) GetValid() bool { + if m != nil { + return m.Valid + } + return false +} + +func init() { + proto.RegisterType((*QueryVerifyStateValuesRequest)(nil), "neutron.state_verifier.v1.QueryVerifyStateValuesRequest") + proto.RegisterType((*QueryVerifyStateValuesResponse)(nil), "neutron.state_verifier.v1.QueryVerifyStateValuesResponse") +} + +func init() { + proto.RegisterFile("neutron/state_verifier/v1/query.proto", fileDescriptor_57fce5d311842a25) +} + +var fileDescriptor_57fce5d311842a25 = []byte{ + // 353 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0xc1, 0x4a, 0x2b, 0x31, + 0x14, 0x86, 0x9b, 0xde, 0xdb, 0x72, 0xc9, 0xe5, 0x5e, 0x70, 0x10, 0xa9, 0x45, 0x87, 0x32, 0x20, + 0x16, 0xa4, 0x09, 0x6d, 0x51, 0xea, 0xd6, 0x07, 0x10, 0x9c, 0x42, 0x17, 0x6e, 0x4a, 0x5a, 0x8f, + 0x33, 0x81, 0x9a, 0x4c, 0x93, 0xcc, 0xd0, 0x6e, 0xdd, 0xb8, 0x15, 0x7c, 0x1e, 0xd7, 0xba, 0x2c, + 0xb8, 0x71, 0x29, 0xad, 0x0f, 0x22, 0x93, 0x69, 0xd5, 0x5a, 0xea, 0xc2, 0xe5, 0x81, 0xf3, 0x7d, + 0xff, 0x9f, 0x1c, 0xbc, 0x27, 0x20, 0x36, 0x4a, 0x0a, 0xaa, 0x0d, 0x33, 0xd0, 0x4d, 0x40, 0xf1, + 0x4b, 0x0e, 0x8a, 0x26, 0x75, 0x3a, 0x8c, 0x41, 0x8d, 0x49, 0xa4, 0xa4, 0x91, 0xce, 0xf6, 0x7c, + 0x8d, 0x2c, 0xaf, 0x91, 0xa4, 0x5e, 0xde, 0x09, 0xa4, 0x0c, 0x06, 0x40, 0x59, 0xc4, 0x29, 0x13, + 0x42, 0x1a, 0x66, 0xb8, 0x14, 0x3a, 0x03, 0xcb, 0xde, 0xc2, 0xcf, 0x85, 0x01, 0xd5, 0x0f, 0x19, + 0x17, 0xa9, 0x97, 0x83, 0xa6, 0x66, 0x94, 0xed, 0x78, 0x37, 0x08, 0xef, 0x9e, 0xa5, 0x61, 0x9d, + 0x54, 0x3b, 0x6e, 0xa7, 0x11, 0x1d, 0x36, 0x88, 0x41, 0xfb, 0x30, 0x8c, 0x41, 0x1b, 0x67, 0x0b, + 0x17, 0x43, 0xe0, 0x41, 0x68, 0x4a, 0xa8, 0x82, 0xaa, 0xbf, 0xfd, 0xf9, 0xe4, 0x9c, 0xe2, 0xff, + 0xda, 0x48, 0xc5, 0x02, 0xe8, 0x26, 0x16, 0x28, 0xe5, 0x2b, 0xbf, 0xaa, 0x7f, 0x1b, 0xfb, 0x64, + 0xd1, 0x77, 0x25, 0x96, 0xb4, 0x33, 0xc0, 0x06, 0xf8, 0xff, 0xf4, 0xa7, 0x49, 0x7b, 0x47, 0xd8, + 0x5d, 0x57, 0x44, 0x47, 0x52, 0x68, 0x70, 0x36, 0x71, 0x21, 0x61, 0x03, 0x7e, 0x61, 0x8b, 0xfc, + 0xf1, 0xb3, 0xa1, 0xf1, 0x80, 0x70, 0xc1, 0x82, 0xce, 0x3d, 0xc2, 0x1b, 0x2b, 0xb4, 0xd3, 0x22, + 0x6b, 0xff, 0x8f, 0x7c, 0xfb, 0xf2, 0xf2, 0xf1, 0x0f, 0xc8, 0xac, 0xaa, 0xd7, 0xbc, 0x7e, 0x7a, + 0xbd, 0xcb, 0xd7, 0x9c, 0x03, 0xba, 0x74, 0xe3, 0xda, 0xc7, 0x8d, 0x2d, 0xda, 0x9d, 0x8b, 0x2d, + 0x7c, 0xe2, 0x3f, 0x4e, 0x5d, 0x34, 0x99, 0xba, 0xe8, 0x65, 0xea, 0xa2, 0xdb, 0x99, 0x9b, 0x9b, + 0xcc, 0xdc, 0xdc, 0xf3, 0xcc, 0xcd, 0x9d, 0xb7, 0x02, 0x6e, 0xc2, 0xb8, 0x47, 0xfa, 0xf2, 0x6a, + 0x21, 0xac, 0x49, 0x15, 0xbc, 0xcb, 0x93, 0x43, 0x3a, 0xfa, 0x9a, 0x60, 0xc6, 0x11, 0xe8, 0x5e, + 0xd1, 0x9e, 0xb9, 0xf9, 0x16, 0x00, 0x00, 0xff, 0xff, 0x90, 0xd2, 0x13, 0x46, 0x6c, 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 + +// 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 { + VerifyStateValues(ctx context.Context, in *QueryVerifyStateValuesRequest, opts ...grpc.CallOption) (*QueryVerifyStateValuesResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) VerifyStateValues(ctx context.Context, in *QueryVerifyStateValuesRequest, opts ...grpc.CallOption) (*QueryVerifyStateValuesResponse, error) { + out := new(QueryVerifyStateValuesResponse) + err := c.cc.Invoke(ctx, "/neutron.state_verifier.v1.Query/VerifyStateValues", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + VerifyStateValues(context.Context, *QueryVerifyStateValuesRequest) (*QueryVerifyStateValuesResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) VerifyStateValues(ctx context.Context, req *QueryVerifyStateValuesRequest) (*QueryVerifyStateValuesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VerifyStateValues not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_VerifyStateValues_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryVerifyStateValuesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).VerifyStateValues(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/neutron.state_verifier.v1.Query/VerifyStateValues", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).VerifyStateValues(ctx, req.(*QueryVerifyStateValuesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "neutron.state_verifier.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "VerifyStateValues", + Handler: _Query_VerifyStateValues_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "neutron/state_verifier/v1/query.proto", +} + +func (m *QueryVerifyStateValuesRequest) 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 *QueryVerifyStateValuesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVerifyStateValuesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.StorageValues) > 0 { + for iNdEx := len(m.StorageValues) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.StorageValues[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Height != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryVerifyStateValuesResponse) 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 *QueryVerifyStateValuesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVerifyStateValuesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Valid { + i-- + if m.Valid { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + 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 *QueryVerifyStateValuesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Height != 0 { + n += 1 + sovQuery(uint64(m.Height)) + } + if len(m.StorageValues) > 0 { + for _, e := range m.StorageValues { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *QueryVerifyStateValuesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Valid { + n += 2 + } + 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 *QueryVerifyStateValuesRequest) 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: QueryVerifyStateValuesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVerifyStateValuesRequest: 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 ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StorageValues", 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.StorageValues = append(m.StorageValues, &types.StorageValue{}) + if err := m.StorageValues[len(m.StorageValues)-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 *QueryVerifyStateValuesResponse) 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: QueryVerifyStateValuesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVerifyStateValuesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Valid", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Valid = bool(v != 0) + 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/state-verifier/types/query.pb.gw.go b/x/state-verifier/types/query.pb.gw.go new file mode 100644 index 000000000..51ec48b3b --- /dev/null +++ b/x/state-verifier/types/query.pb.gw.go @@ -0,0 +1,171 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: neutron/state_verifier/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/metadata" + "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 +var _ = metadata.Join + +var ( + filter_Query_VerifyStateValues_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_VerifyStateValues_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVerifyStateValuesRequest + 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_VerifyStateValues_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.VerifyStateValues(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_VerifyStateValues_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVerifyStateValuesRequest + 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_VerifyStateValues_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.VerifyStateValues(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 to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_VerifyStateValues_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + 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_VerifyStateValues_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_VerifyStateValues_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_VerifyStateValues_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_VerifyStateValues_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_VerifyStateValues_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_VerifyStateValues_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"neutron", "state-verifier", "verify_state_values"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_VerifyStateValues_0 = runtime.ForwardResponseMessage +) diff --git a/x/tokenfactory/keeper/before_send_test.go b/x/tokenfactory/keeper/before_send_test.go index 3ffd7a0f4..3887ccabb 100644 --- a/x/tokenfactory/keeper/before_send_test.go +++ b/x/tokenfactory/keeper/before_send_test.go @@ -2,12 +2,17 @@ package keeper_test import ( "encoding/json" + "fmt" "os" "cosmossdk.io/math" + storetypes "cosmossdk.io/store/types" wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + dextypes "github.com/neutron-org/neutron/v5/x/dex/types" + icqtypes "github.com/neutron-org/neutron/v5/x/interchainqueries/types" "github.com/neutron-org/neutron/v5/x/tokenfactory/types" ) @@ -46,6 +51,127 @@ func (suite *KeeperTestSuite) initBalanceTrackContract(denom string) (sdk.AccAdd return cosmwasmAddress, codeID, factoryDenom } +type SendMsgTestCase struct { + desc string + msg func(denom string) *banktypes.MsgSend + expectPass bool +} + +func (suite *KeeperTestSuite) TestBeforeSendHook() { + for _, tc := range []struct { + desc string + wasmFile string + sendMsgs []SendMsgTestCase + }{ + { + desc: "should not allow sending 100 amount of *any* denom", + wasmFile: "./testdata/no100.wasm", // https://github.com/neutron-org/neutron-dev-contracts/tree/chore/additional-tf-test-contracts/contracts/no100 + sendMsgs: []SendMsgTestCase{ + { + desc: "sending 1 of factorydenom should not error", + msg: func(factorydenom string) *banktypes.MsgSend { + return banktypes.NewMsgSend( + suite.TestAccs[0], + suite.TestAccs[1], + sdk.NewCoins(sdk.NewInt64Coin(factorydenom, 1)), + ) + }, + expectPass: true, + }, + { + desc: "sending 1 of non-factorydenom should not error", + msg: func(factorydenom string) *banktypes.MsgSend { + return banktypes.NewMsgSend( + suite.TestAccs[0], + suite.TestAccs[1], + sdk.NewCoins(sdk.NewInt64Coin("foo", 1)), + ) + }, + expectPass: true, + }, + { + desc: "sending 100 of factorydenom should error", + msg: func(factorydenom string) *banktypes.MsgSend { + return banktypes.NewMsgSend( + suite.TestAccs[0], + suite.TestAccs[1], + sdk.NewCoins(sdk.NewInt64Coin(factorydenom, 100)), + ) + }, + expectPass: false, + }, + { + desc: "sending 100 of non-factorydenom should work", + msg: func(factorydenom string) *banktypes.MsgSend { + return banktypes.NewMsgSend( + suite.TestAccs[0], + suite.TestAccs[1], + sdk.NewCoins(sdk.NewInt64Coin("foo", 100)), + ) + }, + expectPass: true, + }, + { + desc: "having 100 coin within coins should not work", + msg: func(factorydenom string) *banktypes.MsgSend { + return banktypes.NewMsgSend( + suite.TestAccs[0], + suite.TestAccs[1], + sdk.NewCoins(sdk.NewInt64Coin(factorydenom, 100), sdk.NewInt64Coin("foo", 1)), + ) + }, + expectPass: false, + }, + }, + }, + } { + suite.Run(fmt.Sprintf("Case %suite", tc.desc), func() { + // setup test + suite.Setup() + + senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() + suite.TopUpWallet(suite.ChainA.GetContext(), senderAddress, suite.TestAccs[0]) + + // upload and instantiate wasm code + wasmCode, err := os.ReadFile(tc.wasmFile) + suite.Require().NoError(err, "test: %v", tc.desc) + codeID, _, err := suite.contractKeeper.Create(suite.ChainA.GetContext(), suite.TestAccs[0], wasmCode, nil) + suite.Require().NoError(err, "test: %v", tc.desc) + cosmwasmAddress, _, err := suite.contractKeeper.Instantiate(suite.ChainA.GetContext(), codeID, suite.TestAccs[0], suite.TestAccs[0], []byte("{}"), "", sdk.NewCoins()) + suite.Require().NoError(err, "test: %v", tc.desc) + + // create new denom + res, err := suite.msgServer.CreateDenom(suite.ChainA.GetContext(), types.NewMsgCreateDenom(suite.TestAccs[0].String(), "bitcoin")) + suite.Require().NoError(err, "test: %v", tc.desc) + denom := res.GetNewTokenDenom() + + // mint enough coins to the creator + _, err = suite.msgServer.Mint(suite.ChainA.GetContext(), types.NewMsgMint(suite.TestAccs[0].String(), sdk.NewInt64Coin(denom, 1000000000))) + suite.Require().NoError(err) + // mint some non token factory denom coins for testing + suite.FundAcc(sdk.MustAccAddressFromBech32(suite.TestAccs[0].String()), sdk.Coins{sdk.NewInt64Coin("foo", 100000000000)}) + + params := types.DefaultParams() + params.WhitelistedHooks = []*types.WhitelistedHook{{DenomCreator: suite.TestAccs[0].String(), CodeID: 1}} + err = suite.GetNeutronZoneApp(suite.ChainA).TokenFactoryKeeper.SetParams(suite.ChainA.GetContext(), params) + suite.Require().NoError(err) + + // set beforesend hook to the new denom + _, err = suite.msgServer.SetBeforeSendHook(suite.ChainA.GetContext(), types.NewMsgSetBeforeSendHook(suite.TestAccs[0].String(), denom, cosmwasmAddress.String())) + suite.Require().NoError(err, "test: %v", tc.desc) + + for _, sendTc := range tc.sendMsgs { + _, err := suite.bankMsgServer.Send(suite.ChainA.GetContext(), sendTc.msg(denom)) + if sendTc.expectPass { + suite.Require().NoError(err, "test: %v", sendTc.desc) + } else { + suite.Require().Error(err, "test: %v", sendTc.desc) + } + } + }) + } +} + func (suite *KeeperTestSuite) TestTrackBeforeSendWasm() { suite.Setup() @@ -115,3 +241,99 @@ func (suite *KeeperTestSuite) TestNonWhitelistedHooksNotCalled() { // Whitelisted contract is not called suite.Require().Equal("\"0\"", string(queryResp)) } + +// TestInfiniteTrackBeforeSend tests gas metering with infinite loop contract +// to properly test if we are gas metering trackBeforeSend properly. +func (suite *KeeperTestSuite) TestInfiniteTrackBeforeSend() { + for _, tc := range []struct { + name string + wasmFile string + tokenToSend sdk.Coins + useFactoryDenom bool + blockBeforeSend bool + expectedError bool + }{ + { + name: "sending tokenfactory denom from module to module with infinite contract should panic", + wasmFile: "./testdata/infinite_track_beforesend.wasm", // https://github.com/neutron-org/neutron-dev-contracts/tree/chore/additional-tf-test-contracts/contracts/infinite-track-beforesend + useFactoryDenom: true, + }, + { + name: "sending tokenfactory denom from account to account with infinite contract should panic", + wasmFile: "./testdata/infinite_track_beforesend.wasm", + useFactoryDenom: true, + blockBeforeSend: true, + }, + { + name: "sending non-tokenfactory denom from module to module with infinite contract should not panic", + wasmFile: "./testdata/infinite_track_beforesend.wasm", + tokenToSend: sdk.NewCoins(sdk.NewInt64Coin("foo", 1000000)), + useFactoryDenom: false, + }, + { + name: "Try using no 100", + wasmFile: "./testdata/no100.wasm", // https://github.com/neutron-org/neutron-dev-contracts/tree/chore/additional-tf-test-contracts/contracts/no100 + useFactoryDenom: true, + }, + } { + suite.Run(fmt.Sprintf("Case %suite", tc.name), func() { + // setup test + suite.Setup() + + // load wasm file + wasmCode, err := os.ReadFile(tc.wasmFile) + suite.Require().NoError(err) + + // instantiate wasm code + codeID, _, err := suite.contractKeeper.Create(suite.ChainA.GetContext(), suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), wasmCode, nil) + suite.Require().NoError(err, "test: %v", tc.name) + cosmwasmAddress, _, err := suite.contractKeeper.Instantiate(suite.ChainA.GetContext(), codeID, suite.TestAccs[0], suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), []byte("{}"), "", sdk.NewCoins()) + suite.Require().NoError(err, "test: %v", tc.name) + + params := types.DefaultParams() + params.WhitelistedHooks = []*types.WhitelistedHook{{DenomCreator: suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress().String(), CodeID: 1}} + err = suite.GetNeutronZoneApp(suite.ChainA).TokenFactoryKeeper.SetParams(suite.ChainA.GetContext(), params) + suite.Require().NoError(err) + + // create new denom + res, err := suite.msgServer.CreateDenom(suite.ChainA.GetContext(), types.NewMsgCreateDenom(suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress().String(), "bitcoin")) + suite.Require().NoError(err, "test: %v", tc.name) + factoryDenom := res.GetNewTokenDenom() + + var tokenToSend sdk.Coins + if tc.useFactoryDenom { + tokenToSend = sdk.NewCoins(sdk.NewInt64Coin(factoryDenom, 100)) + } else { + tokenToSend = tc.tokenToSend + } + + // send the mint module tokenToSend + if tc.blockBeforeSend { + suite.FundAcc(suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), tokenToSend) + } else { + suite.FundModuleAcc(icqtypes.ModuleName, tokenToSend) + } + + // set beforesend hook to the new denom + // we register infinite loop contract here to test if we are gas metering properly + _, err = suite.msgServer.SetBeforeSendHook(suite.ChainA.GetContext(), types.NewMsgSetBeforeSendHook(suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress().String(), factoryDenom, cosmwasmAddress.String())) + suite.Require().NoError(err, "test: %v", tc.name) + + ctx := suite.ChainA.GetContext().WithGasMeter(storetypes.NewGasMeter(30_000_000)) + + if tc.blockBeforeSend { + err = suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.SendCoins(ctx, suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress(), suite.ChainA.SenderAccounts[1].SenderAccount.GetAddress(), tokenToSend) + suite.Require().Error(err) + } else { + // track before send suppresses in any case, thus we expect no error + err = suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.SendCoinsFromModuleToModule(ctx, icqtypes.ModuleName, dextypes.ModuleName, tokenToSend) + suite.Require().NoError(err) + + // send should happen regardless of trackBeforeSend results + distributionModuleAddress := suite.GetNeutronZoneApp(suite.ChainA).AccountKeeper.GetModuleAddress(dextypes.ModuleName) + distributionModuleBalances := suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.GetAllBalances(suite.ChainA.GetContext(), distributionModuleAddress) + suite.Require().True(distributionModuleBalances.Equal(tokenToSend)) + } + }) + } +} diff --git a/x/tokenfactory/keeper/keeper_test.go b/x/tokenfactory/keeper/keeper_test.go index bbf4b0488..31e5beaad 100644 --- a/x/tokenfactory/keeper/keeper_test.go +++ b/x/tokenfactory/keeper/keeper_test.go @@ -4,9 +4,12 @@ import ( "testing" "cosmossdk.io/math" + wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" "github.com/cometbft/cometbft/crypto/ed25519" "github.com/cosmos/cosmos-sdk/baseapp" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/stretchr/testify/suite" @@ -29,6 +32,10 @@ type KeeperTestSuite struct { TestAccs []sdktypes.AccAddress QueryHelper *baseapp.QueryServiceTestHelper + contractKeeper wasmtypes.ContractOpsKeeper + + bankMsgServer banktypes.MsgServer + queryClient types.QueryClient msgServer types.MsgServer // defaultDenom is on the suite, as it depends on the creator test address. @@ -61,7 +68,10 @@ func (suite *KeeperTestSuite) Setup() { )) suite.Require().NoError(err) + suite.bankMsgServer = bankkeeper.NewMsgServerImpl(suite.GetNeutronZoneApp(suite.ChainA).BankKeeper) suite.msgServer = keeper.NewMsgServerImpl(*tokenFactoryKeeper) + + suite.contractKeeper = wasmkeeper.NewDefaultPermissionKeeper(suite.GetNeutronZoneApp(suite.ChainA).WasmKeeper) } func (suite *KeeperTestSuite) SetupTokenFactory() { diff --git a/x/tokenfactory/keeper/testdata/infinite_track_beforesend.wasm b/x/tokenfactory/keeper/testdata/infinite_track_beforesend.wasm new file mode 100644 index 000000000..44bf738f1 Binary files /dev/null and b/x/tokenfactory/keeper/testdata/infinite_track_beforesend.wasm differ diff --git a/x/tokenfactory/keeper/testdata/no100.wasm b/x/tokenfactory/keeper/testdata/no100.wasm new file mode 100644 index 000000000..57de535eb Binary files /dev/null and b/x/tokenfactory/keeper/testdata/no100.wasm differ diff --git a/x/tokenfactory/types/constants.go b/x/tokenfactory/types/constants.go index 066fcad70..350fe3122 100644 --- a/x/tokenfactory/types/constants.go +++ b/x/tokenfactory/types/constants.go @@ -2,4 +2,6 @@ package types const ConsensusVersion = 2 -var TrackBeforeSendGasLimit = uint64(100_000) +// TrackBeforeSendGasLimit value is increased to allow existing approved tokenfactory hooks to work properly. +// In the next coordinated upgrade, this will become a chain parameter. +var TrackBeforeSendGasLimit = uint64(500_000)