diff --git a/CHANGELOG.md b/CHANGELOG.md index be68da9259..8749a7016b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * Allow marker's transfer authority to prevent transfer of restricted coin with deny list on send [#1518](https://github.com/provenance-io/provenance/issues/1518). +* Add ICQHost and Oracle module to allow cross chain oracle queries [#1497](https://github.com/provenance-io/provenance/issues/1497). * New `GetByAddr` metadata query [#1443](https://github.com/provenance-io/provenance/issues/1443). * Add Trigger module queries to stargate whitelist for smart contracts [#1636](https://github.com/provenance-io/provenance/issues/1636) * Added the saffron upgrade handlers [PR 1648](https://github.com/provenance-io/provenance/pull/1648). diff --git a/app/app.go b/app/app.go index ef00d24bf9..5912fb379f 100644 --- a/app/app.go +++ b/app/app.go @@ -17,6 +17,9 @@ import ( "github.com/rakyll/statik/fs" "github.com/spf13/cast" "github.com/spf13/viper" + icq "github.com/strangelove-ventures/async-icq/v6" + icqkeeper "github.com/strangelove-ventures/async-icq/v6/keeper" + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" @@ -153,6 +156,9 @@ import ( namekeeper "github.com/provenance-io/provenance/x/name/keeper" nametypes "github.com/provenance-io/provenance/x/name/types" namewasm "github.com/provenance-io/provenance/x/name/wasm" + oraclekeeper "github.com/provenance-io/provenance/x/oracle/keeper" + oraclemodule "github.com/provenance-io/provenance/x/oracle/module" + oracletypes "github.com/provenance-io/provenance/x/oracle/types" rewardkeeper "github.com/provenance-io/provenance/x/reward/keeper" rewardmodule "github.com/provenance-io/provenance/x/reward/module" rewardtypes "github.com/provenance-io/provenance/x/reward/types" @@ -207,6 +213,7 @@ var ( ibc.AppModuleBasic{}, ibctransfer.AppModuleBasic{}, ica.AppModuleBasic{}, + icq.AppModuleBasic{}, ibchooks.AppModuleBasic{}, marker.AppModuleBasic{}, @@ -217,6 +224,7 @@ var ( msgfeesmodule.AppModuleBasic{}, rewardmodule.AppModuleBasic{}, triggermodule.AppModuleBasic{}, + oraclemodule.AppModuleBasic{}, holdmodule.AppModuleBasic{}, ) @@ -238,6 +246,7 @@ var ( wasm.ModuleName: {authtypes.Burner}, rewardtypes.ModuleName: nil, triggertypes.ModuleName: nil, + oracletypes.ModuleName: nil, } ) @@ -295,11 +304,13 @@ type App struct { QuarantineKeeper quarantinekeeper.Keeper SanctionKeeper sanctionkeeper.Keeper TriggerKeeper triggerkeeper.Keeper + OracleKeeper oraclekeeper.Keeper IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly IBCHooksKeeper *ibchookskeeper.Keeper ICAHostKeeper *icahostkeeper.Keeper TransferKeeper *ibctransferkeeper.Keeper + ICQKeeper icqkeeper.Keeper MarkerKeeper markerkeeper.Keeper MetadataKeeper metadatakeeper.Keeper @@ -313,6 +324,8 @@ type App struct { ScopedIBCKeeper capabilitykeeper.ScopedKeeper ScopedTransferKeeper capabilitykeeper.ScopedKeeper ScopedICAHostKeeper capabilitykeeper.ScopedKeeper + ScopedICQKeeper capabilitykeeper.ScopedKeeper + ScopedOracleKeeper capabilitykeeper.ScopedKeeper TransferStack *ibchooks.IBCMiddleware Ics20WasmHooks *ibchooks.WasmHooks @@ -370,6 +383,7 @@ func New( ibchost.StoreKey, ibctransfertypes.StoreKey, icahosttypes.StoreKey, + icqtypes.StoreKey, ibchookstypes.StoreKey, metadatatypes.StoreKey, @@ -382,6 +396,7 @@ func New( quarantine.StoreKey, sanction.StoreKey, triggertypes.StoreKey, + oracletypes.StoreKey, hold.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) @@ -417,6 +432,8 @@ func New( scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) scopedWasmKeeper := app.CapabilityKeeper.ScopeToModule(wasm.ModuleName) scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) + scopedICQKeeper := app.CapabilityKeeper.ScopeToModule(icqtypes.ModuleName) + scopedOracleKeeper := app.CapabilityKeeper.ScopeToModule(oracletypes.ModuleName) // capability keeper must be sealed after scope to module registrations are completed. app.CapabilityKeeper.Seal() @@ -558,6 +575,14 @@ func New( icaModule := ica.NewAppModule(nil, app.ICAHostKeeper) icaHostIBCModule := icahost.NewIBCModule(*app.ICAHostKeeper) + app.ICQKeeper = icqkeeper.NewKeeper( + appCodec, keys[icqtypes.StoreKey], app.GetSubspace(icqtypes.ModuleName), + app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + scopedICQKeeper, app.BaseApp, + ) + icqModule := icq.NewAppModule(app.ICQKeeper) + icqIBCModule := icq.NewIBCModule(app.ICQKeeper) + // Init CosmWasm module wasmDir := filepath.Join(homePath, "data", "wasm") @@ -617,6 +642,19 @@ func New( app.Ics20WasmHooks.ContractKeeper = app.WasmKeeper // app.ContractKeeper -- this changes in the next version of wasm to a permissioned keeper app.IBCHooksKeeper.ContractKeeper = app.ContractKeeper + app.ScopedOracleKeeper = scopedOracleKeeper + app.OracleKeeper = *oraclekeeper.NewKeeper( + appCodec, + keys[oracletypes.StoreKey], + keys[oracletypes.MemStoreKey], + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + scopedOracleKeeper, + wasmkeeper.Querier(app.WasmKeeper), + ) + oracleModule := oraclemodule.NewAppModule(appCodec, app.OracleKeeper, app.AccountKeeper, app.BankKeeper, app.IBCKeeper.ChannelKeeper) + unsanctionableAddrs := make([]sdk.AccAddress, 0, len(maccPerms)+1) for mName := range maccPerms { unsanctionableAddrs = append(unsanctionableAddrs, authtypes.NewModuleAddress(mName)) @@ -648,7 +686,9 @@ func New( ibcRouter. AddRoute(ibctransfertypes.ModuleName, app.TransferStack). AddRoute(wasm.ModuleName, wasm.NewIBCHandler(app.WasmKeeper, app.IBCKeeper.ChannelKeeper, app.IBCKeeper.ChannelKeeper)). - AddRoute(icahosttypes.SubModuleName, icaHostIBCModule) + AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). + AddRoute(icqtypes.ModuleName, icqIBCModule). + AddRoute(oracletypes.ModuleName, oracleModule) app.IBCKeeper.SetRouter(ibcRouter) // Create evidence Keeper for to register the IBC light client misbehavior evidence route @@ -699,12 +739,14 @@ func New( wasm.NewAppModule(appCodec, app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper), rewardmodule.NewAppModule(appCodec, app.RewardKeeper, app.AccountKeeper, app.BankKeeper), triggermodule.NewAppModule(appCodec, app.TriggerKeeper, app.AccountKeeper, app.BankKeeper), + oracleModule, holdmodule.NewAppModule(appCodec, app.HoldKeeper), // IBC ibc.NewAppModule(app.IBCKeeper), ibchooks.NewAppModule(app.AccountKeeper, *app.IBCHooksKeeper), ibctransfer.NewAppModule(*app.TransferKeeper), + icqModule, icaModule, ) @@ -739,9 +781,11 @@ func New( paramstypes.ModuleName, msgfeestypes.ModuleName, metadatatypes.ModuleName, + oracletypes.ModuleName, wasm.ModuleName, ibchookstypes.ModuleName, ibctransfertypes.ModuleName, + icqtypes.ModuleName, nametypes.ModuleName, vestingtypes.ModuleName, quarantine.ModuleName, @@ -764,11 +808,13 @@ func New( distrtypes.ModuleName, authz.ModuleName, metadatatypes.ModuleName, + oracletypes.ModuleName, nametypes.ModuleName, genutiltypes.ModuleName, ibchost.ModuleName, ibchookstypes.ModuleName, ibctransfertypes.ModuleName, + icqtypes.ModuleName, msgfeestypes.ModuleName, wasm.ModuleName, slashingtypes.ModuleName, @@ -818,12 +864,14 @@ func New( ibchost.ModuleName, ibctransfertypes.ModuleName, + icqtypes.ModuleName, icatypes.ModuleName, ibchookstypes.ModuleName, // wasm after ibc transfer wasm.ModuleName, rewardtypes.ModuleName, triggertypes.ModuleName, + oracletypes.ModuleName, // no-ops paramstypes.ModuleName, @@ -856,6 +904,7 @@ func New( ibchookstypes.ModuleName, icatypes.ModuleName, + icqtypes.ModuleName, wasm.ModuleName, attributetypes.ModuleName, @@ -865,6 +914,7 @@ func New( nametypes.ModuleName, rewardtypes.ModuleName, triggertypes.ModuleName, + oracletypes.ModuleName, // Last due to v0.44 issue: https://github.com/cosmos/cosmos-sdk/issues/10591 authtypes.ModuleName, @@ -899,6 +949,7 @@ func New( msgfeesmodule.NewAppModule(appCodec, app.MsgFeesKeeper, app.interfaceRegistry), rewardmodule.NewAppModule(appCodec, app.RewardKeeper, app.AccountKeeper, app.BankKeeper), triggermodule.NewAppModule(appCodec, app.TriggerKeeper, app.AccountKeeper, app.BankKeeper), + oraclemodule.NewAppModule(appCodec, app.OracleKeeper, app.AccountKeeper, app.BankKeeper, app.IBCKeeper.ChannelKeeper), holdmodule.NewAppModule(appCodec, app.HoldKeeper), provwasm.NewWrapper(appCodec, app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.NameKeeper), @@ -991,6 +1042,7 @@ func New( app.ScopedIBCKeeper = scopedIBCKeeper app.ScopedTransferKeeper = scopedTransferKeeper + app.ScopedICQKeeper = scopedICQKeeper app.ScopedICAHostKeeper = scopedICAHostKeeper return app @@ -1219,6 +1271,7 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(ibctransfertypes.ModuleName) paramsKeeper.Subspace(ibchost.ModuleName) paramsKeeper.Subspace(icahosttypes.SubModuleName) + paramsKeeper.Subspace(icqtypes.ModuleName) paramsKeeper.Subspace(ibchookstypes.ModuleName) return paramsKeeper diff --git a/app/params/weights.go b/app/params/weights.go index 76080f289b..9a367fd967 100644 --- a/app/params/weights.go +++ b/app/params/weights.go @@ -35,4 +35,7 @@ const ( // Trigger DefaultWeightSubmitCreateTrigger int = 95 DefaultWeightSubmitDestroyTrigger int = 5 + // Oracle + DefaultWeightUpdateOracle int = 25 + DefaultWeightSendOracleQuery int = 75 ) diff --git a/app/sim_test.go b/app/sim_test.go index 3af258a7ea..ecaee2d402 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -73,6 +74,7 @@ func ProvAppStateFn(cdc codec.JSONCodec, simManager *module.SimulationManager) s return func(r *rand.Rand, accs []simtypes.Account, config simtypes.Config) (json.RawMessage, []simtypes.Account, string, time.Time) { appState, simAccs, chainID, genesisTimestamp := sdksim.AppStateFn(cdc, simManager)(r, accs, config) appState = appStateWithICA(appState, cdc) + appState = appStateWithICQ(appState, cdc) return appState, simAccs, chainID, genesisTimestamp } } @@ -96,6 +98,25 @@ func appStateWithICA(appState json.RawMessage, cdc codec.JSONCodec) json.RawMess return appState } +// appStateWithICA checks the given appState for an ica entry. If it's not found, it's populated with the defaults. +func appStateWithICQ(appState json.RawMessage, cdc codec.JSONCodec) json.RawMessage { + rawState := make(map[string]json.RawMessage) + err := json.Unmarshal(appState, &rawState) + if err != nil { + panic(fmt.Sprintf("error unmarshalling appstate: %v", err)) + } + icqGenJSON, icqGenFound := rawState[icqtypes.ModuleName] + if !icqGenFound || len(icqGenJSON) == 0 { + icqGenState := icqtypes.DefaultGenesis() + rawState[icqtypes.ModuleName] = cdc.MustMarshalJSON(icqGenState) + appState, err = json.Marshal(rawState) + if err != nil { + panic(fmt.Sprintf("error marshalling appstate: %v", err)) + } + } + return appState +} + func TestFullAppSimulation(t *testing.T) { config, db, dir, logger, skip, err := sdksim.SetupSimulation("leveldb-app-sim", "Simulation") if skip { diff --git a/app/upgrades.go b/app/upgrades.go index 3a656e4d67..bcc735ab16 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -3,6 +3,8 @@ package app import ( "fmt" + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" + "github.com/cosmos/cosmos-sdk/baseapp" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,6 +18,7 @@ import ( "github.com/provenance-io/provenance/x/hold" ibchookstypes "github.com/provenance-io/provenance/x/ibchooks/types" msgfeetypes "github.com/provenance-io/provenance/x/msgfees/types" + oracletypes "github.com/provenance-io/provenance/x/oracle/types" triggertypes "github.com/provenance-io/provenance/x/trigger/types" ) @@ -106,12 +109,13 @@ var upgrades = map[string]appUpgrade{ app.IBCHooksKeeper.SetParams(ctx, ibchookstypes.DefaultParams()) removeInactiveValidatorDelegations(ctx, app) + setupICQ(ctx, app) return vm, nil }, - Added: []string{hold.ModuleName, ibchookstypes.ModuleName}, + Added: []string{icqtypes.ModuleName, oracletypes.ModuleName, ibchookstypes.ModuleName, hold.ModuleName}, }, - "saffron": { // upgrade for v1.17.0 + "saffron": { // upgrade for v1.17.0, Handler: func(ctx sdk.Context, app *App, vm module.VersionMap) (module.VersionMap, error) { var err error vm, err = runModuleMigrations(ctx, app, vm) @@ -123,10 +127,11 @@ var upgrades = map[string]appUpgrade{ app.IBCHooksKeeper.SetParams(ctx, ibchookstypes.DefaultParams()) removeInactiveValidatorDelegations(ctx, app) + setupICQ(ctx, app) return vm, nil }, - Added: []string{hold.ModuleName, ibchookstypes.ModuleName}, + Added: []string{icqtypes.ModuleName, oracletypes.ModuleName, ibchookstypes.ModuleName, hold.ModuleName}, }, // TODO - Add new upgrade definitions here. } @@ -314,3 +319,10 @@ func fixNameIndexEntries(ctx sdk.Context, app *App) { func setAccountDataNameRecord(ctx sdk.Context, accountK attributetypes.AccountKeeper, nameK attributetypes.NameKeeper) (err error) { return attributekeeper.EnsureModuleAccountAndAccountDataNameRecord(ctx, accountK, nameK) } + +// setupICQ sets the correct default values for ICQKeeper +func setupICQ(ctx sdk.Context, app *App) { + ctx.Logger().Info("Updating ICQ params") + app.ICQKeeper.SetParams(ctx, icqtypes.NewParams(true, []string{"/provenance.oracle.v1.Query/Oracle"})) + ctx.Logger().Info("Done updating ICQ params") +} diff --git a/app/upgrades_test.go b/app/upgrades_test.go index 51a3bc3396..830827f87b 100644 --- a/app/upgrades_test.go +++ b/app/upgrades_test.go @@ -422,6 +422,8 @@ func (s *UpgradeTestSuite) TestSaffronRC1() { expInLog := []string{ "INF Starting module migrations. This may take a significant amount of time to complete. Do not restart node.", "INF removing all delegations from validators that have been inactive (unbonded) for 21 days", + "INF Updating ICQ params", + "INF Done updating ICQ params", } s.AssertUpgradeHandlerLogs("saffron-rc1", expInLog, nil) @@ -434,6 +436,8 @@ func (s *UpgradeTestSuite) TestSaffron() { expInLog := []string{ "INF Starting module migrations. This may take a significant amount of time to complete. Do not restart node.", "INF removing all delegations from validators that have been inactive (unbonded) for 21 days", + "INF Updating ICQ params", + "INF Done updating ICQ params", } s.AssertUpgradeHandlerLogs("saffron", expInLog, nil) diff --git a/docs/proto-docs.md b/docs/proto-docs.md index 2b66ab3c15..9189de1a68 100644 --- a/docs/proto-docs.md +++ b/docs/proto-docs.md @@ -472,6 +472,30 @@ - [Msg](#provenance.name.v1.Msg) +- [provenance/oracle/v1/event.proto](#provenance/oracle/v1/event.proto) + - [EventOracleQueryError](#provenance.oracle.v1.EventOracleQueryError) + - [EventOracleQuerySuccess](#provenance.oracle.v1.EventOracleQuerySuccess) + - [EventOracleQueryTimeout](#provenance.oracle.v1.EventOracleQueryTimeout) + +- [provenance/oracle/v1/genesis.proto](#provenance/oracle/v1/genesis.proto) + - [GenesisState](#provenance.oracle.v1.GenesisState) + +- [provenance/oracle/v1/query.proto](#provenance/oracle/v1/query.proto) + - [QueryOracleAddressRequest](#provenance.oracle.v1.QueryOracleAddressRequest) + - [QueryOracleAddressResponse](#provenance.oracle.v1.QueryOracleAddressResponse) + - [QueryOracleRequest](#provenance.oracle.v1.QueryOracleRequest) + - [QueryOracleResponse](#provenance.oracle.v1.QueryOracleResponse) + + - [Query](#provenance.oracle.v1.Query) + +- [provenance/oracle/v1/tx.proto](#provenance/oracle/v1/tx.proto) + - [MsgSendQueryOracleRequest](#provenance.oracle.v1.MsgSendQueryOracleRequest) + - [MsgSendQueryOracleResponse](#provenance.oracle.v1.MsgSendQueryOracleResponse) + - [MsgUpdateOracleRequest](#provenance.oracle.v1.MsgUpdateOracleRequest) + - [MsgUpdateOracleResponse](#provenance.oracle.v1.MsgUpdateOracleResponse) + + - [Msg](#provenance.oracle.v1.Msg) + - [provenance/reward/v1/reward.proto](#provenance/reward/v1/reward.proto) - [ActionCounter](#provenance.reward.v1.ActionCounter) - [ActionDelegate](#provenance.reward.v1.ActionDelegate) @@ -7227,6 +7251,271 @@ Msg defines the bank Msg service. + +

Top

+ +## provenance/oracle/v1/event.proto + + + + + +### EventOracleQueryError +EventOracleQueryError is an event for when the chain receives an error response from an oracle query + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `channel` | [string](#string) | | channel is the local channel that the oracle query response was received from | +| `sequence_id` | [string](#string) | | sequence_id is a unique identifier of the query | +| `error` | [string](#string) | | error is the error message received from the query | + + + + + + + + +### EventOracleQuerySuccess +EventOracleQuerySuccess is an event for when the chain receives a successful response from an oracle query + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `channel` | [string](#string) | | channel is the local channel that the oracle query response was received from | +| `sequence_id` | [string](#string) | | sequence_id is a unique identifier of the query | +| `result` | [string](#string) | | result is the data received from the query | + + + + + + + + +### EventOracleQueryTimeout +EventOracleQueryTimeout is an event for when the chain receives a timeout from an oracle query + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `channel` | [string](#string) | | channel is the local channel that the oracle timeout was received from | +| `sequence_id` | [string](#string) | | sequence_id is a unique identifier of the query | + + + + + + + + + + + + + + + + +

Top

+ +## provenance/oracle/v1/genesis.proto + + + + + +### GenesisState +GenesisState defines the oracle module's genesis state. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `port_id` | [string](#string) | | The port to assign to the module | +| `oracle` | [string](#string) | | The address of the oracle | + + + + + + + + + + + + + + + + +

Top

+ +## provenance/oracle/v1/query.proto + + + + + +### QueryOracleAddressRequest +QueryOracleAddressRequest queries for the address of the oracle. + + + + + + + + +### QueryOracleAddressResponse +QueryOracleAddressResponse contains the address of the oracle. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | The address of the oracle | + + + + + + + + +### QueryOracleRequest +QueryOracleRequest queries the module's oracle. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `query` | [bytes](#bytes) | | Query contains the query data passed to the oracle. | + + + + + + + + +### QueryOracleResponse +QueryOracleResponse contains the result of the query sent to the oracle. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `data` | [bytes](#bytes) | | Data contains the json data returned from the oracle. | + + + + + + + + + + + + + + +### Query +Query defines the gRPC querier service for oracle module. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `OracleAddress` | [QueryOracleAddressRequest](#provenance.oracle.v1.QueryOracleAddressRequest) | [QueryOracleAddressResponse](#provenance.oracle.v1.QueryOracleAddressResponse) | OracleAddress returns the address of the oracle | GET|/provenance/oracle/v1/oracle_address| +| `Oracle` | [QueryOracleRequest](#provenance.oracle.v1.QueryOracleRequest) | [QueryOracleResponse](#provenance.oracle.v1.QueryOracleResponse) | Oracle forwards a query to the module's oracle | GET|/provenance/oracle/v1/oracle| + + + + + + +

Top

+ +## provenance/oracle/v1/tx.proto + + + + + +### MsgSendQueryOracleRequest +MsgSendQueryOracleRequest queries an oracle on another chain + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `query` | [bytes](#bytes) | | Query contains the query data passed to the oracle. | +| `channel` | [string](#string) | | Channel is the channel to the oracle. | +| `authority` | [string](#string) | | The signing authority for the request | + + + + + + + + +### MsgSendQueryOracleResponse +MsgSendQueryOracleResponse contains the id of the oracle query. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `sequence` | [uint64](#uint64) | | The sequence number that uniquely identifies the query. | + + + + + + + + +### MsgUpdateOracleRequest +MsgUpdateOracleRequest is the request type for updating an oracle's contract address + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `address` | [string](#string) | | The address of the oracle's contract | +| `authority` | [string](#string) | | The signing authorities for the request | + + + + + + + + +### MsgUpdateOracleResponse +MsgUpdateOracleResponse is the response type for updating the oracle. + + + + + + + + + + + + + + +### Msg +Msg + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `UpdateOracle` | [MsgUpdateOracleRequest](#provenance.oracle.v1.MsgUpdateOracleRequest) | [MsgUpdateOracleResponse](#provenance.oracle.v1.MsgUpdateOracleResponse) | UpdateOracle is the RPC endpoint for updating the oracle | | +| `SendQueryOracle` | [MsgSendQueryOracleRequest](#provenance.oracle.v1.MsgSendQueryOracleRequest) | [MsgSendQueryOracleResponse](#provenance.oracle.v1.MsgSendQueryOracleResponse) | SendQueryOracle sends a query to an oracle on another chain | | + + + + +

Top

diff --git a/go.mod b/go.mod index 05065df67d..7f902ca66b 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.16.0 + github.com/strangelove-ventures/async-icq/v6 v6.0.0-rc0 github.com/stretchr/testify v1.8.4 github.com/tendermint/tendermint v0.34.28 github.com/tendermint/tm-db v0.6.7 diff --git a/go.sum b/go.sum index 535980009d..7d3f98ffbc 100644 --- a/go.sum +++ b/go.sum @@ -1078,6 +1078,8 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= +github.com/strangelove-ventures/async-icq/v6 v6.0.0-rc0 h1:gh0/GEH0LGSyQIuCpMVaA8f9GnkeiKqxNY8p8Z+4460= +github.com/strangelove-ventures/async-icq/v6 v6.0.0-rc0/go.mod h1:6jtElXZFjBeT00/mEnyiUif6YKN7pxmeorBpLOMidd8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= diff --git a/proto/provenance/oracle/v1/event.proto b/proto/provenance/oracle/v1/event.proto new file mode 100644 index 0000000000..3327a19b14 --- /dev/null +++ b/proto/provenance/oracle/v1/event.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; +package provenance.oracle.v1; + +option go_package = "github.com/provenance-io/provenance/x/oracle/types"; + +option java_package = "io.provenance.oracle.v1"; +option java_multiple_files = true; + +// EventOracleQuerySuccess is an event for when the chain receives a successful response from an oracle query +message EventOracleQuerySuccess { + // channel is the local channel that the oracle query response was received from + string channel = 1; + // sequence_id is a unique identifier of the query + string sequence_id = 2; + // result is the data received from the query + string result = 3; +} + +// EventOracleQueryError is an event for when the chain receives an error response from an oracle query +message EventOracleQueryError { + // channel is the local channel that the oracle query response was received from + string channel = 1; + // sequence_id is a unique identifier of the query + string sequence_id = 2; + // error is the error message received from the query + string error = 3; +} + +// EventOracleQueryTimeout is an event for when the chain receives a timeout from an oracle query +message EventOracleQueryTimeout { + // channel is the local channel that the oracle timeout was received from + string channel = 1; + // sequence_id is a unique identifier of the query + string sequence_id = 2; +} \ No newline at end of file diff --git a/proto/provenance/oracle/v1/genesis.proto b/proto/provenance/oracle/v1/genesis.proto new file mode 100644 index 0000000000..596b05daef --- /dev/null +++ b/proto/provenance/oracle/v1/genesis.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package provenance.oracle.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/provenance-io/provenance/x/oracle/types"; +option java_package = "io.provenance.oracle.v1"; +option java_multiple_files = true; + +// GenesisState defines the oracle module's genesis state. +message GenesisState { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + + // The port to assign to the module + string port_id = 2; + // The address of the oracle + string oracle = 3; +} \ No newline at end of file diff --git a/proto/provenance/oracle/v1/query.proto b/proto/provenance/oracle/v1/query.proto new file mode 100644 index 0000000000..d922616671 --- /dev/null +++ b/proto/provenance/oracle/v1/query.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; +package provenance.oracle.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos_proto/cosmos.proto"; + +option go_package = "github.com/provenance-io/provenance/x/oracle/types"; +option java_package = "io.provenance.oracle.v1"; +option java_multiple_files = true; + +// Query defines the gRPC querier service for oracle module. +service Query { + // OracleAddress returns the address of the oracle + rpc OracleAddress(QueryOracleAddressRequest) returns (QueryOracleAddressResponse) { + option (google.api.http).get = "/provenance/oracle/v1/oracle_address"; + } + + // Oracle forwards a query to the module's oracle + rpc Oracle(QueryOracleRequest) returns (QueryOracleResponse) { + option (google.api.http).get = "/provenance/oracle/v1/oracle"; + } +} + +// QueryOracleAddressRequest queries for the address of the oracle. +message QueryOracleAddressRequest {} + +// QueryOracleAddressResponse contains the address of the oracle. +message QueryOracleAddressResponse { + // The address of the oracle + string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// QueryOracleRequest queries the module's oracle. +message QueryOracleRequest { + // Query contains the query data passed to the oracle. + bytes query = 1 [(gogoproto.casttype) = "github.com/CosmWasm/wasmd/x/wasm/types.RawContractMessage"]; +} + +// QueryOracleResponse contains the result of the query sent to the oracle. +message QueryOracleResponse { + // Data contains the json data returned from the oracle. + bytes data = 1 [(gogoproto.casttype) = "github.com/CosmWasm/wasmd/x/wasm/types.RawContractMessage"]; +} \ No newline at end of file diff --git a/proto/provenance/oracle/v1/tx.proto b/proto/provenance/oracle/v1/tx.proto new file mode 100644 index 0000000000..ff1a03d0f6 --- /dev/null +++ b/proto/provenance/oracle/v1/tx.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; +package provenance.oracle.v1; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/provenance-io/provenance/x/oracle/types"; +option java_package = "io.provenance.oracle.v1"; +option java_multiple_files = true; + +// Msg +service Msg { + // UpdateOracle is the RPC endpoint for updating the oracle + rpc UpdateOracle(MsgUpdateOracleRequest) returns (MsgUpdateOracleResponse); + // SendQueryOracle sends a query to an oracle on another chain + rpc SendQueryOracle(MsgSendQueryOracleRequest) returns (MsgSendQueryOracleResponse); +} + +// MsgSendQueryOracleRequest queries an oracle on another chain +message MsgSendQueryOracleRequest { + // Query contains the query data passed to the oracle. + bytes query = 1 [(gogoproto.casttype) = "github.com/CosmWasm/wasmd/x/wasm/types.RawContractMessage"]; + // Channel is the channel to the oracle. + string channel = 3; + // The signing authority for the request + string authority = 4 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// MsgSendQueryOracleResponse contains the id of the oracle query. +message MsgSendQueryOracleResponse { + // The sequence number that uniquely identifies the query. + uint64 sequence = 1; +} + +// MsgUpdateOracleRequest is the request type for updating an oracle's contract address +message MsgUpdateOracleRequest { + option (gogoproto.equal) = true; + option (gogoproto.goproto_stringer) = true; + + // The address of the oracle's contract + string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // The signing authorities for the request + string authority = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// MsgUpdateOracleResponse is the response type for updating the oracle. +message MsgUpdateOracleResponse {} \ No newline at end of file diff --git a/x/oracle/client/cli/cli_test.go b/x/oracle/client/cli/cli_test.go new file mode 100644 index 0000000000..fd36b1cfd6 --- /dev/null +++ b/x/oracle/client/cli/cli_test.go @@ -0,0 +1,294 @@ +package cli_test + +import ( + "fmt" + "testing" + + tmcli "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/stretchr/testify/suite" + + "github.com/provenance-io/provenance/internal/antewrapper" + "github.com/provenance-io/provenance/internal/pioconfig" + "github.com/provenance-io/provenance/testutil" + oraclecli "github.com/provenance-io/provenance/x/oracle/client/cli" + "github.com/provenance-io/provenance/x/oracle/types" + oracletypes "github.com/provenance-io/provenance/x/oracle/types" +) + +type IntegrationTestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + keyring keyring.Keyring + keyringDir string + + accountAddr sdk.AccAddress + accountKey *secp256k1.PrivKey + accountAddresses []sdk.AccAddress + + port string + oracle string +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + pioconfig.SetProvenanceConfig("", 0) + s.accountKey = secp256k1.GenPrivKeyFromSecret([]byte("acc2")) + addr, err := sdk.AccAddressFromHexUnsafe(s.accountKey.PubKey().Address().String()) + s.Require().NoError(err) + s.accountAddr = addr + + s.cfg = testutil.DefaultTestNetworkConfig() + genesisState := s.cfg.GenesisState + + s.cfg.NumValidators = 1 + s.GenerateAccountsWithKeyrings(2) + + var genBalances []banktypes.Balance + for i := range s.accountAddresses { + genBalances = append(genBalances, banktypes.Balance{Address: s.accountAddresses[i].String(), Coins: sdk.NewCoins( + sdk.NewCoin("nhash", sdk.NewInt(100000000)), sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(100000000)), + ).Sort()}) + } + var bankGenState banktypes.GenesisState + bankGenState.Params = banktypes.DefaultParams() + bankGenState.Balances = genBalances + bankDataBz, err := s.cfg.Codec.MarshalJSON(&bankGenState) + s.Require().NoError(err, "should be able to marshal bank genesis state when setting up suite") + genesisState[banktypes.ModuleName] = bankDataBz + + var authData authtypes.GenesisState + var genAccounts []authtypes.GenesisAccount + authData.Params = authtypes.DefaultParams() + genAccounts = append(genAccounts, authtypes.NewBaseAccount(s.accountAddresses[0], nil, 3, 0)) + genAccounts = append(genAccounts, authtypes.NewBaseAccount(s.accountAddresses[1], nil, 4, 0)) + accounts, err := authtypes.PackAccounts(genAccounts) + s.Require().NoError(err, "should be able to pack accounts for genesis state when setting up suite") + authData.Accounts = accounts + authDataBz, err := s.cfg.Codec.MarshalJSON(&authData) + s.Require().NoError(err, "should be able to marshal auth genesis state when setting up suite") + genesisState[authtypes.ModuleName] = authDataBz + + s.port = oracletypes.PortID + s.oracle = "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma" + + oracleData := oracletypes.NewGenesisState( + s.port, + s.oracle, + ) + + oracleDataBz, err := s.cfg.Codec.MarshalJSON(oracleData) + s.Require().NoError(err, "should be able to marshal trigger genesis state when setting up suite") + genesisState[oracletypes.ModuleName] = oracleDataBz + + s.cfg.GenesisState = genesisState + + s.cfg.ChainID = antewrapper.SimAppChainID + + s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) + s.Require().NoError(err, "network.New") + + _, err = s.network.WaitForHeight(6) + s.Require().NoError(err, "WaitForHeight") +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) GenerateAccountsWithKeyrings(number int) { + path := hd.CreateHDPath(118, 0, 0).String() + s.keyringDir = s.T().TempDir() + kr, err := keyring.New(s.T().Name(), "test", s.keyringDir, nil, s.cfg.Codec) + s.Require().NoError(err, "Keyring.New") + s.keyring = kr + for i := 0; i < number; i++ { + keyId := fmt.Sprintf("test_key%v", i) + info, _, err := kr.NewMnemonic(keyId, keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err, "Keyring.NewMneomonic") + addr, err := info.GetAddress() + if err != nil { + panic(err) + } + s.accountAddresses = append(s.accountAddresses, addr) + } +} + +func (s *IntegrationTestSuite) TestQueryOracleAddress() { + testCases := []struct { + name string + expectErrMsg string + expectedCode uint32 + expectedAddress string + }{ + { + name: "success - query for oracle address", + expectedAddress: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + expectedCode: 0, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + clientCtx := s.network.Validators[0].ClientCtx + out, err := clitestutil.ExecTestCLICmd(clientCtx, oraclecli.GetQueryOracleAddressCmd(), []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}) + if len(tc.expectErrMsg) > 0 { + s.EqualError(err, tc.expectErrMsg, "should have correct error message for invalid QueryOracleAddress") + } else { + var response types.QueryOracleAddressResponse + s.NoError(err, "should have no error message for valid QueryOracleAddress") + err = s.cfg.Codec.UnmarshalJSON(out.Bytes(), &response) + s.NoError(err, "should have no error message when unmarshalling response to QueryOracleAddress") + s.Equal(tc.expectedAddress, response.Address, "should have the correct oracle address") + } + }) + } +} + +func (s *IntegrationTestSuite) TestOracleUpdate() { + testCases := []struct { + name string + address string + expectErrMsg string + expectedCode uint32 + signer string + }{ + { + name: "success - address updated", + address: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + expectedCode: 0, + signer: s.accountAddresses[0].String(), + }, + { + name: "failure - unable to pass validate basic with bad address", + address: "badaddress", + expectErrMsg: "msg: 0, err: invalid address for oracle: decoding bech32 failed: invalid separator index -1: invalid proposal message", + signer: s.accountAddresses[0].String(), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + clientCtx := s.network.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + + args := []string{ + tc.address, + } + flags := []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, tc.signer), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + } + args = append(args, flags...) + + out, err := clitestutil.ExecTestCLICmd(clientCtx, oraclecli.GetCmdOracleUpdate(), append(args, []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}...)) + var response sdk.TxResponse + marshalErr := clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response) + if len(tc.expectErrMsg) > 0 { + s.Assert().EqualError(err, tc.expectErrMsg, "should have correct error for invalid OracleUpdate request") + s.Assert().Equal(tc.expectedCode, response.Code, "should have correct response code for invalid OracleUpdate request") + } else { + s.Assert().NoError(err, "should have no error for valid OracleUpdate request") + s.Assert().NoError(marshalErr, out.String(), "should have no marshal error for valid OracleUpdate request") + s.Assert().Equal(tc.expectedCode, response.Code, "should have correct response code for valid OracleUpdate request") + } + }) + } +} + +func (s *IntegrationTestSuite) TestSendQuery() { + testCases := []struct { + name string + query string + channel string + expectErrMsg string + expectedCode uint32 + signer string + }{ + { + name: "success - a valid message was attempted to be sent on ibc", + query: "{}", + channel: "channel-1", + expectedCode: 9, + signer: s.accountAddresses[0].String(), + }, + { + name: "failure - invalid query data", + query: "abc", + expectErrMsg: "query data must be json", + channel: "channel-1", + signer: s.accountAddresses[0].String(), + }, + { + name: "failure - invalid channel format", + query: "{}", + expectErrMsg: "invalid channel id", + channel: "a", + signer: s.accountAddresses[0].String(), + }, + { + name: "failure - invalid signer", + query: "{}", + expectErrMsg: "abc.info: key not found", + channel: "channel-1", + signer: "abc", + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + clientCtx := s.network.Validators[0].ClientCtx.WithKeyringDir(s.keyringDir).WithKeyring(s.keyring) + + args := []string{ + tc.channel, + tc.query, + } + flags := []string{ + fmt.Sprintf("--%s=%s", flags.FlagFrom, tc.signer), + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + } + args = append(args, flags...) + + out, err := clitestutil.ExecTestCLICmd(clientCtx, oraclecli.GetCmdSendQuery(), append(args, []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}...)) + var response sdk.TxResponse + marshalErr := clientCtx.Codec.UnmarshalJSON(out.Bytes(), &response) + if len(tc.expectErrMsg) > 0 { + s.Assert().EqualError(err, tc.expectErrMsg, "should have correct error for invalid SendQuery request") + s.Assert().Equal(tc.expectedCode, response.Code, "should have correct response code for invalid SendQuery request") + } else { + s.Assert().NoError(err, "should have no error for valid SendQuery request") + s.Assert().NoError(marshalErr, out.String(), "should have no marshal error for valid SendQuery request") + s.Assert().Equal(tc.expectedCode, response.Code, "should have correct response code for valid SendQuery request") + } + }) + } +} diff --git a/x/oracle/client/cli/query.go b/x/oracle/client/cli/query.go new file mode 100644 index 0000000000..29ea90e673 --- /dev/null +++ b/x/oracle/client/cli/query.go @@ -0,0 +1,61 @@ +package cli + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// GetQueryCmd is the top-level command for oracle CLI queries. +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the oracle module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + queryCmd.AddCommand( + GetQueryOracleAddressCmd(), + ) + return queryCmd +} + +// GetQueryOracleAddressCmd queries for the module's oracle address +func GetQueryOracleAddressCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "address", + Short: "Returns the address of the module's oracle", + Args: cobra.ExactArgs(0), + Aliases: []string{"a"}, + Example: fmt.Sprintf(`%[1]s q oracle address`, version.AppName), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryOracleAddressRequest{} + + res, err := queryClient.OracleAddress(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/oracle/client/cli/tx.go b/x/oracle/client/cli/tx.go new file mode 100644 index 0000000000..ff1a63f0d3 --- /dev/null +++ b/x/oracle/client/cli/tx.go @@ -0,0 +1,119 @@ +package cli + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + sdktx "github.com/cosmos/cosmos-sdk/types/tx" + "github.com/cosmos/cosmos-sdk/version" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// NewTxCmd is the top-level command for oracle CLI transactions. +func NewTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Aliases: []string{"t"}, + Short: "Transaction commands for the oracle module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + GetCmdSendQuery(), + GetCmdOracleUpdate(), + ) + + return txCmd +} + +// GetCmdOracleUpdate is a command to update the address of the module's oracle +func GetCmdOracleUpdate() *cobra.Command { + cmd := &cobra.Command{ + Use: "update
", + Short: "Update the module's oracle address", + Long: "Submit an update oracle via governance proposal along with an initial deposit.", + Args: cobra.ExactArgs(1), + Aliases: []string{"u"}, + Example: fmt.Sprintf(`%[1]s tx oracle update pb1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk --deposit 50000nhash`, version.AppName), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + + msg := types.NewMsgUpdateOracle( + authority.String(), + args[0], + ) + + proposal, govErr := govcli.ReadGovPropFlags(clientCtx, cmd.Flags()) + if govErr != nil { + return govErr + } + proposal.Messages, govErr = sdktx.SetMsgs([]sdk.Msg{msg}) + if govErr != nil { + return govErr + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposal) + }, + } + + govcli.AddGovPropFlagsToCmd(cmd) + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// GetCmdSendQuery is a command to send a query to another chain's oracle +func GetCmdSendQuery() *cobra.Command { + cmd := &cobra.Command{ + Use: "send-query ", + Short: "Send a query to an oracle on a remote chain via IBC", + Args: cobra.ExactArgs(2), + Aliases: []string{"sq"}, + Example: fmt.Sprintf(`%[1]s tx oracle send-query channel-1 '{"query_version":{}}'`, version.AppName), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + channelID := args[0] + + queryData := []byte(args[1]) + if !json.Valid(queryData) { + return errors.New("query data must be json") + } + + msg := types.NewMsgSendQueryOracle( + clientCtx.GetFromAddress().String(), + channelID, + queryData, + ) + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/oracle/keeper/genesis.go b/x/oracle/keeper/genesis.go new file mode 100644 index 0000000000..1f1044fe67 --- /dev/null +++ b/x/oracle/keeper/genesis.go @@ -0,0 +1,39 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// ExportGenesis returns a GenesisState for a given context. +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + oracle, _ := k.GetOracle(ctx) + return &types.GenesisState{ + PortId: k.GetPort(ctx), + Oracle: oracle.String(), + } +} + +// InitGenesis new oracle genesis +func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { + if err := genState.Validate(); err != nil { + panic(err) + } + + k.SetPort(ctx, genState.PortId) + if !k.IsBound(ctx, genState.PortId) { + err := k.BindPort(ctx, genState.PortId) + if err != nil { + panic("could not claim port capability: " + err.Error()) + } + } + + var oracle sdk.AccAddress + if len(genState.Oracle) == 0 { + oracle = sdk.AccAddress{} + } else { + oracle = sdk.MustAccAddressFromBech32(genState.Oracle) + } + k.SetOracle(ctx, oracle) +} diff --git a/x/oracle/keeper/genesis_test.go b/x/oracle/keeper/genesis_test.go new file mode 100644 index 0000000000..ad4136331c --- /dev/null +++ b/x/oracle/keeper/genesis_test.go @@ -0,0 +1,62 @@ +package keeper_test + +import ( + "github.com/provenance-io/provenance/x/oracle/types" +) + +func (s *KeeperTestSuite) TestExportGenesis() { + genesis := s.app.OracleKeeper.ExportGenesis(s.ctx) + s.Assert().Equal("oracle", genesis.PortId, "should export the correct port") + s.Assert().Equal("", genesis.Oracle, "should export the correct oracle address") +} + +func (s *KeeperTestSuite) TestInitGenesis() { + tests := []struct { + name string + genesis *types.GenesisState + err string + mockPort bool + }{ + { + name: "success - valid genesis state", + genesis: types.NewGenesisState("jackthecat", "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma"), + }, + { + name: "success - valid genesis state with empty oracle", + genesis: types.NewGenesisState("jackthecat", ""), + }, + { + name: "failure - invalid port", + genesis: types.NewGenesisState("", ""), + err: "identifier cannot be blank: invalid identifier", + }, + { + name: "failure - invalid oracle", + genesis: types.NewGenesisState("jackthecat", "abc"), + err: "decoding bech32 failed: invalid bech32 string length 3", + }, + { + name: "success - works with existing port", + genesis: types.NewGenesisState("oracle", ""), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if tc.mockPort { + s.app.OracleKeeper.BindPort(s.ctx, "test") + } + if len(tc.err) > 0 { + s.Assert().PanicsWithError(tc.err, func() { + s.app.OracleKeeper.InitGenesis(s.ctx, tc.genesis) + }, "invalid init genesis should cause panic") + } else { + s.app.OracleKeeper.InitGenesis(s.ctx, tc.genesis) + oracle, _ := s.app.OracleKeeper.GetOracle(s.ctx) + s.Assert().Equal(tc.genesis.PortId, s.app.OracleKeeper.GetPort(s.ctx), "should correctly set the port") + s.Assert().True(s.app.OracleKeeper.IsBound(s.ctx, tc.genesis.PortId), "should bind the port") + s.Assert().Equal(tc.genesis.Oracle, oracle.String(), "should get the correct oracle address") + } + }) + } +} diff --git a/x/oracle/keeper/icq.go b/x/oracle/keeper/icq.go new file mode 100644 index 0000000000..1845db6ff4 --- /dev/null +++ b/x/oracle/keeper/icq.go @@ -0,0 +1,45 @@ +package keeper + +import ( + "time" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + + abcitypes "github.com/tendermint/tendermint/abci/types" + + cerrs "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// QueryOracle sends an ICQ to the other chain's module +func (k Keeper) QueryOracle(ctx sdk.Context, query wasmtypes.RawContractMessage, channel string) (uint64, error) { + chanCap, found := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(k.GetPort(ctx), channel)) + if !found { + return 0, cerrs.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + + q := types.QueryOracleRequest{ + Query: query, + } + + reqs := []abcitypes.RequestQuery{ + { + Path: "/provenance.oracle.v1.Query/Oracle", + Data: k.cdc.MustMarshal(&q), + }, + } + + timeoutTimestamp := ctx.BlockTime().Add(time.Minute).UnixNano() + seq, err := k.SendQuery(ctx, types.PortID, channel, chanCap, reqs, clienttypes.ZeroHeight(), uint64(timeoutTimestamp)) + if err != nil { + return 0, err + } + + return seq, nil +} diff --git a/x/oracle/keeper/icq_test.go b/x/oracle/keeper/icq_test.go new file mode 100644 index 0000000000..cde6f6e8ce --- /dev/null +++ b/x/oracle/keeper/icq_test.go @@ -0,0 +1,68 @@ +package keeper_test + +import ( + "github.com/provenance-io/provenance/x/oracle/keeper" +) + +func (s *KeeperTestSuite) TestQueryOracle() { + tests := []struct { + name string + query []byte + channel string + sequence uint64 + err string + scopeMock bool + channelMock bool + ics4Mock bool + }{ + { + name: "failure - missing channel capability", + query: []byte("{}"), + channel: "invalid", + sequence: 0, + err: "module does not own channel capability: channel capability not found", + }, + { + name: "failure - unable to send", + query: []byte("{}"), + channel: "channel-1", + sequence: 0, + err: "channel-1: channel not found", + scopeMock: true, + channelMock: true, + }, + { + name: "success - should send a packet", + query: []byte("{}"), + channel: "channel-1", + sequence: 1, + scopeMock: true, + channelMock: true, + ics4Mock: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if tc.scopeMock { + s.app.OracleKeeper = s.app.OracleKeeper.WithMockScopedKeeper(keeper.MockScopedKeeper{}) + } + if tc.channelMock { + s.app.OracleKeeper = s.app.OracleKeeper.WithMockChannelKeeper(&keeper.MockChannelKeeper{}) + } + if tc.ics4Mock { + s.app.OracleKeeper = s.app.OracleKeeper.WithMockICS4Wrapper(&keeper.MockICS4Wrapper{}) + } + sequence, err := s.app.OracleKeeper.QueryOracle(s.ctx, tc.query, tc.channel) + s.Assert().Equal(int(tc.sequence), int(sequence), "should have correct sequence") + if len(tc.err) > 0 { + s.Assert().EqualError(err, tc.err, "should have the correct error") + + } else { + s.Assert().Nil(err, "should have nil error") + s.Assert().Equal(int(tc.sequence), int(sequence), "should have correct sequence") + } + + }) + } +} diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go new file mode 100644 index 0000000000..de8c6d8a87 --- /dev/null +++ b/x/oracle/keeper/keeper.go @@ -0,0 +1,100 @@ +package keeper + +import ( + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +type Keeper struct { + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + memKey storetypes.StoreKey + + ics4Wrapper types.ICS4Wrapper + channelKeeper types.ChannelKeeper + portKeeper types.PortKeeper + scopedKeeper types.ScopedKeeper + wasmQueryServer wasmtypes.QueryServer + + // the signing authority for the gov proposals + authority string +} + +func NewKeeper( + cdc codec.BinaryCodec, + storeKey, + memKey storetypes.StoreKey, + ics4Wrapper types.ICS4Wrapper, + channelKeeper types.ChannelKeeper, + portKeeper types.PortKeeper, + scopedKeeper types.ScopedKeeper, + wasmQueryServer wasmtypes.QueryServer, +) *Keeper { + return &Keeper{ + storeKey: storeKey, + cdc: cdc, + memKey: memKey, + + ics4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + portKeeper: portKeeper, + scopedKeeper: scopedKeeper, + wasmQueryServer: wasmQueryServer, + authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(), + } +} + +// Logger returns the correctly named logger for the module +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", "x/"+types.ModuleName) +} + +// BindPort stores the provided portID and binds to it +func (k Keeper) BindPort(ctx sdk.Context, portID string) error { + capability := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, capability, host.PortPath(portID)) +} + +// IsBound checks if the interchain query already bound to the desired port +func (k Keeper) IsBound(ctx sdk.Context, portID string) bool { + _, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID)) + return ok +} + +// GetPort returns the portID for the transfer module. Used in ExportGenesis +func (k Keeper) GetPort(ctx sdk.Context) string { + store := ctx.KVStore(k.storeKey) + return string(store.Get(types.GetPortStoreKey())) +} + +// SetPort sets the portID for the transfer module. Used in InitGenesis +func (k Keeper) SetPort(ctx sdk.Context, portID string) { + store := ctx.KVStore(k.storeKey) + store.Set(types.GetPortStoreKey(), []byte(portID)) +} + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, capability *capabilitytypes.Capability, name string) bool { + return k.scopedKeeper.AuthenticateCapability(ctx, capability, name) +} + +// ClaimCapability wraps the scopedKeeper's ClaimCapability function +func (k Keeper) ClaimCapability(ctx sdk.Context, capability *capabilitytypes.Capability, name string) error { + return k.scopedKeeper.ClaimCapability(ctx, capability, name) +} + +// GetAuthority returns the module's authority address +func (k Keeper) GetAuthority() string { + return k.authority +} diff --git a/x/oracle/keeper/keeper_test.go b/x/oracle/keeper/keeper_test.go new file mode 100644 index 0000000000..cf82a3cba9 --- /dev/null +++ b/x/oracle/keeper/keeper_test.go @@ -0,0 +1,60 @@ +package keeper_test + +import ( + "fmt" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/provenance-io/provenance/app" + simapp "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/x/oracle/keeper" + "github.com/provenance-io/provenance/x/oracle/types" + "github.com/stretchr/testify/suite" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" +) + +type KeeperTestSuite struct { + suite.Suite + + app *simapp.App + ctx sdk.Context + queryClient types.QueryClient + msgServer types.MsgServer + + accountAddr sdk.AccAddress + accountKey *secp256k1.PrivKey + keyring keyring.Keyring + keyringDir string + accountAddresses []sdk.AccAddress +} + +func (s *KeeperTestSuite) CreateAccounts(number int) { + for i := 0; i < number; i++ { + accountKey := secp256k1.GenPrivKeyFromSecret([]byte(fmt.Sprintf("acc%d", i+2))) + addr, err := sdk.AccAddressFromHexUnsafe(accountKey.PubKey().Address().String()) + s.Require().NoError(err) + s.accountAddr = addr + s.accountAddresses = append(s.accountAddresses, addr) + } +} + +func (s *KeeperTestSuite) SetupTest() { + s.app = app.Setup(s.T()) + s.CreateAccounts(4) + s.msgServer = keeper.NewMsgServerImpl(&s.app.OracleKeeper) + s.ctx = s.app.BaseApp.NewContext(false, tmproto.Header{Time: time.Now().UTC()}) + s.ctx = s.ctx.WithBlockHeight(100) + + queryHelper := baseapp.NewQueryServerTestHelper(s.ctx, s.app.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, s.app.OracleKeeper) + s.queryClient = types.NewQueryClient(queryHelper) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/oracle/keeper/mocks_test.go b/x/oracle/keeper/mocks_test.go new file mode 100644 index 0000000000..06719d7eda --- /dev/null +++ b/x/oracle/keeper/mocks_test.go @@ -0,0 +1,129 @@ +package keeper + +import ( + "context" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + "github.com/provenance-io/provenance/x/oracle/types" +) + +// This file is available only to unit tests and exposes private things +// so that they can be used in unit tests. + +type MockWasmServer struct { +} + +func (k Keeper) WithWasmQueryServer(server wasmtypes.QueryServer) Keeper { + k.wasmQueryServer = server + return k +} + +func (m MockWasmServer) ContractInfo(context.Context, *wasmtypes.QueryContractInfoRequest) (*wasmtypes.QueryContractInfoResponse, error) { + return nil, nil +} + +func (m MockWasmServer) ContractHistory(context.Context, *wasmtypes.QueryContractHistoryRequest) (*wasmtypes.QueryContractHistoryResponse, error) { + return nil, nil +} + +func (m MockWasmServer) ContractsByCode(context.Context, *wasmtypes.QueryContractsByCodeRequest) (*wasmtypes.QueryContractsByCodeResponse, error) { + return nil, nil +} + +func (m MockWasmServer) AllContractState(context.Context, *wasmtypes.QueryAllContractStateRequest) (*wasmtypes.QueryAllContractStateResponse, error) { + return nil, nil +} + +func (m MockWasmServer) RawContractState(context.Context, *wasmtypes.QueryRawContractStateRequest) (*wasmtypes.QueryRawContractStateResponse, error) { + return nil, nil +} + +func (m MockWasmServer) SmartContractState(context.Context, *wasmtypes.QuerySmartContractStateRequest) (*wasmtypes.QuerySmartContractStateResponse, error) { + return &wasmtypes.QuerySmartContractStateResponse{ + Data: []byte("{}"), + }, nil +} + +func (m MockWasmServer) Code(context.Context, *wasmtypes.QueryCodeRequest) (*wasmtypes.QueryCodeResponse, error) { + return nil, nil +} + +func (m MockWasmServer) Codes(context.Context, *wasmtypes.QueryCodesRequest) (*wasmtypes.QueryCodesResponse, error) { + return nil, nil +} + +func (m MockWasmServer) PinnedCodes(context.Context, *wasmtypes.QueryPinnedCodesRequest) (*wasmtypes.QueryPinnedCodesResponse, error) { + return nil, nil +} + +func (m MockWasmServer) Params(context.Context, *wasmtypes.QueryParamsRequest) (*wasmtypes.QueryParamsResponse, error) { + return nil, nil +} + +func (m MockWasmServer) ContractsByCreator(context.Context, *wasmtypes.QueryContractsByCreatorRequest) (*wasmtypes.QueryContractsByCreatorResponse, error) { + return nil, nil +} + +type MockICS4Wrapper struct { + counter uint64 +} + +func (k Keeper) WithMockICS4Wrapper(ics4wrapper types.ICS4Wrapper) Keeper { + k.ics4Wrapper = ics4wrapper + return k +} + +func (k MockICS4Wrapper) SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, +) (sequence uint64, err error) { + k.counter += 1 + return k.counter, nil +} + +type MockChannelKeeper struct { + counter uint64 +} + +func (k Keeper) WithMockChannelKeeper(channelKeeper types.ChannelKeeper) Keeper { + k.channelKeeper = channelKeeper + return k +} + +func (m *MockChannelKeeper) GetChannel(ctx sdk.Context, portID, channelID string) (channeltypes.Channel, bool) { + return channeltypes.Channel{}, true +} + +func (m *MockChannelKeeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) { + m.counter += 1 + return m.counter, true +} + +type MockScopedKeeper struct { +} + +func (k Keeper) WithMockScopedKeeper(scopedKeeper types.ScopedKeeper) Keeper { + k.scopedKeeper = scopedKeeper + return k +} + +func (m MockScopedKeeper) GetCapability(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) { + return &capabilitytypes.Capability{}, true +} + +func (m MockScopedKeeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return true +} + +func (m MockScopedKeeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return nil +} diff --git a/x/oracle/keeper/msg_server.go b/x/oracle/keeper/msg_server.go new file mode 100644 index 0000000000..106dcc3333 --- /dev/null +++ b/x/oracle/keeper/msg_server.go @@ -0,0 +1,63 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +type msgServer struct { + *Keeper +} + +// NewMsgServerImpl returns an implementation of the account MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper *Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +// UpdateOracle changes the oracle's address to the provided one +func (s msgServer) UpdateOracle(goCtx context.Context, msg *types.MsgUpdateOracleRequest) (*types.MsgUpdateOracleResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if msg.Authority != s.Keeper.GetAuthority() { + return nil, sdkerrors.ErrUnauthorized.Wrapf("expected authority %s got %s", s.Keeper.GetAuthority(), msg.GetAuthority()) + } + + s.Keeper.SetOracle(ctx, sdk.MustAccAddressFromBech32(msg.Address)) + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + ) + + return &types.MsgUpdateOracleResponse{}, nil +} + +// SendQueryOracle sends an icq to another chain's oracle +func (s msgServer) SendQueryOracle(goCtx context.Context, msg *types.MsgSendQueryOracleRequest) (*types.MsgSendQueryOracleResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + seq, err := s.QueryOracle(ctx, msg.Query, msg.Channel) + if err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ), + ) + + return &types.MsgSendQueryOracleResponse{ + Sequence: seq, + }, nil +} diff --git a/x/oracle/keeper/msg_server_test.go b/x/oracle/keeper/msg_server_test.go new file mode 100644 index 0000000000..3397bac147 --- /dev/null +++ b/x/oracle/keeper/msg_server_test.go @@ -0,0 +1,136 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/provenance-io/provenance/x/oracle/keeper" + "github.com/provenance-io/provenance/x/oracle/types" +) + +func (s *KeeperTestSuite) TestUpdateOracle() { + authority := s.app.OracleKeeper.GetAuthority() + event := sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ) + + tests := []struct { + name string + req *types.MsgUpdateOracleRequest + res *types.MsgUpdateOracleResponse + event *sdk.Event + err string + }{ + { + name: "failure - authority does not match module authority", + req: &types.MsgUpdateOracleRequest{ + Address: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + Authority: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + }, + res: nil, + err: fmt.Sprintf("expected authority %s got cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma: unauthorized", authority), + }, + { + name: "success - oracle is updated", + req: &types.MsgUpdateOracleRequest{ + Address: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + Authority: authority, + }, + res: &types.MsgUpdateOracleResponse{}, + event: &event, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + res, err := s.msgServer.UpdateOracle(s.ctx, tc.req) + events := s.ctx.EventManager().Events() + numEvents := len(events) + + if tc.event != nil { + s.Assert().Equal(1, numEvents, "should emit the correct number of events") + s.Assert().Equal(*tc.event, events[0], "should emit the correct event") + } else { + s.Assert().Empty(events, "should not emit events") + } + + if len(tc.err) > 0 { + s.Assert().Nil(res, "should have nil response") + s.Assert().EqualError(err, tc.err, "should have correct error") + } else { + s.Assert().NoError(err, "should not have error") + s.Assert().Equal(tc.res, res, "should have the correct response") + } + }) + } +} + +func (s *KeeperTestSuite) TestSendQueryOracle() { + event := sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + ) + + s.app.OracleKeeper = s.app.OracleKeeper.WithMockICS4Wrapper(keeper.MockICS4Wrapper{}) + s.app.OracleKeeper = s.app.OracleKeeper.WithMockScopedKeeper(keeper.MockScopedKeeper{}) + + tests := []struct { + name string + req *types.MsgSendQueryOracleRequest + res *types.MsgSendQueryOracleResponse + event *sdk.Event + err string + mockChannel bool + }{ + { + name: "failure - a packet should not be sent on invalid channel", + req: &types.MsgSendQueryOracleRequest{ + Query: []byte("{}"), + Channel: "invalid-channel", + Authority: "authority", + }, + res: nil, + err: "port ID (oracle) channel ID (invalid-channel): channel not found", + }, + { + name: "success - a packet should be sent", + req: &types.MsgSendQueryOracleRequest{ + Query: []byte("{}"), + Channel: "channel-1", + Authority: "authority", + }, + res: &types.MsgSendQueryOracleResponse{ + Sequence: 1, + }, + event: &event, + mockChannel: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if tc.mockChannel { + s.app.OracleKeeper = s.app.OracleKeeper.WithMockChannelKeeper(&keeper.MockChannelKeeper{}) + } + res, err := s.msgServer.SendQueryOracle(s.ctx, tc.req) + events := s.ctx.EventManager().Events() + numEvents := len(events) + + if tc.event != nil { + s.Assert().Equal(1, numEvents, "should emit the correct number of events") + s.Assert().Equal(*tc.event, events[0], "should emit the correct event") + } else { + s.Assert().Empty(events, "should not emit events") + } + + if len(tc.err) > 0 { + s.Assert().Nil(res, "should have nil response") + s.Assert().EqualError(err, tc.err, "should have correct error") + } else { + s.Assert().NoError(err, "should not have error") + s.Assert().Equal(tc.res, res, "should have the correct response") + } + }) + } +} diff --git a/x/oracle/keeper/oracle.go b/x/oracle/keeper/oracle.go new file mode 100644 index 0000000000..94ecb24872 --- /dev/null +++ b/x/oracle/keeper/oracle.go @@ -0,0 +1,25 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// SetOracle Sets the oracle used by the module. +func (k Keeper) SetOracle(ctx sdk.Context, oracle sdk.AccAddress) { + store := ctx.KVStore(k.storeKey) + store.Set(types.GetOracleStoreKey(), oracle) +} + +// GetOracle Gets the oracle used by the module. +func (k Keeper) GetOracle(ctx sdk.Context) (oracle sdk.AccAddress, err error) { + store := ctx.KVStore(k.storeKey) + key := types.GetOracleStoreKey() + oracle = store.Get(key) + if len(oracle) == 0 { + return sdk.AccAddress{}, types.ErrMissingOracleAddress + } + + return oracle, err +} diff --git a/x/oracle/keeper/oracle_test.go b/x/oracle/keeper/oracle_test.go new file mode 100644 index 0000000000..545c244cf3 --- /dev/null +++ b/x/oracle/keeper/oracle_test.go @@ -0,0 +1,38 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *KeeperTestSuite) TestGetSetOracle() { + tests := []struct { + name string + address string + err string + }{ + { + name: "failure - address not set", + err: "missing oracle address", + }, + { + name: "success - address can be set", + address: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if len(tc.address) > 0 { + s.app.OracleKeeper.SetOracle(s.ctx, sdk.MustAccAddressFromBech32(tc.address)) + } + oracle, err := s.app.OracleKeeper.GetOracle(s.ctx) + + if len(tc.err) > 0 { + s.Assert().EqualError(err, tc.err, "should throw the correct error") + } else { + s.Assert().NoError(err, "should not throw an error") + s.Assert().Equal(tc.address, oracle.String(), "should get back the set address") + } + }) + } +} diff --git a/x/oracle/keeper/query_server.go b/x/oracle/keeper/query_server.go new file mode 100644 index 0000000000..c69b59ae49 --- /dev/null +++ b/x/oracle/keeper/query_server.go @@ -0,0 +1,47 @@ +package keeper + +import ( + "context" + + wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +var _ types.QueryServer = Keeper{} + +// QueryAddress returns the address of the module's oracle +func (k Keeper) OracleAddress(goCtx context.Context, _ *types.QueryOracleAddressRequest) (*types.QueryOracleAddressResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + oracle, _ := k.GetOracle(ctx) + return &types.QueryOracleAddressResponse{Address: oracle.String()}, nil +} + +// Oracle queries module's oracle +func (k Keeper) Oracle(goCtx context.Context, req *types.QueryOracleRequest) (*types.QueryOracleResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + if err := req.Query.ValidateBasic(); err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid query data") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + addr, err := k.GetOracle(ctx) + if err != nil { + return nil, err + } + query := &wasmtypes.QuerySmartContractStateRequest{ + Address: addr.String(), + QueryData: req.Query, + } + resp, err := k.wasmQueryServer.SmartContractState(ctx, query) + if err != nil { + return nil, err + } + return &types.QueryOracleResponse{Data: resp.Data}, nil +} diff --git a/x/oracle/keeper/query_server_test.go b/x/oracle/keeper/query_server_test.go new file mode 100644 index 0000000000..5a528810a9 --- /dev/null +++ b/x/oracle/keeper/query_server_test.go @@ -0,0 +1,128 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/provenance-io/provenance/x/oracle/keeper" + "github.com/provenance-io/provenance/x/oracle/types" +) + +func (s *KeeperTestSuite) TestOracleAddress() { + tests := []struct { + name string + req *types.QueryOracleAddressRequest + expected *types.QueryOracleAddressResponse + oracle string + err string + }{ + { + name: "failure - should handle nil request", + req: nil, + expected: &types.QueryOracleAddressResponse{Address: ""}, + }, + { + name: "success - should return correct oracle address", + req: &types.QueryOracleAddressRequest{}, + expected: &types.QueryOracleAddressResponse{Address: ""}, + }, + { + name: "success - should return correct oracle address", + req: &types.QueryOracleAddressRequest{}, + oracle: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + expected: &types.QueryOracleAddressResponse{Address: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma"}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if len(tc.oracle) > 0 { + s.app.OracleKeeper.SetOracle(s.ctx, sdk.MustAccAddressFromBech32(tc.oracle)) + } + resp, err := s.app.OracleKeeper.OracleAddress(s.ctx, tc.req) + if len(tc.err) > 0 { + s.Assert().EqualError(err, tc.err, "should return the correct error") + s.Assert().Nil(resp, "response should be nil") + } else { + s.Assert().NoError(err, "should not return an error") + s.Assert().Equal(tc.expected, resp, "should return the correct response") + } + }) + } +} + +func (s *KeeperTestSuite) TestOracle() { + tests := []struct { + name string + req *types.QueryOracleRequest + expected *types.QueryOracleResponse + oracle string + mockEnabled bool + err string + }{ + { + name: "failure - should handle nil request", + req: nil, + err: "rpc error: code = InvalidArgument desc = invalid request", + }, + { + name: "failure - should handle invalid query data", + req: &types.QueryOracleRequest{ + Query: []byte("abc"), + }, + err: "rpc error: code = InvalidArgument desc = invalid query data", + }, + { + name: "failure - should handle unset oracle", + req: &types.QueryOracleRequest{ + Query: []byte("{}"), + }, + err: "missing oracle address", + }, + { + name: "failure - should handle error from contract", + req: &types.QueryOracleRequest{ + Query: []byte("{}"), + }, + err: "missing oracle address", + }, + { + name: "failure - should handle error from contract", + req: &types.QueryOracleRequest{ + Query: []byte("{}"), + }, + oracle: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + err: "contract: not found", + }, + { + name: "success - should handle response from contract", + req: &types.QueryOracleRequest{ + Query: []byte("{}"), + }, + oracle: "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", + expected: &types.QueryOracleResponse{ + Data: []byte("{}"), + }, + mockEnabled: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if tc.mockEnabled { + s.app.OracleKeeper = s.app.OracleKeeper.WithWasmQueryServer(keeper.MockWasmServer{}) + } + + if len(tc.oracle) > 0 { + s.app.OracleKeeper.SetOracle(s.ctx, sdk.MustAccAddressFromBech32(tc.oracle)) + } + + resp, err := s.app.OracleKeeper.Oracle(s.ctx, tc.req) + if len(tc.err) > 0 { + s.Assert().EqualError(err, tc.err, "should return the correct error") + s.Assert().Nil(resp, "response should be nil") + } else { + s.Assert().NoError(err, "should not return an error") + s.Assert().Equal(tc.expected, resp, "should return the correct response") + } + }) + } +} diff --git a/x/oracle/keeper/relay.go b/x/oracle/keeper/relay.go new file mode 100644 index 0000000000..22be438729 --- /dev/null +++ b/x/oracle/keeper/relay.go @@ -0,0 +1,161 @@ +package keeper + +import ( + "strconv" + + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" + + abci "github.com/tendermint/tendermint/abci/types" + + cerrs "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// SendQuery sends and records an icq +func (k Keeper) SendQuery( + ctx sdk.Context, + sourcePort, + sourceChannel string, + chanCap *capabilitytypes.Capability, + reqs []abci.RequestQuery, + _ clienttypes.Height, + timeoutTimestamp uint64, +) (uint64, error) { + sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel) + if !found { + return 0, cerrs.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", sourcePort, sourceChannel) + } + + destinationPort := sourceChannelEnd.GetCounterparty().GetPortID() + destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID() + + data, err := icqtypes.SerializeCosmosQuery(reqs) + if err != nil { + return 0, cerrs.Wrap(err, "could not serialize reqs into cosmos query") + } + icqPacketData := icqtypes.InterchainQueryPacketData{ + Data: data, + } + + return k.createOutgoingPacket(ctx, sourcePort, sourceChannel, destinationPort, destinationChannel, chanCap, icqPacketData, timeoutTimestamp) +} + +func (k Keeper) createOutgoingPacket( + ctx sdk.Context, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel string, + chanCap *capabilitytypes.Capability, + icqPacketData icqtypes.InterchainQueryPacketData, + timeoutTimestamp uint64, +) (uint64, error) { + if err := icqPacketData.ValidateBasic(); err != nil { + return 0, cerrs.Wrap(err, "invalid interchain query packet data") + } + + // get the next sequence + sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel) + if !found { + return 0, cerrs.Wrapf(channeltypes.ErrSequenceSendNotFound, "failed to retrieve next sequence send for channel %s on port %s", sourceChannel, sourcePort) + } + + packet := channeltypes.NewPacket( + icqPacketData.GetBytes(), + sequence, + sourcePort, + sourceChannel, + destinationPort, + destinationChannel, + clienttypes.ZeroHeight(), + timeoutTimestamp, + ) + + if _, err := k.ics4Wrapper.SendPacket(ctx, chanCap, packet.SourcePort, packet.SourceChannel, packet.TimeoutHeight, packet.TimeoutTimestamp, packet.Data); err != nil { + return 0, err + } + + return packet.Sequence, nil +} + +// OnAcknowledgementPacket reacts to an Acknowledgement packet. +func (k Keeper) OnAcknowledgementPacket( + ctx sdk.Context, + modulePacket channeltypes.Packet, + ack channeltypes.Acknowledgement, +) error { + switch resp := ack.Response.(type) { + case *channeltypes.Acknowledgement_Result: + var ackData icqtypes.InterchainQueryPacketAck + if err := icqtypes.ModuleCdc.UnmarshalJSON(resp.Result, &ackData); err != nil { + return cerrs.Wrap(err, "failed to unmarshal interchain query packet ack") + } + resps, err := icqtypes.DeserializeCosmosResponse(ackData.Data) + if err != nil { + return cerrs.Wrap(err, "could not deserialize data to cosmos response") + } + + if len(resps) < 1 { + return cerrs.Wrap(sdkerrors.ErrInvalidRequest, "no responses in interchain query packet ack") + } + + var r types.QueryOracleResponse + if err = k.cdc.Unmarshal(resps[0].Value, &r); err != nil { + return cerrs.Wrapf(err, "failed to unmarshal interchain query response to type %T", resp) + } + + err = ctx.EventManager().EmitTypedEvent(&types.EventOracleQuerySuccess{ + SequenceId: strconv.FormatUint(modulePacket.Sequence, 10), + Result: string(resp.Result), + Channel: modulePacket.DestinationChannel, + }) + + k.Logger(ctx).Info("interchain query ack response", "sequence", modulePacket.Sequence, "response", r) + + if err != nil { + k.Logger(ctx).Error("interchain query ack response was unable to emit event", "sequence", modulePacket.Sequence, "error", err) + return err + } + case *channeltypes.Acknowledgement_Error: + err := ctx.EventManager().EmitTypedEvent(&types.EventOracleQueryError{ + SequenceId: strconv.FormatUint(modulePacket.Sequence, 10), + Error: resp.Error, + Channel: modulePacket.DestinationChannel, + }) + + k.Logger(ctx).Error("interchain query ack error response", "sequence", modulePacket.Sequence, "error", resp.Error) + + if err != nil { + k.Logger(ctx).Error("interchain query ack error response was unable to emit event", "sequence", modulePacket.Sequence, "error", err) + return err + } + } + return nil +} + +// OnTimeoutPacket reacts to a timed out packet. +func (k Keeper) OnTimeoutPacket( + ctx sdk.Context, + modulePacket channeltypes.Packet, +) error { + err := ctx.EventManager().EmitTypedEvent(&types.EventOracleQueryTimeout{ + SequenceId: strconv.FormatUint(modulePacket.Sequence, 10), + Channel: modulePacket.DestinationChannel, + }) + + k.Logger(ctx).Error("Packet timeout", "sequence", modulePacket.Sequence) + + if err != nil { + k.Logger(ctx).Error("interchain query timeout was unable to emit event", "sequence", modulePacket.Sequence, "error", err) + return err + } + + return nil +} diff --git a/x/oracle/keeper/relay_test.go b/x/oracle/keeper/relay_test.go new file mode 100644 index 0000000000..492d7e8ac6 --- /dev/null +++ b/x/oracle/keeper/relay_test.go @@ -0,0 +1,194 @@ +package keeper_test + +import ( + "fmt" + "strconv" + + "github.com/cosmos/cosmos-sdk/codec" + sdktypes "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + proto "github.com/gogo/protobuf/proto" + "github.com/provenance-io/provenance/x/oracle/keeper" + "github.com/provenance-io/provenance/x/oracle/types" + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" + abci "github.com/tendermint/tendermint/abci/types" +) + +func (s *KeeperTestSuite) TestSendQuery() { + tests := []struct { + name string + err string + sequence uint64 + req []abci.RequestQuery + enableMocks bool + }{ + { + name: "failure - invalid channel", + err: "port ID (port) channel ID (channel): channel not found", + sequence: 0, + req: nil, + }, + { + name: "success - valid send query", + sequence: 1, + req: []abci.RequestQuery{{Data: []byte("{}")}}, + enableMocks: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + if tc.enableMocks { + s.app.OracleKeeper = s.app.OracleKeeper.WithMockChannelKeeper(&keeper.MockChannelKeeper{}) + s.app.OracleKeeper = s.app.OracleKeeper.WithMockICS4Wrapper(&keeper.MockICS4Wrapper{}) + } + sequence, err := s.app.OracleKeeper.SendQuery(s.ctx, "port", "channel", nil, tc.req, clienttypes.ZeroHeight(), 0) + if len(tc.err) > 0 { + s.Assert().Equal(int(tc.sequence), int(sequence), "should have correct sequence number") + s.Assert().EqualError(err, tc.err, "should have correct error") + } else { + s.Assert().Equal(int(tc.sequence), int(sequence), "should have correct sequence number") + s.Assert().Nil(err, "should have no error") + } + }) + } +} + +func (s *KeeperTestSuite) TestOnAcknowledgementPacket() { + wasmError := sdkerrors.New("codespace", 2, "jackthecat ran away") + _, code, _ := sdkerrors.ABCIInfo(wasmError, false) + + tests := []struct { + name string + ack channeltypes.Acknowledgement + packet channeltypes.Packet + event proto.Message + err string + }{ + { + name: "success - error event is emitted on ack error", + ack: channeltypes.NewErrorAcknowledgement(wasmError), + packet: channeltypes.Packet{Sequence: 5, DestinationChannel: "oracle-channel"}, + event: &types.EventOracleQueryError{ + SequenceId: strconv.FormatUint(5, 10), + Error: fmt.Sprintf("ABCI code: %d: %s", code, "error handling packet: see events for details"), + Channel: "oracle-channel", + }, + }, + { + name: "success - success event is emitted on ack", + ack: channeltypes.NewResultAcknowledgement(createICQResponse(s.app.AppCodec(), "{}")), + packet: channeltypes.Packet{Sequence: 5, DestinationChannel: "oracle-channel"}, + event: &types.EventOracleQuerySuccess{ + SequenceId: strconv.FormatUint(5, 10), + Result: "{\"data\":\"CgY6BAoCe30=\"}", + Channel: "oracle-channel", + }, + }, + { + name: "failure - invalid icq packet ack in result ack", + ack: channeltypes.NewResultAcknowledgement([]byte("baddata")), + packet: channeltypes.Packet{Sequence: 5}, + event: nil, + err: "failed to unmarshal interchain query packet ack: invalid character 'b' looking for beginning of value", + }, + { + name: "failure - invalid cosmos response in icq packet ack", + ack: channeltypes.NewResultAcknowledgement(createInvalidICQPacketAck()), + packet: channeltypes.Packet{Sequence: 5}, + event: nil, + err: "could not deserialize data to cosmos response: unexpected EOF", + }, + { + name: "failure - empty cosmos response in icq packet ack", + ack: channeltypes.NewResultAcknowledgement(createEmptyICQPacketAck()), + packet: channeltypes.Packet{Sequence: 5}, + event: nil, + err: "no responses in interchain query packet ack: invalid request", + }, + { + name: "failure - invalid query response in cosmos response", + ack: channeltypes.NewResultAcknowledgement(createInvalidCosmosResponse()), + packet: channeltypes.Packet{Sequence: 5}, + event: nil, + err: "failed to unmarshal interchain query response to type *types.Acknowledgement_Result: unexpected EOF", + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + s.ctx = s.ctx.WithEventManager(sdktypes.NewEventManager()) + err := s.app.OracleKeeper.OnAcknowledgementPacket(s.ctx, tc.packet, tc.ack) + + if len(tc.err) > 0 { + s.Assert().EqualError(err, tc.err, "should return expected error") + } else { + s.Assert().NoError(err, "should not return error") + event, _ := sdktypes.TypedEventToEvent(tc.event) + events := s.ctx.EventManager().Events() + s.Assert().Equal(event, events[0], "should emit correct event") + } + }) + } +} + +func (s *KeeperTestSuite) TestOnTimeoutPacket() { + packet := channeltypes.Packet{Sequence: 5, DestinationChannel: "oracle-channel"} + err := s.app.OracleKeeper.OnTimeoutPacket(s.ctx, packet) + event, _ := sdktypes.TypedEventToEvent(&types.EventOracleQueryTimeout{ + SequenceId: strconv.FormatUint(5, 10), + Channel: "oracle-channel", + }) + s.Assert().NoError(err, "should not throw an error") + emitted := s.ctx.EventManager().Events() + s.Assert().Equal(event, emitted[0], "timeout event should be emitted") +} + +func createICQResponse(cdc codec.Codec, response string) []byte { + oracleResponse := types.QueryOracleResponse{ + Data: []byte("{}"), + } + value, _ := cdc.Marshal(&oracleResponse) + bytes, _ := icqtypes.SerializeCosmosResponse([]abci.ResponseQuery{{ + Value: value, + }}) + + icqPacket := icqtypes.InterchainQueryPacketAck{ + Data: bytes, + } + icqBytes, _ := icqtypes.ModuleCdc.MarshalJSON(&icqPacket) + return icqBytes +} + +func createInvalidICQPacketAck() []byte { + icqPacket := icqtypes.InterchainQueryPacketAck{ + Data: []byte("abc"), + } + icqBytes, _ := icqtypes.ModuleCdc.MarshalJSON(&icqPacket) + return icqBytes +} + +func createEmptyICQPacketAck() []byte { + bytes, _ := icqtypes.SerializeCosmosResponse([]abci.ResponseQuery{}) + + icqPacket := icqtypes.InterchainQueryPacketAck{ + Data: bytes, + } + + icqBytes, _ := icqtypes.ModuleCdc.MarshalJSON(&icqPacket) + return icqBytes +} + +func createInvalidCosmosResponse() []byte { + bytes, _ := icqtypes.SerializeCosmosResponse([]abci.ResponseQuery{{ + Value: []byte("baddata"), + }}) + + icqPacket := icqtypes.InterchainQueryPacketAck{ + Data: bytes, + } + icqBytes, _ := icqtypes.ModuleCdc.MarshalJSON(&icqPacket) + return icqBytes +} diff --git a/x/oracle/module/module.go b/x/oracle/module/module.go new file mode 100644 index 0000000000..6566a401bd --- /dev/null +++ b/x/oracle/module/module.go @@ -0,0 +1,199 @@ +package oracle + +import ( + "context" + "encoding/json" + "math/rand" + + "github.com/gorilla/mux" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/tendermint/tendermint/abci/types" + + cerrs "cosmossdk.io/errors" + + sdkclient "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" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + channelkeeper "github.com/cosmos/ibc-go/v6/modules/core/04-channel/keeper" + + "github.com/provenance-io/provenance/x/oracle/client/cli" + "github.com/provenance-io/provenance/x/oracle/keeper" + "github.com/provenance-io/provenance/x/oracle/simulation" + "github.com/provenance-io/provenance/x/oracle/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} +) + +// AppModuleBasic defines the basic application module used by the oracle module. +type AppModuleBasic struct { + cdc codec.Codec +} + +// Name returns the oracle module's name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the oracle module's types for the given codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) { +} + +// RegisterInterfaces registers the oracle module's interface types +func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// DefaultGenesis returns default genesis state as raw bytes for the oracle +// module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis performs genesis state validation for the oracle module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfig, bz json.RawMessage) error { + var data types.GenesisState + if err := cdc.UnmarshalJSON(bz, &data); err != nil { + return cerrs.Wrapf(err, "failed to unmarshal %q genesis state", types.ModuleName) + } + + return data.Validate() +} + +// RegisterRESTRoutes registers the REST routes for the oracle module. +// Deprecated: RegisterRESTRoutes is deprecated. +func (AppModuleBasic) RegisterRESTRoutes(_ sdkclient.Context, _ *mux.Router) {} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the oracle module. +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// GetQueryCmd returns the cli query commands for the oracle module +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// GetTxCmd returns the transaction commands for the oracle module +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.NewTxCmd() +} + +// AppModule implements the sdk.AppModule interface +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper + accountKeeper authkeeper.AccountKeeper + bankKeeper bankkeeper.Keeper + channelKeeper channelkeeper.Keeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper, accountKeeper authkeeper.AccountKeeper, bankKeeper bankkeeper.Keeper, channelKeeper channelkeeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: keeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + channelKeeper: channelKeeper, + } +} + +// GenerateGenesisState creates a randomized GenState of the oracle module. +func (am AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns content functions used to simulate governance proposals. +func (am AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { + // currently no gov proposals exist + return nil +} + +// RandomizedParams returns randomized module parameters for param change proposals. +func (am AppModule) RandomizedParams(_ *rand.Rand) []simtypes.ParamChange { + // currently no module params exist + return nil +} + +// RegisterStoreDecoder registers a func to decode each module's defined types from their corresponding store key +func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) +} + +// WeightedOperations returns simulation operations (i.e msgs) with their respective weight +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.keeper, am.accountKeeper, am.bankKeeper, am.channelKeeper, + ) +} + +// Name returns the oracle module's name. +func (AppModule) Name() string { + return types.ModuleName +} + +// RegisterInvariants does nothing, there are no invariants to enforce +func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// Deprecated: Route returns the message routing key for the oracle module. +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// QuerierRoute returns the route we respond to for abci queries +func (AppModule) QuerierRoute() string { return "" } + +// LegacyQuerierHandler returns the oracle module sdk.Querier. +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// InitGenesis performs genesis initialization for the oracle module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState types.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + am.keeper.InitGenesis(ctx, &genesisState) + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the oracle +// module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(gs) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock is the `BeginBlocker` function run at the beginning of each block to +// process oracle module updates. +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { +} + +// EndBlock The `EndBlocker` abci call is ran at the end of each block. The `EventManager` is monitored +// and `Qualifying Actions` are deduced from newly created events and prior internal state. +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} + +// RegisterServices registers a gRPC query service to respond to the +// module-specific gRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(&am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} diff --git a/x/oracle/module/module_ibc.go b/x/oracle/module/module_ibc.go new file mode 100644 index 0000000000..e044c8cbd2 --- /dev/null +++ b/x/oracle/module/module_ibc.go @@ -0,0 +1,168 @@ +package oracle + +import ( + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" + + cerrs "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v6/modules/core/exported" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// OnChanOpenInit implements the IBCModule interface +func (am AppModule) OnChanOpenInit( + ctx sdk.Context, + _ channeltypes.Order, + _ []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + _ channeltypes.Counterparty, + version string, +) (string, error) { + // Require portID is the portID module is bound to + boundPort := am.keeper.GetPort(ctx) + if boundPort != portID { + return "", cerrs.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) + } + + if version != types.Version { + return "", cerrs.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version) + } + + // Claim channel capability passed back by IBC module + if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + + return version, nil +} + +// OnChanOpenTry implements the IBCModule interface +func (am AppModule) OnChanOpenTry( + ctx sdk.Context, + _ channeltypes.Order, + _ []string, + portID, + channelID string, + chanCap *capabilitytypes.Capability, + _ channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + // Require portID is the portID module is bound to + boundPort := am.keeper.GetPort(ctx) + if boundPort != portID { + return "", cerrs.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort) + } + + if counterpartyVersion != types.Version { + return "", cerrs.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.Version) + } + + // Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos + // (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry) + // If module can already authenticate the capability then module already owns it so we don't need to claim + // Otherwise, module does not have channel capability and we must claim it from IBC + if !am.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) { + // Only claim channel capability passed back by IBC module if we do not already own it + if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", err + } + } + + return types.Version, nil +} + +// OnChanOpenAck implements the IBCModule interface +func (am AppModule) OnChanOpenAck( + _ sdk.Context, + _, + _ string, + _ string, + counterpartyVersion string, +) error { + if counterpartyVersion != types.Version { + return cerrs.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version) + } + return nil +} + +// OnChanOpenConfirm implements the IBCModule interface +func (am AppModule) OnChanOpenConfirm( + _ sdk.Context, + _, + _ string, +) error { + return nil +} + +// OnChanCloseInit implements the IBCModule interface +func (am AppModule) OnChanCloseInit( + _ sdk.Context, + _, + _ string, +) error { + // Disallow user-initiated channel closing for channels + return cerrs.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel") +} + +// OnChanCloseConfirm implements the IBCModule interface +func (am AppModule) OnChanCloseConfirm( + _ sdk.Context, + _, + _ string, +) error { + return nil +} + +// OnRecvPacket implements the IBCModule interface +func (am AppModule) OnRecvPacket( + _ sdk.Context, + _ channeltypes.Packet, + _ sdk.AccAddress, +) ibcexported.Acknowledgement { + return channeltypes.NewErrorAcknowledgement(cerrs.Wrapf(icqtypes.ErrInvalidChannelFlow, "oracle module can not receive packets")) +} + +// OnAcknowledgementPacket implements the IBCModule interface +func (am AppModule) OnAcknowledgementPacket( + ctx sdk.Context, + modulePacket channeltypes.Packet, + acknowledgement []byte, + _ sdk.AccAddress, +) error { + var ack channeltypes.Acknowledgement + if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + return cerrs.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal packet acknowledgement: %v", err) + } + + return am.keeper.OnAcknowledgementPacket(ctx, modulePacket, ack) +} + +// OnTimeoutPacket implements the IBCModule interface +func (am AppModule) OnTimeoutPacket( + ctx sdk.Context, + modulePacket channeltypes.Packet, + _ sdk.AccAddress, +) error { + return am.keeper.OnTimeoutPacket(ctx, modulePacket) +} + +// NegotiateAppVersion implements the IBCModule interface +func (am AppModule) NegotiateAppVersion( + _ sdk.Context, + _ channeltypes.Order, + _ string, + _ string, + _ channeltypes.Counterparty, + proposedVersion string, +) (version string, err error) { + return proposedVersion, nil +} diff --git a/x/oracle/simulation/decoder.go b/x/oracle/simulation/decoder.go new file mode 100644 index 0000000000..9b65480cc3 --- /dev/null +++ b/x/oracle/simulation/decoder.go @@ -0,0 +1,31 @@ +package simulation + +import ( + "bytes" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/kv" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +// NewDecodeStore returns a decoder function closure that unmarshalls the KVPair's +// Value +func NewDecodeStore(_ codec.Codec) func(kvA, kvB kv.Pair) string { + return func(kvA, kvB kv.Pair) string { + switch { + case bytes.Equal(kvA.Key[:1], types.OracleStoreKey): + var attribA, attribB sdk.AccAddress = kvA.Value, kvB.Value + return fmt.Sprintf("Oracle Address: A:[%v] B:[%v]\n", attribA, attribB) + case bytes.Equal(kvA.Key[:1], types.PortStoreKey): + attribA := string(kvA.Value) + attribB := string(kvB.Value) + + return fmt.Sprintf("Port: A:[%v] B:[%v]\n", attribA, attribB) + default: + panic(fmt.Sprintf("unexpected %s key %X (%s)", types.ModuleName, kvA.Key, kvA.Key)) + } + } +} diff --git a/x/oracle/simulation/decoder_test.go b/x/oracle/simulation/decoder_test.go new file mode 100644 index 0000000000..1d5013e5e2 --- /dev/null +++ b/x/oracle/simulation/decoder_test.go @@ -0,0 +1,57 @@ +package simulation_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/types/kv" + + "github.com/provenance-io/provenance/testutil/assertions" + "github.com/provenance-io/provenance/x/oracle/simulation" + "github.com/provenance-io/provenance/x/oracle/types" +) + +func TestDecodeStore(t *testing.T) { + cdc := simapp.MakeTestEncodingConfig().Codec + dec := simulation.NewDecodeStore(cdc) + + tests := []struct { + name string + kvA kv.Pair + kvB kv.Pair + exp string + expPanic string + }{ + { + name: "failure - unknown key type", + kvA: kv.Pair{Key: []byte{0x9a}, Value: []byte{0x9b}}, + kvB: kv.Pair{Key: []byte{0x9c}, Value: []byte{0x9d}}, + expPanic: "unexpected oracle key 9A (\x9a)", + }, + { + name: "success - OracleStoreKey", + kvA: kv.Pair{Key: types.GetOracleStoreKey(), Value: []byte("99")}, + kvB: kv.Pair{Key: types.GetOracleStoreKey(), Value: []byte("88")}, + exp: "Oracle Address: A:[3939] B:[3838]\n", + }, + { + name: "success - PortStoreKey", + kvA: kv.Pair{Key: types.GetPortStoreKey(), Value: []byte("99")}, + kvB: kv.Pair{Key: types.GetPortStoreKey(), Value: []byte("88")}, + exp: "Port: A:[99] B:[88]\n", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual string + testFunc := func() { + actual = dec(tc.kvA, tc.kvB) + } + assertions.RequirePanicEquals(t, testFunc, tc.expPanic, "running decoder") + assert.Equal(t, tc.exp, actual, "decoder result") + }) + } +} diff --git a/x/oracle/simulation/genesis.go b/x/oracle/simulation/genesis.go new file mode 100644 index 0000000000..38669733c5 --- /dev/null +++ b/x/oracle/simulation/genesis.go @@ -0,0 +1,70 @@ +package simulation + +import ( + "encoding/json" + "fmt" + "math/rand" + "strings" + + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + + "github.com/provenance-io/provenance/x/oracle/types" +) + +const ( + Port = "port" +) + +// PortFn randomized port name +func PortFn(r *rand.Rand) string { + if r.Intn(2) > 0 { + return "oracle" + } + length := uint64(randIntBetween(r, 6, 10)) + return strings.ToLower(simtypes.RandStringOfLength(r, int(length))) +} + +// OracleFn randomized oracle address +func OracleFn(r *rand.Rand, accs []simtypes.Account) string { + randomAccount, _ := RandomAccs(r, accs, 1) + if r.Intn(2) > 0 { + return "" + } + return randomAccount[0].Address.String() +} + +// RandomizedGenState generates a random GenesisState for trigger +func RandomizedGenState(simState *module.SimulationState) { + var port string + simState.AppParams.GetOrGenerate( + simState.Cdc, Port, &port, simState.Rand, + func(r *rand.Rand) { port = PortFn(r) }, + ) + + var oracle string + simState.AppParams.GetOrGenerate( + simState.Cdc, Port, &port, simState.Rand, + func(r *rand.Rand) { oracle = OracleFn(r, simState.Accounts) }, + ) + + genesis := types.NewGenesisState(port, oracle) + simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(genesis) + + bz, err := json.MarshalIndent(simState.GenState[types.ModuleName], "", " ") + if err != nil { + panic(err) + } + fmt.Printf("Selected randomly generated oracle parameters:\n%s\n", bz) +} + +// randIntBetween generates a random number between min and max inclusive. +func randIntBetween(r *rand.Rand, min, max int) int { + return r.Intn(max-min+1) + min +} + +// RandomChannel returns a random channel +func RandomChannel(r *rand.Rand) string { + channelNumber := r.Intn(1000) + return fmt.Sprintf("channel-%d", channelNumber) +} diff --git a/x/oracle/simulation/genesis_test.go b/x/oracle/simulation/genesis_test.go new file mode 100644 index 0000000000..7486b29f82 --- /dev/null +++ b/x/oracle/simulation/genesis_test.go @@ -0,0 +1,164 @@ +package simulation_test + +import ( + "encoding/json" + "math/rand" + "testing" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/provenance-io/provenance/x/oracle/simulation" + "github.com/provenance-io/provenance/x/oracle/types" + "github.com/stretchr/testify/assert" +) + +func TestPortFn(t *testing.T) { + tests := []struct { + name string + seed int64 + expected string + }{ + { + name: "success - returns a random port that is not the oracle", + seed: 0, + expected: "vipxlpbshz", + }, + { + name: "success - returns the oracle port", + seed: 1, + expected: "oracle", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + r := rand.New(rand.NewSource(tc.seed)) + port := simulation.PortFn(r) + assert.Equal(t, tc.expected, port, "should return correct random port") + }) + } +} + +func TestOracleFn(t *testing.T) { + accs := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 3) + + tests := []struct { + name string + seed int64 + expected string + accounts []simtypes.Account + }{ + { + name: "success - returns an empty account", + seed: 0, + accounts: accs, + expected: "", + }, + { + name: "success - returns a random account", + seed: 3, + accounts: accs, + expected: "cosmos1tp4es44j4vv8m59za3z0tm64dkmlnm8wg2frhc", + }, + { + name: "success - returns a different random account", + seed: 2, + accounts: accs, + expected: "cosmos12jszjrc0qhjt0ugt2uh4ptwu0h55pq6qfp9ecl", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + r := rand.New(rand.NewSource(tc.seed)) + port := simulation.OracleFn(r, tc.accounts) + assert.Equal(t, tc.expected, port, "should return correct random oracle") + }) + } +} + +func TestRandomizedGenState(t *testing.T) { + accs := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 3) + tests := []struct { + name string + seed int64 + expOracleGen *types.GenesisState + accounts []simtypes.Account + }{ + { + name: "success - can handle no accounts", + seed: 0, + accounts: nil, + expOracleGen: &types.GenesisState{ + PortId: "vipxlpbshz", + Oracle: "", + }, + }, + { + name: "success - can handle accounts", + seed: 1, + accounts: accs, + expOracleGen: &types.GenesisState{ + PortId: "oracle", + Oracle: "", + }, + }, + { + name: "success - has different output", + seed: 2, + accounts: accs, + expOracleGen: &types.GenesisState{ + PortId: "knxndtw", + Oracle: "cosmos10gqqppkly524p6v7hypvvl8sn7wky85jajrph0", + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + simState := &module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: codec.NewProtoCodec(codectypes.NewInterfaceRegistry()), + Rand: rand.New(rand.NewSource(tc.seed)), + GenState: make(map[string]json.RawMessage), + Accounts: tc.accounts, + } + simulation.RandomizedGenState(simState) + + if assert.NotEmpty(t, simState.GenState[types.ModuleName]) { + oracleGenState := &types.GenesisState{} + err := simState.Cdc.UnmarshalJSON(simState.GenState[types.ModuleName], oracleGenState) + if assert.NoError(t, err, "UnmarshalJSON(oracle gen state)") { + assert.Equal(t, tc.expOracleGen, oracleGenState, "hold oracle state") + } + } + }) + } +} + +func TestRandomChannel(t *testing.T) { + + tests := []struct { + name string + seed int64 + expected string + }{ + { + name: "success - returns a random channel", + seed: 3, + expected: "channel-8", + }, + { + name: "success - returns a different random channel", + seed: 2, + expected: "channel-786", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + r := rand.New(rand.NewSource(tc.seed)) + port := simulation.RandomChannel(r) + assert.Equal(t, tc.expected, port, "should return correct random channel") + }) + } +} diff --git a/x/oracle/simulation/operations.go b/x/oracle/simulation/operations.go new file mode 100644 index 0000000000..73fe4036e1 --- /dev/null +++ b/x/oracle/simulation/operations.go @@ -0,0 +1,198 @@ +package simulation + +import ( + "fmt" + "math/rand" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp/helpers" + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/bank/testutil" + "github.com/cosmos/cosmos-sdk/x/simulation" + channelkeeper "github.com/cosmos/ibc-go/v6/modules/core/04-channel/keeper" + + simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/internal/pioconfig" + "github.com/provenance-io/provenance/x/oracle/keeper" + "github.com/provenance-io/provenance/x/oracle/types" +) + +// Simulation operation weights constants +const ( + //nolint:gosec // not credentials + OpWeightMsgUpdateOracle = "op_weight_msg_update_oracle" + //nolint:gosec // not credentials + OpWeightMsgSendOracleQuery = "op_weight_msg_send_oracle_query" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simtypes.AppParams, cdc codec.JSONCodec, k keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper, ck channelkeeper.Keeper, +) simulation.WeightedOperations { + var ( + weightMsgUpdateOracle int + weightMsgSendOracleQuery int + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgUpdateOracle, &weightMsgUpdateOracle, nil, + func(_ *rand.Rand) { + weightMsgUpdateOracle = simappparams.DefaultWeightUpdateOracle + }, + ) + appParams.GetOrGenerate(cdc, OpWeightMsgSendOracleQuery, &weightMsgSendOracleQuery, nil, + func(_ *rand.Rand) { + weightMsgSendOracleQuery = simappparams.DefaultWeightSendOracleQuery + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgUpdateOracle, + SimulateMsgUpdateOracle(k, ak, bk), + ), + simulation.NewWeightedOperation( + weightMsgSendOracleQuery, + SimulateMsgSendQueryOracle(k, ak, bk, ck), + ), + } +} + +// SimulateMsgUpdateOracle sends a MsgUpdateOracle. +func SimulateMsgUpdateOracle(_ keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + raccs, err := RandomAccs(r, accs, uint64(len(accs))) + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(&types.MsgUpdateOracleRequest{}), sdk.MsgTypeURL(&types.MsgUpdateOracleRequest{}), err.Error()), nil, nil + } + + // 50% chance to be from the module's authority + from := raccs[0] + to := raccs[1] + + msg := types.NewMsgUpdateOracle(from.Address.String(), to.Address.String()) + + return Dispatch(r, app, ctx, from, chainID, msg, ak, bk, nil) + } +} + +// SimulateMsgSendQueryOracle sends a MsgSendQueryOracle. +func SimulateMsgSendQueryOracle(_ keeper.Keeper, ak authkeeper.AccountKeeperI, bk bankkeeper.Keeper, ck channelkeeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + raccs, err := RandomAccs(r, accs, 1) + + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{}), sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{}), err.Error()), nil, nil + } + addr := raccs[0] + + channel, err := randomChannel(r, ctx, ck) + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{}), sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{}), err.Error()), nil, nil + } + query := randomQuery(r) + + msg := types.NewMsgSendQueryOracle(addr.Address.String(), channel, query) + return Dispatch(r, app, ctx, addr, chainID, msg, ak, bk, nil) + } +} + +// Dispatch sends an operation to the chain using a given account/funds on account for fees. Failures on the server side +// are handled as no-op msg operations with the error string as the status/response. +func Dispatch( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + from simtypes.Account, + chainID string, + msg sdk.Msg, + ak authkeeper.AccountKeeperI, + bk bankkeeper.Keeper, + futures []simtypes.FutureOperation, +) ( + simtypes.OperationMsg, + []simtypes.FutureOperation, + error, +) { + account := ak.GetAccount(ctx, from.Address) + spendable := bk.SpendableCoins(ctx, account.GetAddress()) + + fees, err := simtypes.RandomFees(r, ctx, spendable) + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), "unable to generate fees"), nil, err + } + err = testutil.FundAccount(bk, ctx, account.GetAddress(), sdk.NewCoins(sdk.Coin{ + Denom: pioconfig.GetProvenanceConfig().BondDenom, + Amount: sdk.NewInt(1_000_000_000_000_000), + })) + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), "unable to fund account"), nil, err + } + txGen := simappparams.MakeTestEncodingConfig().TxConfig + tx, err := helpers.GenSignedMockTx( + r, + txGen, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + from.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), "unable to generate mock tx"), nil, err + } + + _, _, err = app.SimDeliver(txGen.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), err.Error()), nil, nil + } + + return simtypes.NewOperationMsg(msg, true, "", &codec.ProtoCodec{}), futures, nil +} + +func RandomAccs(r *rand.Rand, accs []simtypes.Account, count uint64) ([]simtypes.Account, error) { + if uint64(len(accs)) < count { + return nil, fmt.Errorf("cannot choose %d accounts because there are only %d", count, len(accs)) + } + raccs := make([]simtypes.Account, 0, len(accs)) + raccs = append(raccs, accs...) + r.Shuffle(len(raccs), func(i, j int) { + raccs[i], raccs[j] = raccs[j], raccs[i] + }) + return raccs[:count], nil +} + +func randomChannel(r *rand.Rand, ctx sdk.Context, ck channelkeeper.Keeper) (string, error) { + channels := ck.GetAllChannels(ctx) + if len(channels) == 0 { + return "", fmt.Errorf("cannot get random channel because none exist") + } + idx := r.Intn(len(channels)) + return channels[idx].String(), nil +} + +func randomQuery(r *rand.Rand) []byte { + queryType := randIntBetween(r, 0, 3) + var query string + switch queryType { + case 0: + query = "" + case 1: + query = "{}" + case 2: + query = "{\"version\":{}}" + default: + query = "xyz" + } + + return []byte(query) +} diff --git a/x/oracle/simulation/operations_test.go b/x/oracle/simulation/operations_test.go new file mode 100644 index 0000000000..9d3eca2d23 --- /dev/null +++ b/x/oracle/simulation/operations_test.go @@ -0,0 +1,224 @@ +package simulation_test + +import ( + "bytes" + "fmt" + "math/rand" + "strings" + + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/testutil" + "github.com/provenance-io/provenance/app" + simappparams "github.com/provenance-io/provenance/app/params" + "github.com/provenance-io/provenance/x/oracle/simulation" + "github.com/provenance-io/provenance/x/oracle/types" + "github.com/stretchr/testify/suite" +) + +type SimTestSuite struct { + suite.Suite + + ctx sdk.Context + app *app.App +} + +func (s *SimTestSuite) SetupTest() { + s.app = app.Setup(s.T()) + s.ctx = s.app.BaseApp.NewContext(false, tmproto.Header{}) +} + +// LogOperationMsg logs all fields of the provided operationMsg. +func (s *SimTestSuite) LogOperationMsg(operationMsg simtypes.OperationMsg, msg string, args ...interface{}) { + msgFmt := "%s" + if len(bytes.TrimSpace(operationMsg.Msg)) == 0 { + msgFmt = " %q" + } + fmtLines := []string{ + fmt.Sprintf(msg, args...), + "operationMsg.Route: %q", + "operationMsg.Name: %q", + "operationMsg.Comment: %q", + "operationMsg.OK: %t", + "operationMsg.Msg: " + msgFmt, + } + s.T().Logf(strings.Join(fmtLines, "\n"), + operationMsg.Route, operationMsg.Name, operationMsg.Comment, operationMsg.OK, string(operationMsg.Msg), + ) +} + +func (s *SimTestSuite) TestWeightedOperations() { + cdc := s.app.AppCodec() + appParams := make(simtypes.AppParams) + + weightedOps := simulation.WeightedOperations(appParams, cdc, s.app.OracleKeeper, + s.app.AccountKeeper, s.app.BankKeeper, s.app.IBCKeeper.ChannelKeeper, + ) + + // setup 3 accounts + source := rand.NewSource(1) + r := rand.New(source) + accs := s.getTestingAccounts(r, 3) + + // begin a new block + s.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: s.app.LastBlockHeight() + 1, AppHash: s.app.LastCommitID().Hash}}) + + expected := []struct { + weight int + opMsgRoute string + opMsgName string + }{ + {simappparams.DefaultWeightUpdateOracle, sdk.MsgTypeURL(&types.MsgUpdateOracleRequest{}), sdk.MsgTypeURL(&types.MsgUpdateOracleRequest{})}, + {simappparams.DefaultWeightSendOracleQuery, sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{}), sdk.MsgTypeURL(&types.MsgSendQueryOracleRequest{})}, + } + + expNames := make([]string, len(expected)) + for i, exp := range expected { + expNames[i] = exp.opMsgName + } + + // Run all the ops and get the operation messages and their names. + opMsgs := make([]simtypes.OperationMsg, len(weightedOps)) + actualNames := make([]string, len(weightedOps)) + for i, w := range weightedOps { + opMsgs[i], _, _ = w.Op()(r, s.app.BaseApp, s.ctx, accs, "") + actualNames[i] = opMsgs[i].Name + } + + // First, make sure the op names are as expected since a failure there probably means the rest will fail. + // And it's probably easier to address when you've got a nice list comparison of names and their orderings. + s.Require().Equal(expNames, actualNames, "operation message names") + + // Now assert that each entry was as expected. + for i := range expected { + s.Assert().Equal(expected[i].weight, weightedOps[i].Weight(), "weightedOps[%d].Weight", i) + s.Assert().Equal(expected[i].opMsgRoute, opMsgs[i].Route, "weightedOps[%d] operationMsg.Route", i) + s.Assert().Equal(expected[i].opMsgName, opMsgs[i].Name, "weightedOps[%d] operationMsg.Name", i) + } +} + +func (s *SimTestSuite) TestSimulateMsgUpdateOracle() { + // setup 3 accounts + source := rand.NewSource(1) + r := rand.New(source) + accounts := s.getTestingAccounts(r, 3) + + // begin a new block + s.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: s.app.LastBlockHeight() + 1, AppHash: s.app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgUpdateOracle(s.app.OracleKeeper, s.app.AccountKeeper, s.app.BankKeeper) + operationMsg, futureOperations, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "SimulateMsgUpdateOracle op(...) error") + s.LogOperationMsg(operationMsg, "good") + + var msg types.MsgUpdateOracleRequest + s.Require().NoError(s.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg), "UnmarshalJSON(operationMsg.Msg)") + + s.Assert().True(operationMsg.OK, "operationMsg.OK") + s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Name, "operationMsg.Name") + s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Route, "operationMsg.Route") + s.Assert().Len(futureOperations, 0, "futureOperations") +} + +func (s *SimTestSuite) TestSimulateMsgSendQueryOracle() { + // setup 3 accounts + source := rand.NewSource(1) + r := rand.New(source) + accounts := s.getTestingAccounts(r, 3) + + // begin a new block + s.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: s.app.LastBlockHeight() + 1, AppHash: s.app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgSendQueryOracle(s.app.OracleKeeper, s.app.AccountKeeper, s.app.BankKeeper, s.app.IBCKeeper.ChannelKeeper) + operationMsg, futureOperations, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "SimulateMsgSendQueryOracle op(...) error") + s.LogOperationMsg(operationMsg, "good") + + var msg types.MsgUpdateOracleRequest + s.Require().NoError(s.app.AppCodec().UnmarshalJSON(operationMsg.Msg, &msg), "UnmarshalJSON(operationMsg.Msg)") + + s.Assert().True(operationMsg.OK, "operationMsg.OK") + s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Name, "operationMsg.Name") + s.Assert().Equal(sdk.MsgTypeURL(&msg), operationMsg.Route, "operationMsg.Route") + s.Assert().Len(futureOperations, 0, "futureOperations") +} + +func (s *SimTestSuite) TestRandomAccs() { + source := rand.NewSource(1) + r := rand.New(source) + accounts := s.getTestingAccounts(r, 3) + + tests := []struct { + name string + accs []simtypes.Account + expected []simtypes.Account + count uint64 + err string + }{ + { + name: "valid - return nothing when count is 0", + accs: []simtypes.Account{}, + expected: []simtypes.Account{}, + count: 0, + }, + { + name: "valid - return 1 when count is 1", + accs: []simtypes.Account{accounts[0]}, + expected: []simtypes.Account{accounts[0]}, + count: 1, + }, + { + name: "valid - return multiple when count greater than 1", + accs: []simtypes.Account{accounts[0], accounts[1]}, + expected: []simtypes.Account{accounts[1], accounts[0]}, + count: 2, + }, + { + name: "valid - return is limited by count", + accs: []simtypes.Account{accounts[0], accounts[1], accounts[2]}, + expected: []simtypes.Account{accounts[1]}, + count: 1, + }, + { + name: "invalid - return error when count is greater than length", + accs: []simtypes.Account{accounts[0], accounts[1]}, + expected: []simtypes.Account{}, + count: 3, + err: "cannot choose 3 accounts because there are only 2", + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + raccs, err := simulation.RandomAccs(r, tc.accs, tc.count) + if len(tc.err) == 0 { + s.Require().NoError(err, "should have no error for successful RandomAccs") + s.Require().Equal(tc.expected, raccs, "should have correct output for successful RandomAccs") + } else { + s.Require().EqualError(err, tc.err, "should have correct error message for RandomAccs") + } + }) + } +} + +func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { + accounts := simtypes.RandomAccounts(r, n) + + initAmt := sdk.TokensFromConsensusPower(1000000, sdk.DefaultPowerReduction) + initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) + + // add coins to the accounts + for _, account := range accounts { + acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) + s.app.AccountKeeper.SetAccount(s.ctx, acc) + err := testutil.FundAccount(s.app.BankKeeper, s.ctx, account.Address, initCoins) + s.Require().NoError(err) + } + + return accounts +} diff --git a/x/oracle/spec/01_concepts.md b/x/oracle/spec/01_concepts.md new file mode 100644 index 0000000000..87592f9431 --- /dev/null +++ b/x/oracle/spec/01_concepts.md @@ -0,0 +1,29 @@ + + +# Concepts + +The oracle module is very minimal, but users should understand what the `Oracle` is and how it interacts with `ICQ`. + + + - [Oracle](#oracle) + - [Interchain Queries (ICQ)](#interchain-queries-icq) + + +--- +## Oracle + +The `Oracle` is a custom built CosmWasm smart contract that the chain queries for data. Chain users can update the address with a proposal. + +## Interchain Queries (ICQ) + +`ICQ` is heavily leveraged in order to allow one Provenance Blockcahin to query another Provenance Blockchain's `Oracle`. This module acts as both the `Controller` and receiver of the `Host` in the `ICQ` realm. + +When a user intends to query another chain, they initiate the process by submitting a query through a transaction on the `ICQ Controller`. This `Controller` delivers the query from the transaction to the `ICQ Host` module of the destination chain via `IBC`. Subsequently, the received query is routed by the `ICQ Host` to this module. Upon receipt, the module queries the `Oracle` using the provided input, and the resulting information is then transmitted back to the `ICQ Controller` in the form of an `ACK` message. + +It should be noted that responses, which arrive in the form of the `ACK`, indicate that queries operate asynchronously. Consequently, these results will not be immediately accessible, requiring the user to wait for an emitted event on the response. For additional details, you can refer to the [Async ICQ Module](https://github.com/strangelove-ventures/async-icq) developed by strangelove-ventures. + +### Note + +For `ICQ` to function correctly, it is essential to establish an `unordered channel` connecting the two chains. This channel should be configured utilizing the `oracle` and `icqhost` ports on the `ICQ Controller` and `ICQ Host` correspondingly. The `version` should be designated as `icq-1`. Moreover, it is crucial to ensure that the `HostEnabled` parameter is enabled with a value of `true`, while the `AllowQueries` parameter should encompass the path `"/provenance.oracle.v1.Query/Oracle"`. diff --git a/x/oracle/spec/02_state.md b/x/oracle/spec/02_state.md new file mode 100644 index 0000000000..a2933086fe --- /dev/null +++ b/x/oracle/spec/02_state.md @@ -0,0 +1,26 @@ + + +# State + +The oracle module manages the address of the Oracle and the ICQ state. + + + - [Oracle](#oracle) + - [IBC](#ibc) + + +--- +## Oracle + +The `Oracle` is a CosmWasm smart contract that the module forwards its queries to and relays responses from. Users can manipulate this state by submitting a update oracle proposal. + +* Oracle `0x01 -> []byte{}` + +--- +## IBC + +`IBC` communication exists between the `oracle` and `icqhost` modules. The `oracle` module tracks its channel's `port` in state. + +* Port `0x02 -> []byte{}` diff --git a/x/oracle/spec/03_messages.md b/x/oracle/spec/03_messages.md new file mode 100644 index 0000000000..8eb34eaa0b --- /dev/null +++ b/x/oracle/spec/03_messages.md @@ -0,0 +1,46 @@ + + +# Messages + +In this section we describe the processing of the oracle messages and their corresponding updates to the state. + + + - [Msg/UpdateOracleRequest](#msgupdateoraclerequest) + - [Msg/SendQueryOracleRequest](#msgsendqueryoraclerequest) + + +--- +## Msg/UpdateOracleRequest + +The oracle's address is modified by proposing the `MsgUpdateOracleRequest` message. + +### Request + ++++ https://github.com/provenance-io/provenance/blob/65865991f93e2c1a7647e29be11f6527f49616e6/proto/provenance/oracle/v1/tx.proto#L37-L46 + +### Response + ++++ https://github.com/provenance-io/provenance/blob/65865991f93e2c1a7647e29be11f6527f49616e6/proto/provenance/oracle/v1/tx.proto#L48-L49 + +The message will fail under the following conditions: +* The authority does not match the gov module. +* The new address does not pass basic integrity and format checks. + +## Msg/SendQueryOracleRequest + +Sends a query to another chain's `Oracle` using `ICQ`. + +### Request + ++++ https://github.com/provenance-io/provenance/blob/65865991f93e2c1a7647e29be11f6527f49616e6/proto/provenance/oracle/v1/tx.proto#L21-L29 + +### Response + ++++ https://github.com/provenance-io/provenance/blob/65865991f93e2c1a7647e29be11f6527f49616e6/proto/provenance/oracle/v1/tx.proto#L31-L35 + +The message will fail under the following conditions: +* The authority does not pass basic integrity and format checks. +* The query does not have the correct format. +* The channel is invalid or does not pass basic integrity and format checks. diff --git a/x/oracle/spec/04_queries.md b/x/oracle/spec/04_queries.md new file mode 100644 index 0000000000..c41647b124 --- /dev/null +++ b/x/oracle/spec/04_queries.md @@ -0,0 +1,38 @@ + + +# Queries + +In this section we describe the queries available for looking up oracle information. + + + - [Query Oracle Address](#query-oracle-address) + - [Query Oracle](#query-oracle) + +--- +## Query Oracle Address +The `QueryOracleAddress` query is used to obtain the address of the module's oracle. + +### Request + ++++ https://github.com/provenance-io/provenance/blob/5afab1b1797b0071cf6a19ea5928c5b8f8831329/proto/provenance/oracle/v1/query.proto#L26-L27 + +### Response + ++++ https://github.com/provenance-io/provenance/blob/5afab1b1797b0071cf6a19ea5928c5b8f8831329/proto/provenance/oracle/v1/query.proto#L29-L33 + + +--- +## Query Oracle +The `QueryOracle` query forwards a query to the module's oracle. + +### Request + ++++ https://github.com/provenance-io/provenance/blob/5afab1b1797b0071cf6a19ea5928c5b8f8831329/proto/provenance/oracle/v1/query.proto#L35-L39 + +### Response + ++++ https://github.com/provenance-io/provenance/blob/5afab1b1797b0071cf6a19ea5928c5b8f8831329/proto/provenance/oracle/v1/query.proto#L41-L45 + +The data from the `query` field is a `CosmWasm query` forwarded to the `oracle`. diff --git a/x/oracle/spec/05_events.md b/x/oracle/spec/05_events.md new file mode 100644 index 0000000000..736ff720c5 --- /dev/null +++ b/x/oracle/spec/05_events.md @@ -0,0 +1,45 @@ + + +# Events + +The oracle module emits the following events: + + + - [EventOracleQuerySuccess](#eventoraclequerysuccess) + - [EventOracleQueryError](#eventoraclequeryerror) + - [EventOracleQueryTimeout](#eventoraclequerytimeout) + + +--- +## EventOracleQuerySuccess + +This event is emitted when an `ICQ` response is received from an `ACK` and is successful. + +| Type | Attribute Key | Attribute Value | +| ------------------ | ------------- | ----------------------------------- | +| OracleQuerySuccess | channel | Channel the ICQ request was sent on | +| OracleQuerySuccess | sequence_id | Sequence ID of the ICQ request | +| OracleQuerySuccess | result | Query data obtained from oracle | + +--- +## EventOracleQueryError + +This event is emitted when an `ICQ` response is received from an `ACK` and contains an error. + +| Type | Attribute Key | Attribute Value | +| ---------------- | ------------- | ----------------------------------- | +| OracleQueryError | channel | Channel the ICQ request was sent on | +| OracleQueryError | sequence_id | Sequence ID of the ICQ request | +| OracleQueryError | error | Error received from the module | + +--- +## EventOracleQueryTimeout + +This event is emitted when an `ICQ` request results in a `Timeout`. + +| Type | Attribute Key | Attribute Value | +| ------------------ | ------------- | ----------------------------------- | +| OracleQueryTimeout | channel | Channel the ICQ request was sent on | +| OracleQueryTimeout | sequence_id | Sequence ID of the ICQ request | diff --git a/x/oracle/spec/06_genesis.md b/x/oracle/spec/06_genesis.md new file mode 100644 index 0000000000..7d5e744a0f --- /dev/null +++ b/x/oracle/spec/06_genesis.md @@ -0,0 +1,18 @@ + + +# Oracle Genesis + +In this section we describe the processing of the oracle messages and the corresponding updates to the state. + + + - [Msg/GenesisState](#msggenesisstate) + + +--- +## Msg/GenesisState + +The GenesisState encompasses the upcoming sequence ID for an ICQ packet, the associated parameters, the designated port ID for the module, and the oracle address. These values are both extracted for export and imported for storage within the store. + ++++ https://github.com/provenance-io/provenance/blob/ba0b65c54f61f99c951fe4694271847dbad0fb00/proto/provenance/oracle/v1/genesis.proto#L11-L24 diff --git a/x/oracle/spec/README.md b/x/oracle/spec/README.md new file mode 100644 index 0000000000..46e222a1a5 --- /dev/null +++ b/x/oracle/spec/README.md @@ -0,0 +1,14 @@ +# `oracle` + +## Overview +The oracle module provides the Provenance Blockchain with the capability to dynamically expose query endpoints through Interchain Queries (ICQ) + +One challenge that the Provenance Blockchain faces is supporting each Provenance Blockchain Zone with a unique set of queries. It is not feasible to create an evolving set of queries for each chain. Furthermore, it is not desirable for other parties to request Provenance to build these endpoints for them and then upgrade. This module resolves these issues by enabling Provenance Blockchain zones to manage their own oracle. + +## Contents +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[Messages](03_messages.md)** +4. **[Queries](04_queries.md)** +5. **[Events](05_events.md)** +6. **[Genesis](06_genesis.md)** \ No newline at end of file diff --git a/x/oracle/types/codec.go b/x/oracle/types/codec.go new file mode 100644 index 0000000000..14841c0fc2 --- /dev/null +++ b/x/oracle/types/codec.go @@ -0,0 +1,28 @@ +package types + +import ( + "github.com/gogo/protobuf/proto" + + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ignoring RegisterLegacyAminoCodec registers all the necessary types and interfaces for the +// double check +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgUpdateOracleRequest{}, + &MsgSendQueryOracleRequest{}, + ) + + registry.RegisterImplementations((*proto.Message)(nil), + &QueryOracleRequest{}, + &QueryOracleResponse{}, + ) +} + +var ( + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) diff --git a/x/oracle/types/errors.go b/x/oracle/types/errors.go new file mode 100644 index 0000000000..78debf6fbf --- /dev/null +++ b/x/oracle/types/errors.go @@ -0,0 +1,11 @@ +package types + +import ( + cerrs "cosmossdk.io/errors" +) + +var ( + ErrInvalidPacketTimeout = cerrs.Register(ModuleName, 3, "invalid packet timeout") + ErrInvalidVersion = cerrs.Register(ModuleName, 4, "invalid version") + ErrMissingOracleAddress = cerrs.Register(ModuleName, 5, "missing oracle address") +) diff --git a/x/oracle/types/event.pb.go b/x/oracle/types/event.pb.go new file mode 100644 index 0000000000..7dd3d9462d --- /dev/null +++ b/x/oracle/types/event.pb.go @@ -0,0 +1,927 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: provenance/oracle/v1/event.proto + +package types + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// EventOracleQuerySuccess is an event for when the chain receives a successful response from an oracle query +type EventOracleQuerySuccess struct { + // channel is the local channel that the oracle query response was received from + Channel string `protobuf:"bytes,1,opt,name=channel,proto3" json:"channel,omitempty"` + // sequence_id is a unique identifier of the query + SequenceId string `protobuf:"bytes,2,opt,name=sequence_id,json=sequenceId,proto3" json:"sequence_id,omitempty"` + // result is the data received from the query + Result string `protobuf:"bytes,3,opt,name=result,proto3" json:"result,omitempty"` +} + +func (m *EventOracleQuerySuccess) Reset() { *m = EventOracleQuerySuccess{} } +func (m *EventOracleQuerySuccess) String() string { return proto.CompactTextString(m) } +func (*EventOracleQuerySuccess) ProtoMessage() {} +func (*EventOracleQuerySuccess) Descriptor() ([]byte, []int) { + return fileDescriptor_e98d10c8454ad24d, []int{0} +} +func (m *EventOracleQuerySuccess) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventOracleQuerySuccess) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventOracleQuerySuccess.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 *EventOracleQuerySuccess) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventOracleQuerySuccess.Merge(m, src) +} +func (m *EventOracleQuerySuccess) XXX_Size() int { + return m.Size() +} +func (m *EventOracleQuerySuccess) XXX_DiscardUnknown() { + xxx_messageInfo_EventOracleQuerySuccess.DiscardUnknown(m) +} + +var xxx_messageInfo_EventOracleQuerySuccess proto.InternalMessageInfo + +func (m *EventOracleQuerySuccess) GetChannel() string { + if m != nil { + return m.Channel + } + return "" +} + +func (m *EventOracleQuerySuccess) GetSequenceId() string { + if m != nil { + return m.SequenceId + } + return "" +} + +func (m *EventOracleQuerySuccess) GetResult() string { + if m != nil { + return m.Result + } + return "" +} + +// EventOracleQueryError is an event for when the chain receives an error response from an oracle query +type EventOracleQueryError struct { + // channel is the local channel that the oracle query response was received from + Channel string `protobuf:"bytes,1,opt,name=channel,proto3" json:"channel,omitempty"` + // sequence_id is a unique identifier of the query + SequenceId string `protobuf:"bytes,2,opt,name=sequence_id,json=sequenceId,proto3" json:"sequence_id,omitempty"` + // error is the error message received from the query + Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` +} + +func (m *EventOracleQueryError) Reset() { *m = EventOracleQueryError{} } +func (m *EventOracleQueryError) String() string { return proto.CompactTextString(m) } +func (*EventOracleQueryError) ProtoMessage() {} +func (*EventOracleQueryError) Descriptor() ([]byte, []int) { + return fileDescriptor_e98d10c8454ad24d, []int{1} +} +func (m *EventOracleQueryError) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventOracleQueryError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventOracleQueryError.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 *EventOracleQueryError) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventOracleQueryError.Merge(m, src) +} +func (m *EventOracleQueryError) XXX_Size() int { + return m.Size() +} +func (m *EventOracleQueryError) XXX_DiscardUnknown() { + xxx_messageInfo_EventOracleQueryError.DiscardUnknown(m) +} + +var xxx_messageInfo_EventOracleQueryError proto.InternalMessageInfo + +func (m *EventOracleQueryError) GetChannel() string { + if m != nil { + return m.Channel + } + return "" +} + +func (m *EventOracleQueryError) GetSequenceId() string { + if m != nil { + return m.SequenceId + } + return "" +} + +func (m *EventOracleQueryError) GetError() string { + if m != nil { + return m.Error + } + return "" +} + +// EventOracleQueryTimeout is an event for when the chain receives a timeout from an oracle query +type EventOracleQueryTimeout struct { + // channel is the local channel that the oracle timeout was received from + Channel string `protobuf:"bytes,1,opt,name=channel,proto3" json:"channel,omitempty"` + // sequence_id is a unique identifier of the query + SequenceId string `protobuf:"bytes,2,opt,name=sequence_id,json=sequenceId,proto3" json:"sequence_id,omitempty"` +} + +func (m *EventOracleQueryTimeout) Reset() { *m = EventOracleQueryTimeout{} } +func (m *EventOracleQueryTimeout) String() string { return proto.CompactTextString(m) } +func (*EventOracleQueryTimeout) ProtoMessage() {} +func (*EventOracleQueryTimeout) Descriptor() ([]byte, []int) { + return fileDescriptor_e98d10c8454ad24d, []int{2} +} +func (m *EventOracleQueryTimeout) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventOracleQueryTimeout) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventOracleQueryTimeout.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 *EventOracleQueryTimeout) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventOracleQueryTimeout.Merge(m, src) +} +func (m *EventOracleQueryTimeout) XXX_Size() int { + return m.Size() +} +func (m *EventOracleQueryTimeout) XXX_DiscardUnknown() { + xxx_messageInfo_EventOracleQueryTimeout.DiscardUnknown(m) +} + +var xxx_messageInfo_EventOracleQueryTimeout proto.InternalMessageInfo + +func (m *EventOracleQueryTimeout) GetChannel() string { + if m != nil { + return m.Channel + } + return "" +} + +func (m *EventOracleQueryTimeout) GetSequenceId() string { + if m != nil { + return m.SequenceId + } + return "" +} + +func init() { + proto.RegisterType((*EventOracleQuerySuccess)(nil), "provenance.oracle.v1.EventOracleQuerySuccess") + proto.RegisterType((*EventOracleQueryError)(nil), "provenance.oracle.v1.EventOracleQueryError") + proto.RegisterType((*EventOracleQueryTimeout)(nil), "provenance.oracle.v1.EventOracleQueryTimeout") +} + +func init() { proto.RegisterFile("provenance/oracle/v1/event.proto", fileDescriptor_e98d10c8454ad24d) } + +var fileDescriptor_e98d10c8454ad24d = []byte{ + // 258 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x28, 0x28, 0xca, 0x2f, + 0x4b, 0xcd, 0x4b, 0xcc, 0x4b, 0x4e, 0xd5, 0xcf, 0x2f, 0x4a, 0x4c, 0xce, 0x49, 0xd5, 0x2f, 0x33, + 0xd4, 0x4f, 0x2d, 0x4b, 0xcd, 0x2b, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x41, 0xa8, + 0xd0, 0x83, 0xa8, 0xd0, 0x2b, 0x33, 0x54, 0xca, 0xe1, 0x12, 0x77, 0x05, 0x29, 0xf2, 0x07, 0x8b, + 0x04, 0x96, 0xa6, 0x16, 0x55, 0x06, 0x97, 0x26, 0x27, 0xa7, 0x16, 0x17, 0x0b, 0x49, 0x70, 0xb1, + 0x27, 0x67, 0x24, 0xe6, 0xe5, 0xa5, 0xe6, 0x48, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x06, 0xc1, 0xb8, + 0x42, 0xf2, 0x5c, 0xdc, 0xc5, 0xa9, 0x85, 0xa5, 0xa9, 0x79, 0xc9, 0xa9, 0xf1, 0x99, 0x29, 0x12, + 0x4c, 0x60, 0x59, 0x2e, 0x98, 0x90, 0x67, 0x8a, 0x90, 0x18, 0x17, 0x5b, 0x51, 0x6a, 0x71, 0x69, + 0x4e, 0x89, 0x04, 0x33, 0x58, 0x0e, 0xca, 0x53, 0xca, 0xe0, 0x12, 0x45, 0xb7, 0xcd, 0xb5, 0xa8, + 0x28, 0xbf, 0x88, 0x12, 0xbb, 0x44, 0xb8, 0x58, 0x53, 0x41, 0x66, 0x40, 0xad, 0x82, 0x70, 0x94, + 0x42, 0x30, 0xfd, 0x15, 0x92, 0x99, 0x9b, 0x9a, 0x5f, 0x5a, 0x42, 0x81, 0x5d, 0x4e, 0xe9, 0x27, + 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, + 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0xc0, 0x25, 0x9e, 0x99, 0xaf, 0x87, 0x2d, 0x80, + 0x03, 0x18, 0xa3, 0x8c, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x11, + 0x4a, 0x74, 0x33, 0xf3, 0x91, 0x78, 0xfa, 0x15, 0xb0, 0x58, 0x2b, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, + 0x62, 0x03, 0xc7, 0x99, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x36, 0xdb, 0x1f, 0x32, 0xd7, 0x01, + 0x00, 0x00, +} + +func (m *EventOracleQuerySuccess) 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 *EventOracleQuerySuccess) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventOracleQuerySuccess) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Result) > 0 { + i -= len(m.Result) + copy(dAtA[i:], m.Result) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Result))) + i-- + dAtA[i] = 0x1a + } + if len(m.SequenceId) > 0 { + i -= len(m.SequenceId) + copy(dAtA[i:], m.SequenceId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SequenceId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Channel) > 0 { + i -= len(m.Channel) + copy(dAtA[i:], m.Channel) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Channel))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventOracleQueryError) 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 *EventOracleQueryError) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventOracleQueryError) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Error) > 0 { + i -= len(m.Error) + copy(dAtA[i:], m.Error) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Error))) + i-- + dAtA[i] = 0x1a + } + if len(m.SequenceId) > 0 { + i -= len(m.SequenceId) + copy(dAtA[i:], m.SequenceId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SequenceId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Channel) > 0 { + i -= len(m.Channel) + copy(dAtA[i:], m.Channel) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Channel))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventOracleQueryTimeout) 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 *EventOracleQueryTimeout) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventOracleQueryTimeout) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.SequenceId) > 0 { + i -= len(m.SequenceId) + copy(dAtA[i:], m.SequenceId) + i = encodeVarintEvent(dAtA, i, uint64(len(m.SequenceId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Channel) > 0 { + i -= len(m.Channel) + copy(dAtA[i:], m.Channel) + i = encodeVarintEvent(dAtA, i, uint64(len(m.Channel))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEvent(dAtA []byte, offset int, v uint64) int { + offset -= sovEvent(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *EventOracleQuerySuccess) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Channel) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.SequenceId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.Result) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + +func (m *EventOracleQueryError) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Channel) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.SequenceId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.Error) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + +func (m *EventOracleQueryTimeout) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Channel) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + l = len(m.SequenceId) + if l > 0 { + n += 1 + l + sovEvent(uint64(l)) + } + return n +} + +func sovEvent(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvent(x uint64) (n int) { + return sovEvent(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *EventOracleQuerySuccess) 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 ErrIntOverflowEvent + } + 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: EventOracleQuerySuccess: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventOracleQuerySuccess: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SequenceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SequenceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Result", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Result = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventOracleQueryError) 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 ErrIntOverflowEvent + } + 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: EventOracleQueryError: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventOracleQueryError: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SequenceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SequenceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Error = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventOracleQueryTimeout) 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 ErrIntOverflowEvent + } + 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: EventOracleQueryTimeout: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventOracleQueryTimeout: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SequenceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvent + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvent + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvent + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SequenceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvent(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvent + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvent(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, ErrIntOverflowEvent + } + 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, ErrIntOverflowEvent + } + 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, ErrIntOverflowEvent + } + 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, ErrInvalidLengthEvent + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvent + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvent + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvent = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvent = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvent = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/oracle/types/expected_keepers.go b/x/oracle/types/expected_keepers.go new file mode 100644 index 0000000000..cf3dbc6cf5 --- /dev/null +++ b/x/oracle/types/expected_keepers.go @@ -0,0 +1,40 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" +) + +// ICS4Wrapper defines the expected ICS4Wrapper for middleware +type ICS4Wrapper interface { + SendPacket( + ctx sdk.Context, + chanCap *capabilitytypes.Capability, + sourcePort string, + sourceChannel string, + timeoutHeight clienttypes.Height, + timeoutTimestamp uint64, + data []byte, + ) (sequence uint64, err error) +} + +// ChannelKeeper defines the expected IBC channel keeper +type ChannelKeeper interface { + GetChannel(ctx sdk.Context, portID, channelID string) (channeltypes.Channel, bool) + GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) +} + +// PortKeeper defines the expected IBC port keeper +type PortKeeper interface { + BindPort(ctx sdk.Context, portID string) *capabilitytypes.Capability + IsBound(ctx sdk.Context, portID string) bool +} + +// ScopedKeeper defines the expected x/capability scoped keeper interface +type ScopedKeeper interface { + GetCapability(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) + AuthenticateCapability(ctx sdk.Context, capability *capabilitytypes.Capability, name string) bool + ClaimCapability(ctx sdk.Context, capability *capabilitytypes.Capability, name string) error +} diff --git a/x/oracle/types/genesis.go b/x/oracle/types/genesis.go new file mode 100644 index 0000000000..c87f3f2456 --- /dev/null +++ b/x/oracle/types/genesis.go @@ -0,0 +1,33 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" +) + +func NewGenesisState(port string, oracle string) *GenesisState { + return &GenesisState{ + PortId: port, + Oracle: oracle, + } +} + +// DefaultGenesis returns the default oracle genesis state +func DefaultGenesis() *GenesisState { + return NewGenesisState(PortID, "") +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + if err := host.PortIdentifierValidator(gs.PortId); err != nil { + return err + } + + _, err := sdk.AccAddressFromBech32(gs.Oracle) + if len(gs.Oracle) > 0 && err != nil { + return err + } + + return nil +} diff --git a/x/oracle/types/genesis.pb.go b/x/oracle/types/genesis.pb.go new file mode 100644 index 0000000000..9cb13dfa61 --- /dev/null +++ b/x/oracle/types/genesis.pb.go @@ -0,0 +1,361 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: provenance/oracle/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the oracle module's genesis state. +type GenesisState struct { + // The port to assign to the module + PortId string `protobuf:"bytes,2,opt,name=port_id,json=portId,proto3" json:"port_id,omitempty"` + // The address of the oracle + Oracle string `protobuf:"bytes,3,opt,name=oracle,proto3" json:"oracle,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_f8d8aecd974cfd80, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func init() { + proto.RegisterType((*GenesisState)(nil), "provenance.oracle.v1.GenesisState") +} + +func init() { + proto.RegisterFile("provenance/oracle/v1/genesis.proto", fileDescriptor_f8d8aecd974cfd80) +} + +var fileDescriptor_f8d8aecd974cfd80 = []byte{ + // 211 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2a, 0x28, 0xca, 0x2f, + 0x4b, 0xcd, 0x4b, 0xcc, 0x4b, 0x4e, 0xd5, 0xcf, 0x2f, 0x4a, 0x4c, 0xce, 0x49, 0xd5, 0x2f, 0x33, + 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, + 0x41, 0xa8, 0xd1, 0x83, 0xa8, 0xd1, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x2b, + 0xd0, 0x07, 0xb1, 0x20, 0x6a, 0x95, 0x3c, 0xb9, 0x78, 0xdc, 0x21, 0x9a, 0x83, 0x4b, 0x12, 0x4b, + 0x52, 0x85, 0xc4, 0xb9, 0xd8, 0x0b, 0xf2, 0x8b, 0x4a, 0xe2, 0x33, 0x53, 0x24, 0x98, 0x14, 0x18, + 0x35, 0x38, 0x83, 0xd8, 0x40, 0x5c, 0xcf, 0x14, 0x21, 0x31, 0x2e, 0x36, 0x88, 0x59, 0x12, 0xcc, + 0x10, 0x71, 0x08, 0xcf, 0x8a, 0xa3, 0x63, 0x81, 0x3c, 0xc3, 0x8b, 0x05, 0xf2, 0x0c, 0x4e, 0xe9, + 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, + 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0xc0, 0x25, 0x9e, 0x09, 0xb6, 0x0e, 0xc3, + 0x4d, 0x01, 0x8c, 0x51, 0x46, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, + 0x08, 0x25, 0xba, 0x99, 0xf9, 0x48, 0x3c, 0xfd, 0x0a, 0x98, 0x57, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, + 0x93, 0xd8, 0xc0, 0x4e, 0x37, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x6d, 0x21, 0xbd, 0x0c, + 0x01, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Oracle) > 0 { + i -= len(m.Oracle) + copy(dAtA[i:], m.Oracle) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Oracle))) + i-- + dAtA[i] = 0x1a + } + if len(m.PortId) > 0 { + i -= len(m.PortId) + copy(dAtA[i:], m.PortId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.PortId))) + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.PortId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.Oracle) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PortId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PortId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Oracle", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Oracle = string(dAtA[iNdEx:postIndex]) + 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/oracle/types/genesis_test.go b/x/oracle/types/genesis_test.go new file mode 100644 index 0000000000..026e55dd36 --- /dev/null +++ b/x/oracle/types/genesis_test.go @@ -0,0 +1,61 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewGenesisState(t *testing.T) { + port := "random" + oracle := "oracle" + + genesis := NewGenesisState(port, oracle) + assert.Equal(t, port, genesis.PortId, "port id must match") + assert.Equal(t, oracle, genesis.Oracle, "oracle must match") +} + +func TestDefaultGenesis(t *testing.T) { + genesis := DefaultGenesis() + + assert.Equal(t, PortID, genesis.PortId, "port id must match") + assert.Equal(t, "", genesis.Oracle, "oracle must match") +} + +func TestGenesisValidate(t *testing.T) { + tests := []struct { + name string + state *GenesisState + err string + }{ + { + name: "success - all fields are valid", + state: NewGenesisState(PortID, "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma"), + }, + { + name: "success - all fields are valid with empty oracle", + state: NewGenesisState(PortID, ""), + }, + { + name: "failure - port id is invalid", + state: NewGenesisState("x", ""), + err: "identifier x has invalid length: 1, must be between 2-128 characters: invalid identifier", + }, + { + name: "failure - oracle is invalid", + state: NewGenesisState(PortID, "abc"), + err: "decoding bech32 failed: invalid bech32 string length 3", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + res := tc.state.Validate() + if len(tc.err) > 0 { + assert.EqualError(t, res, tc.err, "Genesis.Validate") + } else { + assert.NoError(t, res, "Genesis.Validate") + } + }) + } +} diff --git a/x/oracle/types/keys.go b/x/oracle/types/keys.go new file mode 100644 index 0000000000..105475d81f --- /dev/null +++ b/x/oracle/types/keys.go @@ -0,0 +1,51 @@ +package types + +import ( + icqtypes "github.com/strangelove-ventures/async-icq/v6/types" +) + +const ( + // ModuleName defines the module name + ModuleName = "oracle" + + // StoreKey is string representation of the store key for marker + StoreKey = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_interquery" + + // Version defines the current version the IBC module supports + Version = icqtypes.Version + + // PortID is the default port id that module binds to + PortID = "oracle" +) + +// The Oracle module's KVStore categorizes each item in the store using a single byte prefix +// Any additional bytes appended after this prefix are to help in making multiple unique entries per category +// The keys are relatively simple and are used for module setup and configuration +// +// OracleStoreKey +// - 0x01: sdk.AccAddress +// | 1 | +// +// +// PortStoreKey +// - 0x02: string +// | 1 | +var ( + // OracleStoreKey is the key for the module's oracle address + OracleStoreKey = []byte{0x01} + // PortStoreKey defines the key to store the port ID in store + PortStoreKey = []byte{0x02} +) + +// GetOracleStoreKey is a function to get the key for the oracle's address in store +func GetOracleStoreKey() []byte { + return OracleStoreKey +} + +// GetPortStoreKey is a function to get the key for the port in store +func GetPortStoreKey() []byte { + return PortStoreKey +} diff --git a/x/oracle/types/keys_test.go b/x/oracle/types/keys_test.go new file mode 100644 index 0000000000..8aed3ea1c6 --- /dev/null +++ b/x/oracle/types/keys_test.go @@ -0,0 +1,17 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetOracleStoreKey(t *testing.T) { + key := GetOracleStoreKey() + assert.EqualValues(t, OracleStoreKey, key[0:1], "must return correct oracle key") +} + +func TestGetPortStoreKey(t *testing.T) { + key := GetPortStoreKey() + assert.EqualValues(t, PortStoreKey, key[0:1], "must return correct port key") +} diff --git a/x/oracle/types/msgs.go b/x/oracle/types/msgs.go new file mode 100644 index 0000000000..04b593dcb2 --- /dev/null +++ b/x/oracle/types/msgs.go @@ -0,0 +1,65 @@ +package types + +import ( + fmt "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/ibc-go/v6/modules/core/24-host" +) + +var ( + _ sdk.Msg = &MsgUpdateOracleRequest{} + _ sdk.Msg = &MsgSendQueryOracleRequest{} +) + +// NewMsgSendQueryOracle creates a new MsgSendQueryOracleRequest +func NewMsgSendQueryOracle(creator, channelID string, query []byte) *MsgSendQueryOracleRequest { + return &MsgSendQueryOracleRequest{ + Authority: creator, + Channel: channelID, + Query: query, + } +} + +// GetSigners indicates that the message must have been signed by the parent. +func (msg MsgSendQueryOracleRequest) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{sdk.MustAccAddressFromBech32(msg.Authority)} +} + +// ValidateBasic runs stateless validation checks on the message. +func (msg MsgSendQueryOracleRequest) ValidateBasic() error { + if err := host.ChannelIdentifierValidator(msg.Channel); err != nil { + return fmt.Errorf("invalid channel id") + } + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return fmt.Errorf("invalid authority address: %w", err) + } + if err := msg.Query.ValidateBasic(); err != nil { + return fmt.Errorf("invalid query data: %w", err) + } + return nil +} + +// NewMsgUpdateOracle creates a new MsgUpdateOracleRequest +func NewMsgUpdateOracle(creator, addr string) *MsgUpdateOracleRequest { + return &MsgUpdateOracleRequest{ + Authority: creator, + Address: addr, + } +} + +// GetSigners indicates that the message must have been signed by the parent. +func (msg MsgUpdateOracleRequest) GetSigners() []sdk.AccAddress { + return []sdk.AccAddress{sdk.MustAccAddressFromBech32(msg.Authority)} +} + +// ValidateBasic runs stateless validation checks on the message. +func (msg MsgUpdateOracleRequest) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Address); err != nil { + return fmt.Errorf("invalid address for oracle: %w", err) + } + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return fmt.Errorf("invalid authority address: %w", err) + } + return nil +} diff --git a/x/oracle/types/msgs_test.go b/x/oracle/types/msgs_test.go new file mode 100644 index 0000000000..f5e5cb200a --- /dev/null +++ b/x/oracle/types/msgs_test.go @@ -0,0 +1,120 @@ +package types + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" +) + +func TestNewMsgQueryOracle(t *testing.T) { + authority := "creator" + channel := "channel" + query := []byte{0x01, 0x02, 0x04} + + msg := NewMsgSendQueryOracle(authority, channel, query) + assert.Equal(t, authority, msg.Authority, "must have the correct authority") + assert.Equal(t, channel, msg.Channel, "must have the correct channel") + assert.EqualValues(t, query, msg.Query, "must have the correct query") +} + +func TestNewMsgUpdateOracle(t *testing.T) { + authority := "creator" + address := "address" + + msg := NewMsgUpdateOracle(authority, address) + assert.Equal(t, authority, msg.Authority, "must have the correct authority") + assert.Equal(t, address, msg.Address, "must have the correct address") +} + +func TestMsgUpdateOracleRequestGetSigners(t *testing.T) { + authority := sdk.MustAccAddressFromBech32("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma") + address := "address" + + msg := NewMsgUpdateOracle(authority.String(), address) + signers := msg.GetSigners() + assert.Equal(t, []sdk.AccAddress{authority}, signers, "must have the correct signers") +} + +func TestMsgUpdateOracleRequestValidateBasic(t *testing.T) { + tests := []struct { + name string + msg *MsgUpdateOracleRequest + err string + }{ + { + name: "success - all fields are valid", + msg: NewMsgUpdateOracle("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma"), + }, + { + name: "failure - invalid authority", + msg: NewMsgUpdateOracle("jackthecat", "cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma"), + err: "invalid authority address: decoding bech32 failed: invalid separator index -1", + }, + { + name: "failure - invalid address", + msg: NewMsgUpdateOracle("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", "jackthecat"), + err: "invalid address for oracle: decoding bech32 failed: invalid separator index -1", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + res := tc.msg.ValidateBasic() + if len(tc.err) > 0 { + assert.EqualError(t, res, tc.err, "MsgUpdateOracleRequest.ValidateBasic") + } else { + assert.NoError(t, res, "MsgUpdateOracleRequest.ValidateBasic") + } + }) + } +} + +func TestMsgSendQueryOracleRequestGetSigners(t *testing.T) { + authority := sdk.MustAccAddressFromBech32("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma") + channel := "channel-1" + query := []byte{0x01, 0x02, 0x04} + + msg := NewMsgSendQueryOracle(authority.String(), channel, query) + signers := msg.GetSigners() + assert.Equal(t, []sdk.AccAddress{authority}, signers, "must have the correct signers") +} + +func TestMsgSendQueryOracleRequestValidateBasic(t *testing.T) { + tests := []struct { + name string + msg *MsgSendQueryOracleRequest + err string + }{ + { + name: "success - all fields are valid", + msg: NewMsgSendQueryOracle("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", "channel-1", []byte("{}")), + }, + { + name: "failure - invalid authority", + msg: NewMsgSendQueryOracle("jackthecat", "channel-1", []byte("{}")), + err: "invalid authority address: decoding bech32 failed: invalid separator index -1", + }, + { + name: "failure - invalid channel", + msg: NewMsgSendQueryOracle("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", "bad", []byte("{}")), + err: "invalid channel id", + }, + { + name: "failure - invalid query", + msg: NewMsgSendQueryOracle("cosmos1w6t0l7z0yerj49ehnqwqaayxqpe3u7e23edgma", "channel-1", []byte{}), + err: "invalid query data: invalid", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + res := tc.msg.ValidateBasic() + if len(tc.err) > 0 { + assert.EqualError(t, res, tc.err, "NewMsgSendQueryOracleRequest.ValidateBasic") + } else { + assert.NoError(t, res, "NewMsgSendQueryOracleRequest.ValidateBasic") + } + }) + } +} diff --git a/x/oracle/types/query.pb.go b/x/oracle/types/query.pb.go new file mode 100644 index 0000000000..d30296b904 --- /dev/null +++ b/x/oracle/types/query.pb.go @@ -0,0 +1,930 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: provenance/oracle/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_CosmWasm_wasmd_x_wasm_types "github.com/CosmWasm/wasmd/x/wasm/types" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryOracleAddressRequest queries for the address of the oracle. +type QueryOracleAddressRequest struct { +} + +func (m *QueryOracleAddressRequest) Reset() { *m = QueryOracleAddressRequest{} } +func (m *QueryOracleAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryOracleAddressRequest) ProtoMessage() {} +func (*QueryOracleAddressRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_169907f611744c57, []int{0} +} +func (m *QueryOracleAddressRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOracleAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOracleAddressRequest.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 *QueryOracleAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOracleAddressRequest.Merge(m, src) +} +func (m *QueryOracleAddressRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryOracleAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOracleAddressRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOracleAddressRequest proto.InternalMessageInfo + +// QueryOracleAddressResponse contains the address of the oracle. +type QueryOracleAddressResponse struct { + // The address of the oracle + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *QueryOracleAddressResponse) Reset() { *m = QueryOracleAddressResponse{} } +func (m *QueryOracleAddressResponse) String() string { return proto.CompactTextString(m) } +func (*QueryOracleAddressResponse) ProtoMessage() {} +func (*QueryOracleAddressResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_169907f611744c57, []int{1} +} +func (m *QueryOracleAddressResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOracleAddressResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOracleAddressResponse.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 *QueryOracleAddressResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOracleAddressResponse.Merge(m, src) +} +func (m *QueryOracleAddressResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryOracleAddressResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOracleAddressResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOracleAddressResponse proto.InternalMessageInfo + +func (m *QueryOracleAddressResponse) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +// QueryOracleRequest queries the module's oracle. +type QueryOracleRequest struct { + // Query contains the query data passed to the oracle. + Query github_com_CosmWasm_wasmd_x_wasm_types.RawContractMessage `protobuf:"bytes,1,opt,name=query,proto3,casttype=github.com/CosmWasm/wasmd/x/wasm/types.RawContractMessage" json:"query,omitempty"` +} + +func (m *QueryOracleRequest) Reset() { *m = QueryOracleRequest{} } +func (m *QueryOracleRequest) String() string { return proto.CompactTextString(m) } +func (*QueryOracleRequest) ProtoMessage() {} +func (*QueryOracleRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_169907f611744c57, []int{2} +} +func (m *QueryOracleRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOracleRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOracleRequest.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 *QueryOracleRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOracleRequest.Merge(m, src) +} +func (m *QueryOracleRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryOracleRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOracleRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOracleRequest proto.InternalMessageInfo + +func (m *QueryOracleRequest) GetQuery() github_com_CosmWasm_wasmd_x_wasm_types.RawContractMessage { + if m != nil { + return m.Query + } + return nil +} + +// QueryOracleResponse contains the result of the query sent to the oracle. +type QueryOracleResponse struct { + // Data contains the json data returned from the oracle. + Data github_com_CosmWasm_wasmd_x_wasm_types.RawContractMessage `protobuf:"bytes,1,opt,name=data,proto3,casttype=github.com/CosmWasm/wasmd/x/wasm/types.RawContractMessage" json:"data,omitempty"` +} + +func (m *QueryOracleResponse) Reset() { *m = QueryOracleResponse{} } +func (m *QueryOracleResponse) String() string { return proto.CompactTextString(m) } +func (*QueryOracleResponse) ProtoMessage() {} +func (*QueryOracleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_169907f611744c57, []int{3} +} +func (m *QueryOracleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryOracleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryOracleResponse.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 *QueryOracleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryOracleResponse.Merge(m, src) +} +func (m *QueryOracleResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryOracleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryOracleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryOracleResponse proto.InternalMessageInfo + +func (m *QueryOracleResponse) GetData() github_com_CosmWasm_wasmd_x_wasm_types.RawContractMessage { + if m != nil { + return m.Data + } + return nil +} + +func init() { + proto.RegisterType((*QueryOracleAddressRequest)(nil), "provenance.oracle.v1.QueryOracleAddressRequest") + proto.RegisterType((*QueryOracleAddressResponse)(nil), "provenance.oracle.v1.QueryOracleAddressResponse") + proto.RegisterType((*QueryOracleRequest)(nil), "provenance.oracle.v1.QueryOracleRequest") + proto.RegisterType((*QueryOracleResponse)(nil), "provenance.oracle.v1.QueryOracleResponse") +} + +func init() { proto.RegisterFile("provenance/oracle/v1/query.proto", fileDescriptor_169907f611744c57) } + +var fileDescriptor_169907f611744c57 = []byte{ + // 422 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x92, 0xbf, 0xae, 0xd3, 0x30, + 0x14, 0xc6, 0xeb, 0x2b, 0xee, 0x45, 0x58, 0xb0, 0x98, 0x4a, 0xdc, 0x1b, 0xaa, 0x50, 0x45, 0x15, + 0x2a, 0x12, 0x8d, 0x69, 0x99, 0x18, 0x18, 0x68, 0x67, 0x44, 0x9b, 0x0e, 0x48, 0x2c, 0x95, 0x9b, + 0x58, 0x6e, 0xa4, 0xc6, 0x27, 0x8d, 0xdd, 0x7f, 0x2b, 0xbc, 0x00, 0x12, 0x2f, 0xc0, 0x23, 0x30, + 0xf0, 0x10, 0x8c, 0x15, 0x2c, 0x4c, 0x08, 0xb5, 0x3c, 0x05, 0x13, 0xaa, 0x9d, 0xaa, 0xad, 0x14, + 0xa0, 0xc3, 0x9d, 0xe2, 0xf8, 0x7c, 0xfe, 0x7e, 0x9f, 0x7d, 0x0e, 0xae, 0xa6, 0x19, 0xcc, 0xb8, + 0x64, 0x32, 0xe4, 0x14, 0x32, 0x16, 0x8e, 0x39, 0x9d, 0x35, 0xe9, 0x64, 0xca, 0xb3, 0xa5, 0x9f, + 0x66, 0xa0, 0x81, 0x94, 0xf7, 0x0a, 0xdf, 0x2a, 0xfc, 0x59, 0xd3, 0x29, 0x0b, 0x10, 0x60, 0x04, + 0x74, 0xbb, 0xb2, 0x5a, 0xa7, 0x22, 0x00, 0xc4, 0x98, 0x53, 0x96, 0xc6, 0x94, 0x49, 0x09, 0x9a, + 0xe9, 0x18, 0xa4, 0xca, 0xab, 0x57, 0x21, 0xa8, 0x04, 0xd4, 0xc0, 0x1e, 0xb3, 0x3f, 0xb6, 0xe4, + 0xdd, 0xc7, 0x57, 0xbd, 0x2d, 0xf3, 0x95, 0x01, 0xbc, 0x88, 0xa2, 0x8c, 0x2b, 0x15, 0xf0, 0xc9, + 0x94, 0x2b, 0xed, 0x75, 0xb1, 0x53, 0x54, 0x54, 0x29, 0x48, 0xc5, 0x49, 0x0b, 0xdf, 0x64, 0x76, + 0xeb, 0x12, 0x55, 0x51, 0xfd, 0x56, 0xfb, 0xf2, 0xeb, 0xe7, 0x46, 0x39, 0x77, 0xcf, 0xc5, 0x7d, + 0x9d, 0xc5, 0x52, 0x04, 0x3b, 0xa1, 0x17, 0x63, 0x72, 0xe0, 0x98, 0x73, 0x48, 0x1f, 0x9f, 0x9b, + 0x8b, 0x1b, 0x9f, 0xdb, 0xed, 0xe7, 0xbf, 0x7f, 0x3c, 0x78, 0x26, 0x62, 0x3d, 0x9a, 0x0e, 0xfd, + 0x10, 0x12, 0xda, 0x01, 0x95, 0xbc, 0x66, 0x2a, 0xa1, 0x73, 0xa6, 0x92, 0x88, 0x2e, 0xcc, 0x97, + 0xea, 0x65, 0xca, 0x95, 0x1f, 0xb0, 0x79, 0x07, 0xa4, 0xce, 0x58, 0xa8, 0x5f, 0x72, 0xa5, 0x98, + 0xe0, 0x81, 0xf5, 0xf2, 0x46, 0xf8, 0xee, 0x11, 0x2a, 0x4f, 0xdd, 0xc3, 0x37, 0x22, 0xa6, 0xd9, + 0xf5, 0xa0, 0x8c, 0x55, 0xeb, 0xd3, 0x19, 0x3e, 0x37, 0x28, 0xf2, 0x11, 0xe1, 0x3b, 0x47, 0x8f, + 0x45, 0xa8, 0x5f, 0xd4, 0x45, 0xff, 0xaf, 0x6f, 0xee, 0x3c, 0x39, 0xfd, 0x80, 0xbd, 0x91, 0xf7, + 0xf8, 0xed, 0xb7, 0x5f, 0x1f, 0xce, 0x1e, 0x92, 0x1a, 0x2d, 0x1c, 0x29, 0xbb, 0x1a, 0xe4, 0x1d, + 0x20, 0xef, 0x10, 0xbe, 0xb0, 0x3e, 0xa4, 0xfe, 0x5f, 0xd4, 0x2e, 0xd4, 0xa3, 0x13, 0x94, 0x79, + 0x9a, 0x9a, 0x49, 0xe3, 0x92, 0xca, 0xbf, 0xd2, 0xb4, 0xc5, 0x97, 0xb5, 0x8b, 0x56, 0x6b, 0x17, + 0xfd, 0x5c, 0xbb, 0xe8, 0xfd, 0xc6, 0x2d, 0xad, 0x36, 0x6e, 0xe9, 0xfb, 0xc6, 0x2d, 0xe1, 0x7b, + 0x31, 0x14, 0xc2, 0xba, 0xe8, 0x4d, 0xeb, 0xa0, 0x51, 0x7b, 0x49, 0x23, 0x86, 0x43, 0xd4, 0x62, + 0x07, 0x33, 0x4d, 0x1b, 0x5e, 0x98, 0x31, 0x7f, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x78, + 0xa0, 0x70, 0x6f, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // OracleAddress returns the address of the oracle + OracleAddress(ctx context.Context, in *QueryOracleAddressRequest, opts ...grpc.CallOption) (*QueryOracleAddressResponse, error) + // Oracle forwards a query to the module's oracle + Oracle(ctx context.Context, in *QueryOracleRequest, opts ...grpc.CallOption) (*QueryOracleResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) OracleAddress(ctx context.Context, in *QueryOracleAddressRequest, opts ...grpc.CallOption) (*QueryOracleAddressResponse, error) { + out := new(QueryOracleAddressResponse) + err := c.cc.Invoke(ctx, "/provenance.oracle.v1.Query/OracleAddress", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Oracle(ctx context.Context, in *QueryOracleRequest, opts ...grpc.CallOption) (*QueryOracleResponse, error) { + out := new(QueryOracleResponse) + err := c.cc.Invoke(ctx, "/provenance.oracle.v1.Query/Oracle", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // OracleAddress returns the address of the oracle + OracleAddress(context.Context, *QueryOracleAddressRequest) (*QueryOracleAddressResponse, error) + // Oracle forwards a query to the module's oracle + Oracle(context.Context, *QueryOracleRequest) (*QueryOracleResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) OracleAddress(ctx context.Context, req *QueryOracleAddressRequest) (*QueryOracleAddressResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OracleAddress not implemented") +} +func (*UnimplementedQueryServer) Oracle(ctx context.Context, req *QueryOracleRequest) (*QueryOracleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Oracle not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_OracleAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryOracleAddressRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).OracleAddress(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/provenance.oracle.v1.Query/OracleAddress", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).OracleAddress(ctx, req.(*QueryOracleAddressRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Oracle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryOracleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Oracle(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/provenance.oracle.v1.Query/Oracle", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Oracle(ctx, req.(*QueryOracleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "provenance.oracle.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "OracleAddress", + Handler: _Query_OracleAddress_Handler, + }, + { + MethodName: "Oracle", + Handler: _Query_Oracle_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "provenance/oracle/v1/query.proto", +} + +func (m *QueryOracleAddressRequest) 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 *QueryOracleAddressRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOracleAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryOracleAddressResponse) 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 *QueryOracleAddressResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOracleAddressResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryOracleRequest) 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 *QueryOracleRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOracleRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryOracleResponse) 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 *QueryOracleResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryOracleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Data) > 0 { + i -= len(m.Data) + copy(dAtA[i:], m.Data) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryOracleAddressRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryOracleAddressResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryOracleRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Query) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryOracleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryOracleAddressRequest) 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: QueryOracleAddressRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOracleAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryOracleAddressResponse) 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: QueryOracleAddressResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOracleAddressResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryOracleRequest) 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: QueryOracleRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOracleRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = append(m.Query[:0], dAtA[iNdEx:postIndex]...) + if m.Query == nil { + m.Query = []byte{} + } + 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 *QueryOracleResponse) 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: QueryOracleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryOracleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/oracle/types/query.pb.gw.go b/x/oracle/types/query.pb.gw.go new file mode 100644 index 0000000000..890ce9af78 --- /dev/null +++ b/x/oracle/types/query.pb.gw.go @@ -0,0 +1,228 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: provenance/oracle/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage + +func request_Query_OracleAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOracleAddressRequest + var metadata runtime.ServerMetadata + + msg, err := client.OracleAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_OracleAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOracleAddressRequest + var metadata runtime.ServerMetadata + + msg, err := server.OracleAddress(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_Oracle_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Oracle_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOracleRequest + 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_Oracle_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Oracle(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Oracle_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryOracleRequest + 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_Oracle_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Oracle(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_OracleAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_OracleAddress_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_OracleAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Oracle_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Oracle_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Oracle_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_OracleAddress_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_OracleAddress_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_OracleAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Oracle_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_Oracle_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_Oracle_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_OracleAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"provenance", "oracle", "v1", "oracle_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Oracle_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"provenance", "oracle", "v1"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_OracleAddress_0 = runtime.ForwardResponseMessage + + forward_Query_Oracle_0 = runtime.ForwardResponseMessage +) diff --git a/x/oracle/types/tx.pb.go b/x/oracle/types/tx.pb.go new file mode 100644 index 0000000000..348db4fe6a --- /dev/null +++ b/x/oracle/types/tx.pb.go @@ -0,0 +1,1096 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: provenance/oracle/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_CosmWasm_wasmd_x_wasm_types "github.com/CosmWasm/wasmd/x/wasm/types" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSendQueryOracleRequest queries an oracle on another chain +type MsgSendQueryOracleRequest struct { + // Query contains the query data passed to the oracle. + Query github_com_CosmWasm_wasmd_x_wasm_types.RawContractMessage `protobuf:"bytes,1,opt,name=query,proto3,casttype=github.com/CosmWasm/wasmd/x/wasm/types.RawContractMessage" json:"query,omitempty"` + // Channel is the channel to the oracle. + Channel string `protobuf:"bytes,3,opt,name=channel,proto3" json:"channel,omitempty"` + // The signing authority for the request + Authority string `protobuf:"bytes,4,opt,name=authority,proto3" json:"authority,omitempty"` +} + +func (m *MsgSendQueryOracleRequest) Reset() { *m = MsgSendQueryOracleRequest{} } +func (m *MsgSendQueryOracleRequest) String() string { return proto.CompactTextString(m) } +func (*MsgSendQueryOracleRequest) ProtoMessage() {} +func (*MsgSendQueryOracleRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_66a39dda41c6a784, []int{0} +} +func (m *MsgSendQueryOracleRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSendQueryOracleRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSendQueryOracleRequest.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 *MsgSendQueryOracleRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSendQueryOracleRequest.Merge(m, src) +} +func (m *MsgSendQueryOracleRequest) XXX_Size() int { + return m.Size() +} +func (m *MsgSendQueryOracleRequest) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSendQueryOracleRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSendQueryOracleRequest proto.InternalMessageInfo + +func (m *MsgSendQueryOracleRequest) GetQuery() github_com_CosmWasm_wasmd_x_wasm_types.RawContractMessage { + if m != nil { + return m.Query + } + return nil +} + +func (m *MsgSendQueryOracleRequest) GetChannel() string { + if m != nil { + return m.Channel + } + return "" +} + +func (m *MsgSendQueryOracleRequest) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +// MsgSendQueryOracleResponse contains the id of the oracle query. +type MsgSendQueryOracleResponse struct { + // The sequence number that uniquely identifies the query. + Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` +} + +func (m *MsgSendQueryOracleResponse) Reset() { *m = MsgSendQueryOracleResponse{} } +func (m *MsgSendQueryOracleResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSendQueryOracleResponse) ProtoMessage() {} +func (*MsgSendQueryOracleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_66a39dda41c6a784, []int{1} +} +func (m *MsgSendQueryOracleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSendQueryOracleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSendQueryOracleResponse.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 *MsgSendQueryOracleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSendQueryOracleResponse.Merge(m, src) +} +func (m *MsgSendQueryOracleResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSendQueryOracleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSendQueryOracleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSendQueryOracleResponse proto.InternalMessageInfo + +func (m *MsgSendQueryOracleResponse) GetSequence() uint64 { + if m != nil { + return m.Sequence + } + return 0 +} + +// MsgUpdateOracleRequest is the request type for updating an oracle's contract address +type MsgUpdateOracleRequest struct { + // The address of the oracle's contract + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // The signing authorities for the request + Authority string `protobuf:"bytes,2,opt,name=authority,proto3" json:"authority,omitempty"` +} + +func (m *MsgUpdateOracleRequest) Reset() { *m = MsgUpdateOracleRequest{} } +func (m *MsgUpdateOracleRequest) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateOracleRequest) ProtoMessage() {} +func (*MsgUpdateOracleRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_66a39dda41c6a784, []int{2} +} +func (m *MsgUpdateOracleRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateOracleRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateOracleRequest.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 *MsgUpdateOracleRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateOracleRequest.Merge(m, src) +} +func (m *MsgUpdateOracleRequest) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateOracleRequest) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateOracleRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateOracleRequest proto.InternalMessageInfo + +func (m *MsgUpdateOracleRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *MsgUpdateOracleRequest) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +// MsgUpdateOracleResponse is the response type for updating the oracle. +type MsgUpdateOracleResponse struct { +} + +func (m *MsgUpdateOracleResponse) Reset() { *m = MsgUpdateOracleResponse{} } +func (m *MsgUpdateOracleResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateOracleResponse) ProtoMessage() {} +func (*MsgUpdateOracleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_66a39dda41c6a784, []int{3} +} +func (m *MsgUpdateOracleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateOracleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateOracleResponse.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 *MsgUpdateOracleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateOracleResponse.Merge(m, src) +} +func (m *MsgUpdateOracleResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateOracleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateOracleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateOracleResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgSendQueryOracleRequest)(nil), "provenance.oracle.v1.MsgSendQueryOracleRequest") + proto.RegisterType((*MsgSendQueryOracleResponse)(nil), "provenance.oracle.v1.MsgSendQueryOracleResponse") + proto.RegisterType((*MsgUpdateOracleRequest)(nil), "provenance.oracle.v1.MsgUpdateOracleRequest") + proto.RegisterType((*MsgUpdateOracleResponse)(nil), "provenance.oracle.v1.MsgUpdateOracleResponse") +} + +func init() { proto.RegisterFile("provenance/oracle/v1/tx.proto", fileDescriptor_66a39dda41c6a784) } + +var fileDescriptor_66a39dda41c6a784 = []byte{ + // 443 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x41, 0x6f, 0xd3, 0x30, + 0x14, 0xc7, 0x6b, 0x36, 0xd8, 0x66, 0x4d, 0x42, 0xb2, 0x2a, 0x96, 0x46, 0x22, 0x9d, 0x72, 0xda, + 0x81, 0xc6, 0xac, 0x48, 0x08, 0x90, 0x38, 0xd0, 0x9d, 0x23, 0x20, 0x15, 0x42, 0xe2, 0x82, 0xbc, + 0xc4, 0x72, 0x23, 0x16, 0x3b, 0xf3, 0x73, 0xba, 0xf6, 0x4b, 0x20, 0x8e, 0x1c, 0xf7, 0x21, 0xf8, + 0x04, 0x9c, 0x38, 0x56, 0x9c, 0x38, 0x21, 0xd4, 0x5e, 0xfa, 0x19, 0x38, 0xa1, 0xc4, 0x2d, 0x6d, + 0x21, 0xa0, 0x9e, 0x92, 0xf7, 0xde, 0xff, 0x3d, 0xfb, 0x67, 0xfd, 0x1f, 0xbe, 0x9b, 0x6b, 0x35, + 0xe4, 0x92, 0xc9, 0x98, 0x53, 0xa5, 0x59, 0x7c, 0xc1, 0xe9, 0xf0, 0x94, 0x9a, 0x51, 0x90, 0x6b, + 0x65, 0x14, 0x69, 0xae, 0xca, 0x81, 0x2d, 0x07, 0xc3, 0x53, 0xb7, 0x15, 0x2b, 0xc8, 0x14, 0xbc, + 0xad, 0x34, 0xd4, 0x06, 0xb6, 0xc1, 0x6d, 0x0a, 0x25, 0x94, 0xcd, 0x97, 0x7f, 0x36, 0xeb, 0x7f, + 0x46, 0xb8, 0x15, 0x82, 0xe8, 0x73, 0x99, 0xbc, 0x2c, 0xb8, 0x1e, 0x3f, 0xaf, 0x46, 0x45, 0xfc, + 0xb2, 0xe0, 0x60, 0x48, 0x1f, 0xdf, 0xbc, 0x2c, 0xb3, 0x0e, 0x3a, 0x46, 0x27, 0x87, 0xbd, 0xa7, + 0x3f, 0xbf, 0xb7, 0x1f, 0x8b, 0xd4, 0x0c, 0x8a, 0xf3, 0x20, 0x56, 0x19, 0x3d, 0x53, 0x90, 0xbd, + 0x66, 0x90, 0xd1, 0x2b, 0x06, 0x59, 0x42, 0x47, 0xd5, 0x97, 0x9a, 0x71, 0xce, 0x21, 0x88, 0xd8, + 0xd5, 0x99, 0x92, 0x46, 0xb3, 0xd8, 0x84, 0x1c, 0x80, 0x09, 0x1e, 0xd9, 0x59, 0xc4, 0xc1, 0x7b, + 0xf1, 0x80, 0x49, 0xc9, 0x2f, 0x9c, 0x9d, 0x63, 0x74, 0x72, 0x10, 0x2d, 0x43, 0xf2, 0x10, 0x1f, + 0xb0, 0xc2, 0x0c, 0x94, 0x4e, 0xcd, 0xd8, 0xd9, 0x2d, 0x6b, 0x3d, 0xe7, 0xeb, 0xa7, 0x4e, 0x73, + 0xc1, 0xf1, 0x2c, 0x49, 0x34, 0x07, 0xe8, 0x1b, 0x9d, 0x4a, 0x11, 0xad, 0xa4, 0xfe, 0x23, 0xec, + 0xd6, 0x31, 0x40, 0xae, 0x24, 0x70, 0xe2, 0xe2, 0x7d, 0x28, 0x79, 0x64, 0xcc, 0x2b, 0x8e, 0xdd, + 0xe8, 0x77, 0xec, 0xbf, 0x47, 0xf8, 0x4e, 0x08, 0xe2, 0x55, 0x9e, 0x30, 0xc3, 0x37, 0xd9, 0xbb, + 0x78, 0x8f, 0xd9, 0x03, 0xab, 0xae, 0xff, 0x5d, 0x65, 0x29, 0xdc, 0x04, 0xb8, 0xb1, 0x35, 0xc0, + 0x93, 0xfd, 0x8f, 0xd7, 0x6d, 0x34, 0xbf, 0x6e, 0x23, 0xbf, 0x85, 0x8f, 0xfe, 0xba, 0x8f, 0xe5, + 0xe8, 0xce, 0x11, 0xde, 0x09, 0x41, 0x90, 0x77, 0xf8, 0x70, 0xbd, 0x4e, 0xee, 0x05, 0x75, 0x56, + 0x08, 0xea, 0xb1, 0xdc, 0xce, 0x96, 0xea, 0xc5, 0xe3, 0x19, 0x7c, 0xfb, 0x8f, 0x77, 0x25, 0xf4, + 0x9f, 0x13, 0xea, 0x5d, 0xe4, 0xde, 0xdf, 0xbe, 0xc1, 0x9e, 0xda, 0x13, 0x5f, 0xa6, 0x1e, 0x9a, + 0x4c, 0x3d, 0xf4, 0x63, 0xea, 0xa1, 0x0f, 0x33, 0xaf, 0x31, 0x99, 0x79, 0x8d, 0x6f, 0x33, 0xaf, + 0x81, 0x8f, 0x52, 0x55, 0x3b, 0xed, 0x05, 0x7a, 0xd3, 0x5d, 0x73, 0xe6, 0x4a, 0xd2, 0x49, 0xd5, + 0x5a, 0x44, 0x47, 0xcb, 0x5d, 0xaa, 0x5c, 0x7a, 0x7e, 0xab, 0xda, 0x82, 0x07, 0xbf, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x49, 0x33, 0xee, 0xe2, 0x6d, 0x03, 0x00, 0x00, +} + +func (this *MsgUpdateOracleRequest) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MsgUpdateOracleRequest) + if !ok { + that2, ok := that.(MsgUpdateOracleRequest) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Address != that1.Address { + return false + } + if this.Authority != that1.Authority { + return false + } + return true +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // UpdateOracle is the RPC endpoint for updating the oracle + UpdateOracle(ctx context.Context, in *MsgUpdateOracleRequest, opts ...grpc.CallOption) (*MsgUpdateOracleResponse, error) + // SendQueryOracle sends a query to an oracle on another chain + SendQueryOracle(ctx context.Context, in *MsgSendQueryOracleRequest, opts ...grpc.CallOption) (*MsgSendQueryOracleResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) UpdateOracle(ctx context.Context, in *MsgUpdateOracleRequest, opts ...grpc.CallOption) (*MsgUpdateOracleResponse, error) { + out := new(MsgUpdateOracleResponse) + err := c.cc.Invoke(ctx, "/provenance.oracle.v1.Msg/UpdateOracle", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) SendQueryOracle(ctx context.Context, in *MsgSendQueryOracleRequest, opts ...grpc.CallOption) (*MsgSendQueryOracleResponse, error) { + out := new(MsgSendQueryOracleResponse) + err := c.cc.Invoke(ctx, "/provenance.oracle.v1.Msg/SendQueryOracle", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // UpdateOracle is the RPC endpoint for updating the oracle + UpdateOracle(context.Context, *MsgUpdateOracleRequest) (*MsgUpdateOracleResponse, error) + // SendQueryOracle sends a query to an oracle on another chain + SendQueryOracle(context.Context, *MsgSendQueryOracleRequest) (*MsgSendQueryOracleResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) UpdateOracle(ctx context.Context, req *MsgUpdateOracleRequest) (*MsgUpdateOracleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateOracle not implemented") +} +func (*UnimplementedMsgServer) SendQueryOracle(ctx context.Context, req *MsgSendQueryOracleRequest) (*MsgSendQueryOracleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendQueryOracle not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_UpdateOracle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateOracleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateOracle(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/provenance.oracle.v1.Msg/UpdateOracle", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateOracle(ctx, req.(*MsgUpdateOracleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_SendQueryOracle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSendQueryOracleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SendQueryOracle(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/provenance.oracle.v1.Msg/SendQueryOracle", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SendQueryOracle(ctx, req.(*MsgSendQueryOracleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "provenance.oracle.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateOracle", + Handler: _Msg_UpdateOracle_Handler, + }, + { + MethodName: "SendQueryOracle", + Handler: _Msg_SendQueryOracle_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "provenance/oracle/v1/tx.proto", +} + +func (m *MsgSendQueryOracleRequest) 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 *MsgSendQueryOracleRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSendQueryOracleRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0x22 + } + if len(m.Channel) > 0 { + i -= len(m.Channel) + copy(dAtA[i:], m.Channel) + i = encodeVarintTx(dAtA, i, uint64(len(m.Channel))) + i-- + dAtA[i] = 0x1a + } + if len(m.Query) > 0 { + i -= len(m.Query) + copy(dAtA[i:], m.Query) + i = encodeVarintTx(dAtA, i, uint64(len(m.Query))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSendQueryOracleResponse) 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 *MsgSendQueryOracleResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSendQueryOracleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Sequence != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Sequence)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateOracleRequest) 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 *MsgUpdateOracleRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateOracleRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0x12 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateOracleResponse) 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 *MsgUpdateOracleResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateOracleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSendQueryOracleRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Query) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Channel) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgSendQueryOracleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sequence != 0 { + n += 1 + sovTx(uint64(m.Sequence)) + } + return n +} + +func (m *MsgUpdateOracleRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgUpdateOracleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSendQueryOracleRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSendQueryOracleRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSendQueryOracleRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Query", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Query = append(m.Query[:0], dAtA[iNdEx:postIndex]...) + if m.Query == nil { + m.Query = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgSendQueryOracleResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSendQueryOracleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSendQueryOracleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) + } + m.Sequence = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Sequence |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateOracleRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateOracleRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateOracleRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateOracleResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateOracleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateOracleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)