From 1cb6e7acbcb01fc078e0cf4241c21fb02620aced Mon Sep 17 00:00:00 2001 From: aleem1314 Date: Tue, 28 Feb 2023 14:30:54 +0530 Subject: [PATCH 1/3] feat: add proto files --- proto/wasm/v1/authz.proto | 109 + proto/wasm/v1/genesis.proto | 46 + proto/wasm/v1/ibc.proto | 31 + proto/wasm/v1/proposal.proto | 272 ++ proto/wasm/v1/query.proto | 263 ++ proto/wasm/v1/tx.proto | 192 ++ proto/wasm/v1/types.proto | 144 + x/wasm/types/authz.pb.go | 1805 +++++++++++ x/wasm/types/genesis.pb.go | 1388 +++++++++ x/wasm/types/ibc.pb.go | 592 ++++ x/wasm/types/proposal.pb.go | 5697 ++++++++++++++++++++++++++++++++++ x/wasm/types/query.pb.go | 5481 ++++++++++++++++++++++++++++++++ x/wasm/types/query.pb.gw.go | 1243 ++++++++ x/wasm/types/tx.pb.go | 4304 +++++++++++++++++++++++++ x/wasm/types/types.pb.go | 2483 +++++++++++++++ 15 files changed, 24050 insertions(+) create mode 100644 proto/wasm/v1/authz.proto create mode 100644 proto/wasm/v1/genesis.proto create mode 100644 proto/wasm/v1/ibc.proto create mode 100644 proto/wasm/v1/proposal.proto create mode 100644 proto/wasm/v1/query.proto create mode 100644 proto/wasm/v1/tx.proto create mode 100644 proto/wasm/v1/types.proto create mode 100644 x/wasm/types/authz.pb.go create mode 100644 x/wasm/types/genesis.pb.go create mode 100644 x/wasm/types/ibc.pb.go create mode 100644 x/wasm/types/proposal.pb.go create mode 100644 x/wasm/types/query.pb.go create mode 100644 x/wasm/types/query.pb.gw.go create mode 100644 x/wasm/types/tx.pb.go create mode 100644 x/wasm/types/types.pb.go diff --git a/proto/wasm/v1/authz.proto b/proto/wasm/v1/authz.proto new file mode 100644 index 00000000..ac1a2499 --- /dev/null +++ b/proto/wasm/v1/authz.proto @@ -0,0 +1,109 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "google/protobuf/any.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; +option (gogoproto.goproto_getters_all) = false; + +// ContractExecutionAuthorization defines authorization for wasm execute. +// Since: wasmd 0.30 +message ContractExecutionAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + // Grants for contract executions + repeated ContractGrant grants = 1 [ (gogoproto.nullable) = false ]; +} + +// ContractMigrationAuthorization defines authorization for wasm contract +// migration. Since: wasmd 0.30 +message ContractMigrationAuthorization { + option (cosmos_proto.implements_interface) = "Authorization"; + + // Grants for contract migrations + repeated ContractGrant grants = 1 [ (gogoproto.nullable) = false ]; +} + +// ContractGrant a granted permission for a single contract +// Since: wasmd 0.30 +message ContractGrant { + // Contract is the bech32 address of the smart contract + string contract = 1; + + // Limit defines execution limits that are enforced and updated when the grant + // is applied. When the limit lapsed the grant is removed. + google.protobuf.Any limit = 2 + [ (cosmos_proto.accepts_interface) = "ContractAuthzLimitX" ]; + + // Filter define more fine-grained control on the message payload passed + // to the contract in the operation. When no filter applies on execution, the + // operation is prohibited. + google.protobuf.Any filter = 3 + [ (cosmos_proto.accepts_interface) = "ContractAuthzFilterX" ]; +} + +// MaxCallsLimit limited number of calls to the contract. No funds transferable. +// Since: wasmd 0.30 +message MaxCallsLimit { + option (cosmos_proto.implements_interface) = "ContractAuthzLimitX"; + + // Remaining number that is decremented on each execution + uint64 remaining = 1; +} + +// MaxFundsLimit defines the maximal amounts that can be sent to the contract. +// Since: wasmd 0.30 +message MaxFundsLimit { + option (cosmos_proto.implements_interface) = "ContractAuthzLimitX"; + + // Amounts is the maximal amount of tokens transferable to the contract. + repeated cosmos.base.v1beta1.Coin amounts = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// CombinedLimit defines the maximal amounts that can be sent to a contract and +// the maximal number of calls executable. Both need to remain >0 to be valid. +// Since: wasmd 0.30 +message CombinedLimit { + option (cosmos_proto.implements_interface) = "ContractAuthzLimitX"; + + // Remaining number that is decremented on each execution + uint64 calls_remaining = 1; + // Amounts is the maximal amount of tokens transferable to the contract. + repeated cosmos.base.v1beta1.Coin amounts = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// AllowAllMessagesFilter is a wildcard to allow any type of contract payload +// message. +// Since: wasmd 0.30 +message AllowAllMessagesFilter { + option (cosmos_proto.implements_interface) = "ContractAuthzFilterX"; +} + +// AcceptedMessageKeysFilter accept only the specific contract message keys in +// the json object to be executed. +// Since: wasmd 0.30 +message AcceptedMessageKeysFilter { + option (cosmos_proto.implements_interface) = "ContractAuthzFilterX"; + + // Messages is the list of unique keys + repeated string keys = 1; +} + +// AcceptedMessagesFilter accept only the specific raw contract messages to be +// executed. +// Since: wasmd 0.30 +message AcceptedMessagesFilter { + option (cosmos_proto.implements_interface) = "ContractAuthzFilterX"; + + // Messages is the list of raw contract messages + repeated bytes messages = 1 [ (gogoproto.casttype) = "RawContractMessage" ]; +} \ No newline at end of file diff --git a/proto/wasm/v1/genesis.proto b/proto/wasm/v1/genesis.proto new file mode 100644 index 00000000..30fb8352 --- /dev/null +++ b/proto/wasm/v1/genesis.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "gogoproto/gogo.proto"; +import "wasm/v1/types.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; + +// GenesisState - genesis state of x/wasm +message GenesisState { + Params params = 1 [ (gogoproto.nullable) = false ]; + repeated Code codes = 2 + [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "codes,omitempty" ]; + repeated Contract contracts = 3 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "contracts,omitempty" + ]; + repeated Sequence sequences = 4 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "sequences,omitempty" + ]; +} + +// Code struct encompasses CodeInfo and CodeBytes +message Code { + uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ]; + CodeInfo code_info = 2 [ (gogoproto.nullable) = false ]; + bytes code_bytes = 3; + // Pinned to wasmvm cache + bool pinned = 4; +} + +// Contract struct encompasses ContractAddress, ContractInfo, and ContractState +message Contract { + string contract_address = 1; + ContractInfo contract_info = 2 [ (gogoproto.nullable) = false ]; + repeated Model contract_state = 3 [ (gogoproto.nullable) = false ]; + repeated ContractCodeHistoryEntry contract_code_history = 4 + [ (gogoproto.nullable) = false ]; +} + +// Sequence key and value of an id generation counter +message Sequence { + bytes id_key = 1 [ (gogoproto.customname) = "IDKey" ]; + uint64 value = 2; +} \ No newline at end of file diff --git a/proto/wasm/v1/ibc.proto b/proto/wasm/v1/ibc.proto new file mode 100644 index 00000000..583cae3c --- /dev/null +++ b/proto/wasm/v1/ibc.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; +option (gogoproto.goproto_getters_all) = false; + +// MsgIBCSend +message MsgIBCSend { + // the channel by which the packet will be sent + string channel = 2 [ (gogoproto.moretags) = "yaml:\"source_channel\"" ]; + + // Timeout height relative to the current block height. + // The timeout is disabled when set to 0. + uint64 timeout_height = 4 + [ (gogoproto.moretags) = "yaml:\"timeout_height\"" ]; + // Timeout timestamp (in nanoseconds) relative to the current block timestamp. + // The timeout is disabled when set to 0. + uint64 timeout_timestamp = 5 + [ (gogoproto.moretags) = "yaml:\"timeout_timestamp\"" ]; + + // Data is the payload to transfer. We must not make assumption what format or + // content is in here. + bytes data = 6; +} + +// MsgIBCCloseChannel port and channel need to be owned by the contract +message MsgIBCCloseChannel { + string channel = 2 [ (gogoproto.moretags) = "yaml:\"source_channel\"" ]; +} \ No newline at end of file diff --git a/proto/wasm/v1/proposal.proto b/proto/wasm/v1/proposal.proto new file mode 100644 index 00000000..77ddb790 --- /dev/null +++ b/proto/wasm/v1/proposal.proto @@ -0,0 +1,272 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "wasm/v1/types.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; +option (gogoproto.goproto_stringer_all) = false; +option (gogoproto.goproto_getters_all) = false; +option (gogoproto.equal_all) = true; + +// StoreCodeProposal gov proposal content type to submit WASM code to the system +message StoreCodeProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // RunAs is the address that is passed to the contract's environment as sender + string run_as = 3; + // WASMByteCode can be raw or gzip compressed + bytes wasm_byte_code = 4 [ (gogoproto.customname) = "WASMByteCode" ]; + // Used in v1beta1 + reserved 5, 6; + // InstantiatePermission to apply on contract creation, optional + AccessConfig instantiate_permission = 7; + // UnpinCode code on upload, optional + bool unpin_code = 8; + // Source is the URL where the code is hosted + string source = 9; + // Builder is the docker image used to build the code deterministically, used + // for smart contract verification + string builder = 10; + // CodeHash is the SHA256 sum of the code outputted by builder, used for smart + // contract verification + bytes code_hash = 11; +} + +// InstantiateContractProposal gov proposal content type to instantiate a +// contract. +message InstantiateContractProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // RunAs is the address that is passed to the contract's environment as sender + string run_as = 3; + // Admin is an optional address that can execute migrations + string admin = 4; + // CodeID is the reference to the stored WASM code + uint64 code_id = 5 [ (gogoproto.customname) = "CodeID" ]; + // Label is optional metadata to be stored with a constract instance. + string label = 6; + // Msg json encoded message to be passed to the contract on instantiation + bytes msg = 7 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 8 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// InstantiateContract2Proposal gov proposal content type to instantiate +// contract 2 +message InstantiateContract2Proposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // RunAs is the address that is passed to the contract's enviroment as sender + string run_as = 3; + // Admin is an optional address that can execute migrations + string admin = 4; + // CodeID is the reference to the stored WASM code + uint64 code_id = 5 [ (gogoproto.customname) = "CodeID" ]; + // Label is optional metadata to be stored with a constract instance. + string label = 6; + // Msg json encode message to be passed to the contract on instantiation + bytes msg = 7 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 8 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // Salt is an arbitrary value provided by the sender. Size can be 1 to 64. + bytes salt = 9; + // FixMsg include the msg value into the hash for the predictable address. + // Default is false + bool fix_msg = 10; +} + +// MigrateContractProposal gov proposal content type to migrate a contract. +message MigrateContractProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // Note: skipping 3 as this was previously used for unneeded run_as + + // Contract is the address of the smart contract + string contract = 4; + // CodeID references the new WASM code + uint64 code_id = 5 [ (gogoproto.customname) = "CodeID" ]; + // Msg json encoded message to be passed to the contract on migration + bytes msg = 6 [ (gogoproto.casttype) = "RawContractMessage" ]; +} + +// SudoContractProposal gov proposal content type to call sudo on a contract. +message SudoContractProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // Contract is the address of the smart contract + string contract = 3; + // Msg json encoded message to be passed to the contract as sudo + bytes msg = 4 [ (gogoproto.casttype) = "RawContractMessage" ]; +} + +// ExecuteContractProposal gov proposal content type to call execute on a +// contract. +message ExecuteContractProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // RunAs is the address that is passed to the contract's environment as sender + string run_as = 3; + // Contract is the address of the smart contract + string contract = 4; + // Msg json encoded message to be passed to the contract as execute + bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 6 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// UpdateAdminProposal gov proposal content type to set an admin for a contract. +message UpdateAdminProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // NewAdmin address to be set + string new_admin = 3 [ (gogoproto.moretags) = "yaml:\"new_admin\"" ]; + // Contract is the address of the smart contract + string contract = 4; +} + +// ClearAdminProposal gov proposal content type to clear the admin of a +// contract. +message ClearAdminProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // Contract is the address of the smart contract + string contract = 3; +} + +// PinCodesProposal gov proposal content type to pin a set of code ids in the +// wasmvm cache. +message PinCodesProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + // Description is a human readable text + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + // CodeIDs references the new WASM codes + repeated uint64 code_ids = 3 [ + (gogoproto.customname) = "CodeIDs", + (gogoproto.moretags) = "yaml:\"code_ids\"" + ]; +} + +// UnpinCodesProposal gov proposal content type to unpin a set of code ids in +// the wasmvm cache. +message UnpinCodesProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + // Description is a human readable text + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + // CodeIDs references the WASM codes + repeated uint64 code_ids = 3 [ + (gogoproto.customname) = "CodeIDs", + (gogoproto.moretags) = "yaml:\"code_ids\"" + ]; +} + +// AccessConfigUpdate contains the code id and the access config to be +// applied. +message AccessConfigUpdate { + // CodeID is the reference to the stored WASM code to be updated + uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ]; + // InstantiatePermission to apply to the set of code ids + AccessConfig instantiate_permission = 2 [ (gogoproto.nullable) = false ]; +} + +// UpdateInstantiateConfigProposal gov proposal content type to update +// instantiate config to a set of code ids. +message UpdateInstantiateConfigProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1 [ (gogoproto.moretags) = "yaml:\"title\"" ]; + // Description is a human readable text + string description = 2 [ (gogoproto.moretags) = "yaml:\"description\"" ]; + // AccessConfigUpdate contains the list of code ids and the access config + // to be applied. + repeated AccessConfigUpdate access_config_updates = 3 + [ (gogoproto.nullable) = false ]; +} + +// StoreAndInstantiateContractProposal gov proposal content type to store +// and instantiate the contract. +message StoreAndInstantiateContractProposal { + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + + // Title is a short summary + string title = 1; + // Description is a human readable text + string description = 2; + // RunAs is the address that is passed to the contract's environment as sender + string run_as = 3; + // WASMByteCode can be raw or gzip compressed + bytes wasm_byte_code = 4 [ (gogoproto.customname) = "WASMByteCode" ]; + // InstantiatePermission to apply on contract creation, optional + AccessConfig instantiate_permission = 5; + // UnpinCode code on upload, optional + bool unpin_code = 6; + // Admin is an optional address that can execute migrations + string admin = 7; + // Label is optional metadata to be stored with a constract instance. + string label = 8; + // Msg json encoded message to be passed to the contract on instantiation + bytes msg = 9 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 10 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // Source is the URL where the code is hosted + string source = 11; + // Builder is the docker image used to build the code deterministically, used + // for smart contract verification + string builder = 12; + // CodeHash is the SHA256 sum of the code outputted by builder, used for smart + // contract verification + bytes code_hash = 13; +} \ No newline at end of file diff --git a/proto/wasm/v1/query.proto b/proto/wasm/v1/query.proto new file mode 100644 index 00000000..925e6f37 --- /dev/null +++ b/proto/wasm/v1/query.proto @@ -0,0 +1,263 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "gogoproto/gogo.proto"; +import "wasm/v1/types.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; +option (gogoproto.goproto_getters_all) = false; +option (gogoproto.equal_all) = false; + +// Query provides defines the gRPC querier service +service Query { + // ContractInfo gets the contract meta data + rpc ContractInfo(QueryContractInfoRequest) + returns (QueryContractInfoResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/contract/{address}"; + } + // ContractHistory gets the contract code history + rpc ContractHistory(QueryContractHistoryRequest) + returns (QueryContractHistoryResponse) { + option (google.api.http).get = + "/cosmwasm/wasm/v1/contract/{address}/history"; + } + // ContractsByCode lists all smart contracts for a code id + rpc ContractsByCode(QueryContractsByCodeRequest) + returns (QueryContractsByCodeResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/code/{code_id}/contracts"; + } + // AllContractState gets all raw store data for a single contract + rpc AllContractState(QueryAllContractStateRequest) + returns (QueryAllContractStateResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/contract/{address}/state"; + } + // RawContractState gets single key from the raw store data of a contract + rpc RawContractState(QueryRawContractStateRequest) + returns (QueryRawContractStateResponse) { + option (google.api.http).get = + "/cosmwasm/wasm/v1/contract/{address}/raw/{query_data}"; + } + // SmartContractState get smart query result from the contract + rpc SmartContractState(QuerySmartContractStateRequest) + returns (QuerySmartContractStateResponse) { + option (google.api.http).get = + "/cosmwasm/wasm/v1/contract/{address}/smart/{query_data}"; + } + // Code gets the binary code and metadata for a singe wasm code + rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/code/{code_id}"; + } + // Codes gets the metadata for all stored wasm codes + rpc Codes(QueryCodesRequest) returns (QueryCodesResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/code"; + } + + // PinnedCodes gets the pinned code ids + rpc PinnedCodes(QueryPinnedCodesRequest) returns (QueryPinnedCodesResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/codes/pinned"; + } + + // Params gets the module params + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/cosmwasm/wasm/v1/codes/params"; + } + + // ContractsByCreator gets the contracts by creator + rpc ContractsByCreator(QueryContractsByCreatorRequest) + returns (QueryContractsByCreatorResponse) { + option (google.api.http).get = + "/cosmwasm/wasm/v1/contracts/creator/{creator_address}"; + } +} + +// QueryContractInfoRequest is the request type for the Query/ContractInfo RPC +// method +message QueryContractInfoRequest { + // address is the address of the contract to query + string address = 1; +} +// QueryContractInfoResponse is the response type for the Query/ContractInfo RPC +// method +message QueryContractInfoResponse { + option (gogoproto.equal) = true; + + // address is the address of the contract + string address = 1; + ContractInfo contract_info = 2 [ + (gogoproto.embed) = true, + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "" + ]; +} + +// QueryContractHistoryRequest is the request type for the Query/ContractHistory +// RPC method +message QueryContractHistoryRequest { + // address is the address of the contract to query + string address = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryContractHistoryResponse is the response type for the +// Query/ContractHistory RPC method +message QueryContractHistoryResponse { + repeated ContractCodeHistoryEntry entries = 1 + [ (gogoproto.nullable) = false ]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryContractsByCodeRequest is the request type for the Query/ContractsByCode +// RPC method +message QueryContractsByCodeRequest { + uint64 code_id = 1; // grpc-gateway_out does not support Go style CodID + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryContractsByCodeResponse is the response type for the +// Query/ContractsByCode RPC method +message QueryContractsByCodeResponse { + // contracts are a set of contract addresses + repeated string contracts = 1; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryAllContractStateRequest is the request type for the +// Query/AllContractState RPC method +message QueryAllContractStateRequest { + // address is the address of the contract + string address = 1; + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryAllContractStateResponse is the response type for the +// Query/AllContractState RPC method +message QueryAllContractStateResponse { + repeated Model models = 1 [ (gogoproto.nullable) = false ]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryRawContractStateRequest is the request type for the +// Query/RawContractState RPC method +message QueryRawContractStateRequest { + // address is the address of the contract + string address = 1; + bytes query_data = 2; +} + +// QueryRawContractStateResponse is the response type for the +// Query/RawContractState RPC method +message QueryRawContractStateResponse { + // Data contains the raw store data + bytes data = 1; +} + +// QuerySmartContractStateRequest is the request type for the +// Query/SmartContractState RPC method +message QuerySmartContractStateRequest { + // address is the address of the contract + string address = 1; + // QueryData contains the query data passed to the contract + bytes query_data = 2 [ (gogoproto.casttype) = "RawContractMessage" ]; +} + +// QuerySmartContractStateResponse is the response type for the +// Query/SmartContractState RPC method +message QuerySmartContractStateResponse { + // Data contains the json data returned from the smart contract + bytes data = 1 [ (gogoproto.casttype) = "RawContractMessage" ]; +} + +// QueryCodeRequest is the request type for the Query/Code RPC method +message QueryCodeRequest { + uint64 code_id = 1; // grpc-gateway_out does not support Go style CodID +} + +// CodeInfoResponse contains code meta data from CodeInfo +message CodeInfoResponse { + option (gogoproto.equal) = true; + + uint64 code_id = 1 [ + (gogoproto.customname) = "CodeID", + (gogoproto.jsontag) = "id" + ]; // id for legacy support + string creator = 2; + bytes data_hash = 3 + [ (gogoproto.casttype) = + "github.com/tendermint/tendermint/libs/bytes.HexBytes" ]; + // Used in v1beta1 + reserved 4, 5; + AccessConfig instantiate_permission = 6 [ (gogoproto.nullable) = false ]; +} + +// QueryCodeResponse is the response type for the Query/Code RPC method +message QueryCodeResponse { + option (gogoproto.equal) = true; + CodeInfoResponse code_info = 1 + [ (gogoproto.embed) = true, (gogoproto.jsontag) = "" ]; + bytes data = 2 [ (gogoproto.jsontag) = "data" ]; +} + +// QueryCodesRequest is the request type for the Query/Codes RPC method +message QueryCodesRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryCodesResponse is the response type for the Query/Codes RPC method +message QueryCodesResponse { + repeated CodeInfoResponse code_infos = 1 [ (gogoproto.nullable) = false ]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryPinnedCodesRequest is the request type for the Query/PinnedCodes +// RPC method +message QueryPinnedCodesRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryPinnedCodesResponse is the response type for the +// Query/PinnedCodes RPC method +message QueryPinnedCodesResponse { + repeated uint64 code_ids = 1 + [ (gogoproto.nullable) = false, (gogoproto.customname) = "CodeIDs" ]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1 [ (gogoproto.nullable) = false ]; +} + +// QueryContractsByCreatorRequest is the request type for the +// Query/ContractsByCreator RPC method. +message QueryContractsByCreatorRequest { + // CreatorAddress is the address of contract creator + string creator_address = 1; + // Pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryContractsByCreatorResponse is the response type for the +// Query/ContractsByCreator RPC method. +message QueryContractsByCreatorResponse { + // ContractAddresses result set + repeated string contract_addresses = 1; + // Pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} \ No newline at end of file diff --git a/proto/wasm/v1/tx.proto b/proto/wasm/v1/tx.proto new file mode 100644 index 00000000..77c3a6d8 --- /dev/null +++ b/proto/wasm/v1/tx.proto @@ -0,0 +1,192 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; +import "wasm/v1/types.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; +option (gogoproto.goproto_getters_all) = false; + +// Msg defines the wasm Msg service. +service Msg { + // StoreCode to submit Wasm code to the system + rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse); + // InstantiateContract creates a new smart contract instance for the given + // code id. + rpc InstantiateContract(MsgInstantiateContract) + returns (MsgInstantiateContractResponse); + // InstantiateContract2 creates a new smart contract instance for the given + // code id with a predictable address + rpc InstantiateContract2(MsgInstantiateContract2) + returns (MsgInstantiateContract2Response); + // Execute submits the given message data to a smart contract + rpc ExecuteContract(MsgExecuteContract) returns (MsgExecuteContractResponse); + // Migrate runs a code upgrade/ downgrade for a smart contract + rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse); + // UpdateAdmin sets a new admin for a smart contract + rpc UpdateAdmin(MsgUpdateAdmin) returns (MsgUpdateAdminResponse); + // ClearAdmin removes any admin stored for a smart contract + rpc ClearAdmin(MsgClearAdmin) returns (MsgClearAdminResponse); + // UpdateInstantiateConfig updates instantiate config for a smart contract + rpc UpdateInstantiateConfig(MsgUpdateInstantiateConfig) + returns (MsgUpdateInstantiateConfigResponse); +} + +// MsgStoreCode submit Wasm code to the system +message MsgStoreCode { + // Sender is the that actor that signed the messages + string sender = 1; + // WASMByteCode can be raw or gzip compressed + bytes wasm_byte_code = 2 [ (gogoproto.customname) = "WASMByteCode" ]; + // Used in v1beta1 + reserved 3, 4; + // InstantiatePermission access control to apply on contract creation, + // optional + AccessConfig instantiate_permission = 5; +} +// MsgStoreCodeResponse returns store result data. +message MsgStoreCodeResponse { + // CodeID is the reference to the stored WASM code + uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ]; + // Checksum is the sha256 hash of the stored code + bytes checksum = 2; +} + +// MsgInstantiateContract create a new smart contract instance for the given +// code id. +message MsgInstantiateContract { + // Sender is the that actor that signed the messages + string sender = 1; + // Admin is an optional address that can execute migrations + string admin = 2; + // CodeID is the reference to the stored WASM code + uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ]; + // Label is optional metadata to be stored with a contract instance. + string label = 4; + // Msg json encoded message to be passed to the contract on instantiation + bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 6 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// MsgInstantiateContract2 create a new smart contract instance for the given +// code id with a predicable address. +message MsgInstantiateContract2 { + // Sender is the that actor that signed the messages + string sender = 1; + // Admin is an optional address that can execute migrations + string admin = 2; + // CodeID is the reference to the stored WASM code + uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ]; + // Label is optional metadata to be stored with a contract instance. + string label = 4; + // Msg json encoded message to be passed to the contract on instantiation + bytes msg = 5 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on instantiation + repeated cosmos.base.v1beta1.Coin funds = 6 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; + // Salt is an arbitrary value provided by the sender. Size can be 1 to 64. + bytes salt = 7; + // FixMsg include the msg value into the hash for the predictable address. + // Default is false + bool fix_msg = 8; +} + +// MsgInstantiateContractResponse return instantiation result data +message MsgInstantiateContractResponse { + // Address is the bech32 address of the new contract instance. + string address = 1; + // Data contains bytes to returned from the contract + bytes data = 2; +} + +// MsgInstantiateContract2Response return instantiation result data +message MsgInstantiateContract2Response { + // Address is the bech32 address of the new contract instance. + string address = 1; + // Data contains bytes to returned from the contract + bytes data = 2; +} + +// MsgExecuteContract submits the given message data to a smart contract +message MsgExecuteContract { + // Sender is the that actor that signed the messages + string sender = 1; + // Contract is the address of the smart contract + string contract = 2; + // Msg json encoded message to be passed to the contract + bytes msg = 3 [ (gogoproto.casttype) = "RawContractMessage" ]; + // Funds coins that are transferred to the contract on execution + repeated cosmos.base.v1beta1.Coin funds = 5 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + ]; +} + +// MsgExecuteContractResponse returns execution result data. +message MsgExecuteContractResponse { + // Data contains bytes to returned from the contract + bytes data = 1; +} + +// MsgMigrateContract runs a code upgrade/ downgrade for a smart contract +message MsgMigrateContract { + // Sender is the that actor that signed the messages + string sender = 1; + // Contract is the address of the smart contract + string contract = 2; + // CodeID references the new WASM code + uint64 code_id = 3 [ (gogoproto.customname) = "CodeID" ]; + // Msg json encoded message to be passed to the contract on migration + bytes msg = 4 [ (gogoproto.casttype) = "RawContractMessage" ]; +} + +// MsgMigrateContractResponse returns contract migration result data. +message MsgMigrateContractResponse { + // Data contains same raw bytes returned as data from the wasm contract. + // (May be empty) + bytes data = 1; +} + +// MsgUpdateAdmin sets a new admin for a smart contract +message MsgUpdateAdmin { + // Sender is the that actor that signed the messages + string sender = 1; + // NewAdmin address to be set + string new_admin = 2; + // Contract is the address of the smart contract + string contract = 3; +} + +// MsgUpdateAdminResponse returns empty data +message MsgUpdateAdminResponse {} + +// MsgClearAdmin removes any admin stored for a smart contract +message MsgClearAdmin { + // Sender is the actor that signed the messages + string sender = 1; + // Contract is the address of the smart contract + string contract = 3; +} + +// MsgClearAdminResponse returns empty data +message MsgClearAdminResponse {} + +// MsgUpdateInstantiateConfig updates instantiate config for a smart contract +message MsgUpdateInstantiateConfig { + // Sender is the that actor that signed the messages + string sender = 1; + // CodeID references the stored WASM code + uint64 code_id = 2 [ (gogoproto.customname) = "CodeID" ]; + // NewInstantiatePermission is the new access control + AccessConfig new_instantiate_permission = 3; +} + +// MsgUpdateInstantiateConfigResponse returns empty data +message MsgUpdateInstantiateConfigResponse {} \ No newline at end of file diff --git a/proto/wasm/v1/types.proto b/proto/wasm/v1/types.proto new file mode 100644 index 00000000..0f5bd6e6 --- /dev/null +++ b/proto/wasm/v1/types.proto @@ -0,0 +1,144 @@ +syntax = "proto3"; +package cosmwasm.wasm.v1; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +option go_package = "github.com/cerc-io/laconicd/x/wasm/types"; +option (gogoproto.goproto_getters_all) = false; +option (gogoproto.equal_all) = true; + +// AccessType permission types +enum AccessType { + option (gogoproto.goproto_enum_prefix) = false; + option (gogoproto.goproto_enum_stringer) = false; + // AccessTypeUnspecified placeholder for empty value + ACCESS_TYPE_UNSPECIFIED = 0 + [ (gogoproto.enumvalue_customname) = "AccessTypeUnspecified" ]; + // AccessTypeNobody forbidden + ACCESS_TYPE_NOBODY = 1 + [ (gogoproto.enumvalue_customname) = "AccessTypeNobody" ]; + // AccessTypeOnlyAddress restricted to a single address + // Deprecated: use AccessTypeAnyOfAddresses instead + ACCESS_TYPE_ONLY_ADDRESS = 2 + [ (gogoproto.enumvalue_customname) = "AccessTypeOnlyAddress" ]; + // AccessTypeEverybody unrestricted + ACCESS_TYPE_EVERYBODY = 3 + [ (gogoproto.enumvalue_customname) = "AccessTypeEverybody" ]; + // AccessTypeAnyOfAddresses allow any of the addresses + ACCESS_TYPE_ANY_OF_ADDRESSES = 4 + [ (gogoproto.enumvalue_customname) = "AccessTypeAnyOfAddresses" ]; +} + +// AccessTypeParam +message AccessTypeParam { + option (gogoproto.goproto_stringer) = true; + AccessType value = 1 [ (gogoproto.moretags) = "yaml:\"value\"" ]; +} + +// AccessConfig access control type. +message AccessConfig { + option (gogoproto.goproto_stringer) = true; + AccessType permission = 1 [ (gogoproto.moretags) = "yaml:\"permission\"" ]; + + // Address + // Deprecated: replaced by addresses + string address = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ]; + repeated string addresses = 3 [ (gogoproto.moretags) = "yaml:\"addresses\"" ]; +} + +// Params defines the set of wasm parameters. +message Params { + option (gogoproto.goproto_stringer) = false; + AccessConfig code_upload_access = 1 [ + (gogoproto.nullable) = false, + (gogoproto.moretags) = "yaml:\"code_upload_access\"" + ]; + AccessType instantiate_default_permission = 2 + [ (gogoproto.moretags) = "yaml:\"instantiate_default_permission\"" ]; +} + +// CodeInfo is data for the uploaded contract WASM code +message CodeInfo { + // CodeHash is the unique identifier created by wasmvm + bytes code_hash = 1; + // Creator address who initially stored the code + string creator = 2; + // Used in v1beta1 + reserved 3, 4; + // InstantiateConfig access control to apply on contract creation, optional + AccessConfig instantiate_config = 5 [ (gogoproto.nullable) = false ]; +} + +// ContractInfo stores a WASM contract instance +message ContractInfo { + option (gogoproto.equal) = true; + + // CodeID is the reference to the stored Wasm code + uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ]; + // Creator address who initially instantiated the contract + string creator = 2; + // Admin is an optional address that can execute migrations + string admin = 3; + // Label is optional metadata to be stored with a contract instance. + string label = 4; + // Created Tx position when the contract was instantiated. + AbsoluteTxPosition created = 5; + string ibc_port_id = 6 [ (gogoproto.customname) = "IBCPortID" ]; + + // Extension is an extension point to store custom metadata within the + // persistence model. + google.protobuf.Any extension = 7 + [ (cosmos_proto.accepts_interface) = "ContractInfoExtension" ]; +} + +// ContractCodeHistoryOperationType actions that caused a code change +enum ContractCodeHistoryOperationType { + option (gogoproto.goproto_enum_prefix) = false; + // ContractCodeHistoryOperationTypeUnspecified placeholder for empty value + CONTRACT_CODE_HISTORY_OPERATION_TYPE_UNSPECIFIED = 0 + [ (gogoproto.enumvalue_customname) = + "ContractCodeHistoryOperationTypeUnspecified" ]; + // ContractCodeHistoryOperationTypeInit on chain contract instantiation + CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT = 1 + [ (gogoproto.enumvalue_customname) = + "ContractCodeHistoryOperationTypeInit" ]; + // ContractCodeHistoryOperationTypeMigrate code migration + CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE = 2 + [ (gogoproto.enumvalue_customname) = + "ContractCodeHistoryOperationTypeMigrate" ]; + // ContractCodeHistoryOperationTypeGenesis based on genesis data + CONTRACT_CODE_HISTORY_OPERATION_TYPE_GENESIS = 3 + [ (gogoproto.enumvalue_customname) = + "ContractCodeHistoryOperationTypeGenesis" ]; +} + +// ContractCodeHistoryEntry metadata to a contract. +message ContractCodeHistoryEntry { + ContractCodeHistoryOperationType operation = 1; + // CodeID is the reference to the stored WASM code + uint64 code_id = 2 [ (gogoproto.customname) = "CodeID" ]; + // Updated Tx position when the operation was executed. + AbsoluteTxPosition updated = 3; + bytes msg = 4 [ (gogoproto.casttype) = "RawContractMessage" ]; +} + +// AbsoluteTxPosition is a unique transaction position that allows for global +// ordering of transactions. +message AbsoluteTxPosition { + // BlockHeight is the block the contract was created at + uint64 block_height = 1; + // TxIndex is a monotonic counter within the block (actual transaction index, + // or gas consumed) + uint64 tx_index = 2; +} + +// Model is a struct that holds a KV pair +message Model { + // hex-encode key to read it better (this is often ascii) + bytes key = 1 [ (gogoproto.casttype) = + "github.com/tendermint/tendermint/libs/bytes.HexBytes" ]; + // base64-encode raw value + bytes value = 2; +} \ No newline at end of file diff --git a/x/wasm/types/authz.pb.go b/x/wasm/types/authz.pb.go new file mode 100644 index 00000000..11f06ce5 --- /dev/null +++ b/x/wasm/types/authz.pb.go @@ -0,0 +1,1805 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/authz.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/codec/types" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types1 "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/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 + +// ContractExecutionAuthorization defines authorization for wasm execute. +// Since: wasmd 0.30 +type ContractExecutionAuthorization struct { + // Grants for contract executions + Grants []ContractGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants"` +} + +func (m *ContractExecutionAuthorization) Reset() { *m = ContractExecutionAuthorization{} } +func (m *ContractExecutionAuthorization) String() string { return proto.CompactTextString(m) } +func (*ContractExecutionAuthorization) ProtoMessage() {} +func (*ContractExecutionAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{0} +} +func (m *ContractExecutionAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractExecutionAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractExecutionAuthorization.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 *ContractExecutionAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractExecutionAuthorization.Merge(m, src) +} +func (m *ContractExecutionAuthorization) XXX_Size() int { + return m.Size() +} +func (m *ContractExecutionAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_ContractExecutionAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractExecutionAuthorization proto.InternalMessageInfo + +// ContractMigrationAuthorization defines authorization for wasm contract +// migration. Since: wasmd 0.30 +type ContractMigrationAuthorization struct { + // Grants for contract migrations + Grants []ContractGrant `protobuf:"bytes,1,rep,name=grants,proto3" json:"grants"` +} + +func (m *ContractMigrationAuthorization) Reset() { *m = ContractMigrationAuthorization{} } +func (m *ContractMigrationAuthorization) String() string { return proto.CompactTextString(m) } +func (*ContractMigrationAuthorization) ProtoMessage() {} +func (*ContractMigrationAuthorization) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{1} +} +func (m *ContractMigrationAuthorization) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractMigrationAuthorization) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractMigrationAuthorization.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 *ContractMigrationAuthorization) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractMigrationAuthorization.Merge(m, src) +} +func (m *ContractMigrationAuthorization) XXX_Size() int { + return m.Size() +} +func (m *ContractMigrationAuthorization) XXX_DiscardUnknown() { + xxx_messageInfo_ContractMigrationAuthorization.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractMigrationAuthorization proto.InternalMessageInfo + +// ContractGrant a granted permission for a single contract +// Since: wasmd 0.30 +type ContractGrant struct { + // Contract is the bech32 address of the smart contract + Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` + // Limit defines execution limits that are enforced and updated when the grant + // is applied. When the limit lapsed the grant is removed. + Limit *types.Any `protobuf:"bytes,2,opt,name=limit,proto3" json:"limit,omitempty"` + // Filter define more fine-grained control on the message payload passed + // to the contract in the operation. When no filter applies on execution, the + // operation is prohibited. + Filter *types.Any `protobuf:"bytes,3,opt,name=filter,proto3" json:"filter,omitempty"` +} + +func (m *ContractGrant) Reset() { *m = ContractGrant{} } +func (m *ContractGrant) String() string { return proto.CompactTextString(m) } +func (*ContractGrant) ProtoMessage() {} +func (*ContractGrant) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{2} +} +func (m *ContractGrant) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractGrant) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractGrant.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 *ContractGrant) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractGrant.Merge(m, src) +} +func (m *ContractGrant) XXX_Size() int { + return m.Size() +} +func (m *ContractGrant) XXX_DiscardUnknown() { + xxx_messageInfo_ContractGrant.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractGrant proto.InternalMessageInfo + +// MaxCallsLimit limited number of calls to the contract. No funds transferable. +// Since: wasmd 0.30 +type MaxCallsLimit struct { + // Remaining number that is decremented on each execution + Remaining uint64 `protobuf:"varint,1,opt,name=remaining,proto3" json:"remaining,omitempty"` +} + +func (m *MaxCallsLimit) Reset() { *m = MaxCallsLimit{} } +func (m *MaxCallsLimit) String() string { return proto.CompactTextString(m) } +func (*MaxCallsLimit) ProtoMessage() {} +func (*MaxCallsLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{3} +} +func (m *MaxCallsLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MaxCallsLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MaxCallsLimit.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 *MaxCallsLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaxCallsLimit.Merge(m, src) +} +func (m *MaxCallsLimit) XXX_Size() int { + return m.Size() +} +func (m *MaxCallsLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MaxCallsLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MaxCallsLimit proto.InternalMessageInfo + +// MaxFundsLimit defines the maximal amounts that can be sent to the contract. +// Since: wasmd 0.30 +type MaxFundsLimit struct { + // Amounts is the maximal amount of tokens transferable to the contract. + Amounts github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=amounts,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amounts"` +} + +func (m *MaxFundsLimit) Reset() { *m = MaxFundsLimit{} } +func (m *MaxFundsLimit) String() string { return proto.CompactTextString(m) } +func (*MaxFundsLimit) ProtoMessage() {} +func (*MaxFundsLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{4} +} +func (m *MaxFundsLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MaxFundsLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MaxFundsLimit.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 *MaxFundsLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_MaxFundsLimit.Merge(m, src) +} +func (m *MaxFundsLimit) XXX_Size() int { + return m.Size() +} +func (m *MaxFundsLimit) XXX_DiscardUnknown() { + xxx_messageInfo_MaxFundsLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_MaxFundsLimit proto.InternalMessageInfo + +// CombinedLimit defines the maximal amounts that can be sent to a contract and +// the maximal number of calls executable. Both need to remain >0 to be valid. +// Since: wasmd 0.30 +type CombinedLimit struct { + // Remaining number that is decremented on each execution + CallsRemaining uint64 `protobuf:"varint,1,opt,name=calls_remaining,json=callsRemaining,proto3" json:"calls_remaining,omitempty"` + // Amounts is the maximal amount of tokens transferable to the contract. + Amounts github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=amounts,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"amounts"` +} + +func (m *CombinedLimit) Reset() { *m = CombinedLimit{} } +func (m *CombinedLimit) String() string { return proto.CompactTextString(m) } +func (*CombinedLimit) ProtoMessage() {} +func (*CombinedLimit) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{5} +} +func (m *CombinedLimit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CombinedLimit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CombinedLimit.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 *CombinedLimit) XXX_Merge(src proto.Message) { + xxx_messageInfo_CombinedLimit.Merge(m, src) +} +func (m *CombinedLimit) XXX_Size() int { + return m.Size() +} +func (m *CombinedLimit) XXX_DiscardUnknown() { + xxx_messageInfo_CombinedLimit.DiscardUnknown(m) +} + +var xxx_messageInfo_CombinedLimit proto.InternalMessageInfo + +// AllowAllMessagesFilter is a wildcard to allow any type of contract payload +// message. +// Since: wasmd 0.30 +type AllowAllMessagesFilter struct { +} + +func (m *AllowAllMessagesFilter) Reset() { *m = AllowAllMessagesFilter{} } +func (m *AllowAllMessagesFilter) String() string { return proto.CompactTextString(m) } +func (*AllowAllMessagesFilter) ProtoMessage() {} +func (*AllowAllMessagesFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{6} +} +func (m *AllowAllMessagesFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AllowAllMessagesFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AllowAllMessagesFilter.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 *AllowAllMessagesFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_AllowAllMessagesFilter.Merge(m, src) +} +func (m *AllowAllMessagesFilter) XXX_Size() int { + return m.Size() +} +func (m *AllowAllMessagesFilter) XXX_DiscardUnknown() { + xxx_messageInfo_AllowAllMessagesFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_AllowAllMessagesFilter proto.InternalMessageInfo + +// AcceptedMessageKeysFilter accept only the specific contract message keys in +// the json object to be executed. +// Since: wasmd 0.30 +type AcceptedMessageKeysFilter struct { + // Messages is the list of unique keys + Keys []string `protobuf:"bytes,1,rep,name=keys,proto3" json:"keys,omitempty"` +} + +func (m *AcceptedMessageKeysFilter) Reset() { *m = AcceptedMessageKeysFilter{} } +func (m *AcceptedMessageKeysFilter) String() string { return proto.CompactTextString(m) } +func (*AcceptedMessageKeysFilter) ProtoMessage() {} +func (*AcceptedMessageKeysFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{7} +} +func (m *AcceptedMessageKeysFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AcceptedMessageKeysFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AcceptedMessageKeysFilter.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 *AcceptedMessageKeysFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_AcceptedMessageKeysFilter.Merge(m, src) +} +func (m *AcceptedMessageKeysFilter) XXX_Size() int { + return m.Size() +} +func (m *AcceptedMessageKeysFilter) XXX_DiscardUnknown() { + xxx_messageInfo_AcceptedMessageKeysFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_AcceptedMessageKeysFilter proto.InternalMessageInfo + +// AcceptedMessagesFilter accept only the specific raw contract messages to be +// executed. +// Since: wasmd 0.30 +type AcceptedMessagesFilter struct { + // Messages is the list of raw contract messages + Messages []RawContractMessage `protobuf:"bytes,1,rep,name=messages,proto3,casttype=RawContractMessage" json:"messages,omitempty"` +} + +func (m *AcceptedMessagesFilter) Reset() { *m = AcceptedMessagesFilter{} } +func (m *AcceptedMessagesFilter) String() string { return proto.CompactTextString(m) } +func (*AcceptedMessagesFilter) ProtoMessage() {} +func (*AcceptedMessagesFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_18e24ed4b0e45a19, []int{8} +} +func (m *AcceptedMessagesFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AcceptedMessagesFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AcceptedMessagesFilter.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 *AcceptedMessagesFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_AcceptedMessagesFilter.Merge(m, src) +} +func (m *AcceptedMessagesFilter) XXX_Size() int { + return m.Size() +} +func (m *AcceptedMessagesFilter) XXX_DiscardUnknown() { + xxx_messageInfo_AcceptedMessagesFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_AcceptedMessagesFilter proto.InternalMessageInfo + +func init() { + proto.RegisterType((*ContractExecutionAuthorization)(nil), "cosmwasm.wasm.v1.ContractExecutionAuthorization") + proto.RegisterType((*ContractMigrationAuthorization)(nil), "cosmwasm.wasm.v1.ContractMigrationAuthorization") + proto.RegisterType((*ContractGrant)(nil), "cosmwasm.wasm.v1.ContractGrant") + proto.RegisterType((*MaxCallsLimit)(nil), "cosmwasm.wasm.v1.MaxCallsLimit") + proto.RegisterType((*MaxFundsLimit)(nil), "cosmwasm.wasm.v1.MaxFundsLimit") + proto.RegisterType((*CombinedLimit)(nil), "cosmwasm.wasm.v1.CombinedLimit") + proto.RegisterType((*AllowAllMessagesFilter)(nil), "cosmwasm.wasm.v1.AllowAllMessagesFilter") + proto.RegisterType((*AcceptedMessageKeysFilter)(nil), "cosmwasm.wasm.v1.AcceptedMessageKeysFilter") + proto.RegisterType((*AcceptedMessagesFilter)(nil), "cosmwasm.wasm.v1.AcceptedMessagesFilter") +} + +func init() { proto.RegisterFile("wasm/v1/authz.proto", fileDescriptor_18e24ed4b0e45a19) } + +var fileDescriptor_18e24ed4b0e45a19 = []byte{ + // 581 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x54, 0xbb, 0x6e, 0xdb, 0x3c, + 0x14, 0xb6, 0x92, 0xfc, 0xf9, 0x13, 0xa6, 0xe9, 0x45, 0x09, 0x52, 0x27, 0x28, 0xe4, 0xc0, 0x4b, + 0xbd, 0x58, 0xac, 0xdd, 0x2d, 0x40, 0x07, 0xdb, 0xa8, 0x8b, 0xa2, 0xf5, 0xa2, 0x29, 0xe8, 0x12, + 0x50, 0x34, 0x2d, 0x13, 0x91, 0x48, 0x43, 0xa4, 0x7c, 0x7b, 0x89, 0xf6, 0x39, 0x3a, 0x7b, 0xe8, + 0x23, 0x18, 0x9e, 0x32, 0x76, 0x4a, 0x5b, 0xfb, 0x2d, 0x3a, 0x15, 0x22, 0x29, 0x27, 0x36, 0xe0, + 0x8c, 0xed, 0x22, 0xf1, 0x5c, 0xbe, 0xef, 0x7c, 0x3c, 0xe7, 0x48, 0xe0, 0x68, 0x80, 0x44, 0x04, + 0xfb, 0x15, 0x88, 0x12, 0xd9, 0x1d, 0xbb, 0xbd, 0x98, 0x4b, 0x6e, 0x3f, 0xc5, 0x5c, 0x44, 0x69, + 0xc0, 0x55, 0x8f, 0x7e, 0xe5, 0xec, 0x38, 0xe0, 0x01, 0x57, 0x41, 0x98, 0x9e, 0x74, 0xde, 0xd9, + 0x69, 0x9a, 0xc7, 0xc5, 0x95, 0x0e, 0x68, 0xc3, 0x84, 0x1c, 0x6d, 0x41, 0x1f, 0x09, 0x02, 0xfb, + 0x15, 0x9f, 0x48, 0x54, 0x81, 0x98, 0x53, 0x96, 0x41, 0x03, 0xce, 0x83, 0x90, 0x40, 0x65, 0xf9, + 0x49, 0x07, 0x22, 0x36, 0xd2, 0xa1, 0x62, 0x0c, 0x9c, 0x06, 0x67, 0x32, 0x46, 0x58, 0xbe, 0x1d, + 0x12, 0x9c, 0x48, 0xca, 0x59, 0x2d, 0x91, 0x5d, 0x1e, 0xd3, 0x31, 0x4a, 0x0d, 0xfb, 0x0d, 0xd8, + 0x0d, 0x62, 0xc4, 0xa4, 0xc8, 0x5b, 0xe7, 0xdb, 0xa5, 0x83, 0x6a, 0xc1, 0x5d, 0x17, 0xec, 0x66, + 0x0c, 0xef, 0xd2, 0xbc, 0xfa, 0xce, 0xf4, 0xb6, 0x90, 0xf3, 0x0c, 0xe8, 0xe2, 0xd9, 0x6c, 0x52, + 0x3e, 0x5c, 0x61, 0xbc, 0x5f, 0xb3, 0x45, 0x83, 0x18, 0xfd, 0x8d, 0x9a, 0xdf, 0x2c, 0x70, 0xb8, + 0x02, 0xb1, 0xcf, 0xc0, 0x1e, 0x36, 0x8e, 0xbc, 0x75, 0x6e, 0x95, 0xf6, 0xbd, 0xa5, 0x6d, 0x37, + 0xc0, 0x7f, 0x21, 0x8d, 0xa8, 0xcc, 0x6f, 0x9d, 0x5b, 0xa5, 0x83, 0xea, 0xb1, 0xab, 0x1b, 0xe8, + 0x66, 0x0d, 0x74, 0x6b, 0x6c, 0x54, 0x7f, 0x3e, 0x9b, 0x94, 0x8f, 0x32, 0xce, 0xb4, 0xda, 0xf8, + 0x63, 0x8a, 0xb9, 0xf4, 0x34, 0xd6, 0x6e, 0x82, 0xdd, 0x0e, 0x0d, 0x25, 0x89, 0xf3, 0xdb, 0x0f, + 0xb0, 0xe4, 0x67, 0x93, 0xf2, 0xf1, 0x0a, 0x4b, 0x53, 0x81, 0x2e, 0x3d, 0x83, 0x2e, 0x36, 0xc1, + 0x61, 0x0b, 0x0d, 0x1b, 0x28, 0x0c, 0x85, 0x2a, 0x60, 0xbf, 0x00, 0xfb, 0x31, 0x89, 0x10, 0x65, + 0x94, 0x05, 0x4a, 0xfa, 0x8e, 0x77, 0xe7, 0xb8, 0xd8, 0x24, 0xab, 0xf8, 0xd9, 0x52, 0x44, 0xcd, + 0x84, 0xb5, 0x0d, 0x11, 0x01, 0xff, 0xa3, 0x88, 0x27, 0x77, 0x7d, 0x3e, 0x75, 0xcd, 0x5e, 0xa5, + 0x9b, 0xe4, 0x9a, 0x4d, 0x72, 0x1b, 0x9c, 0xb2, 0xfa, 0xab, 0xb4, 0xc3, 0x5f, 0x7f, 0x14, 0x4a, + 0x01, 0x95, 0xdd, 0xc4, 0x77, 0x31, 0x8f, 0xcc, 0x12, 0x9a, 0x57, 0x59, 0xb4, 0xaf, 0xa1, 0x1c, + 0xf5, 0x88, 0x50, 0x00, 0xe1, 0x65, 0xdc, 0x9b, 0x15, 0xe9, 0xa1, 0x44, 0x3e, 0x65, 0xa4, 0xad, + 0x15, 0xbd, 0x04, 0x4f, 0x70, 0x7a, 0xd1, 0xab, 0xf5, 0x0b, 0x3e, 0x56, 0x6e, 0x2f, 0xf3, 0xde, + 0x97, 0xbe, 0xf5, 0x2f, 0xa4, 0x57, 0xc1, 0x49, 0x2d, 0x0c, 0xf9, 0xa0, 0x16, 0x86, 0x2d, 0x22, + 0x04, 0x0a, 0x88, 0xd0, 0x73, 0xbb, 0xd8, 0x38, 0xd0, 0xe2, 0x7b, 0x70, 0x5a, 0xc3, 0x98, 0xf4, + 0x24, 0x69, 0x1b, 0xcc, 0x07, 0x32, 0x32, 0x30, 0xdb, 0x06, 0x3b, 0xd7, 0x64, 0xa4, 0x07, 0xb1, + 0xef, 0xa9, 0xf3, 0x03, 0x54, 0x1d, 0x70, 0xb2, 0x46, 0x95, 0xf1, 0x54, 0xc1, 0x5e, 0x64, 0x3c, + 0x8a, 0xeb, 0x51, 0xfd, 0xe4, 0xf7, 0x6d, 0xc1, 0xf6, 0xd0, 0x60, 0xf9, 0xcd, 0xe9, 0xb0, 0xb7, + 0xcc, 0xdb, 0x5c, 0xa7, 0xde, 0x9c, 0xfe, 0x72, 0x72, 0xd3, 0xb9, 0x63, 0xdd, 0xcc, 0x1d, 0xeb, + 0xe7, 0xdc, 0xb1, 0xbe, 0x2c, 0x9c, 0xdc, 0xcd, 0xc2, 0xc9, 0x7d, 0x5f, 0x38, 0xb9, 0x4f, 0x2b, + 0x0d, 0x25, 0x31, 0x2e, 0x53, 0x0e, 0x43, 0x84, 0x39, 0xa3, 0xb8, 0x0d, 0x87, 0x50, 0xfd, 0xed, + 0x54, 0x5b, 0xfd, 0x5d, 0xb5, 0xf3, 0xaf, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x33, 0x98, 0x4b, + 0x2f, 0x02, 0x05, 0x00, 0x00, +} + +func (m *ContractExecutionAuthorization) 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 *ContractExecutionAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractExecutionAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Grants) > 0 { + for iNdEx := len(m.Grants) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Grants[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ContractMigrationAuthorization) 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 *ContractMigrationAuthorization) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractMigrationAuthorization) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Grants) > 0 { + for iNdEx := len(m.Grants) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Grants[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ContractGrant) 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 *ContractGrant) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractGrant) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Filter != nil { + { + size, err := m.Filter.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Limit != nil { + { + size, err := m.Limit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MaxCallsLimit) 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 *MaxCallsLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MaxCallsLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Remaining != 0 { + i = encodeVarintAuthz(dAtA, i, uint64(m.Remaining)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MaxFundsLimit) 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 *MaxFundsLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MaxFundsLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amounts) > 0 { + for iNdEx := len(m.Amounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *CombinedLimit) 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 *CombinedLimit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CombinedLimit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Amounts) > 0 { + for iNdEx := len(m.Amounts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Amounts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintAuthz(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.CallsRemaining != 0 { + i = encodeVarintAuthz(dAtA, i, uint64(m.CallsRemaining)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AllowAllMessagesFilter) 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 *AllowAllMessagesFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AllowAllMessagesFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *AcceptedMessageKeysFilter) 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 *AcceptedMessageKeysFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AcceptedMessageKeysFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Keys) > 0 { + for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Keys[iNdEx]) + copy(dAtA[i:], m.Keys[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Keys[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *AcceptedMessagesFilter) 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 *AcceptedMessagesFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AcceptedMessagesFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Messages) > 0 { + for iNdEx := len(m.Messages) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Messages[iNdEx]) + copy(dAtA[i:], m.Messages[iNdEx]) + i = encodeVarintAuthz(dAtA, i, uint64(len(m.Messages[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintAuthz(dAtA []byte, offset int, v uint64) int { + offset -= sovAuthz(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ContractExecutionAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Grants) > 0 { + for _, e := range m.Grants { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *ContractMigrationAuthorization) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Grants) > 0 { + for _, e := range m.Grants { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *ContractGrant) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovAuthz(uint64(l)) + } + if m.Limit != nil { + l = m.Limit.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + if m.Filter != nil { + l = m.Filter.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + return n +} + +func (m *MaxCallsLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Remaining != 0 { + n += 1 + sovAuthz(uint64(m.Remaining)) + } + return n +} + +func (m *MaxFundsLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Amounts) > 0 { + for _, e := range m.Amounts { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *CombinedLimit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CallsRemaining != 0 { + n += 1 + sovAuthz(uint64(m.CallsRemaining)) + } + if len(m.Amounts) > 0 { + for _, e := range m.Amounts { + l = e.Size() + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *AllowAllMessagesFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *AcceptedMessageKeysFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Keys) > 0 { + for _, s := range m.Keys { + l = len(s) + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func (m *AcceptedMessagesFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Messages) > 0 { + for _, b := range m.Messages { + l = len(b) + n += 1 + l + sovAuthz(uint64(l)) + } + } + return n +} + +func sovAuthz(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozAuthz(x uint64) (n int) { + return sovAuthz(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ContractExecutionAuthorization) 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 ErrIntOverflowAuthz + } + 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: ContractExecutionAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractExecutionAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grants = append(m.Grants, ContractGrant{}) + if err := m.Grants[len(m.Grants)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractMigrationAuthorization) 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 ErrIntOverflowAuthz + } + 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: ContractMigrationAuthorization: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractMigrationAuthorization: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Grants", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Grants = append(m.Grants, ContractGrant{}) + if err := m.Grants[len(m.Grants)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractGrant) 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 ErrIntOverflowAuthz + } + 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: ContractGrant: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractGrant: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + 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 ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Limit == nil { + m.Limit = &types.Any{} + } + if err := m.Limit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Filter", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Filter == nil { + m.Filter = &types.Any{} + } + if err := m.Filter.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MaxCallsLimit) 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 ErrIntOverflowAuthz + } + 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: MaxCallsLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaxCallsLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Remaining", wireType) + } + m.Remaining = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Remaining |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MaxFundsLimit) 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 ErrIntOverflowAuthz + } + 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: MaxFundsLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MaxFundsLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amounts = append(m.Amounts, types1.Coin{}) + if err := m.Amounts[len(m.Amounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CombinedLimit) 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 ErrIntOverflowAuthz + } + 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: CombinedLimit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CombinedLimit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CallsRemaining", wireType) + } + m.CallsRemaining = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CallsRemaining |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amounts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Amounts = append(m.Amounts, types1.Coin{}) + if err := m.Amounts[len(m.Amounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AllowAllMessagesFilter) 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 ErrIntOverflowAuthz + } + 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: AllowAllMessagesFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AllowAllMessagesFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AcceptedMessageKeysFilter) 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 ErrIntOverflowAuthz + } + 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: AcceptedMessageKeysFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AcceptedMessageKeysFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Keys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + 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 ErrInvalidLengthAuthz + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Keys = append(m.Keys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AcceptedMessagesFilter) 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 ErrIntOverflowAuthz + } + 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: AcceptedMessagesFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AcceptedMessagesFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Messages", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowAuthz + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthAuthz + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthAuthz + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Messages = append(m.Messages, make([]byte, postIndex-iNdEx)) + copy(m.Messages[len(m.Messages)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipAuthz(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthAuthz + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipAuthz(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, ErrIntOverflowAuthz + } + 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, ErrIntOverflowAuthz + } + 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, ErrIntOverflowAuthz + } + 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, ErrInvalidLengthAuthz + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupAuthz + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthAuthz + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthAuthz = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowAuthz = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupAuthz = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/wasm/types/genesis.pb.go b/x/wasm/types/genesis.pb.go new file mode 100644 index 00000000..ed245411 --- /dev/null +++ b/x/wasm/types/genesis.pb.go @@ -0,0 +1,1388 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/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 - genesis state of x/wasm +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + Codes []Code `protobuf:"bytes,2,rep,name=codes,proto3" json:"codes,omitempty"` + Contracts []Contract `protobuf:"bytes,3,rep,name=contracts,proto3" json:"contracts,omitempty"` + Sequences []Sequence `protobuf:"bytes,4,rep,name=sequences,proto3" json:"sequences,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_26bed03189c69aaf, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func (m *GenesisState) GetCodes() []Code { + if m != nil { + return m.Codes + } + return nil +} + +func (m *GenesisState) GetContracts() []Contract { + if m != nil { + return m.Contracts + } + return nil +} + +func (m *GenesisState) GetSequences() []Sequence { + if m != nil { + return m.Sequences + } + return nil +} + +// Code struct encompasses CodeInfo and CodeBytes +type Code struct { + CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + CodeInfo CodeInfo `protobuf:"bytes,2,opt,name=code_info,json=codeInfo,proto3" json:"code_info"` + CodeBytes []byte `protobuf:"bytes,3,opt,name=code_bytes,json=codeBytes,proto3" json:"code_bytes,omitempty"` + // Pinned to wasmvm cache + Pinned bool `protobuf:"varint,4,opt,name=pinned,proto3" json:"pinned,omitempty"` +} + +func (m *Code) Reset() { *m = Code{} } +func (m *Code) String() string { return proto.CompactTextString(m) } +func (*Code) ProtoMessage() {} +func (*Code) Descriptor() ([]byte, []int) { + return fileDescriptor_26bed03189c69aaf, []int{1} +} +func (m *Code) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Code) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Code.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 *Code) XXX_Merge(src proto.Message) { + xxx_messageInfo_Code.Merge(m, src) +} +func (m *Code) XXX_Size() int { + return m.Size() +} +func (m *Code) XXX_DiscardUnknown() { + xxx_messageInfo_Code.DiscardUnknown(m) +} + +var xxx_messageInfo_Code proto.InternalMessageInfo + +func (m *Code) GetCodeID() uint64 { + if m != nil { + return m.CodeID + } + return 0 +} + +func (m *Code) GetCodeInfo() CodeInfo { + if m != nil { + return m.CodeInfo + } + return CodeInfo{} +} + +func (m *Code) GetCodeBytes() []byte { + if m != nil { + return m.CodeBytes + } + return nil +} + +func (m *Code) GetPinned() bool { + if m != nil { + return m.Pinned + } + return false +} + +// Contract struct encompasses ContractAddress, ContractInfo, and ContractState +type Contract struct { + ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` + ContractInfo ContractInfo `protobuf:"bytes,2,opt,name=contract_info,json=contractInfo,proto3" json:"contract_info"` + ContractState []Model `protobuf:"bytes,3,rep,name=contract_state,json=contractState,proto3" json:"contract_state"` + ContractCodeHistory []ContractCodeHistoryEntry `protobuf:"bytes,4,rep,name=contract_code_history,json=contractCodeHistory,proto3" json:"contract_code_history"` +} + +func (m *Contract) Reset() { *m = Contract{} } +func (m *Contract) String() string { return proto.CompactTextString(m) } +func (*Contract) ProtoMessage() {} +func (*Contract) Descriptor() ([]byte, []int) { + return fileDescriptor_26bed03189c69aaf, []int{2} +} +func (m *Contract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Contract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Contract.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 *Contract) XXX_Merge(src proto.Message) { + xxx_messageInfo_Contract.Merge(m, src) +} +func (m *Contract) XXX_Size() int { + return m.Size() +} +func (m *Contract) XXX_DiscardUnknown() { + xxx_messageInfo_Contract.DiscardUnknown(m) +} + +var xxx_messageInfo_Contract proto.InternalMessageInfo + +func (m *Contract) GetContractAddress() string { + if m != nil { + return m.ContractAddress + } + return "" +} + +func (m *Contract) GetContractInfo() ContractInfo { + if m != nil { + return m.ContractInfo + } + return ContractInfo{} +} + +func (m *Contract) GetContractState() []Model { + if m != nil { + return m.ContractState + } + return nil +} + +func (m *Contract) GetContractCodeHistory() []ContractCodeHistoryEntry { + if m != nil { + return m.ContractCodeHistory + } + return nil +} + +// Sequence key and value of an id generation counter +type Sequence struct { + IDKey []byte `protobuf:"bytes,1,opt,name=id_key,json=idKey,proto3" json:"id_key,omitempty"` + Value uint64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *Sequence) Reset() { *m = Sequence{} } +func (m *Sequence) String() string { return proto.CompactTextString(m) } +func (*Sequence) ProtoMessage() {} +func (*Sequence) Descriptor() ([]byte, []int) { + return fileDescriptor_26bed03189c69aaf, []int{3} +} +func (m *Sequence) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Sequence) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Sequence.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 *Sequence) XXX_Merge(src proto.Message) { + xxx_messageInfo_Sequence.Merge(m, src) +} +func (m *Sequence) XXX_Size() int { + return m.Size() +} +func (m *Sequence) XXX_DiscardUnknown() { + xxx_messageInfo_Sequence.DiscardUnknown(m) +} + +var xxx_messageInfo_Sequence proto.InternalMessageInfo + +func (m *Sequence) GetIDKey() []byte { + if m != nil { + return m.IDKey + } + return nil +} + +func (m *Sequence) GetValue() uint64 { + if m != nil { + return m.Value + } + return 0 +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "cosmwasm.wasm.v1.GenesisState") + proto.RegisterType((*Code)(nil), "cosmwasm.wasm.v1.Code") + proto.RegisterType((*Contract)(nil), "cosmwasm.wasm.v1.Contract") + proto.RegisterType((*Sequence)(nil), "cosmwasm.wasm.v1.Sequence") +} + +func init() { proto.RegisterFile("wasm/v1/genesis.proto", fileDescriptor_26bed03189c69aaf) } + +var fileDescriptor_26bed03189c69aaf = []byte{ + // 547 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x93, 0x4f, 0x6f, 0xd3, 0x30, + 0x18, 0xc6, 0x9b, 0x2e, 0x0d, 0xad, 0x57, 0xd8, 0xe4, 0xfd, 0x8b, 0x8a, 0x48, 0xab, 0x72, 0x29, + 0x08, 0x1a, 0x6d, 0x48, 0xdc, 0x38, 0x10, 0x3a, 0x41, 0x35, 0x21, 0xa1, 0x4c, 0x5c, 0xb8, 0x54, + 0xa9, 0xed, 0x75, 0x16, 0x4d, 0x1c, 0x62, 0xb7, 0x90, 0x6f, 0xc1, 0x57, 0xe0, 0xce, 0x37, 0xe0, + 0x0b, 0xec, 0xb8, 0x23, 0xa7, 0x0a, 0xa5, 0x37, 0x3e, 0x05, 0xb2, 0xe3, 0x64, 0x11, 0x5b, 0x2f, + 0x55, 0xfd, 0xbe, 0xcf, 0xf3, 0x8b, 0xfd, 0xf8, 0x35, 0x38, 0xf8, 0x1a, 0xf0, 0xd0, 0x5d, 0x1e, + 0xbb, 0x33, 0x12, 0x11, 0x4e, 0xf9, 0x30, 0x4e, 0x98, 0x60, 0x70, 0x17, 0x31, 0x1e, 0xca, 0xd6, + 0x50, 0xfd, 0x2c, 0x8f, 0x3b, 0xfb, 0x33, 0x36, 0x63, 0xaa, 0xe9, 0xca, 0x7f, 0xb9, 0xae, 0xb3, + 0x57, 0xd8, 0x45, 0x1a, 0x13, 0x6d, 0xee, 0xff, 0xaa, 0x83, 0xf6, 0xdb, 0x1c, 0x77, 0x2e, 0x02, + 0x41, 0xe0, 0x4b, 0x60, 0xc5, 0x41, 0x12, 0x84, 0xdc, 0x36, 0x7a, 0xc6, 0x60, 0xfb, 0xc4, 0x1e, + 0xfe, 0x8f, 0x1f, 0x7e, 0x50, 0x7d, 0xcf, 0xbc, 0x5a, 0x75, 0x6b, 0xbe, 0x56, 0xc3, 0x53, 0xd0, + 0x40, 0x0c, 0x13, 0x6e, 0xd7, 0x7b, 0x5b, 0x83, 0xed, 0x93, 0xc3, 0xdb, 0xb6, 0x37, 0x0c, 0x13, + 0xef, 0x48, 0x9a, 0xfe, 0xae, 0xba, 0x3b, 0x4a, 0xfc, 0x8c, 0x85, 0x54, 0x90, 0x30, 0x16, 0xa9, + 0x9f, 0xbb, 0xe1, 0x47, 0xd0, 0x42, 0x2c, 0x12, 0x49, 0x80, 0x04, 0xb7, 0xb7, 0x14, 0xaa, 0x73, + 0x17, 0x2a, 0x97, 0x78, 0x0f, 0x35, 0x6e, 0xaf, 0x34, 0x55, 0x90, 0x37, 0x24, 0x89, 0xe5, 0xe4, + 0xcb, 0x82, 0x44, 0x88, 0x70, 0xdb, 0xdc, 0x84, 0x3d, 0xd7, 0x92, 0x1b, 0x6c, 0x69, 0xaa, 0x62, + 0xcb, 0x62, 0xff, 0x87, 0x01, 0x4c, 0x79, 0x2c, 0xf8, 0x18, 0xdc, 0x93, 0xfb, 0x9f, 0x50, 0xac, + 0x62, 0x33, 0x3d, 0x90, 0xad, 0xba, 0x96, 0x6c, 0x8d, 0x47, 0xbe, 0x25, 0x5b, 0x63, 0x0c, 0x5f, + 0xc9, 0xb3, 0x49, 0x51, 0x74, 0xc1, 0xec, 0xba, 0x4a, 0xb7, 0x73, 0x77, 0x4c, 0xe3, 0xe8, 0x82, + 0xe9, 0x7c, 0x9b, 0x48, 0xaf, 0xe1, 0x23, 0x00, 0x94, 0x7d, 0x9a, 0x0a, 0x22, 0xb3, 0x31, 0x06, + 0x6d, 0x5f, 0x01, 0x3d, 0x59, 0x80, 0x87, 0xc0, 0x8a, 0x69, 0x14, 0x11, 0x6c, 0x9b, 0x3d, 0x63, + 0xd0, 0xf4, 0xf5, 0xaa, 0xff, 0xb3, 0x0e, 0x9a, 0x45, 0x5e, 0xf0, 0x09, 0xd8, 0x2d, 0x42, 0x99, + 0x04, 0x18, 0x27, 0x84, 0xe7, 0xf7, 0xdc, 0xf2, 0x77, 0x8a, 0xfa, 0xeb, 0xbc, 0x0c, 0xc7, 0xe0, + 0x7e, 0x29, 0xad, 0xec, 0xd8, 0xd9, 0x7c, 0x1b, 0x95, 0x5d, 0xb7, 0x51, 0xa5, 0x06, 0x47, 0xe0, + 0x41, 0x89, 0xe2, 0x72, 0xca, 0xf4, 0xcd, 0x1e, 0xdd, 0x66, 0xbd, 0x67, 0x98, 0xcc, 0x35, 0xa4, + 0xfc, 0x7e, 0x3e, 0x99, 0x18, 0x1c, 0x94, 0x14, 0x15, 0xc4, 0x25, 0xe5, 0x82, 0x25, 0xa9, 0xbe, + 0xcf, 0xa7, 0x9b, 0x37, 0x26, 0x23, 0x7d, 0x97, 0x8b, 0x4f, 0x23, 0x91, 0xa4, 0x9a, 0x5f, 0x0e, + 0x4d, 0xa5, 0xdf, 0xf7, 0x40, 0xb3, 0x18, 0x03, 0xd8, 0x03, 0x16, 0xc5, 0x93, 0xcf, 0x24, 0x55, + 0x19, 0xb5, 0xbd, 0x56, 0xb6, 0xea, 0x36, 0xc6, 0xa3, 0x33, 0x92, 0xfa, 0x0d, 0x8a, 0xcf, 0x48, + 0x0a, 0xf7, 0x41, 0x63, 0x19, 0xcc, 0x17, 0x44, 0x85, 0x63, 0xfa, 0xf9, 0xc2, 0xf3, 0xae, 0x32, + 0xc7, 0xb8, 0xce, 0x1c, 0xe3, 0x4f, 0xe6, 0x18, 0xdf, 0xd7, 0x4e, 0xed, 0x7a, 0xed, 0xd4, 0x7e, + 0xaf, 0x9d, 0xda, 0xa7, 0xc1, 0x8c, 0x8a, 0xcb, 0xc5, 0x74, 0x88, 0x58, 0xe8, 0x22, 0x92, 0xa0, + 0xe7, 0x94, 0xb9, 0xf3, 0x00, 0xb1, 0x88, 0x22, 0xec, 0x7e, 0x73, 0xd5, 0x0b, 0x55, 0xcf, 0x73, + 0x6a, 0xa9, 0xf7, 0xf9, 0xe2, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x86, 0x77, 0x26, 0x11, 0xf5, + 0x03, 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.Sequences) > 0 { + for iNdEx := len(m.Sequences) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Sequences[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Contracts) > 0 { + for iNdEx := len(m.Contracts) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Contracts[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Codes) > 0 { + for iNdEx := len(m.Codes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Codes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *Code) 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 *Code) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Code) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pinned { + i-- + if m.Pinned { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.CodeBytes) > 0 { + i -= len(m.CodeBytes) + copy(dAtA[i:], m.CodeBytes) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.CodeBytes))) + i-- + dAtA[i] = 0x1a + } + { + size, err := m.CodeInfo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.CodeID != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Contract) 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 *Contract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Contract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ContractCodeHistory) > 0 { + for iNdEx := len(m.ContractCodeHistory) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractCodeHistory[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.ContractState) > 0 { + for iNdEx := len(m.ContractState) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ContractState[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + { + size, err := m.ContractInfo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.ContractAddress) > 0 { + i -= len(m.ContractAddress) + copy(dAtA[i:], m.ContractAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ContractAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *Sequence) 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 *Sequence) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Sequence) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x10 + } + if len(m.IDKey) > 0 { + i -= len(m.IDKey) + copy(dAtA[i:], m.IDKey) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.IDKey))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.Codes) > 0 { + for _, e := range m.Codes { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Contracts) > 0 { + for _, e := range m.Contracts { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.Sequences) > 0 { + for _, e := range m.Sequences { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *Code) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeID != 0 { + n += 1 + sovGenesis(uint64(m.CodeID)) + } + l = m.CodeInfo.Size() + n += 1 + l + sovGenesis(uint64(l)) + l = len(m.CodeBytes) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Pinned { + n += 2 + } + return n +} + +func (m *Contract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ContractAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = m.ContractInfo.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.ContractState) > 0 { + for _, e := range m.ContractState { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ContractCodeHistory) > 0 { + for _, e := range m.ContractCodeHistory { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *Sequence) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.IDKey) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Value != 0 { + n += 1 + sovGenesis(uint64(m.Value)) + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Codes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Codes = append(m.Codes, Code{}) + if err := m.Codes[len(m.Codes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contracts", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contracts = append(m.Contracts, Contract{}) + if err := m.Contracts[len(m.Contracts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequences", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sequences = append(m.Sequences, Sequence{}) + if err := m.Sequences[len(m.Sequences)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Code) 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: Code: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Code: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CodeInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeBytes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CodeBytes = append(m.CodeBytes[:0], dAtA[iNdEx:postIndex]...) + if m.CodeBytes == nil { + m.CodeBytes = []byte{} + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pinned", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Pinned = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Contract) 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: Contract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Contract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ContractInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractState", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractState = append(m.ContractState, Model{}) + if err := m.ContractState[len(m.ContractState)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractCodeHistory", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ContractCodeHistory = append(m.ContractCodeHistory, ContractCodeHistoryEntry{}) + if err := m.ContractCodeHistory[len(m.ContractCodeHistory)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Sequence) 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: Sequence: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Sequence: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IDKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IDKey = append(m.IDKey[:0], dAtA[iNdEx:postIndex]...) + if m.IDKey == nil { + m.IDKey = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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/wasm/types/ibc.pb.go b/x/wasm/types/ibc.pb.go new file mode 100644 index 00000000..aea69188 --- /dev/null +++ b/x/wasm/types/ibc.pb.go @@ -0,0 +1,592 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/ibc.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/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 + +// MsgIBCSend +type MsgIBCSend struct { + // the channel by which the packet will be sent + Channel string `protobuf:"bytes,2,opt,name=channel,proto3" json:"channel,omitempty" yaml:"source_channel"` + // Timeout height relative to the current block height. + // The timeout is disabled when set to 0. + TimeoutHeight uint64 `protobuf:"varint,4,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty" yaml:"timeout_height"` + // Timeout timestamp (in nanoseconds) relative to the current block timestamp. + // The timeout is disabled when set to 0. + TimeoutTimestamp uint64 `protobuf:"varint,5,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty" yaml:"timeout_timestamp"` + // Data is the payload to transfer. We must not make assumption what format or + // content is in here. + Data []byte `protobuf:"bytes,6,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgIBCSend) Reset() { *m = MsgIBCSend{} } +func (m *MsgIBCSend) String() string { return proto.CompactTextString(m) } +func (*MsgIBCSend) ProtoMessage() {} +func (*MsgIBCSend) Descriptor() ([]byte, []int) { + return fileDescriptor_9cdfabf504f9c734, []int{0} +} +func (m *MsgIBCSend) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgIBCSend) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgIBCSend.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 *MsgIBCSend) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgIBCSend.Merge(m, src) +} +func (m *MsgIBCSend) XXX_Size() int { + return m.Size() +} +func (m *MsgIBCSend) XXX_DiscardUnknown() { + xxx_messageInfo_MsgIBCSend.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgIBCSend proto.InternalMessageInfo + +// MsgIBCCloseChannel port and channel need to be owned by the contract +type MsgIBCCloseChannel struct { + Channel string `protobuf:"bytes,2,opt,name=channel,proto3" json:"channel,omitempty" yaml:"source_channel"` +} + +func (m *MsgIBCCloseChannel) Reset() { *m = MsgIBCCloseChannel{} } +func (m *MsgIBCCloseChannel) String() string { return proto.CompactTextString(m) } +func (*MsgIBCCloseChannel) ProtoMessage() {} +func (*MsgIBCCloseChannel) Descriptor() ([]byte, []int) { + return fileDescriptor_9cdfabf504f9c734, []int{1} +} +func (m *MsgIBCCloseChannel) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgIBCCloseChannel) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgIBCCloseChannel.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 *MsgIBCCloseChannel) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgIBCCloseChannel.Merge(m, src) +} +func (m *MsgIBCCloseChannel) XXX_Size() int { + return m.Size() +} +func (m *MsgIBCCloseChannel) XXX_DiscardUnknown() { + xxx_messageInfo_MsgIBCCloseChannel.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgIBCCloseChannel proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgIBCSend)(nil), "cosmwasm.wasm.v1.MsgIBCSend") + proto.RegisterType((*MsgIBCCloseChannel)(nil), "cosmwasm.wasm.v1.MsgIBCCloseChannel") +} + +func init() { proto.RegisterFile("wasm/v1/ibc.proto", fileDescriptor_9cdfabf504f9c734) } + +var fileDescriptor_9cdfabf504f9c734 = []byte{ + // 306 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0x4f, 0x2c, 0xce, + 0xd5, 0x2f, 0x33, 0xd4, 0xcf, 0x4c, 0x4a, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x48, + 0xce, 0x2f, 0xce, 0x05, 0x09, 0xeb, 0x81, 0x89, 0x32, 0x43, 0x29, 0x91, 0xf4, 0xfc, 0xf4, 0x7c, + 0xb0, 0xa4, 0x3e, 0x88, 0x05, 0x51, 0xa7, 0xf4, 0x88, 0x91, 0x8b, 0xcb, 0xb7, 0x38, 0xdd, 0xd3, + 0xc9, 0x39, 0x38, 0x35, 0x2f, 0x45, 0xc8, 0x98, 0x8b, 0x3d, 0x39, 0x23, 0x31, 0x2f, 0x2f, 0x35, + 0x47, 0x82, 0x49, 0x81, 0x51, 0x83, 0xd3, 0x49, 0xf2, 0xd3, 0x3d, 0x79, 0xd1, 0xca, 0xc4, 0xdc, + 0x1c, 0x2b, 0xa5, 0xe2, 0xfc, 0xd2, 0xa2, 0xe4, 0xd4, 0x78, 0xa8, 0xbc, 0x52, 0x10, 0x4c, 0xa5, + 0x90, 0x03, 0x17, 0x5f, 0x49, 0x66, 0x6e, 0x6a, 0x7e, 0x69, 0x49, 0x7c, 0x46, 0x6a, 0x66, 0x7a, + 0x46, 0x89, 0x04, 0x8b, 0x02, 0xa3, 0x06, 0x0b, 0xb2, 0x5e, 0x54, 0x79, 0xa5, 0x20, 0x5e, 0xa8, + 0x80, 0x07, 0x98, 0x2f, 0xe4, 0xc9, 0x25, 0x08, 0x53, 0x01, 0xa2, 0x8b, 0x4b, 0x12, 0x73, 0x0b, + 0x24, 0x58, 0xc1, 0x86, 0xc8, 0x7c, 0xba, 0x27, 0x2f, 0x81, 0x6a, 0x08, 0x5c, 0x89, 0x52, 0x90, + 0x00, 0x54, 0x2c, 0x04, 0x26, 0x24, 0x24, 0xc4, 0xc5, 0x92, 0x92, 0x58, 0x92, 0x28, 0xc1, 0xa6, + 0xc0, 0xa8, 0xc1, 0x13, 0x04, 0x66, 0x2b, 0x79, 0x72, 0x09, 0x41, 0xfc, 0xe8, 0x9c, 0x93, 0x5f, + 0x9c, 0xea, 0x0c, 0x75, 0x36, 0x39, 0x7e, 0x75, 0x72, 0x3b, 0xf1, 0x50, 0x8e, 0xe1, 0xc4, 0x23, + 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, + 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, 0x34, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, + 0x92, 0xf3, 0x73, 0xf5, 0x93, 0x53, 0x8b, 0x92, 0x75, 0x33, 0xf3, 0xf5, 0x73, 0x12, 0x93, 0xf3, + 0xf3, 0x32, 0x93, 0x53, 0xf4, 0x2b, 0xf4, 0xc1, 0xd1, 0x54, 0x52, 0x59, 0x90, 0x5a, 0x9c, 0xc4, + 0x06, 0x0e, 0x7e, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x89, 0x6d, 0x8c, 0xf6, 0xbb, 0x01, + 0x00, 0x00, +} + +func (m *MsgIBCSend) 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 *MsgIBCSend) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgIBCSend) 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 = encodeVarintIbc(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0x32 + } + if m.TimeoutTimestamp != 0 { + i = encodeVarintIbc(dAtA, i, uint64(m.TimeoutTimestamp)) + i-- + dAtA[i] = 0x28 + } + if m.TimeoutHeight != 0 { + i = encodeVarintIbc(dAtA, i, uint64(m.TimeoutHeight)) + i-- + dAtA[i] = 0x20 + } + if len(m.Channel) > 0 { + i -= len(m.Channel) + copy(dAtA[i:], m.Channel) + i = encodeVarintIbc(dAtA, i, uint64(len(m.Channel))) + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func (m *MsgIBCCloseChannel) 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 *MsgIBCCloseChannel) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgIBCCloseChannel) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Channel) > 0 { + i -= len(m.Channel) + copy(dAtA[i:], m.Channel) + i = encodeVarintIbc(dAtA, i, uint64(len(m.Channel))) + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func encodeVarintIbc(dAtA []byte, offset int, v uint64) int { + offset -= sovIbc(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgIBCSend) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Channel) + if l > 0 { + n += 1 + l + sovIbc(uint64(l)) + } + if m.TimeoutHeight != 0 { + n += 1 + sovIbc(uint64(m.TimeoutHeight)) + } + if m.TimeoutTimestamp != 0 { + n += 1 + sovIbc(uint64(m.TimeoutTimestamp)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovIbc(uint64(l)) + } + return n +} + +func (m *MsgIBCCloseChannel) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Channel) + if l > 0 { + n += 1 + l + sovIbc(uint64(l)) + } + return n +} + +func sovIbc(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozIbc(x uint64) (n int) { + return sovIbc(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgIBCSend) 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 ErrIntOverflowIbc + } + 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: MsgIBCSend: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgIBCSend: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + 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 ErrIntOverflowIbc + } + 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 ErrInvalidLengthIbc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIbc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutHeight", wireType) + } + m.TimeoutHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIbc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TimeoutHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType) + } + m.TimeoutTimestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIbc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TimeoutTimestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + 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 ErrIntOverflowIbc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthIbc + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthIbc + } + 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 := skipIbc(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthIbc + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgIBCCloseChannel) 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 ErrIntOverflowIbc + } + 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: MsgIBCCloseChannel: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgIBCCloseChannel: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + 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 ErrIntOverflowIbc + } + 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 ErrInvalidLengthIbc + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIbc + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipIbc(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthIbc + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipIbc(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, ErrIntOverflowIbc + } + 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, ErrIntOverflowIbc + } + 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, ErrIntOverflowIbc + } + 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, ErrInvalidLengthIbc + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupIbc + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthIbc + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthIbc = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowIbc = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupIbc = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/wasm/types/proposal.pb.go b/x/wasm/types/proposal.pb.go new file mode 100644 index 00000000..ab4e2d16 --- /dev/null +++ b/x/wasm/types/proposal.pb.go @@ -0,0 +1,5697 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/proposal.proto + +package types + +import ( + bytes "bytes" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/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 + +// StoreCodeProposal gov proposal content type to submit WASM code to the system +type StoreCodeProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // RunAs is the address that is passed to the contract's environment as sender + RunAs string `protobuf:"bytes,3,opt,name=run_as,json=runAs,proto3" json:"run_as,omitempty"` + // WASMByteCode can be raw or gzip compressed + WASMByteCode []byte `protobuf:"bytes,4,opt,name=wasm_byte_code,json=wasmByteCode,proto3" json:"wasm_byte_code,omitempty"` + // InstantiatePermission to apply on contract creation, optional + InstantiatePermission *AccessConfig `protobuf:"bytes,7,opt,name=instantiate_permission,json=instantiatePermission,proto3" json:"instantiate_permission,omitempty"` + // UnpinCode code on upload, optional + UnpinCode bool `protobuf:"varint,8,opt,name=unpin_code,json=unpinCode,proto3" json:"unpin_code,omitempty"` + // Source is the URL where the code is hosted + Source string `protobuf:"bytes,9,opt,name=source,proto3" json:"source,omitempty"` + // Builder is the docker image used to build the code deterministically, used + // for smart contract verification + Builder string `protobuf:"bytes,10,opt,name=builder,proto3" json:"builder,omitempty"` + // CodeHash is the SHA256 sum of the code outputted by builder, used for smart + // contract verification + CodeHash []byte `protobuf:"bytes,11,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` +} + +func (m *StoreCodeProposal) Reset() { *m = StoreCodeProposal{} } +func (*StoreCodeProposal) ProtoMessage() {} +func (*StoreCodeProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{0} +} +func (m *StoreCodeProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StoreCodeProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StoreCodeProposal.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 *StoreCodeProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoreCodeProposal.Merge(m, src) +} +func (m *StoreCodeProposal) XXX_Size() int { + return m.Size() +} +func (m *StoreCodeProposal) XXX_DiscardUnknown() { + xxx_messageInfo_StoreCodeProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_StoreCodeProposal proto.InternalMessageInfo + +// InstantiateContractProposal gov proposal content type to instantiate a +// contract. +type InstantiateContractProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // RunAs is the address that is passed to the contract's environment as sender + RunAs string `protobuf:"bytes,3,opt,name=run_as,json=runAs,proto3" json:"run_as,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,4,opt,name=admin,proto3" json:"admin,omitempty"` + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,5,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Label is optional metadata to be stored with a constract instance. + Label string `protobuf:"bytes,6,opt,name=label,proto3" json:"label,omitempty"` + // Msg json encoded message to be passed to the contract on instantiation + Msg RawContractMessage `protobuf:"bytes,7,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,8,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` +} + +func (m *InstantiateContractProposal) Reset() { *m = InstantiateContractProposal{} } +func (*InstantiateContractProposal) ProtoMessage() {} +func (*InstantiateContractProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{1} +} +func (m *InstantiateContractProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InstantiateContractProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InstantiateContractProposal.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 *InstantiateContractProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_InstantiateContractProposal.Merge(m, src) +} +func (m *InstantiateContractProposal) XXX_Size() int { + return m.Size() +} +func (m *InstantiateContractProposal) XXX_DiscardUnknown() { + xxx_messageInfo_InstantiateContractProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_InstantiateContractProposal proto.InternalMessageInfo + +// InstantiateContract2Proposal gov proposal content type to instantiate +// contract 2 +type InstantiateContract2Proposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // RunAs is the address that is passed to the contract's enviroment as sender + RunAs string `protobuf:"bytes,3,opt,name=run_as,json=runAs,proto3" json:"run_as,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,4,opt,name=admin,proto3" json:"admin,omitempty"` + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,5,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Label is optional metadata to be stored with a constract instance. + Label string `protobuf:"bytes,6,opt,name=label,proto3" json:"label,omitempty"` + // Msg json encode message to be passed to the contract on instantiation + Msg RawContractMessage `protobuf:"bytes,7,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,8,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` + // Salt is an arbitrary value provided by the sender. Size can be 1 to 64. + Salt []byte `protobuf:"bytes,9,opt,name=salt,proto3" json:"salt,omitempty"` + // FixMsg include the msg value into the hash for the predictable address. + // Default is false + FixMsg bool `protobuf:"varint,10,opt,name=fix_msg,json=fixMsg,proto3" json:"fix_msg,omitempty"` +} + +func (m *InstantiateContract2Proposal) Reset() { *m = InstantiateContract2Proposal{} } +func (*InstantiateContract2Proposal) ProtoMessage() {} +func (*InstantiateContract2Proposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{2} +} +func (m *InstantiateContract2Proposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *InstantiateContract2Proposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_InstantiateContract2Proposal.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 *InstantiateContract2Proposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_InstantiateContract2Proposal.Merge(m, src) +} +func (m *InstantiateContract2Proposal) XXX_Size() int { + return m.Size() +} +func (m *InstantiateContract2Proposal) XXX_DiscardUnknown() { + xxx_messageInfo_InstantiateContract2Proposal.DiscardUnknown(m) +} + +var xxx_messageInfo_InstantiateContract2Proposal proto.InternalMessageInfo + +// MigrateContractProposal gov proposal content type to migrate a contract. +type MigrateContractProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,4,opt,name=contract,proto3" json:"contract,omitempty"` + // CodeID references the new WASM code + CodeID uint64 `protobuf:"varint,5,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Msg json encoded message to be passed to the contract on migration + Msg RawContractMessage `protobuf:"bytes,6,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` +} + +func (m *MigrateContractProposal) Reset() { *m = MigrateContractProposal{} } +func (*MigrateContractProposal) ProtoMessage() {} +func (*MigrateContractProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{3} +} +func (m *MigrateContractProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MigrateContractProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MigrateContractProposal.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 *MigrateContractProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_MigrateContractProposal.Merge(m, src) +} +func (m *MigrateContractProposal) XXX_Size() int { + return m.Size() +} +func (m *MigrateContractProposal) XXX_DiscardUnknown() { + xxx_messageInfo_MigrateContractProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_MigrateContractProposal proto.InternalMessageInfo + +// SudoContractProposal gov proposal content type to call sudo on a contract. +type SudoContractProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,3,opt,name=contract,proto3" json:"contract,omitempty"` + // Msg json encoded message to be passed to the contract as sudo + Msg RawContractMessage `protobuf:"bytes,4,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` +} + +func (m *SudoContractProposal) Reset() { *m = SudoContractProposal{} } +func (*SudoContractProposal) ProtoMessage() {} +func (*SudoContractProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{4} +} +func (m *SudoContractProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SudoContractProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SudoContractProposal.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 *SudoContractProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_SudoContractProposal.Merge(m, src) +} +func (m *SudoContractProposal) XXX_Size() int { + return m.Size() +} +func (m *SudoContractProposal) XXX_DiscardUnknown() { + xxx_messageInfo_SudoContractProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_SudoContractProposal proto.InternalMessageInfo + +// ExecuteContractProposal gov proposal content type to call execute on a +// contract. +type ExecuteContractProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // RunAs is the address that is passed to the contract's environment as sender + RunAs string `protobuf:"bytes,3,opt,name=run_as,json=runAs,proto3" json:"run_as,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,4,opt,name=contract,proto3" json:"contract,omitempty"` + // Msg json encoded message to be passed to the contract as execute + Msg RawContractMessage `protobuf:"bytes,5,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` +} + +func (m *ExecuteContractProposal) Reset() { *m = ExecuteContractProposal{} } +func (*ExecuteContractProposal) ProtoMessage() {} +func (*ExecuteContractProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{5} +} +func (m *ExecuteContractProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExecuteContractProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExecuteContractProposal.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 *ExecuteContractProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExecuteContractProposal.Merge(m, src) +} +func (m *ExecuteContractProposal) XXX_Size() int { + return m.Size() +} +func (m *ExecuteContractProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ExecuteContractProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ExecuteContractProposal proto.InternalMessageInfo + +// UpdateAdminProposal gov proposal content type to set an admin for a contract. +type UpdateAdminProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // NewAdmin address to be set + NewAdmin string `protobuf:"bytes,3,opt,name=new_admin,json=newAdmin,proto3" json:"new_admin,omitempty" yaml:"new_admin"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,4,opt,name=contract,proto3" json:"contract,omitempty"` +} + +func (m *UpdateAdminProposal) Reset() { *m = UpdateAdminProposal{} } +func (*UpdateAdminProposal) ProtoMessage() {} +func (*UpdateAdminProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{6} +} +func (m *UpdateAdminProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateAdminProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateAdminProposal.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 *UpdateAdminProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateAdminProposal.Merge(m, src) +} +func (m *UpdateAdminProposal) XXX_Size() int { + return m.Size() +} +func (m *UpdateAdminProposal) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateAdminProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateAdminProposal proto.InternalMessageInfo + +// ClearAdminProposal gov proposal content type to clear the admin of a +// contract. +type ClearAdminProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,3,opt,name=contract,proto3" json:"contract,omitempty"` +} + +func (m *ClearAdminProposal) Reset() { *m = ClearAdminProposal{} } +func (*ClearAdminProposal) ProtoMessage() {} +func (*ClearAdminProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{7} +} +func (m *ClearAdminProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ClearAdminProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ClearAdminProposal.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 *ClearAdminProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ClearAdminProposal.Merge(m, src) +} +func (m *ClearAdminProposal) XXX_Size() int { + return m.Size() +} +func (m *ClearAdminProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ClearAdminProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ClearAdminProposal proto.InternalMessageInfo + +// PinCodesProposal gov proposal content type to pin a set of code ids in the +// wasmvm cache. +type PinCodesProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + // CodeIDs references the new WASM codes + CodeIDs []uint64 `protobuf:"varint,3,rep,packed,name=code_ids,json=codeIds,proto3" json:"code_ids,omitempty" yaml:"code_ids"` +} + +func (m *PinCodesProposal) Reset() { *m = PinCodesProposal{} } +func (*PinCodesProposal) ProtoMessage() {} +func (*PinCodesProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{8} +} +func (m *PinCodesProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PinCodesProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PinCodesProposal.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 *PinCodesProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_PinCodesProposal.Merge(m, src) +} +func (m *PinCodesProposal) XXX_Size() int { + return m.Size() +} +func (m *PinCodesProposal) XXX_DiscardUnknown() { + xxx_messageInfo_PinCodesProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_PinCodesProposal proto.InternalMessageInfo + +// UnpinCodesProposal gov proposal content type to unpin a set of code ids in +// the wasmvm cache. +type UnpinCodesProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + // CodeIDs references the WASM codes + CodeIDs []uint64 `protobuf:"varint,3,rep,packed,name=code_ids,json=codeIds,proto3" json:"code_ids,omitempty" yaml:"code_ids"` +} + +func (m *UnpinCodesProposal) Reset() { *m = UnpinCodesProposal{} } +func (*UnpinCodesProposal) ProtoMessage() {} +func (*UnpinCodesProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{9} +} +func (m *UnpinCodesProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UnpinCodesProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UnpinCodesProposal.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 *UnpinCodesProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnpinCodesProposal.Merge(m, src) +} +func (m *UnpinCodesProposal) XXX_Size() int { + return m.Size() +} +func (m *UnpinCodesProposal) XXX_DiscardUnknown() { + xxx_messageInfo_UnpinCodesProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_UnpinCodesProposal proto.InternalMessageInfo + +// AccessConfigUpdate contains the code id and the access config to be +// applied. +type AccessConfigUpdate struct { + // CodeID is the reference to the stored WASM code to be updated + CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // InstantiatePermission to apply to the set of code ids + InstantiatePermission AccessConfig `protobuf:"bytes,2,opt,name=instantiate_permission,json=instantiatePermission,proto3" json:"instantiate_permission"` +} + +func (m *AccessConfigUpdate) Reset() { *m = AccessConfigUpdate{} } +func (*AccessConfigUpdate) ProtoMessage() {} +func (*AccessConfigUpdate) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{10} +} +func (m *AccessConfigUpdate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessConfigUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessConfigUpdate.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 *AccessConfigUpdate) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessConfigUpdate.Merge(m, src) +} +func (m *AccessConfigUpdate) XXX_Size() int { + return m.Size() +} +func (m *AccessConfigUpdate) XXX_DiscardUnknown() { + xxx_messageInfo_AccessConfigUpdate.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessConfigUpdate proto.InternalMessageInfo + +// UpdateInstantiateConfigProposal gov proposal content type to update +// instantiate config to a set of code ids. +type UpdateInstantiateConfigProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + // AccessConfigUpdate contains the list of code ids and the access config + // to be applied. + AccessConfigUpdates []AccessConfigUpdate `protobuf:"bytes,3,rep,name=access_config_updates,json=accessConfigUpdates,proto3" json:"access_config_updates"` +} + +func (m *UpdateInstantiateConfigProposal) Reset() { *m = UpdateInstantiateConfigProposal{} } +func (*UpdateInstantiateConfigProposal) ProtoMessage() {} +func (*UpdateInstantiateConfigProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{11} +} +func (m *UpdateInstantiateConfigProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UpdateInstantiateConfigProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UpdateInstantiateConfigProposal.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 *UpdateInstantiateConfigProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_UpdateInstantiateConfigProposal.Merge(m, src) +} +func (m *UpdateInstantiateConfigProposal) XXX_Size() int { + return m.Size() +} +func (m *UpdateInstantiateConfigProposal) XXX_DiscardUnknown() { + xxx_messageInfo_UpdateInstantiateConfigProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_UpdateInstantiateConfigProposal proto.InternalMessageInfo + +// StoreAndInstantiateContractProposal gov proposal content type to store +// and instantiate the contract. +type StoreAndInstantiateContractProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // RunAs is the address that is passed to the contract's environment as sender + RunAs string `protobuf:"bytes,3,opt,name=run_as,json=runAs,proto3" json:"run_as,omitempty"` + // WASMByteCode can be raw or gzip compressed + WASMByteCode []byte `protobuf:"bytes,4,opt,name=wasm_byte_code,json=wasmByteCode,proto3" json:"wasm_byte_code,omitempty"` + // InstantiatePermission to apply on contract creation, optional + InstantiatePermission *AccessConfig `protobuf:"bytes,5,opt,name=instantiate_permission,json=instantiatePermission,proto3" json:"instantiate_permission,omitempty"` + // UnpinCode code on upload, optional + UnpinCode bool `protobuf:"varint,6,opt,name=unpin_code,json=unpinCode,proto3" json:"unpin_code,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,7,opt,name=admin,proto3" json:"admin,omitempty"` + // Label is optional metadata to be stored with a constract instance. + Label string `protobuf:"bytes,8,opt,name=label,proto3" json:"label,omitempty"` + // Msg json encoded message to be passed to the contract on instantiation + Msg RawContractMessage `protobuf:"bytes,9,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,10,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` + // Source is the URL where the code is hosted + Source string `protobuf:"bytes,11,opt,name=source,proto3" json:"source,omitempty"` + // Builder is the docker image used to build the code deterministically, used + // for smart contract verification + Builder string `protobuf:"bytes,12,opt,name=builder,proto3" json:"builder,omitempty"` + // CodeHash is the SHA256 sum of the code outputted by builder, used for smart + // contract verification + CodeHash []byte `protobuf:"bytes,13,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` +} + +func (m *StoreAndInstantiateContractProposal) Reset() { *m = StoreAndInstantiateContractProposal{} } +func (*StoreAndInstantiateContractProposal) ProtoMessage() {} +func (*StoreAndInstantiateContractProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_b0ecdddd39c2db20, []int{12} +} +func (m *StoreAndInstantiateContractProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StoreAndInstantiateContractProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StoreAndInstantiateContractProposal.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 *StoreAndInstantiateContractProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_StoreAndInstantiateContractProposal.Merge(m, src) +} +func (m *StoreAndInstantiateContractProposal) XXX_Size() int { + return m.Size() +} +func (m *StoreAndInstantiateContractProposal) XXX_DiscardUnknown() { + xxx_messageInfo_StoreAndInstantiateContractProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_StoreAndInstantiateContractProposal proto.InternalMessageInfo + +func init() { + proto.RegisterType((*StoreCodeProposal)(nil), "cosmwasm.wasm.v1.StoreCodeProposal") + proto.RegisterType((*InstantiateContractProposal)(nil), "cosmwasm.wasm.v1.InstantiateContractProposal") + proto.RegisterType((*InstantiateContract2Proposal)(nil), "cosmwasm.wasm.v1.InstantiateContract2Proposal") + proto.RegisterType((*MigrateContractProposal)(nil), "cosmwasm.wasm.v1.MigrateContractProposal") + proto.RegisterType((*SudoContractProposal)(nil), "cosmwasm.wasm.v1.SudoContractProposal") + proto.RegisterType((*ExecuteContractProposal)(nil), "cosmwasm.wasm.v1.ExecuteContractProposal") + proto.RegisterType((*UpdateAdminProposal)(nil), "cosmwasm.wasm.v1.UpdateAdminProposal") + proto.RegisterType((*ClearAdminProposal)(nil), "cosmwasm.wasm.v1.ClearAdminProposal") + proto.RegisterType((*PinCodesProposal)(nil), "cosmwasm.wasm.v1.PinCodesProposal") + proto.RegisterType((*UnpinCodesProposal)(nil), "cosmwasm.wasm.v1.UnpinCodesProposal") + proto.RegisterType((*AccessConfigUpdate)(nil), "cosmwasm.wasm.v1.AccessConfigUpdate") + proto.RegisterType((*UpdateInstantiateConfigProposal)(nil), "cosmwasm.wasm.v1.UpdateInstantiateConfigProposal") + proto.RegisterType((*StoreAndInstantiateContractProposal)(nil), "cosmwasm.wasm.v1.StoreAndInstantiateContractProposal") +} + +func init() { proto.RegisterFile("wasm/v1/proposal.proto", fileDescriptor_b0ecdddd39c2db20) } + +var fileDescriptor_b0ecdddd39c2db20 = []byte{ + // 1025 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x57, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0x8f, 0xf3, 0xc7, 0x71, 0x26, 0x01, 0xc2, 0x34, 0x4d, 0xbd, 0x5d, 0xb0, 0xa3, 0x2c, 0x42, + 0xb9, 0x34, 0x21, 0x45, 0x42, 0xb0, 0xb7, 0xb8, 0x20, 0xd1, 0x95, 0x8a, 0x2a, 0x57, 0x15, 0x12, + 0x48, 0x58, 0x13, 0x7b, 0xe2, 0x8e, 0x48, 0x3c, 0x91, 0xc7, 0xee, 0x9f, 0x33, 0x17, 0x24, 0x2e, + 0x9c, 0x10, 0x1f, 0x01, 0x71, 0x43, 0xda, 0x23, 0x1f, 0xa0, 0xda, 0x0b, 0xcb, 0x6d, 0x0f, 0x28, + 0xb0, 0xe9, 0x8d, 0x63, 0x8f, 0x9c, 0xd0, 0xcc, 0x38, 0xd9, 0xb4, 0xb4, 0xc9, 0x96, 0x6d, 0x8b, + 0x84, 0xf6, 0xd2, 0xe6, 0xcd, 0x9b, 0x37, 0xf3, 0x7b, 0xbf, 0xf7, 0xe6, 0xf9, 0x3d, 0x50, 0x3d, + 0x40, 0x6c, 0xd0, 0xda, 0x6f, 0xb7, 0x86, 0x21, 0x1d, 0x52, 0x86, 0xfa, 0xcd, 0x61, 0x48, 0x23, + 0x0a, 0xcb, 0x2e, 0x65, 0x03, 0xae, 0x6b, 0x8a, 0x3f, 0xfb, 0xed, 0xd5, 0x8a, 0x4f, 0x7d, 0x2a, + 0x94, 0x2d, 0xfe, 0x4b, 0xee, 0x5b, 0xbd, 0xc3, 0xf7, 0x51, 0xe6, 0x48, 0x85, 0x14, 0x12, 0x95, + 0x21, 0xa5, 0x56, 0x17, 0x31, 0xdc, 0xda, 0x6f, 0x77, 0x71, 0x84, 0xda, 0x2d, 0x97, 0x92, 0x20, + 0xd1, 0x2f, 0x4d, 0xae, 0x8e, 0x8e, 0x86, 0x38, 0x31, 0xaa, 0x7f, 0x93, 0x01, 0xaf, 0xef, 0x44, + 0x34, 0xc4, 0x1b, 0xd4, 0xc3, 0xdb, 0x09, 0x26, 0x58, 0x01, 0xb9, 0x88, 0x44, 0x7d, 0xac, 0x2b, + 0x35, 0xa5, 0x51, 0xb0, 0xa5, 0x00, 0x6b, 0xa0, 0xe8, 0x61, 0xe6, 0x86, 0x64, 0x18, 0x11, 0x1a, + 0xe8, 0x69, 0xa1, 0x9b, 0x5d, 0x82, 0xcb, 0x40, 0x0d, 0xe3, 0xc0, 0x41, 0x4c, 0xcf, 0x48, 0xc3, + 0x30, 0x0e, 0x3a, 0x0c, 0xbe, 0x07, 0x5e, 0xe5, 0x77, 0x3b, 0xdd, 0xa3, 0x08, 0x3b, 0x2e, 0xf5, + 0xb0, 0x9e, 0xad, 0x29, 0x8d, 0x92, 0x55, 0x1e, 0x8f, 0xcc, 0xd2, 0xa7, 0x9d, 0x9d, 0x2d, 0xeb, + 0x28, 0x12, 0x00, 0xec, 0x12, 0xdf, 0x37, 0x91, 0xe0, 0x2e, 0xa8, 0x92, 0x80, 0x45, 0x28, 0x88, + 0x08, 0x8a, 0xb0, 0x33, 0xc4, 0xe1, 0x80, 0x30, 0xc6, 0xef, 0xce, 0xd7, 0x94, 0x46, 0x71, 0xdd, + 0x68, 0x9e, 0x67, 0xad, 0xd9, 0x71, 0x5d, 0xcc, 0xd8, 0x06, 0x0d, 0x7a, 0xc4, 0xb7, 0x97, 0x67, + 0xac, 0xb7, 0xa7, 0xc6, 0xf0, 0x4d, 0x00, 0xe2, 0x60, 0x48, 0x02, 0x09, 0x45, 0xab, 0x29, 0x0d, + 0xcd, 0x2e, 0x88, 0x15, 0x71, 0x6b, 0x15, 0xa8, 0x8c, 0xc6, 0xa1, 0x8b, 0xf5, 0x82, 0x70, 0x22, + 0x91, 0xa0, 0x0e, 0xf2, 0xdd, 0x98, 0xf4, 0x3d, 0x1c, 0xea, 0x40, 0x28, 0x26, 0x22, 0xbc, 0x0b, + 0x0a, 0xfc, 0x28, 0x67, 0x0f, 0xb1, 0x3d, 0xbd, 0xc8, 0x5d, 0xb3, 0x35, 0xbe, 0xf0, 0x31, 0x62, + 0x7b, 0xf7, 0x8d, 0x47, 0x0f, 0xd7, 0x56, 0x93, 0x40, 0xf9, 0x74, 0xbf, 0x99, 0x44, 0xa6, 0xb9, + 0x41, 0x83, 0x08, 0x07, 0xd1, 0x83, 0xac, 0x96, 0x2b, 0xab, 0x0f, 0xb2, 0x9a, 0x5a, 0xce, 0xd7, + 0xff, 0x4c, 0x83, 0xbb, 0x9b, 0xcf, 0x30, 0xf3, 0x2d, 0x21, 0x72, 0xa3, 0x9b, 0x8a, 0x4b, 0x05, + 0xe4, 0x90, 0x37, 0x20, 0x81, 0x08, 0x47, 0xc1, 0x96, 0x02, 0xbc, 0x07, 0xf2, 0xc2, 0x1b, 0xe2, + 0xe9, 0xb9, 0x9a, 0xd2, 0xc8, 0x5a, 0x60, 0x3c, 0x32, 0x55, 0x4e, 0xcd, 0xe6, 0x87, 0xb6, 0xca, + 0x55, 0x9b, 0x1e, 0x37, 0xed, 0xa3, 0x2e, 0xee, 0xeb, 0xaa, 0x34, 0x15, 0x02, 0x6c, 0x80, 0xcc, + 0x80, 0xf9, 0x22, 0x3a, 0x25, 0xab, 0xfa, 0xd7, 0xc8, 0x84, 0x36, 0x3a, 0x98, 0x78, 0xb1, 0x85, + 0x19, 0x43, 0x3e, 0xb6, 0xf9, 0x16, 0x88, 0x40, 0xae, 0x17, 0x07, 0x1e, 0xd3, 0xb5, 0x5a, 0xa6, + 0x51, 0x5c, 0xbf, 0xd3, 0x4c, 0x18, 0xe2, 0xc9, 0x3b, 0x43, 0x11, 0x09, 0xac, 0x77, 0x8e, 0x47, + 0x66, 0xea, 0xc7, 0xdf, 0xcd, 0x86, 0x4f, 0xa2, 0xbd, 0xb8, 0xdb, 0x74, 0xe9, 0x20, 0xc9, 0xfb, + 0xe4, 0xdf, 0x1a, 0xf3, 0xbe, 0x4c, 0x72, 0x9a, 0x1b, 0x30, 0x5b, 0x9e, 0xbc, 0x88, 0xf8, 0xfa, + 0xf7, 0x19, 0xf0, 0xc6, 0x05, 0x64, 0xaf, 0xbf, 0x64, 0xfb, 0x5f, 0xb0, 0x0d, 0x21, 0xc8, 0x32, + 0xd4, 0x8f, 0xc4, 0x9b, 0x29, 0xd9, 0xe2, 0x37, 0x5c, 0x01, 0xf9, 0x1e, 0x39, 0x74, 0x38, 0x48, + 0x20, 0x5e, 0x99, 0xda, 0x23, 0x87, 0x5b, 0xcc, 0x5f, 0x18, 0x9a, 0xdf, 0x14, 0xb0, 0xb2, 0x45, + 0xfc, 0xf0, 0x3a, 0xdf, 0xc0, 0x2a, 0xd0, 0xdc, 0xe4, 0xac, 0x24, 0x02, 0x53, 0xf9, 0xf9, 0x82, + 0x90, 0xd0, 0xad, 0x2e, 0xa4, 0x7b, 0xa1, 0x7b, 0x0f, 0x15, 0x50, 0xd9, 0x89, 0x3d, 0x7a, 0x23, + 0xbe, 0x65, 0xce, 0xf9, 0x96, 0xc0, 0xce, 0xbe, 0x38, 0xec, 0x9f, 0xd2, 0x60, 0xe5, 0xa3, 0x43, + 0xec, 0xc6, 0x37, 0x5f, 0x99, 0xe6, 0x05, 0x2b, 0x71, 0x28, 0x77, 0x85, 0xb4, 0x57, 0xff, 0xb3, + 0x22, 0xf3, 0xb3, 0x02, 0x96, 0x76, 0x87, 0x1e, 0x8a, 0x70, 0x87, 0x3f, 0xf7, 0x17, 0xe6, 0xab, + 0x0d, 0x0a, 0x01, 0x3e, 0x70, 0x64, 0x21, 0x11, 0x94, 0x59, 0x95, 0xd3, 0x91, 0x59, 0x3e, 0x42, + 0x83, 0xfe, 0xfd, 0xfa, 0x54, 0x55, 0xb7, 0xb5, 0x00, 0x1f, 0x88, 0x2b, 0xe7, 0x71, 0xb9, 0x10, + 0xfe, 0xd7, 0x0a, 0x80, 0x1b, 0x7d, 0x8c, 0xc2, 0xeb, 0x41, 0x3f, 0x27, 0x4f, 0x17, 0x42, 0xf9, + 0x45, 0x01, 0xe5, 0x6d, 0xf9, 0x89, 0x66, 0x53, 0x20, 0x6f, 0x9f, 0x01, 0x62, 0x95, 0x4f, 0x47, + 0x66, 0x49, 0x52, 0x21, 0x96, 0xeb, 0x13, 0x68, 0xef, 0x5f, 0x00, 0xcd, 0xaa, 0x9e, 0x8e, 0x4c, + 0x28, 0x77, 0xcf, 0x28, 0xeb, 0x67, 0x21, 0x7f, 0x00, 0xb4, 0xa4, 0x34, 0xf0, 0x14, 0xcd, 0x34, + 0xb2, 0x96, 0x31, 0x1e, 0x99, 0x79, 0x59, 0x1b, 0xd8, 0xe9, 0xc8, 0x7c, 0x4d, 0x9e, 0x30, 0xd9, + 0x54, 0xb7, 0xf3, 0xb2, 0x5e, 0x2c, 0xce, 0x8d, 0x5f, 0x15, 0x00, 0x77, 0x27, 0x6d, 0xc7, 0xff, + 0xc4, 0xa7, 0xef, 0x14, 0x00, 0x67, 0x7b, 0x30, 0x99, 0xfb, 0xb3, 0x05, 0x56, 0xb9, 0xb4, 0xc0, + 0x7e, 0x7e, 0x69, 0xbb, 0x97, 0x7e, 0x9e, 0x76, 0xcf, 0xca, 0xf2, 0x47, 0x7c, 0x49, 0xd3, 0x57, + 0xff, 0x2a, 0x0d, 0x4c, 0x09, 0xe6, 0xec, 0x37, 0xbf, 0x47, 0xfc, 0x5b, 0x64, 0xfe, 0x0b, 0xb0, + 0x8c, 0x04, 0x64, 0xc7, 0x15, 0x57, 0x3b, 0xb1, 0x80, 0x24, 0xc3, 0x50, 0x5c, 0x7f, 0x6b, 0xbe, + 0x87, 0x12, 0x7f, 0xe2, 0xe7, 0x12, 0xfa, 0x87, 0x66, 0x71, 0x78, 0x1e, 0x65, 0xc1, 0x3d, 0xd1, + 0xee, 0x77, 0x02, 0xef, 0x16, 0x1b, 0xcd, 0xeb, 0x1f, 0x00, 0x72, 0xd7, 0x37, 0x00, 0xa8, 0xe7, + 0x07, 0x80, 0x69, 0xa3, 0x96, 0x9f, 0x6d, 0xd4, 0xa6, 0x3d, 0x98, 0x76, 0x41, 0x0f, 0x56, 0xb8, + 0xc2, 0xc7, 0x08, 0xdc, 0x58, 0x0f, 0xf6, 0x6c, 0x72, 0x29, 0x5e, 0x36, 0xb9, 0x94, 0xe6, 0x4c, + 0x2e, 0xaf, 0x5c, 0x6d, 0x72, 0xb1, 0x3e, 0x39, 0x7e, 0x6a, 0xa4, 0x9e, 0x3c, 0x35, 0x52, 0x3f, + 0x8c, 0x0d, 0xe5, 0x78, 0x6c, 0x28, 0x8f, 0xc7, 0x86, 0xf2, 0xc7, 0xd8, 0x50, 0xbe, 0x3d, 0x31, + 0x52, 0x8f, 0x4f, 0x8c, 0xd4, 0x93, 0x13, 0x23, 0xf5, 0xd9, 0x19, 0x2f, 0x70, 0xe8, 0xae, 0x11, + 0xda, 0xea, 0x23, 0x97, 0x06, 0xc4, 0xf5, 0x5a, 0x87, 0x2d, 0x31, 0x94, 0x0a, 0x5f, 0xba, 0xaa, + 0x18, 0x49, 0xdf, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x93, 0xd3, 0xc7, 0x8d, 0x24, 0x0f, 0x00, + 0x00, +} + +func (this *StoreCodeProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*StoreCodeProposal) + if !ok { + that2, ok := that.(StoreCodeProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.RunAs != that1.RunAs { + return false + } + if !bytes.Equal(this.WASMByteCode, that1.WASMByteCode) { + return false + } + if !this.InstantiatePermission.Equal(that1.InstantiatePermission) { + return false + } + if this.UnpinCode != that1.UnpinCode { + return false + } + if this.Source != that1.Source { + return false + } + if this.Builder != that1.Builder { + return false + } + if !bytes.Equal(this.CodeHash, that1.CodeHash) { + return false + } + return true +} +func (this *InstantiateContractProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*InstantiateContractProposal) + if !ok { + that2, ok := that.(InstantiateContractProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.RunAs != that1.RunAs { + return false + } + if this.Admin != that1.Admin { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if this.Label != that1.Label { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + if len(this.Funds) != len(that1.Funds) { + return false + } + for i := range this.Funds { + if !this.Funds[i].Equal(&that1.Funds[i]) { + return false + } + } + return true +} +func (this *InstantiateContract2Proposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*InstantiateContract2Proposal) + if !ok { + that2, ok := that.(InstantiateContract2Proposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.RunAs != that1.RunAs { + return false + } + if this.Admin != that1.Admin { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if this.Label != that1.Label { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + if len(this.Funds) != len(that1.Funds) { + return false + } + for i := range this.Funds { + if !this.Funds[i].Equal(&that1.Funds[i]) { + return false + } + } + if !bytes.Equal(this.Salt, that1.Salt) { + return false + } + if this.FixMsg != that1.FixMsg { + return false + } + return true +} +func (this *MigrateContractProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*MigrateContractProposal) + if !ok { + that2, ok := that.(MigrateContractProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.Contract != that1.Contract { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + return true +} +func (this *SudoContractProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*SudoContractProposal) + if !ok { + that2, ok := that.(SudoContractProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.Contract != that1.Contract { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + return true +} +func (this *ExecuteContractProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ExecuteContractProposal) + if !ok { + that2, ok := that.(ExecuteContractProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.RunAs != that1.RunAs { + return false + } + if this.Contract != that1.Contract { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + if len(this.Funds) != len(that1.Funds) { + return false + } + for i := range this.Funds { + if !this.Funds[i].Equal(&that1.Funds[i]) { + return false + } + } + return true +} +func (this *UpdateAdminProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UpdateAdminProposal) + if !ok { + that2, ok := that.(UpdateAdminProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.NewAdmin != that1.NewAdmin { + return false + } + if this.Contract != that1.Contract { + return false + } + return true +} +func (this *ClearAdminProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ClearAdminProposal) + if !ok { + that2, ok := that.(ClearAdminProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.Contract != that1.Contract { + return false + } + return true +} +func (this *PinCodesProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PinCodesProposal) + if !ok { + that2, ok := that.(PinCodesProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if len(this.CodeIDs) != len(that1.CodeIDs) { + return false + } + for i := range this.CodeIDs { + if this.CodeIDs[i] != that1.CodeIDs[i] { + return false + } + } + return true +} +func (this *UnpinCodesProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UnpinCodesProposal) + if !ok { + that2, ok := that.(UnpinCodesProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if len(this.CodeIDs) != len(that1.CodeIDs) { + return false + } + for i := range this.CodeIDs { + if this.CodeIDs[i] != that1.CodeIDs[i] { + return false + } + } + return true +} +func (this *AccessConfigUpdate) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*AccessConfigUpdate) + if !ok { + that2, ok := that.(AccessConfigUpdate) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if !this.InstantiatePermission.Equal(&that1.InstantiatePermission) { + return false + } + return true +} +func (this *UpdateInstantiateConfigProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UpdateInstantiateConfigProposal) + if !ok { + that2, ok := that.(UpdateInstantiateConfigProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if len(this.AccessConfigUpdates) != len(that1.AccessConfigUpdates) { + return false + } + for i := range this.AccessConfigUpdates { + if !this.AccessConfigUpdates[i].Equal(&that1.AccessConfigUpdates[i]) { + return false + } + } + return true +} +func (this *StoreAndInstantiateContractProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*StoreAndInstantiateContractProposal) + if !ok { + that2, ok := that.(StoreAndInstantiateContractProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if this.RunAs != that1.RunAs { + return false + } + if !bytes.Equal(this.WASMByteCode, that1.WASMByteCode) { + return false + } + if !this.InstantiatePermission.Equal(that1.InstantiatePermission) { + return false + } + if this.UnpinCode != that1.UnpinCode { + return false + } + if this.Admin != that1.Admin { + return false + } + if this.Label != that1.Label { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + if len(this.Funds) != len(that1.Funds) { + return false + } + for i := range this.Funds { + if !this.Funds[i].Equal(&that1.Funds[i]) { + return false + } + } + if this.Source != that1.Source { + return false + } + if this.Builder != that1.Builder { + return false + } + if !bytes.Equal(this.CodeHash, that1.CodeHash) { + return false + } + return true +} +func (m *StoreCodeProposal) 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 *StoreCodeProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StoreCodeProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CodeHash) > 0 { + i -= len(m.CodeHash) + copy(dAtA[i:], m.CodeHash) + i = encodeVarintProposal(dAtA, i, uint64(len(m.CodeHash))) + i-- + dAtA[i] = 0x5a + } + if len(m.Builder) > 0 { + i -= len(m.Builder) + copy(dAtA[i:], m.Builder) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Builder))) + i-- + dAtA[i] = 0x52 + } + if len(m.Source) > 0 { + i -= len(m.Source) + copy(dAtA[i:], m.Source) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Source))) + i-- + dAtA[i] = 0x4a + } + if m.UnpinCode { + i-- + if m.UnpinCode { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + } + if m.InstantiatePermission != nil { + { + size, err := m.InstantiatePermission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.WASMByteCode) > 0 { + i -= len(m.WASMByteCode) + copy(dAtA[i:], m.WASMByteCode) + i = encodeVarintProposal(dAtA, i, uint64(len(m.WASMByteCode))) + i-- + dAtA[i] = 0x22 + } + if len(m.RunAs) > 0 { + i -= len(m.RunAs) + copy(dAtA[i:], m.RunAs) + i = encodeVarintProposal(dAtA, i, uint64(len(m.RunAs))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *InstantiateContractProposal) 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 *InstantiateContractProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InstantiateContractProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x3a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x32 + } + if m.CodeID != 0 { + i = encodeVarintProposal(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x28 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x22 + } + if len(m.RunAs) > 0 { + i -= len(m.RunAs) + copy(dAtA[i:], m.RunAs) + i = encodeVarintProposal(dAtA, i, uint64(len(m.RunAs))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *InstantiateContract2Proposal) 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 *InstantiateContract2Proposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *InstantiateContract2Proposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.FixMsg { + i-- + if m.FixMsg { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + } + if len(m.Salt) > 0 { + i -= len(m.Salt) + copy(dAtA[i:], m.Salt) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Salt))) + i-- + dAtA[i] = 0x4a + } + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x3a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x32 + } + if m.CodeID != 0 { + i = encodeVarintProposal(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x28 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x22 + } + if len(m.RunAs) > 0 { + i -= len(m.RunAs) + copy(dAtA[i:], m.RunAs) + i = encodeVarintProposal(dAtA, i, uint64(len(m.RunAs))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MigrateContractProposal) 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 *MigrateContractProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MigrateContractProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x32 + } + if m.CodeID != 0 { + i = encodeVarintProposal(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x28 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x22 + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SudoContractProposal) 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 *SudoContractProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SudoContractProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x22 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ExecuteContractProposal) 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 *ExecuteContractProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExecuteContractProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x2a + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x22 + } + if len(m.RunAs) > 0 { + i -= len(m.RunAs) + copy(dAtA[i:], m.RunAs) + i = encodeVarintProposal(dAtA, i, uint64(len(m.RunAs))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UpdateAdminProposal) 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 *UpdateAdminProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateAdminProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x22 + } + if len(m.NewAdmin) > 0 { + i -= len(m.NewAdmin) + copy(dAtA[i:], m.NewAdmin) + i = encodeVarintProposal(dAtA, i, uint64(len(m.NewAdmin))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ClearAdminProposal) 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 *ClearAdminProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ClearAdminProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PinCodesProposal) 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 *PinCodesProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PinCodesProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CodeIDs) > 0 { + dAtA3 := make([]byte, len(m.CodeIDs)*10) + var j2 int + for _, num := range m.CodeIDs { + for num >= 1<<7 { + dAtA3[j2] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j2++ + } + dAtA3[j2] = uint8(num) + j2++ + } + i -= j2 + copy(dAtA[i:], dAtA3[:j2]) + i = encodeVarintProposal(dAtA, i, uint64(j2)) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UnpinCodesProposal) 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 *UnpinCodesProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UnpinCodesProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CodeIDs) > 0 { + dAtA5 := make([]byte, len(m.CodeIDs)*10) + var j4 int + for _, num := range m.CodeIDs { + for num >= 1<<7 { + dAtA5[j4] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j4++ + } + dAtA5[j4] = uint8(num) + j4++ + } + i -= j4 + copy(dAtA[i:], dAtA5[:j4]) + i = encodeVarintProposal(dAtA, i, uint64(j4)) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AccessConfigUpdate) 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 *AccessConfigUpdate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessConfigUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.InstantiatePermission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.CodeID != 0 { + i = encodeVarintProposal(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *UpdateInstantiateConfigProposal) 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 *UpdateInstantiateConfigProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UpdateInstantiateConfigProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AccessConfigUpdates) > 0 { + for iNdEx := len(m.AccessConfigUpdates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AccessConfigUpdates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StoreAndInstantiateContractProposal) 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 *StoreAndInstantiateContractProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StoreAndInstantiateContractProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CodeHash) > 0 { + i -= len(m.CodeHash) + copy(dAtA[i:], m.CodeHash) + i = encodeVarintProposal(dAtA, i, uint64(len(m.CodeHash))) + i-- + dAtA[i] = 0x6a + } + if len(m.Builder) > 0 { + i -= len(m.Builder) + copy(dAtA[i:], m.Builder) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Builder))) + i-- + dAtA[i] = 0x62 + } + if len(m.Source) > 0 { + i -= len(m.Source) + copy(dAtA[i:], m.Source) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Source))) + i-- + dAtA[i] = 0x5a + } + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x4a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x42 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x3a + } + if m.UnpinCode { + i-- + if m.UnpinCode { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } + if m.InstantiatePermission != nil { + { + size, err := m.InstantiatePermission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintProposal(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.WASMByteCode) > 0 { + i -= len(m.WASMByteCode) + copy(dAtA[i:], m.WASMByteCode) + i = encodeVarintProposal(dAtA, i, uint64(len(m.WASMByteCode))) + i-- + dAtA[i] = 0x22 + } + if len(m.RunAs) > 0 { + i -= len(m.RunAs) + copy(dAtA[i:], m.RunAs) + i = encodeVarintProposal(dAtA, i, uint64(len(m.RunAs))) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintProposal(dAtA []byte, offset int, v uint64) int { + offset -= sovProposal(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *StoreCodeProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.RunAs) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.WASMByteCode) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if m.InstantiatePermission != nil { + l = m.InstantiatePermission.Size() + n += 1 + l + sovProposal(uint64(l)) + } + if m.UnpinCode { + n += 2 + } + l = len(m.Source) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Builder) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.CodeHash) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + return n +} + +func (m *InstantiateContractProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.RunAs) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovProposal(uint64(m.CodeID)) + } + l = len(m.Label) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovProposal(uint64(l)) + } + } + return n +} + +func (m *InstantiateContract2Proposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.RunAs) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovProposal(uint64(m.CodeID)) + } + l = len(m.Label) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovProposal(uint64(l)) + } + } + l = len(m.Salt) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if m.FixMsg { + n += 2 + } + return n +} + +func (m *MigrateContractProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovProposal(uint64(m.CodeID)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + return n +} + +func (m *SudoContractProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + return n +} + +func (m *ExecuteContractProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.RunAs) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovProposal(uint64(l)) + } + } + return n +} + +func (m *UpdateAdminProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.NewAdmin) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + return n +} + +func (m *ClearAdminProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + return n +} + +func (m *PinCodesProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.CodeIDs) > 0 { + l = 0 + for _, e := range m.CodeIDs { + l += sovProposal(uint64(e)) + } + n += 1 + sovProposal(uint64(l)) + l + } + return n +} + +func (m *UnpinCodesProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.CodeIDs) > 0 { + l = 0 + for _, e := range m.CodeIDs { + l += sovProposal(uint64(e)) + } + n += 1 + sovProposal(uint64(l)) + l + } + return n +} + +func (m *AccessConfigUpdate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeID != 0 { + n += 1 + sovProposal(uint64(m.CodeID)) + } + l = m.InstantiatePermission.Size() + n += 1 + l + sovProposal(uint64(l)) + return n +} + +func (m *UpdateInstantiateConfigProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.AccessConfigUpdates) > 0 { + for _, e := range m.AccessConfigUpdates { + l = e.Size() + n += 1 + l + sovProposal(uint64(l)) + } + } + return n +} + +func (m *StoreAndInstantiateContractProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.RunAs) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.WASMByteCode) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if m.InstantiatePermission != nil { + l = m.InstantiatePermission.Size() + n += 1 + l + sovProposal(uint64(l)) + } + if m.UnpinCode { + n += 2 + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Label) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovProposal(uint64(l)) + } + } + l = len(m.Source) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Builder) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.CodeHash) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + return n +} + +func sovProposal(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozProposal(x uint64) (n int) { + return sovProposal(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *StoreCodeProposal) 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 ErrIntOverflowProposal + } + 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: StoreCodeProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreCodeProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RunAs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RunAs = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WASMByteCode", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WASMByteCode = append(m.WASMByteCode[:0], dAtA[iNdEx:postIndex]...) + if m.WASMByteCode == nil { + m.WASMByteCode = []byte{} + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiatePermission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.InstantiatePermission == nil { + m.InstantiatePermission = &AccessConfig{} + } + if err := m.InstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnpinCode", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnpinCode = bool(v != 0) + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Source = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Builder", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Builder = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CodeHash = append(m.CodeHash[:0], dAtA[iNdEx:postIndex]...) + if m.CodeHash == nil { + m.CodeHash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InstantiateContractProposal) 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 ErrIntOverflowProposal + } + 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: InstantiateContractProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InstantiateContractProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RunAs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RunAs = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *InstantiateContract2Proposal) 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 ErrIntOverflowProposal + } + 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: InstantiateContract2Proposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InstantiateContract2Proposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RunAs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RunAs = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Salt", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Salt = append(m.Salt[:0], dAtA[iNdEx:postIndex]...) + if m.Salt == nil { + m.Salt = []byte{} + } + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FixMsg", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FixMsg = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MigrateContractProposal) 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 ErrIntOverflowProposal + } + 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: MigrateContractProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MigrateContractProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SudoContractProposal) 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 ErrIntOverflowProposal + } + 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: SudoContractProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SudoContractProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ExecuteContractProposal) 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 ErrIntOverflowProposal + } + 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: ExecuteContractProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExecuteContractProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RunAs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RunAs = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateAdminProposal) 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 ErrIntOverflowProposal + } + 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: UpdateAdminProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateAdminProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewAdmin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewAdmin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ClearAdminProposal) 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 ErrIntOverflowProposal + } + 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: ClearAdminProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ClearAdminProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PinCodesProposal) 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 ErrIntOverflowProposal + } + 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: PinCodesProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PinCodesProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.CodeIDs) == 0 { + m.CodeIDs = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field CodeIDs", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UnpinCodesProposal) 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 ErrIntOverflowProposal + } + 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: UnpinCodesProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UnpinCodesProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.CodeIDs) == 0 { + m.CodeIDs = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field CodeIDs", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessConfigUpdate) 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 ErrIntOverflowProposal + } + 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: AccessConfigUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessConfigUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiatePermission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UpdateInstantiateConfigProposal) 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 ErrIntOverflowProposal + } + 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: UpdateInstantiateConfigProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UpdateInstantiateConfigProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AccessConfigUpdates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AccessConfigUpdates = append(m.AccessConfigUpdates, AccessConfigUpdate{}) + if err := m.AccessConfigUpdates[len(m.AccessConfigUpdates)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StoreAndInstantiateContractProposal) 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 ErrIntOverflowProposal + } + 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: StoreAndInstantiateContractProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StoreAndInstantiateContractProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RunAs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RunAs = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WASMByteCode", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WASMByteCode = append(m.WASMByteCode[:0], dAtA[iNdEx:postIndex]...) + if m.WASMByteCode == nil { + m.WASMByteCode = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiatePermission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.InstantiatePermission == nil { + m.InstantiatePermission = &AccessConfig{} + } + if err := m.InstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnpinCode", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.UnpinCode = bool(v != 0) + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Source = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Builder", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + 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 ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Builder = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CodeHash = append(m.CodeHash[:0], dAtA[iNdEx:postIndex]...) + if m.CodeHash == nil { + m.CodeHash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipProposal(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, ErrIntOverflowProposal + } + 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, ErrIntOverflowProposal + } + 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, ErrIntOverflowProposal + } + 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, ErrInvalidLengthProposal + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupProposal + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthProposal + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthProposal = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowProposal = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupProposal = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/wasm/types/query.pb.go b/x/wasm/types/query.pb.go new file mode 100644 index 00000000..b809723d --- /dev/null +++ b/x/wasm/types/query.pb.go @@ -0,0 +1,5481 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/query.proto + +package types + +import ( + bytes "bytes" + context "context" + fmt "fmt" + query "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + github_com_tendermint_tendermint_libs_bytes "github.com/tendermint/tendermint/libs/bytes" + _ "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 + +// QueryContractInfoRequest is the request type for the Query/ContractInfo RPC +// method +type QueryContractInfoRequest struct { + // address is the address of the contract to query + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *QueryContractInfoRequest) Reset() { *m = QueryContractInfoRequest{} } +func (m *QueryContractInfoRequest) String() string { return proto.CompactTextString(m) } +func (*QueryContractInfoRequest) ProtoMessage() {} +func (*QueryContractInfoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{0} +} +func (m *QueryContractInfoRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractInfoRequest.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 *QueryContractInfoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractInfoRequest.Merge(m, src) +} +func (m *QueryContractInfoRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryContractInfoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractInfoRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractInfoRequest proto.InternalMessageInfo + +// QueryContractInfoResponse is the response type for the Query/ContractInfo RPC +// method +type QueryContractInfoResponse struct { + // address is the address of the contract + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + ContractInfo `protobuf:"bytes,2,opt,name=contract_info,json=contractInfo,proto3,embedded=contract_info" json:""` +} + +func (m *QueryContractInfoResponse) Reset() { *m = QueryContractInfoResponse{} } +func (m *QueryContractInfoResponse) String() string { return proto.CompactTextString(m) } +func (*QueryContractInfoResponse) ProtoMessage() {} +func (*QueryContractInfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{1} +} +func (m *QueryContractInfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractInfoResponse.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 *QueryContractInfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractInfoResponse.Merge(m, src) +} +func (m *QueryContractInfoResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryContractInfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractInfoResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractInfoResponse proto.InternalMessageInfo + +// QueryContractHistoryRequest is the request type for the Query/ContractHistory +// RPC method +type QueryContractHistoryRequest struct { + // address is the address of the contract to query + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryContractHistoryRequest) Reset() { *m = QueryContractHistoryRequest{} } +func (m *QueryContractHistoryRequest) String() string { return proto.CompactTextString(m) } +func (*QueryContractHistoryRequest) ProtoMessage() {} +func (*QueryContractHistoryRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{2} +} +func (m *QueryContractHistoryRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractHistoryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractHistoryRequest.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 *QueryContractHistoryRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractHistoryRequest.Merge(m, src) +} +func (m *QueryContractHistoryRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryContractHistoryRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractHistoryRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractHistoryRequest proto.InternalMessageInfo + +// QueryContractHistoryResponse is the response type for the +// Query/ContractHistory RPC method +type QueryContractHistoryResponse struct { + Entries []ContractCodeHistoryEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryContractHistoryResponse) Reset() { *m = QueryContractHistoryResponse{} } +func (m *QueryContractHistoryResponse) String() string { return proto.CompactTextString(m) } +func (*QueryContractHistoryResponse) ProtoMessage() {} +func (*QueryContractHistoryResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{3} +} +func (m *QueryContractHistoryResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractHistoryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractHistoryResponse.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 *QueryContractHistoryResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractHistoryResponse.Merge(m, src) +} +func (m *QueryContractHistoryResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryContractHistoryResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractHistoryResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractHistoryResponse proto.InternalMessageInfo + +// QueryContractsByCodeRequest is the request type for the Query/ContractsByCode +// RPC method +type QueryContractsByCodeRequest struct { + CodeId uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryContractsByCodeRequest) Reset() { *m = QueryContractsByCodeRequest{} } +func (m *QueryContractsByCodeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryContractsByCodeRequest) ProtoMessage() {} +func (*QueryContractsByCodeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{4} +} +func (m *QueryContractsByCodeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractsByCodeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractsByCodeRequest.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 *QueryContractsByCodeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractsByCodeRequest.Merge(m, src) +} +func (m *QueryContractsByCodeRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryContractsByCodeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractsByCodeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractsByCodeRequest proto.InternalMessageInfo + +// QueryContractsByCodeResponse is the response type for the +// Query/ContractsByCode RPC method +type QueryContractsByCodeResponse struct { + // contracts are a set of contract addresses + Contracts []string `protobuf:"bytes,1,rep,name=contracts,proto3" json:"contracts,omitempty"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryContractsByCodeResponse) Reset() { *m = QueryContractsByCodeResponse{} } +func (m *QueryContractsByCodeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryContractsByCodeResponse) ProtoMessage() {} +func (*QueryContractsByCodeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{5} +} +func (m *QueryContractsByCodeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractsByCodeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractsByCodeResponse.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 *QueryContractsByCodeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractsByCodeResponse.Merge(m, src) +} +func (m *QueryContractsByCodeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryContractsByCodeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractsByCodeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractsByCodeResponse proto.InternalMessageInfo + +// QueryAllContractStateRequest is the request type for the +// Query/AllContractState RPC method +type QueryAllContractStateRequest struct { + // address is the address of the contract + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllContractStateRequest) Reset() { *m = QueryAllContractStateRequest{} } +func (m *QueryAllContractStateRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAllContractStateRequest) ProtoMessage() {} +func (*QueryAllContractStateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{6} +} +func (m *QueryAllContractStateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllContractStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllContractStateRequest.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 *QueryAllContractStateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllContractStateRequest.Merge(m, src) +} +func (m *QueryAllContractStateRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAllContractStateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllContractStateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllContractStateRequest proto.InternalMessageInfo + +// QueryAllContractStateResponse is the response type for the +// Query/AllContractState RPC method +type QueryAllContractStateResponse struct { + Models []Model `protobuf:"bytes,1,rep,name=models,proto3" json:"models"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAllContractStateResponse) Reset() { *m = QueryAllContractStateResponse{} } +func (m *QueryAllContractStateResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllContractStateResponse) ProtoMessage() {} +func (*QueryAllContractStateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{7} +} +func (m *QueryAllContractStateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllContractStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllContractStateResponse.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 *QueryAllContractStateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllContractStateResponse.Merge(m, src) +} +func (m *QueryAllContractStateResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllContractStateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllContractStateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllContractStateResponse proto.InternalMessageInfo + +// QueryRawContractStateRequest is the request type for the +// Query/RawContractState RPC method +type QueryRawContractStateRequest struct { + // address is the address of the contract + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + QueryData []byte `protobuf:"bytes,2,opt,name=query_data,json=queryData,proto3" json:"query_data,omitempty"` +} + +func (m *QueryRawContractStateRequest) Reset() { *m = QueryRawContractStateRequest{} } +func (m *QueryRawContractStateRequest) String() string { return proto.CompactTextString(m) } +func (*QueryRawContractStateRequest) ProtoMessage() {} +func (*QueryRawContractStateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{8} +} +func (m *QueryRawContractStateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRawContractStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRawContractStateRequest.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 *QueryRawContractStateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRawContractStateRequest.Merge(m, src) +} +func (m *QueryRawContractStateRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryRawContractStateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRawContractStateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRawContractStateRequest proto.InternalMessageInfo + +// QueryRawContractStateResponse is the response type for the +// Query/RawContractState RPC method +type QueryRawContractStateResponse struct { + // Data contains the raw store data + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *QueryRawContractStateResponse) Reset() { *m = QueryRawContractStateResponse{} } +func (m *QueryRawContractStateResponse) String() string { return proto.CompactTextString(m) } +func (*QueryRawContractStateResponse) ProtoMessage() {} +func (*QueryRawContractStateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{9} +} +func (m *QueryRawContractStateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryRawContractStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryRawContractStateResponse.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 *QueryRawContractStateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryRawContractStateResponse.Merge(m, src) +} +func (m *QueryRawContractStateResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryRawContractStateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryRawContractStateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryRawContractStateResponse proto.InternalMessageInfo + +// QuerySmartContractStateRequest is the request type for the +// Query/SmartContractState RPC method +type QuerySmartContractStateRequest struct { + // address is the address of the contract + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // QueryData contains the query data passed to the contract + QueryData RawContractMessage `protobuf:"bytes,2,opt,name=query_data,json=queryData,proto3,casttype=RawContractMessage" json:"query_data,omitempty"` +} + +func (m *QuerySmartContractStateRequest) Reset() { *m = QuerySmartContractStateRequest{} } +func (m *QuerySmartContractStateRequest) String() string { return proto.CompactTextString(m) } +func (*QuerySmartContractStateRequest) ProtoMessage() {} +func (*QuerySmartContractStateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{10} +} +func (m *QuerySmartContractStateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySmartContractStateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySmartContractStateRequest.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 *QuerySmartContractStateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySmartContractStateRequest.Merge(m, src) +} +func (m *QuerySmartContractStateRequest) XXX_Size() int { + return m.Size() +} +func (m *QuerySmartContractStateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySmartContractStateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySmartContractStateRequest proto.InternalMessageInfo + +// QuerySmartContractStateResponse is the response type for the +// Query/SmartContractState RPC method +type QuerySmartContractStateResponse struct { + // Data contains the json data returned from the smart contract + Data RawContractMessage `protobuf:"bytes,1,opt,name=data,proto3,casttype=RawContractMessage" json:"data,omitempty"` +} + +func (m *QuerySmartContractStateResponse) Reset() { *m = QuerySmartContractStateResponse{} } +func (m *QuerySmartContractStateResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySmartContractStateResponse) ProtoMessage() {} +func (*QuerySmartContractStateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{11} +} +func (m *QuerySmartContractStateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySmartContractStateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySmartContractStateResponse.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 *QuerySmartContractStateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySmartContractStateResponse.Merge(m, src) +} +func (m *QuerySmartContractStateResponse) XXX_Size() int { + return m.Size() +} +func (m *QuerySmartContractStateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySmartContractStateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySmartContractStateResponse proto.InternalMessageInfo + +// QueryCodeRequest is the request type for the Query/Code RPC method +type QueryCodeRequest struct { + CodeId uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` +} + +func (m *QueryCodeRequest) Reset() { *m = QueryCodeRequest{} } +func (m *QueryCodeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryCodeRequest) ProtoMessage() {} +func (*QueryCodeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{12} +} +func (m *QueryCodeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCodeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCodeRequest.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 *QueryCodeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCodeRequest.Merge(m, src) +} +func (m *QueryCodeRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryCodeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCodeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCodeRequest proto.InternalMessageInfo + +// CodeInfoResponse contains code meta data from CodeInfo +type CodeInfoResponse struct { + CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"id"` + Creator string `protobuf:"bytes,2,opt,name=creator,proto3" json:"creator,omitempty"` + DataHash github_com_tendermint_tendermint_libs_bytes.HexBytes `protobuf:"bytes,3,opt,name=data_hash,json=dataHash,proto3,casttype=github.com/tendermint/tendermint/libs/bytes.HexBytes" json:"data_hash,omitempty"` + InstantiatePermission AccessConfig `protobuf:"bytes,6,opt,name=instantiate_permission,json=instantiatePermission,proto3" json:"instantiate_permission"` +} + +func (m *CodeInfoResponse) Reset() { *m = CodeInfoResponse{} } +func (m *CodeInfoResponse) String() string { return proto.CompactTextString(m) } +func (*CodeInfoResponse) ProtoMessage() {} +func (*CodeInfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{13} +} +func (m *CodeInfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CodeInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CodeInfoResponse.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 *CodeInfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_CodeInfoResponse.Merge(m, src) +} +func (m *CodeInfoResponse) XXX_Size() int { + return m.Size() +} +func (m *CodeInfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_CodeInfoResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_CodeInfoResponse proto.InternalMessageInfo + +// QueryCodeResponse is the response type for the Query/Code RPC method +type QueryCodeResponse struct { + *CodeInfoResponse `protobuf:"bytes,1,opt,name=code_info,json=codeInfo,proto3,embedded=code_info" json:""` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data"` +} + +func (m *QueryCodeResponse) Reset() { *m = QueryCodeResponse{} } +func (m *QueryCodeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryCodeResponse) ProtoMessage() {} +func (*QueryCodeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{14} +} +func (m *QueryCodeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCodeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCodeResponse.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 *QueryCodeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCodeResponse.Merge(m, src) +} +func (m *QueryCodeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryCodeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCodeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCodeResponse proto.InternalMessageInfo + +// QueryCodesRequest is the request type for the Query/Codes RPC method +type QueryCodesRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryCodesRequest) Reset() { *m = QueryCodesRequest{} } +func (m *QueryCodesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryCodesRequest) ProtoMessage() {} +func (*QueryCodesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{15} +} +func (m *QueryCodesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCodesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCodesRequest.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 *QueryCodesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCodesRequest.Merge(m, src) +} +func (m *QueryCodesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryCodesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCodesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCodesRequest proto.InternalMessageInfo + +// QueryCodesResponse is the response type for the Query/Codes RPC method +type QueryCodesResponse struct { + CodeInfos []CodeInfoResponse `protobuf:"bytes,1,rep,name=code_infos,json=codeInfos,proto3" json:"code_infos"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryCodesResponse) Reset() { *m = QueryCodesResponse{} } +func (m *QueryCodesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryCodesResponse) ProtoMessage() {} +func (*QueryCodesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{16} +} +func (m *QueryCodesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryCodesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryCodesResponse.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 *QueryCodesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryCodesResponse.Merge(m, src) +} +func (m *QueryCodesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryCodesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryCodesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryCodesResponse proto.InternalMessageInfo + +// QueryPinnedCodesRequest is the request type for the Query/PinnedCodes +// RPC method +type QueryPinnedCodesRequest struct { + // pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPinnedCodesRequest) Reset() { *m = QueryPinnedCodesRequest{} } +func (m *QueryPinnedCodesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPinnedCodesRequest) ProtoMessage() {} +func (*QueryPinnedCodesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{17} +} +func (m *QueryPinnedCodesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPinnedCodesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPinnedCodesRequest.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 *QueryPinnedCodesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPinnedCodesRequest.Merge(m, src) +} +func (m *QueryPinnedCodesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryPinnedCodesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPinnedCodesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPinnedCodesRequest proto.InternalMessageInfo + +// QueryPinnedCodesResponse is the response type for the +// Query/PinnedCodes RPC method +type QueryPinnedCodesResponse struct { + CodeIDs []uint64 `protobuf:"varint,1,rep,packed,name=code_ids,json=codeIds,proto3" json:"code_ids,omitempty"` + // pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryPinnedCodesResponse) Reset() { *m = QueryPinnedCodesResponse{} } +func (m *QueryPinnedCodesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPinnedCodesResponse) ProtoMessage() {} +func (*QueryPinnedCodesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{18} +} +func (m *QueryPinnedCodesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryPinnedCodesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryPinnedCodesResponse.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 *QueryPinnedCodesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPinnedCodesResponse.Merge(m, src) +} +func (m *QueryPinnedCodesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryPinnedCodesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPinnedCodesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryPinnedCodesResponse proto.InternalMessageInfo + +// QueryParamsRequest is the request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{19} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is the response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params defines the parameters of the module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{20} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +// QueryContractsByCreatorRequest is the request type for the +// Query/ContractsByCreator RPC method. +type QueryContractsByCreatorRequest struct { + // CreatorAddress is the address of contract creator + CreatorAddress string `protobuf:"bytes,1,opt,name=creator_address,json=creatorAddress,proto3" json:"creator_address,omitempty"` + // Pagination defines an optional pagination for the request. + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryContractsByCreatorRequest) Reset() { *m = QueryContractsByCreatorRequest{} } +func (m *QueryContractsByCreatorRequest) String() string { return proto.CompactTextString(m) } +func (*QueryContractsByCreatorRequest) ProtoMessage() {} +func (*QueryContractsByCreatorRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{21} +} +func (m *QueryContractsByCreatorRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractsByCreatorRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractsByCreatorRequest.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 *QueryContractsByCreatorRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractsByCreatorRequest.Merge(m, src) +} +func (m *QueryContractsByCreatorRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryContractsByCreatorRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractsByCreatorRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractsByCreatorRequest proto.InternalMessageInfo + +// QueryContractsByCreatorResponse is the response type for the +// Query/ContractsByCreator RPC method. +type QueryContractsByCreatorResponse struct { + // ContractAddresses result set + ContractAddresses []string `protobuf:"bytes,1,rep,name=contract_addresses,json=contractAddresses,proto3" json:"contract_addresses,omitempty"` + // Pagination defines the pagination in the response. + Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryContractsByCreatorResponse) Reset() { *m = QueryContractsByCreatorResponse{} } +func (m *QueryContractsByCreatorResponse) String() string { return proto.CompactTextString(m) } +func (*QueryContractsByCreatorResponse) ProtoMessage() {} +func (*QueryContractsByCreatorResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6c2ba325d04e1903, []int{22} +} +func (m *QueryContractsByCreatorResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryContractsByCreatorResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryContractsByCreatorResponse.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 *QueryContractsByCreatorResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryContractsByCreatorResponse.Merge(m, src) +} +func (m *QueryContractsByCreatorResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryContractsByCreatorResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryContractsByCreatorResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryContractsByCreatorResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*QueryContractInfoRequest)(nil), "cosmwasm.wasm.v1.QueryContractInfoRequest") + proto.RegisterType((*QueryContractInfoResponse)(nil), "cosmwasm.wasm.v1.QueryContractInfoResponse") + proto.RegisterType((*QueryContractHistoryRequest)(nil), "cosmwasm.wasm.v1.QueryContractHistoryRequest") + proto.RegisterType((*QueryContractHistoryResponse)(nil), "cosmwasm.wasm.v1.QueryContractHistoryResponse") + proto.RegisterType((*QueryContractsByCodeRequest)(nil), "cosmwasm.wasm.v1.QueryContractsByCodeRequest") + proto.RegisterType((*QueryContractsByCodeResponse)(nil), "cosmwasm.wasm.v1.QueryContractsByCodeResponse") + proto.RegisterType((*QueryAllContractStateRequest)(nil), "cosmwasm.wasm.v1.QueryAllContractStateRequest") + proto.RegisterType((*QueryAllContractStateResponse)(nil), "cosmwasm.wasm.v1.QueryAllContractStateResponse") + proto.RegisterType((*QueryRawContractStateRequest)(nil), "cosmwasm.wasm.v1.QueryRawContractStateRequest") + proto.RegisterType((*QueryRawContractStateResponse)(nil), "cosmwasm.wasm.v1.QueryRawContractStateResponse") + proto.RegisterType((*QuerySmartContractStateRequest)(nil), "cosmwasm.wasm.v1.QuerySmartContractStateRequest") + proto.RegisterType((*QuerySmartContractStateResponse)(nil), "cosmwasm.wasm.v1.QuerySmartContractStateResponse") + proto.RegisterType((*QueryCodeRequest)(nil), "cosmwasm.wasm.v1.QueryCodeRequest") + proto.RegisterType((*CodeInfoResponse)(nil), "cosmwasm.wasm.v1.CodeInfoResponse") + proto.RegisterType((*QueryCodeResponse)(nil), "cosmwasm.wasm.v1.QueryCodeResponse") + proto.RegisterType((*QueryCodesRequest)(nil), "cosmwasm.wasm.v1.QueryCodesRequest") + proto.RegisterType((*QueryCodesResponse)(nil), "cosmwasm.wasm.v1.QueryCodesResponse") + proto.RegisterType((*QueryPinnedCodesRequest)(nil), "cosmwasm.wasm.v1.QueryPinnedCodesRequest") + proto.RegisterType((*QueryPinnedCodesResponse)(nil), "cosmwasm.wasm.v1.QueryPinnedCodesResponse") + proto.RegisterType((*QueryParamsRequest)(nil), "cosmwasm.wasm.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "cosmwasm.wasm.v1.QueryParamsResponse") + proto.RegisterType((*QueryContractsByCreatorRequest)(nil), "cosmwasm.wasm.v1.QueryContractsByCreatorRequest") + proto.RegisterType((*QueryContractsByCreatorResponse)(nil), "cosmwasm.wasm.v1.QueryContractsByCreatorResponse") +} + +func init() { proto.RegisterFile("wasm/v1/query.proto", fileDescriptor_6c2ba325d04e1903) } + +var fileDescriptor_6c2ba325d04e1903 = []byte{ + // 1339 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x98, 0xcd, 0x6f, 0x1b, 0xc5, + 0x1b, 0xc7, 0x3d, 0xa9, 0xe3, 0x97, 0x69, 0xfa, 0xab, 0x3b, 0xed, 0x2f, 0x31, 0x26, 0x5d, 0x47, + 0x4b, 0x49, 0xd3, 0x34, 0xd9, 0x25, 0x69, 0x42, 0x01, 0x09, 0xa1, 0x38, 0x85, 0x26, 0x91, 0x22, + 0xa5, 0x5b, 0x21, 0x24, 0x7a, 0xb0, 0xc6, 0xbb, 0x13, 0x67, 0x25, 0x7b, 0xd7, 0xd9, 0x99, 0x24, + 0xb5, 0xa2, 0x00, 0xaa, 0xc4, 0x0d, 0xf1, 0x22, 0xc4, 0x81, 0x03, 0x82, 0x03, 0x2a, 0x9c, 0xe1, + 0x82, 0xb8, 0x72, 0xc9, 0x31, 0x12, 0x17, 0x4e, 0x16, 0x38, 0x1c, 0x50, 0xfe, 0x84, 0x9e, 0xd0, + 0xce, 0xce, 0x3a, 0xbb, 0xb6, 0x37, 0x76, 0x2a, 0x8b, 0x8b, 0xb5, 0xbb, 0xf3, 0xcc, 0x3c, 0x9f, + 0xe7, 0x3b, 0xcf, 0xcc, 0xf3, 0xc8, 0xf0, 0xea, 0x1e, 0xa6, 0x55, 0x75, 0x77, 0x4e, 0xdd, 0xde, + 0x21, 0x4e, 0x5d, 0xa9, 0x39, 0x36, 0xb3, 0x51, 0x46, 0xb7, 0x69, 0xd5, 0x1d, 0x50, 0xf8, 0xcf, + 0xee, 0x5c, 0xee, 0x5a, 0xd9, 0x2e, 0xdb, 0x7c, 0x50, 0x75, 0x9f, 0x3c, 0xbb, 0x5c, 0x6b, 0x32, + 0xab, 0xd7, 0x08, 0x15, 0x1f, 0xc7, 0xcb, 0xb6, 0x5d, 0xae, 0x10, 0x15, 0xd7, 0x4c, 0x15, 0x5b, + 0x96, 0xcd, 0x30, 0x33, 0x6d, 0xcb, 0x1f, 0x9d, 0x76, 0x97, 0xb6, 0xa9, 0x5a, 0xc2, 0x94, 0x78, + 0x3e, 0xd5, 0xdd, 0xb9, 0x12, 0x61, 0x78, 0x4e, 0xad, 0xe1, 0xb2, 0x69, 0x71, 0x63, 0xcf, 0x56, + 0x5e, 0x80, 0xd9, 0x07, 0xae, 0xc5, 0xb2, 0x6d, 0x31, 0x07, 0xeb, 0x6c, 0xd5, 0xda, 0xb4, 0x35, + 0xb2, 0xbd, 0x43, 0x28, 0x43, 0x59, 0x98, 0xc4, 0x86, 0xe1, 0x10, 0x4a, 0xb3, 0x60, 0x02, 0x4c, + 0xa5, 0x35, 0xff, 0x55, 0xfe, 0x14, 0xc0, 0x17, 0xba, 0x4c, 0xa3, 0x35, 0xdb, 0xa2, 0x24, 0x7a, + 0x1e, 0x7a, 0x00, 0x2f, 0xe9, 0x62, 0x46, 0xd1, 0xb4, 0x36, 0xed, 0xec, 0xd0, 0x04, 0x98, 0xba, + 0x38, 0x2f, 0x29, 0xed, 0x62, 0x28, 0xc1, 0x85, 0x0b, 0x23, 0x87, 0x8d, 0x7c, 0xec, 0xa8, 0x91, + 0x07, 0x27, 0x8d, 0x7c, 0x4c, 0x1b, 0xd1, 0x03, 0x63, 0x6f, 0xc4, 0xff, 0xf9, 0x2e, 0x0f, 0xe4, + 0x0f, 0xe1, 0x8b, 0x21, 0x9e, 0x15, 0x93, 0x32, 0xdb, 0xa9, 0xf7, 0x8c, 0x04, 0xbd, 0x03, 0xe1, + 0xa9, 0x26, 0x02, 0x67, 0x52, 0xf1, 0x04, 0x54, 0x5c, 0x01, 0x15, 0x6f, 0xd3, 0x84, 0x80, 0xca, + 0x06, 0x2e, 0x13, 0xb1, 0xaa, 0x16, 0x98, 0x29, 0xff, 0x0c, 0xe0, 0x78, 0x77, 0x02, 0x21, 0xca, + 0x1a, 0x4c, 0x12, 0x8b, 0x39, 0x26, 0x71, 0x11, 0x2e, 0x4c, 0x5d, 0x9c, 0x9f, 0x8e, 0x0e, 0x7a, + 0xd9, 0x36, 0x88, 0x98, 0xff, 0xb6, 0xc5, 0x9c, 0x7a, 0x21, 0xee, 0x0a, 0xa0, 0xf9, 0x0b, 0xa0, + 0xfb, 0x5d, 0xa0, 0x6f, 0xf6, 0x84, 0xf6, 0x40, 0x42, 0xd4, 0x1f, 0xb4, 0xc9, 0x46, 0x0b, 0x75, + 0xd7, 0xb7, 0x2f, 0xdb, 0x18, 0x4c, 0xea, 0xb6, 0x41, 0x8a, 0xa6, 0xc1, 0x65, 0x8b, 0x6b, 0x09, + 0xf7, 0x75, 0xd5, 0x18, 0x98, 0x6a, 0x1f, 0xb7, 0xab, 0xd6, 0x02, 0x10, 0xaa, 0x8d, 0xc3, 0xb4, + 0xbf, 0xdb, 0x9e, 0x6e, 0x69, 0xed, 0xf4, 0xc3, 0xe0, 0x74, 0xf8, 0xc8, 0xe7, 0x58, 0xaa, 0x54, + 0x7c, 0x94, 0x87, 0x0c, 0x33, 0xf2, 0xdf, 0x25, 0xd0, 0xb7, 0x00, 0x5e, 0x8f, 0x40, 0x10, 0x5a, + 0x2c, 0xc2, 0x44, 0xd5, 0x36, 0x48, 0xc5, 0x4f, 0xa0, 0xb1, 0xce, 0x04, 0x5a, 0x77, 0xc7, 0x45, + 0xb6, 0x08, 0xe3, 0xc1, 0x89, 0xf4, 0x9e, 0xd0, 0x48, 0xc3, 0x7b, 0xe7, 0xd4, 0xe8, 0x3a, 0x84, + 0xdc, 0x47, 0xd1, 0xc0, 0x0c, 0x73, 0x84, 0x11, 0x2d, 0xcd, 0xbf, 0xdc, 0xc3, 0x0c, 0xcb, 0x77, + 0x44, 0xe4, 0x9d, 0x0b, 0x8b, 0xc8, 0x11, 0x8c, 0xf3, 0x99, 0x80, 0xcf, 0xe4, 0xcf, 0xf2, 0x36, + 0x94, 0xf8, 0xa4, 0x87, 0x55, 0xec, 0xb0, 0x73, 0xf2, 0x2c, 0x76, 0xf2, 0x14, 0x46, 0x9f, 0x35, + 0xf2, 0x28, 0x40, 0xb0, 0x4e, 0x28, 0x75, 0x95, 0x08, 0x70, 0xae, 0xc3, 0x7c, 0xa4, 0x4b, 0x41, + 0x3a, 0x1d, 0x24, 0x8d, 0x5c, 0xd3, 0x8b, 0xe0, 0x36, 0xcc, 0x88, 0xdc, 0xef, 0x7d, 0xe2, 0xe4, + 0x6f, 0x86, 0x60, 0xc6, 0x35, 0x0c, 0x5d, 0xb4, 0xb7, 0xda, 0xac, 0x0b, 0x99, 0x66, 0x23, 0x9f, + 0xe0, 0x66, 0xf7, 0x4e, 0x1a, 0xf9, 0x21, 0xd3, 0x68, 0x9d, 0xd8, 0x2c, 0x4c, 0xea, 0x0e, 0xc1, + 0xcc, 0x76, 0x78, 0xbc, 0x69, 0xcd, 0x7f, 0x45, 0xef, 0xc2, 0xb4, 0x8b, 0x53, 0xdc, 0xc2, 0x74, + 0x2b, 0x7b, 0x81, 0x73, 0xbf, 0xf6, 0xac, 0x91, 0x5f, 0x28, 0x9b, 0x6c, 0x6b, 0xa7, 0xa4, 0xe8, + 0x76, 0x55, 0x65, 0xc4, 0x32, 0x88, 0x53, 0x35, 0x2d, 0x16, 0x7c, 0xac, 0x98, 0x25, 0xaa, 0x96, + 0xea, 0x8c, 0x50, 0x65, 0x85, 0x3c, 0x2e, 0xb8, 0x0f, 0x5a, 0xca, 0x5d, 0x6a, 0x05, 0xd3, 0x2d, + 0xf4, 0x08, 0x8e, 0x9a, 0x16, 0x65, 0xd8, 0x62, 0x26, 0x66, 0xa4, 0x58, 0x73, 0x27, 0x51, 0xea, + 0xa6, 0x60, 0x22, 0xea, 0xce, 0x5f, 0xd2, 0x75, 0x42, 0xe9, 0xb2, 0x6d, 0x6d, 0x9a, 0x65, 0x91, + 0xc4, 0xff, 0x0f, 0xac, 0xb1, 0xd1, 0x5a, 0xc2, 0xbb, 0xf4, 0xd7, 0xe2, 0xa9, 0x78, 0x66, 0x78, + 0x2d, 0x9e, 0x1a, 0xce, 0x24, 0xe4, 0x27, 0x00, 0x5e, 0x09, 0xa8, 0x29, 0x04, 0x5a, 0x75, 0xaf, + 0x0f, 0x57, 0x20, 0xb7, 0xd6, 0x00, 0xee, 0x57, 0xee, 0x76, 0xed, 0x86, 0x75, 0x2d, 0xa4, 0x5a, + 0xb5, 0x26, 0xa5, 0x8b, 0x31, 0x34, 0x2e, 0x76, 0xd6, 0xcb, 0x96, 0xd4, 0x49, 0x23, 0xcf, 0xdf, + 0xbd, 0xbd, 0x14, 0x55, 0xe8, 0x51, 0x80, 0x81, 0xfa, 0x5b, 0x1a, 0xbe, 0x20, 0xc0, 0x73, 0x5f, + 0x10, 0x4f, 0x01, 0x44, 0xc1, 0xd5, 0x45, 0x88, 0xf7, 0x21, 0x6c, 0x85, 0xe8, 0xdf, 0x0c, 0xfd, + 0xc4, 0xe8, 0xe9, 0x9b, 0xf6, 0xe3, 0x1b, 0xe0, 0x3d, 0x81, 0xe1, 0x18, 0xe7, 0xdc, 0x30, 0x2d, + 0x8b, 0x18, 0x67, 0x68, 0xf1, 0xfc, 0x97, 0xe5, 0x67, 0x40, 0xb4, 0x2d, 0x21, 0x1f, 0xad, 0x33, + 0x98, 0x12, 0xa7, 0xc2, 0xd3, 0x23, 0x5e, 0xb8, 0xec, 0xc6, 0xda, 0x6c, 0xe4, 0x93, 0xde, 0xd1, + 0xa0, 0x5a, 0xd2, 0x3b, 0x15, 0x03, 0x0c, 0xfa, 0x9a, 0xd8, 0x9c, 0x0d, 0xec, 0xe0, 0xaa, 0x1f, + 0xaf, 0xbc, 0x0e, 0xaf, 0x86, 0xbe, 0x0a, 0xc2, 0x57, 0x61, 0xa2, 0xc6, 0xbf, 0x88, 0x74, 0xc8, + 0x76, 0xee, 0x97, 0x37, 0xc3, 0xbf, 0xca, 0x3d, 0x6b, 0xf9, 0x0b, 0x20, 0x2e, 0xbd, 0x60, 0xb9, + 0xf4, 0x8e, 0xb1, 0xaf, 0xf0, 0x4d, 0x78, 0x59, 0x1c, 0xec, 0x62, 0xf8, 0xf2, 0xfb, 0x9f, 0xf8, + 0xbc, 0x34, 0xe0, 0xba, 0xf5, 0x35, 0x10, 0xb7, 0x62, 0x37, 0x26, 0x11, 0xef, 0x2c, 0x44, 0xad, + 0xb6, 0x4f, 0x50, 0x11, 0xbf, 0x9c, 0x5f, 0xf1, 0x47, 0x96, 0xfc, 0x81, 0x81, 0x6d, 0xca, 0xfc, + 0x6f, 0x97, 0xe0, 0x30, 0x67, 0x43, 0x5f, 0x01, 0x38, 0x12, 0x6c, 0x29, 0x51, 0x97, 0xee, 0x2b, + 0xaa, 0x0f, 0xce, 0xdd, 0xee, 0xcb, 0xd6, 0xf3, 0x2f, 0xcf, 0x3c, 0xf9, 0xfd, 0xef, 0x2f, 0x87, + 0x26, 0xd1, 0x0d, 0xd5, 0x9f, 0xa4, 0xfa, 0x1d, 0xbc, 0x1f, 0xa9, 0xba, 0x2f, 0x44, 0x38, 0x40, + 0x4f, 0x01, 0xbc, 0xdc, 0xd6, 0x31, 0xa2, 0xd9, 0x1e, 0xee, 0xc2, 0xbd, 0x6d, 0x4e, 0xe9, 0xd7, + 0x5c, 0x00, 0x2e, 0x70, 0x40, 0x05, 0xcd, 0xf4, 0x03, 0xa8, 0x6e, 0x09, 0xa8, 0xef, 0x03, 0xa0, + 0xa2, 0x49, 0xeb, 0x09, 0x1a, 0xee, 0x26, 0x7b, 0x82, 0xb6, 0xf5, 0x7e, 0xf2, 0x3c, 0x07, 0x9d, + 0x41, 0xd3, 0xdd, 0x40, 0x0d, 0xa2, 0xee, 0x8b, 0x53, 0x7e, 0xa0, 0x9e, 0x76, 0x84, 0x3f, 0x00, + 0x98, 0x69, 0x6f, 0xa0, 0x50, 0x94, 0xe3, 0x88, 0x66, 0x2f, 0xa7, 0xf6, 0x6d, 0xdf, 0x0f, 0x69, + 0x87, 0xa4, 0x94, 0x43, 0xfd, 0x04, 0x60, 0xa6, 0xbd, 0xe1, 0x89, 0x24, 0x8d, 0x68, 0xb9, 0x22, + 0x49, 0xa3, 0x3a, 0x29, 0xf9, 0x4d, 0x4e, 0x7a, 0x17, 0x2d, 0xf6, 0x45, 0xea, 0xe0, 0x3d, 0x75, + 0xff, 0xb4, 0x53, 0x3a, 0x40, 0xbf, 0x02, 0x88, 0x3a, 0xbb, 0x1f, 0xf4, 0x4a, 0x04, 0x46, 0x64, + 0x6f, 0x96, 0x9b, 0x3b, 0xc7, 0x0c, 0x81, 0xfe, 0x16, 0x47, 0x7f, 0x1d, 0xdd, 0xed, 0x4f, 0x64, + 0x77, 0xa1, 0x30, 0x7c, 0x1d, 0xc6, 0x79, 0xda, 0xca, 0x91, 0x79, 0x78, 0x9a, 0xab, 0x2f, 0x9d, + 0x69, 0x23, 0x88, 0xa6, 0x38, 0x91, 0x8c, 0x26, 0x7a, 0x25, 0x28, 0x72, 0xe0, 0x30, 0xaf, 0x51, + 0xe8, 0xac, 0x75, 0xfd, 0xaa, 0x91, 0xbb, 0x71, 0xb6, 0x91, 0xf0, 0x2e, 0x71, 0xef, 0x59, 0x34, + 0xda, 0xdd, 0x3b, 0xfa, 0x04, 0xc0, 0x8b, 0x81, 0xf2, 0x88, 0x6e, 0x45, 0xac, 0xda, 0x59, 0xa6, + 0x73, 0xd3, 0xfd, 0x98, 0x0a, 0x8c, 0x49, 0x8e, 0x31, 0x81, 0xa4, 0xee, 0x18, 0x54, 0xad, 0xf1, + 0x49, 0xe8, 0x00, 0x26, 0xbc, 0x9a, 0x86, 0xa2, 0xc2, 0x0b, 0x95, 0xce, 0xdc, 0xcb, 0x3d, 0xac, + 0xfa, 0x76, 0xef, 0x39, 0xfd, 0x05, 0x40, 0xd4, 0x59, 0xa1, 0x22, 0x33, 0x37, 0xb2, 0xc0, 0x46, + 0x66, 0x6e, 0x74, 0xf9, 0xeb, 0xe7, 0xd0, 0x51, 0x55, 0x94, 0x67, 0x75, 0xbf, 0xad, 0x7c, 0x1f, + 0x14, 0xd6, 0x0e, 0xff, 0x92, 0x62, 0x3f, 0x36, 0xa5, 0xd8, 0x61, 0x53, 0x02, 0x47, 0x4d, 0x09, + 0xfc, 0xd9, 0x94, 0xc0, 0xe7, 0xc7, 0x52, 0xec, 0xe8, 0x58, 0x8a, 0xfd, 0x71, 0x2c, 0xc5, 0xde, + 0x9f, 0x0a, 0xf4, 0xea, 0x3a, 0x71, 0xf4, 0x59, 0xd3, 0x56, 0x2b, 0x58, 0xb7, 0x2d, 0x53, 0x37, + 0xd4, 0xc7, 0x9e, 0x33, 0xfe, 0xf7, 0x51, 0x29, 0xc1, 0xff, 0xf5, 0xb9, 0xf3, 0x6f, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x1e, 0x58, 0xe1, 0x26, 0x93, 0x12, 0x00, 0x00, +} + +func (this *QueryContractInfoResponse) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*QueryContractInfoResponse) + if !ok { + that2, ok := that.(QueryContractInfoResponse) + 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.ContractInfo.Equal(&that1.ContractInfo) { + return false + } + return true +} +func (this *CodeInfoResponse) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*CodeInfoResponse) + if !ok { + that2, ok := that.(CodeInfoResponse) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if this.Creator != that1.Creator { + return false + } + if !bytes.Equal(this.DataHash, that1.DataHash) { + return false + } + if !this.InstantiatePermission.Equal(&that1.InstantiatePermission) { + return false + } + return true +} +func (this *QueryCodeResponse) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*QueryCodeResponse) + if !ok { + that2, ok := that.(QueryCodeResponse) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.CodeInfoResponse.Equal(that1.CodeInfoResponse) { + return false + } + if !bytes.Equal(this.Data, that1.Data) { + 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 + +// 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 { + // ContractInfo gets the contract meta data + ContractInfo(ctx context.Context, in *QueryContractInfoRequest, opts ...grpc.CallOption) (*QueryContractInfoResponse, error) + // ContractHistory gets the contract code history + ContractHistory(ctx context.Context, in *QueryContractHistoryRequest, opts ...grpc.CallOption) (*QueryContractHistoryResponse, error) + // ContractsByCode lists all smart contracts for a code id + ContractsByCode(ctx context.Context, in *QueryContractsByCodeRequest, opts ...grpc.CallOption) (*QueryContractsByCodeResponse, error) + // AllContractState gets all raw store data for a single contract + AllContractState(ctx context.Context, in *QueryAllContractStateRequest, opts ...grpc.CallOption) (*QueryAllContractStateResponse, error) + // RawContractState gets single key from the raw store data of a contract + RawContractState(ctx context.Context, in *QueryRawContractStateRequest, opts ...grpc.CallOption) (*QueryRawContractStateResponse, error) + // SmartContractState get smart query result from the contract + SmartContractState(ctx context.Context, in *QuerySmartContractStateRequest, opts ...grpc.CallOption) (*QuerySmartContractStateResponse, error) + // Code gets the binary code and metadata for a singe wasm code + Code(ctx context.Context, in *QueryCodeRequest, opts ...grpc.CallOption) (*QueryCodeResponse, error) + // Codes gets the metadata for all stored wasm codes + Codes(ctx context.Context, in *QueryCodesRequest, opts ...grpc.CallOption) (*QueryCodesResponse, error) + // PinnedCodes gets the pinned code ids + PinnedCodes(ctx context.Context, in *QueryPinnedCodesRequest, opts ...grpc.CallOption) (*QueryPinnedCodesResponse, error) + // Params gets the module params + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // ContractsByCreator gets the contracts by creator + ContractsByCreator(ctx context.Context, in *QueryContractsByCreatorRequest, opts ...grpc.CallOption) (*QueryContractsByCreatorResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) ContractInfo(ctx context.Context, in *QueryContractInfoRequest, opts ...grpc.CallOption) (*QueryContractInfoResponse, error) { + out := new(QueryContractInfoResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/ContractInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ContractHistory(ctx context.Context, in *QueryContractHistoryRequest, opts ...grpc.CallOption) (*QueryContractHistoryResponse, error) { + out := new(QueryContractHistoryResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/ContractHistory", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ContractsByCode(ctx context.Context, in *QueryContractsByCodeRequest, opts ...grpc.CallOption) (*QueryContractsByCodeResponse, error) { + out := new(QueryContractsByCodeResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/ContractsByCode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AllContractState(ctx context.Context, in *QueryAllContractStateRequest, opts ...grpc.CallOption) (*QueryAllContractStateResponse, error) { + out := new(QueryAllContractStateResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/AllContractState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) RawContractState(ctx context.Context, in *QueryRawContractStateRequest, opts ...grpc.CallOption) (*QueryRawContractStateResponse, error) { + out := new(QueryRawContractStateResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/RawContractState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) SmartContractState(ctx context.Context, in *QuerySmartContractStateRequest, opts ...grpc.CallOption) (*QuerySmartContractStateResponse, error) { + out := new(QuerySmartContractStateResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/SmartContractState", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Code(ctx context.Context, in *QueryCodeRequest, opts ...grpc.CallOption) (*QueryCodeResponse, error) { + out := new(QueryCodeResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/Code", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Codes(ctx context.Context, in *QueryCodesRequest, opts ...grpc.CallOption) (*QueryCodesResponse, error) { + out := new(QueryCodesResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/Codes", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) PinnedCodes(ctx context.Context, in *QueryPinnedCodesRequest, opts ...grpc.CallOption) (*QueryPinnedCodesResponse, error) { + out := new(QueryPinnedCodesResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/PinnedCodes", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) ContractsByCreator(ctx context.Context, in *QueryContractsByCreatorRequest, opts ...grpc.CallOption) (*QueryContractsByCreatorResponse, error) { + out := new(QueryContractsByCreatorResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Query/ContractsByCreator", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // ContractInfo gets the contract meta data + ContractInfo(context.Context, *QueryContractInfoRequest) (*QueryContractInfoResponse, error) + // ContractHistory gets the contract code history + ContractHistory(context.Context, *QueryContractHistoryRequest) (*QueryContractHistoryResponse, error) + // ContractsByCode lists all smart contracts for a code id + ContractsByCode(context.Context, *QueryContractsByCodeRequest) (*QueryContractsByCodeResponse, error) + // AllContractState gets all raw store data for a single contract + AllContractState(context.Context, *QueryAllContractStateRequest) (*QueryAllContractStateResponse, error) + // RawContractState gets single key from the raw store data of a contract + RawContractState(context.Context, *QueryRawContractStateRequest) (*QueryRawContractStateResponse, error) + // SmartContractState get smart query result from the contract + SmartContractState(context.Context, *QuerySmartContractStateRequest) (*QuerySmartContractStateResponse, error) + // Code gets the binary code and metadata for a singe wasm code + Code(context.Context, *QueryCodeRequest) (*QueryCodeResponse, error) + // Codes gets the metadata for all stored wasm codes + Codes(context.Context, *QueryCodesRequest) (*QueryCodesResponse, error) + // PinnedCodes gets the pinned code ids + PinnedCodes(context.Context, *QueryPinnedCodesRequest) (*QueryPinnedCodesResponse, error) + // Params gets the module params + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // ContractsByCreator gets the contracts by creator + ContractsByCreator(context.Context, *QueryContractsByCreatorRequest) (*QueryContractsByCreatorResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) ContractInfo(ctx context.Context, req *QueryContractInfoRequest) (*QueryContractInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContractInfo not implemented") +} +func (*UnimplementedQueryServer) ContractHistory(ctx context.Context, req *QueryContractHistoryRequest) (*QueryContractHistoryResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContractHistory not implemented") +} +func (*UnimplementedQueryServer) ContractsByCode(ctx context.Context, req *QueryContractsByCodeRequest) (*QueryContractsByCodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContractsByCode not implemented") +} +func (*UnimplementedQueryServer) AllContractState(ctx context.Context, req *QueryAllContractStateRequest) (*QueryAllContractStateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllContractState not implemented") +} +func (*UnimplementedQueryServer) RawContractState(ctx context.Context, req *QueryRawContractStateRequest) (*QueryRawContractStateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RawContractState not implemented") +} +func (*UnimplementedQueryServer) SmartContractState(ctx context.Context, req *QuerySmartContractStateRequest) (*QuerySmartContractStateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SmartContractState not implemented") +} +func (*UnimplementedQueryServer) Code(ctx context.Context, req *QueryCodeRequest) (*QueryCodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Code not implemented") +} +func (*UnimplementedQueryServer) Codes(ctx context.Context, req *QueryCodesRequest) (*QueryCodesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Codes not implemented") +} +func (*UnimplementedQueryServer) PinnedCodes(ctx context.Context, req *QueryPinnedCodesRequest) (*QueryPinnedCodesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method PinnedCodes not implemented") +} +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} +func (*UnimplementedQueryServer) ContractsByCreator(ctx context.Context, req *QueryContractsByCreatorRequest) (*QueryContractsByCreatorResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ContractsByCreator not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_ContractInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryContractInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ContractInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/ContractInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ContractInfo(ctx, req.(*QueryContractInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ContractHistory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryContractHistoryRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ContractHistory(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/ContractHistory", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ContractHistory(ctx, req.(*QueryContractHistoryRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ContractsByCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryContractsByCodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ContractsByCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/ContractsByCode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ContractsByCode(ctx, req.(*QueryContractsByCodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AllContractState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllContractStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllContractState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/AllContractState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllContractState(ctx, req.(*QueryAllContractStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_RawContractState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryRawContractStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).RawContractState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/RawContractState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).RawContractState(ctx, req.(*QueryRawContractStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_SmartContractState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySmartContractStateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).SmartContractState(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/SmartContractState", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).SmartContractState(ctx, req.(*QuerySmartContractStateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Code_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryCodeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Code(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/Code", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Code(ctx, req.(*QueryCodeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Codes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryCodesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Codes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/Codes", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Codes(ctx, req.(*QueryCodesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_PinnedCodes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPinnedCodesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).PinnedCodes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/PinnedCodes", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).PinnedCodes(ctx, req.(*QueryPinnedCodesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_ContractsByCreator_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryContractsByCreatorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ContractsByCreator(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Query/ContractsByCreator", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ContractsByCreator(ctx, req.(*QueryContractsByCreatorRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cosmwasm.wasm.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ContractInfo", + Handler: _Query_ContractInfo_Handler, + }, + { + MethodName: "ContractHistory", + Handler: _Query_ContractHistory_Handler, + }, + { + MethodName: "ContractsByCode", + Handler: _Query_ContractsByCode_Handler, + }, + { + MethodName: "AllContractState", + Handler: _Query_AllContractState_Handler, + }, + { + MethodName: "RawContractState", + Handler: _Query_RawContractState_Handler, + }, + { + MethodName: "SmartContractState", + Handler: _Query_SmartContractState_Handler, + }, + { + MethodName: "Code", + Handler: _Query_Code_Handler, + }, + { + MethodName: "Codes", + Handler: _Query_Codes_Handler, + }, + { + MethodName: "PinnedCodes", + Handler: _Query_PinnedCodes_Handler, + }, + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + { + MethodName: "ContractsByCreator", + Handler: _Query_ContractsByCreator_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "wasm/v1/query.proto", +} + +func (m *QueryContractInfoRequest) 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 *QueryContractInfoRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractInfoRequest) 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 *QueryContractInfoResponse) 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 *QueryContractInfoResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.ContractInfo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + 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 *QueryContractHistoryRequest) 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 *QueryContractHistoryRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractHistoryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + 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 *QueryContractHistoryResponse) 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 *QueryContractHistoryResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractHistoryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Entries) > 0 { + for iNdEx := len(m.Entries) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Entries[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryContractsByCodeRequest) 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 *QueryContractsByCodeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractsByCodeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.CodeId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.CodeId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryContractsByCodeResponse) 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 *QueryContractsByCodeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractsByCodeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Contracts) > 0 { + for iNdEx := len(m.Contracts) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Contracts[iNdEx]) + copy(dAtA[i:], m.Contracts[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Contracts[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryAllContractStateRequest) 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 *QueryAllContractStateRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllContractStateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + 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 *QueryAllContractStateResponse) 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 *QueryAllContractStateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllContractStateResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.Models) > 0 { + for iNdEx := len(m.Models) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Models[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryRawContractStateRequest) 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 *QueryRawContractStateRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRawContractStateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.QueryData) > 0 { + i -= len(m.QueryData) + copy(dAtA[i:], m.QueryData) + i = encodeVarintQuery(dAtA, i, uint64(len(m.QueryData))) + i-- + dAtA[i] = 0x12 + } + 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 *QueryRawContractStateResponse) 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 *QueryRawContractStateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryRawContractStateResponse) 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 (m *QuerySmartContractStateRequest) 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 *QuerySmartContractStateRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySmartContractStateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.QueryData) > 0 { + i -= len(m.QueryData) + copy(dAtA[i:], m.QueryData) + i = encodeVarintQuery(dAtA, i, uint64(len(m.QueryData))) + i-- + dAtA[i] = 0x12 + } + 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 *QuerySmartContractStateResponse) 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 *QuerySmartContractStateResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySmartContractStateResponse) 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 (m *QueryCodeRequest) 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 *QueryCodeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCodeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CodeId != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.CodeId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *CodeInfoResponse) 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 *CodeInfoResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CodeInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.InstantiatePermission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.DataHash) > 0 { + i -= len(m.DataHash) + copy(dAtA[i:], m.DataHash) + i = encodeVarintQuery(dAtA, i, uint64(len(m.DataHash))) + i-- + dAtA[i] = 0x1a + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0x12 + } + if m.CodeID != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryCodeResponse) 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 *QueryCodeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCodeResponse) 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] = 0x12 + } + if m.CodeInfoResponse != nil { + { + size, err := m.CodeInfoResponse.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryCodesRequest) 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 *QueryCodesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCodesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryCodesResponse) 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 *QueryCodesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryCodesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.CodeInfos) > 0 { + for iNdEx := len(m.CodeInfos) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.CodeInfos[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QueryPinnedCodesRequest) 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 *QueryPinnedCodesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPinnedCodesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + return len(dAtA) - i, nil +} + +func (m *QueryPinnedCodesResponse) 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 *QueryPinnedCodesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryPinnedCodesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.CodeIDs) > 0 { + dAtA15 := make([]byte, len(m.CodeIDs)*10) + var j14 int + for _, num := range m.CodeIDs { + for num >= 1<<7 { + dAtA15[j14] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j14++ + } + dAtA15[j14] = uint8(num) + j14++ + } + i -= j14 + copy(dAtA[i:], dAtA15[:j14]) + i = encodeVarintQuery(dAtA, i, uint64(j14)) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryParamsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *QueryContractsByCreatorRequest) 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 *QueryContractsByCreatorRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractsByCreatorRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.CreatorAddress) > 0 { + i -= len(m.CreatorAddress) + copy(dAtA[i:], m.CreatorAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.CreatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryContractsByCreatorResponse) 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 *QueryContractsByCreatorResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryContractsByCreatorResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if len(m.ContractAddresses) > 0 { + for iNdEx := len(m.ContractAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ContractAddresses[iNdEx]) + copy(dAtA[i:], m.ContractAddresses[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ContractAddresses[iNdEx]))) + 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 *QueryContractInfoRequest) 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 *QueryContractInfoResponse) 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)) + } + l = m.ContractInfo.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryContractHistoryRequest) 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)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryContractHistoryResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Entries) > 0 { + for _, e := range m.Entries { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryContractsByCodeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeId != 0 { + n += 1 + sovQuery(uint64(m.CodeId)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryContractsByCodeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Contracts) > 0 { + for _, s := range m.Contracts { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllContractStateRequest) 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)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAllContractStateResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Models) > 0 { + for _, e := range m.Models { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRawContractStateRequest) 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)) + } + l = len(m.QueryData) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryRawContractStateResponse) 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 (m *QuerySmartContractStateRequest) 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)) + } + l = len(m.QueryData) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QuerySmartContractStateResponse) 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 (m *QueryCodeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeId != 0 { + n += 1 + sovQuery(uint64(m.CodeId)) + } + return n +} + +func (m *CodeInfoResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeID != 0 { + n += 1 + sovQuery(uint64(m.CodeID)) + } + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.DataHash) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = m.InstantiatePermission.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryCodeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeInfoResponse != nil { + l = m.CodeInfoResponse.Size() + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryCodesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryCodesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CodeInfos) > 0 { + for _, e := range m.CodeInfos { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPinnedCodesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryPinnedCodesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.CodeIDs) > 0 { + l = 0 + for _, e := range m.CodeIDs { + l += sovQuery(uint64(e)) + } + n += 1 + sovQuery(uint64(l)) + l + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryContractsByCreatorRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.CreatorAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryContractsByCreatorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.ContractAddresses) > 0 { + for _, s := range m.ContractAddresses { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryContractInfoRequest) 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: QueryContractInfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractInfoRequest: 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 *QueryContractInfoResponse) 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: QueryContractInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractInfoResponse: 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractInfo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ContractInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractHistoryRequest) 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: QueryContractHistoryRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractHistoryRequest: 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractHistoryResponse) 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: QueryContractHistoryResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractHistoryResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Entries", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Entries = append(m.Entries, ContractCodeHistoryEntry{}) + if err := m.Entries[len(m.Entries)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractsByCodeRequest) 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: QueryContractsByCodeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractsByCodeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeId", wireType) + } + m.CodeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractsByCodeResponse) 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: QueryContractsByCodeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractsByCodeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contracts", 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.Contracts = append(m.Contracts, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllContractStateRequest) 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: QueryAllContractStateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllContractStateRequest: 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllContractStateResponse) 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: QueryAllContractStateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllContractStateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Models", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Models = append(m.Models, Model{}) + if err := m.Models[len(m.Models)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryRawContractStateRequest) 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: QueryRawContractStateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRawContractStateRequest: 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryData", 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.QueryData = append(m.QueryData[:0], dAtA[iNdEx:postIndex]...) + if m.QueryData == nil { + m.QueryData = []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 *QueryRawContractStateResponse) 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: QueryRawContractStateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryRawContractStateResponse: 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 (m *QuerySmartContractStateRequest) 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: QuerySmartContractStateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySmartContractStateRequest: 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QueryData", 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.QueryData = append(m.QueryData[:0], dAtA[iNdEx:postIndex]...) + if m.QueryData == nil { + m.QueryData = []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 *QuerySmartContractStateResponse) 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: QuerySmartContractStateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySmartContractStateResponse: 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 (m *QueryCodeRequest) 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: QueryCodeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCodeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeId", wireType) + } + m.CodeId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CodeInfoResponse) 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: CodeInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CodeInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", 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.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DataHash", 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.DataHash = append(m.DataHash[:0], dAtA[iNdEx:postIndex]...) + if m.DataHash == nil { + m.DataHash = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiatePermission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryCodeResponse) 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: QueryCodeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCodeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeInfoResponse", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.CodeInfoResponse == nil { + m.CodeInfoResponse = &CodeInfoResponse{} + } + if err := m.CodeInfoResponse.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + 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 (m *QueryCodesRequest) 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: QueryCodesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCodesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryCodesResponse) 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: QueryCodesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryCodesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeInfos", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CodeInfos = append(m.CodeInfos, CodeInfoResponse{}) + if err := m.CodeInfos[len(m.CodeInfos)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPinnedCodesRequest) 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: QueryPinnedCodesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPinnedCodesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryPinnedCodesResponse) 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: QueryPinnedCodesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryPinnedCodesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.CodeIDs) == 0 { + m.CodeIDs = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field CodeIDs", wireType) + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractsByCreatorRequest) 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: QueryContractsByCreatorRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractsByCreatorRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatorAddress", 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.CreatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryContractsByCreatorResponse) 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: QueryContractsByCreatorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryContractsByCreatorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractAddresses", 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.ContractAddresses = append(m.ContractAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageResponse{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/wasm/types/query.pb.gw.go b/x/wasm/types/query.pb.gw.go new file mode 100644 index 00000000..a2423842 --- /dev/null +++ b/x/wasm/types/query.pb.gw.go @@ -0,0 +1,1243 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: wasm/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_ContractInfo_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractInfoRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := client.ContractInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ContractInfo_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractInfoRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + msg, err := server.ContractInfo(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_ContractHistory_0 = &utilities.DoubleArray{Encoding: map[string]int{"address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_ContractHistory_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractHistoryRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractHistory_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ContractHistory(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ContractHistory_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractHistoryRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractHistory_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ContractHistory(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_ContractsByCode_0 = &utilities.DoubleArray{Encoding: map[string]int{"code_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_ContractsByCode_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractsByCodeRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["code_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "code_id") + } + + protoReq.CodeId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "code_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractsByCode_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ContractsByCode(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ContractsByCode_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractsByCodeRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["code_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "code_id") + } + + protoReq.CodeId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "code_id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractsByCode_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ContractsByCode(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_AllContractState_0 = &utilities.DoubleArray{Encoding: map[string]int{"address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_AllContractState_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllContractStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AllContractState_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.AllContractState(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllContractState_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllContractStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AllContractState_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.AllContractState(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_RawContractState_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRawContractStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["query_data"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "query_data") + } + + protoReq.QueryData, err = runtime.Bytes(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "query_data", err) + } + + msg, err := client.RawContractState(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_RawContractState_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryRawContractStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["query_data"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "query_data") + } + + protoReq.QueryData, err = runtime.Bytes(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "query_data", err) + } + + msg, err := server.RawContractState(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_SmartContractState_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySmartContractStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["query_data"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "query_data") + } + + protoReq.QueryData, err = runtime.Bytes(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "query_data", err) + } + + msg, err := client.SmartContractState(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_SmartContractState_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySmartContractStateRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") + } + + protoReq.Address, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) + } + + val, ok = pathParams["query_data"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "query_data") + } + + protoReq.QueryData, err = runtime.Bytes(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "query_data", err) + } + + msg, err := server.SmartContractState(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_Code_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCodeRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["code_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "code_id") + } + + protoReq.CodeId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "code_id", err) + } + + msg, err := client.Code(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Code_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCodeRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["code_id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "code_id") + } + + protoReq.CodeId, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "code_id", err) + } + + msg, err := server.Code(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_Codes_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_Codes_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCodesRequest + 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_Codes_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Codes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Codes_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryCodesRequest + 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_Codes_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.Codes(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_PinnedCodes_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_PinnedCodes_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPinnedCodesRequest + 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_PinnedCodes_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.PinnedCodes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_PinnedCodes_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPinnedCodesRequest + 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_PinnedCodes_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.PinnedCodes(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_ContractsByCreator_0 = &utilities.DoubleArray{Encoding: map[string]int{"creator_address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_ContractsByCreator_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractsByCreatorRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["creator_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "creator_address") + } + + protoReq.CreatorAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator_address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractsByCreator_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ContractsByCreator(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ContractsByCreator_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryContractsByCreatorRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["creator_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "creator_address") + } + + protoReq.CreatorAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "creator_address", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_ContractsByCreator_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ContractsByCreator(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_ContractInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ContractInfo_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ContractInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractHistory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ContractHistory_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ContractHistory_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractsByCode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ContractsByCode_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ContractsByCode_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllContractState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllContractState_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllContractState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RawContractState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_RawContractState_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_RawContractState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SmartContractState_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_SmartContractState_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_SmartContractState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Code_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Code_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Code_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Codes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Codes_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Codes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PinnedCodes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_PinnedCodes_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_PinnedCodes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractsByCreator_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ContractsByCreator_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ContractsByCreator_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_ContractInfo_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_ContractInfo_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_ContractInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractHistory_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_ContractHistory_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_ContractHistory_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractsByCode_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_ContractsByCode_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_ContractsByCode_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AllContractState_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_AllContractState_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_AllContractState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_RawContractState_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_RawContractState_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_RawContractState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_SmartContractState_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_SmartContractState_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_SmartContractState_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Code_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_Code_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_Code_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Codes_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_Codes_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_Codes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_PinnedCodes_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_PinnedCodes_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_PinnedCodes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_ContractsByCreator_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_ContractsByCreator_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_ContractsByCreator_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_ContractInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmwasm", "wasm", "v1", "contract", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ContractHistory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"cosmwasm", "wasm", "v1", "contract", "address", "history"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ContractsByCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"cosmwasm", "wasm", "v1", "code", "code_id", "contracts"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"cosmwasm", "wasm", "v1", "contract", "address", "state"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_RawContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"cosmwasm", "wasm", "v1", "contract", "address", "raw", "query_data"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_SmartContractState_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5, 1, 0, 4, 1, 5, 6}, []string{"cosmwasm", "wasm", "v1", "contract", "address", "smart", "query_data"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Code_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmwasm", "wasm", "v1", "code", "code_id"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Codes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmwasm", "wasm", "v1", "code"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_PinnedCodes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmwasm", "wasm", "v1", "codes", "pinned"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmwasm", "wasm", "v1", "codes", "params"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_ContractsByCreator_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmwasm", "wasm", "v1", "contracts", "creator", "creator_address"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_ContractInfo_0 = runtime.ForwardResponseMessage + + forward_Query_ContractHistory_0 = runtime.ForwardResponseMessage + + forward_Query_ContractsByCode_0 = runtime.ForwardResponseMessage + + forward_Query_AllContractState_0 = runtime.ForwardResponseMessage + + forward_Query_RawContractState_0 = runtime.ForwardResponseMessage + + forward_Query_SmartContractState_0 = runtime.ForwardResponseMessage + + forward_Query_Code_0 = runtime.ForwardResponseMessage + + forward_Query_Codes_0 = runtime.ForwardResponseMessage + + forward_Query_PinnedCodes_0 = runtime.ForwardResponseMessage + + forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_ContractsByCreator_0 = runtime.ForwardResponseMessage +) diff --git a/x/wasm/types/tx.pb.go b/x/wasm/types/tx.pb.go new file mode 100644 index 00000000..15ffef71 --- /dev/null +++ b/x/wasm/types/tx.pb.go @@ -0,0 +1,4304 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/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 + +// MsgStoreCode submit Wasm code to the system +type MsgStoreCode struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // WASMByteCode can be raw or gzip compressed + WASMByteCode []byte `protobuf:"bytes,2,opt,name=wasm_byte_code,json=wasmByteCode,proto3" json:"wasm_byte_code,omitempty"` + // InstantiatePermission access control to apply on contract creation, + // optional + InstantiatePermission *AccessConfig `protobuf:"bytes,5,opt,name=instantiate_permission,json=instantiatePermission,proto3" json:"instantiate_permission,omitempty"` +} + +func (m *MsgStoreCode) Reset() { *m = MsgStoreCode{} } +func (m *MsgStoreCode) String() string { return proto.CompactTextString(m) } +func (*MsgStoreCode) ProtoMessage() {} +func (*MsgStoreCode) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{0} +} +func (m *MsgStoreCode) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgStoreCode) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgStoreCode.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 *MsgStoreCode) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgStoreCode.Merge(m, src) +} +func (m *MsgStoreCode) XXX_Size() int { + return m.Size() +} +func (m *MsgStoreCode) XXX_DiscardUnknown() { + xxx_messageInfo_MsgStoreCode.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgStoreCode proto.InternalMessageInfo + +// MsgStoreCodeResponse returns store result data. +type MsgStoreCodeResponse struct { + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Checksum is the sha256 hash of the stored code + Checksum []byte `protobuf:"bytes,2,opt,name=checksum,proto3" json:"checksum,omitempty"` +} + +func (m *MsgStoreCodeResponse) Reset() { *m = MsgStoreCodeResponse{} } +func (m *MsgStoreCodeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgStoreCodeResponse) ProtoMessage() {} +func (*MsgStoreCodeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{1} +} +func (m *MsgStoreCodeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgStoreCodeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgStoreCodeResponse.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 *MsgStoreCodeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgStoreCodeResponse.Merge(m, src) +} +func (m *MsgStoreCodeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgStoreCodeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgStoreCodeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgStoreCodeResponse proto.InternalMessageInfo + +// MsgInstantiateContract create a new smart contract instance for the given +// code id. +type MsgInstantiateContract struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"` + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,3,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Label is optional metadata to be stored with a contract instance. + Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` + // Msg json encoded message to be passed to the contract on instantiation + Msg RawContractMessage `protobuf:"bytes,5,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` +} + +func (m *MsgInstantiateContract) Reset() { *m = MsgInstantiateContract{} } +func (m *MsgInstantiateContract) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContract) ProtoMessage() {} +func (*MsgInstantiateContract) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{2} +} +func (m *MsgInstantiateContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInstantiateContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContract.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 *MsgInstantiateContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContract.Merge(m, src) +} +func (m *MsgInstantiateContract) XXX_Size() int { + return m.Size() +} +func (m *MsgInstantiateContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContract proto.InternalMessageInfo + +// MsgInstantiateContract2 create a new smart contract instance for the given +// code id with a predicable address. +type MsgInstantiateContract2 struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,2,opt,name=admin,proto3" json:"admin,omitempty"` + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,3,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Label is optional metadata to be stored with a contract instance. + Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` + // Msg json encoded message to be passed to the contract on instantiation + Msg RawContractMessage `protobuf:"bytes,5,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on instantiation + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,6,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` + // Salt is an arbitrary value provided by the sender. Size can be 1 to 64. + Salt []byte `protobuf:"bytes,7,opt,name=salt,proto3" json:"salt,omitempty"` + // FixMsg include the msg value into the hash for the predictable address. + // Default is false + FixMsg bool `protobuf:"varint,8,opt,name=fix_msg,json=fixMsg,proto3" json:"fix_msg,omitempty"` +} + +func (m *MsgInstantiateContract2) Reset() { *m = MsgInstantiateContract2{} } +func (m *MsgInstantiateContract2) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContract2) ProtoMessage() {} +func (*MsgInstantiateContract2) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{3} +} +func (m *MsgInstantiateContract2) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInstantiateContract2) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContract2.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 *MsgInstantiateContract2) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContract2.Merge(m, src) +} +func (m *MsgInstantiateContract2) XXX_Size() int { + return m.Size() +} +func (m *MsgInstantiateContract2) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContract2.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContract2 proto.InternalMessageInfo + +// MsgInstantiateContractResponse return instantiation result data +type MsgInstantiateContractResponse struct { + // Address is the bech32 address of the new contract instance. + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // Data contains bytes to returned from the contract + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgInstantiateContractResponse) Reset() { *m = MsgInstantiateContractResponse{} } +func (m *MsgInstantiateContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContractResponse) ProtoMessage() {} +func (*MsgInstantiateContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{4} +} +func (m *MsgInstantiateContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInstantiateContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContractResponse.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 *MsgInstantiateContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContractResponse.Merge(m, src) +} +func (m *MsgInstantiateContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgInstantiateContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContractResponse proto.InternalMessageInfo + +// MsgInstantiateContract2Response return instantiation result data +type MsgInstantiateContract2Response struct { + // Address is the bech32 address of the new contract instance. + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // Data contains bytes to returned from the contract + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgInstantiateContract2Response) Reset() { *m = MsgInstantiateContract2Response{} } +func (m *MsgInstantiateContract2Response) String() string { return proto.CompactTextString(m) } +func (*MsgInstantiateContract2Response) ProtoMessage() {} +func (*MsgInstantiateContract2Response) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{5} +} +func (m *MsgInstantiateContract2Response) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgInstantiateContract2Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgInstantiateContract2Response.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 *MsgInstantiateContract2Response) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgInstantiateContract2Response.Merge(m, src) +} +func (m *MsgInstantiateContract2Response) XXX_Size() int { + return m.Size() +} +func (m *MsgInstantiateContract2Response) XXX_DiscardUnknown() { + xxx_messageInfo_MsgInstantiateContract2Response.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgInstantiateContract2Response proto.InternalMessageInfo + +// MsgExecuteContract submits the given message data to a smart contract +type MsgExecuteContract struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,2,opt,name=contract,proto3" json:"contract,omitempty"` + // Msg json encoded message to be passed to the contract + Msg RawContractMessage `protobuf:"bytes,3,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` + // Funds coins that are transferred to the contract on execution + Funds github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,5,rep,name=funds,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds"` +} + +func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} } +func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) } +func (*MsgExecuteContract) ProtoMessage() {} +func (*MsgExecuteContract) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{6} +} +func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExecuteContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExecuteContract.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 *MsgExecuteContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExecuteContract.Merge(m, src) +} +func (m *MsgExecuteContract) XXX_Size() int { + return m.Size() +} +func (m *MsgExecuteContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExecuteContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExecuteContract proto.InternalMessageInfo + +// MsgExecuteContractResponse returns execution result data. +type MsgExecuteContractResponse struct { + // Data contains bytes to returned from the contract + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgExecuteContractResponse) Reset() { *m = MsgExecuteContractResponse{} } +func (m *MsgExecuteContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgExecuteContractResponse) ProtoMessage() {} +func (*MsgExecuteContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{7} +} +func (m *MsgExecuteContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExecuteContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExecuteContractResponse.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 *MsgExecuteContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExecuteContractResponse.Merge(m, src) +} +func (m *MsgExecuteContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgExecuteContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExecuteContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExecuteContractResponse proto.InternalMessageInfo + +// MsgMigrateContract runs a code upgrade/ downgrade for a smart contract +type MsgMigrateContract struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,2,opt,name=contract,proto3" json:"contract,omitempty"` + // CodeID references the new WASM code + CodeID uint64 `protobuf:"varint,3,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Msg json encoded message to be passed to the contract on migration + Msg RawContractMessage `protobuf:"bytes,4,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` +} + +func (m *MsgMigrateContract) Reset() { *m = MsgMigrateContract{} } +func (m *MsgMigrateContract) String() string { return proto.CompactTextString(m) } +func (*MsgMigrateContract) ProtoMessage() {} +func (*MsgMigrateContract) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{8} +} +func (m *MsgMigrateContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMigrateContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMigrateContract.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 *MsgMigrateContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMigrateContract.Merge(m, src) +} +func (m *MsgMigrateContract) XXX_Size() int { + return m.Size() +} +func (m *MsgMigrateContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMigrateContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMigrateContract proto.InternalMessageInfo + +// MsgMigrateContractResponse returns contract migration result data. +type MsgMigrateContractResponse struct { + // Data contains same raw bytes returned as data from the wasm contract. + // (May be empty) + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (m *MsgMigrateContractResponse) Reset() { *m = MsgMigrateContractResponse{} } +func (m *MsgMigrateContractResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMigrateContractResponse) ProtoMessage() {} +func (*MsgMigrateContractResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{9} +} +func (m *MsgMigrateContractResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMigrateContractResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMigrateContractResponse.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 *MsgMigrateContractResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMigrateContractResponse.Merge(m, src) +} +func (m *MsgMigrateContractResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMigrateContractResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMigrateContractResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMigrateContractResponse proto.InternalMessageInfo + +// MsgUpdateAdmin sets a new admin for a smart contract +type MsgUpdateAdmin struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // NewAdmin address to be set + NewAdmin string `protobuf:"bytes,2,opt,name=new_admin,json=newAdmin,proto3" json:"new_admin,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,3,opt,name=contract,proto3" json:"contract,omitempty"` +} + +func (m *MsgUpdateAdmin) Reset() { *m = MsgUpdateAdmin{} } +func (m *MsgUpdateAdmin) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateAdmin) ProtoMessage() {} +func (*MsgUpdateAdmin) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{10} +} +func (m *MsgUpdateAdmin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateAdmin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateAdmin.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 *MsgUpdateAdmin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateAdmin.Merge(m, src) +} +func (m *MsgUpdateAdmin) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateAdmin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateAdmin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateAdmin proto.InternalMessageInfo + +// MsgUpdateAdminResponse returns empty data +type MsgUpdateAdminResponse struct { +} + +func (m *MsgUpdateAdminResponse) Reset() { *m = MsgUpdateAdminResponse{} } +func (m *MsgUpdateAdminResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateAdminResponse) ProtoMessage() {} +func (*MsgUpdateAdminResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{11} +} +func (m *MsgUpdateAdminResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateAdminResponse.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 *MsgUpdateAdminResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateAdminResponse.Merge(m, src) +} +func (m *MsgUpdateAdminResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateAdminResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateAdminResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateAdminResponse proto.InternalMessageInfo + +// MsgClearAdmin removes any admin stored for a smart contract +type MsgClearAdmin struct { + // Sender is the actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,3,opt,name=contract,proto3" json:"contract,omitempty"` +} + +func (m *MsgClearAdmin) Reset() { *m = MsgClearAdmin{} } +func (m *MsgClearAdmin) String() string { return proto.CompactTextString(m) } +func (*MsgClearAdmin) ProtoMessage() {} +func (*MsgClearAdmin) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{12} +} +func (m *MsgClearAdmin) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgClearAdmin) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgClearAdmin.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 *MsgClearAdmin) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgClearAdmin.Merge(m, src) +} +func (m *MsgClearAdmin) XXX_Size() int { + return m.Size() +} +func (m *MsgClearAdmin) XXX_DiscardUnknown() { + xxx_messageInfo_MsgClearAdmin.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgClearAdmin proto.InternalMessageInfo + +// MsgClearAdminResponse returns empty data +type MsgClearAdminResponse struct { +} + +func (m *MsgClearAdminResponse) Reset() { *m = MsgClearAdminResponse{} } +func (m *MsgClearAdminResponse) String() string { return proto.CompactTextString(m) } +func (*MsgClearAdminResponse) ProtoMessage() {} +func (*MsgClearAdminResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{13} +} +func (m *MsgClearAdminResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgClearAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgClearAdminResponse.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 *MsgClearAdminResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgClearAdminResponse.Merge(m, src) +} +func (m *MsgClearAdminResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgClearAdminResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgClearAdminResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgClearAdminResponse proto.InternalMessageInfo + +// MsgUpdateInstantiateConfig updates instantiate config for a smart contract +type MsgUpdateInstantiateConfig struct { + // Sender is the that actor that signed the messages + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` + // CodeID references the stored WASM code + CodeID uint64 `protobuf:"varint,2,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // NewInstantiatePermission is the new access control + NewInstantiatePermission *AccessConfig `protobuf:"bytes,3,opt,name=new_instantiate_permission,json=newInstantiatePermission,proto3" json:"new_instantiate_permission,omitempty"` +} + +func (m *MsgUpdateInstantiateConfig) Reset() { *m = MsgUpdateInstantiateConfig{} } +func (m *MsgUpdateInstantiateConfig) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateInstantiateConfig) ProtoMessage() {} +func (*MsgUpdateInstantiateConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{14} +} +func (m *MsgUpdateInstantiateConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateInstantiateConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateInstantiateConfig.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 *MsgUpdateInstantiateConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateInstantiateConfig.Merge(m, src) +} +func (m *MsgUpdateInstantiateConfig) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateInstantiateConfig) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateInstantiateConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateInstantiateConfig proto.InternalMessageInfo + +// MsgUpdateInstantiateConfigResponse returns empty data +type MsgUpdateInstantiateConfigResponse struct { +} + +func (m *MsgUpdateInstantiateConfigResponse) Reset() { *m = MsgUpdateInstantiateConfigResponse{} } +func (m *MsgUpdateInstantiateConfigResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateInstantiateConfigResponse) ProtoMessage() {} +func (*MsgUpdateInstantiateConfigResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d5300ac1684bd7bc, []int{15} +} +func (m *MsgUpdateInstantiateConfigResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateInstantiateConfigResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateInstantiateConfigResponse.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 *MsgUpdateInstantiateConfigResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateInstantiateConfigResponse.Merge(m, src) +} +func (m *MsgUpdateInstantiateConfigResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateInstantiateConfigResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateInstantiateConfigResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateInstantiateConfigResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgStoreCode)(nil), "cosmwasm.wasm.v1.MsgStoreCode") + proto.RegisterType((*MsgStoreCodeResponse)(nil), "cosmwasm.wasm.v1.MsgStoreCodeResponse") + proto.RegisterType((*MsgInstantiateContract)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract") + proto.RegisterType((*MsgInstantiateContract2)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract2") + proto.RegisterType((*MsgInstantiateContractResponse)(nil), "cosmwasm.wasm.v1.MsgInstantiateContractResponse") + proto.RegisterType((*MsgInstantiateContract2Response)(nil), "cosmwasm.wasm.v1.MsgInstantiateContract2Response") + proto.RegisterType((*MsgExecuteContract)(nil), "cosmwasm.wasm.v1.MsgExecuteContract") + proto.RegisterType((*MsgExecuteContractResponse)(nil), "cosmwasm.wasm.v1.MsgExecuteContractResponse") + proto.RegisterType((*MsgMigrateContract)(nil), "cosmwasm.wasm.v1.MsgMigrateContract") + proto.RegisterType((*MsgMigrateContractResponse)(nil), "cosmwasm.wasm.v1.MsgMigrateContractResponse") + proto.RegisterType((*MsgUpdateAdmin)(nil), "cosmwasm.wasm.v1.MsgUpdateAdmin") + proto.RegisterType((*MsgUpdateAdminResponse)(nil), "cosmwasm.wasm.v1.MsgUpdateAdminResponse") + proto.RegisterType((*MsgClearAdmin)(nil), "cosmwasm.wasm.v1.MsgClearAdmin") + proto.RegisterType((*MsgClearAdminResponse)(nil), "cosmwasm.wasm.v1.MsgClearAdminResponse") + proto.RegisterType((*MsgUpdateInstantiateConfig)(nil), "cosmwasm.wasm.v1.MsgUpdateInstantiateConfig") + proto.RegisterType((*MsgUpdateInstantiateConfigResponse)(nil), "cosmwasm.wasm.v1.MsgUpdateInstantiateConfigResponse") +} + +func init() { proto.RegisterFile("wasm/v1/tx.proto", fileDescriptor_d5300ac1684bd7bc) } + +var fileDescriptor_d5300ac1684bd7bc = []byte{ + // 908 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x56, 0xcd, 0x6e, 0xe3, 0x54, + 0x14, 0x8e, 0x9b, 0x9f, 0xa6, 0xa7, 0x61, 0x88, 0x3c, 0x99, 0xd6, 0x18, 0xc9, 0x89, 0xcc, 0x08, + 0x8c, 0x34, 0x63, 0x37, 0x01, 0xb1, 0x6f, 0x02, 0x48, 0x1d, 0xc9, 0x80, 0x5c, 0x0d, 0x23, 0x10, + 0x52, 0x74, 0x63, 0xdf, 0x78, 0xac, 0x49, 0x7c, 0x83, 0xef, 0x6d, 0x93, 0x2e, 0x78, 0x05, 0xc4, + 0x8e, 0x77, 0xe0, 0x05, 0xd8, 0xb0, 0x41, 0x6c, 0xba, 0x9c, 0x0d, 0x12, 0xab, 0x02, 0xe9, 0x5b, + 0xb0, 0x42, 0xbe, 0xfe, 0xa9, 0x93, 0xb1, 0xd3, 0x14, 0xc4, 0x8a, 0x4d, 0x72, 0xcf, 0xf5, 0x77, + 0xfe, 0xbe, 0x73, 0x8e, 0x8f, 0xa1, 0x39, 0x47, 0x74, 0x6a, 0x9c, 0x77, 0x0d, 0xb6, 0xd0, 0x67, + 0x01, 0x61, 0x44, 0x6c, 0xda, 0x84, 0x4e, 0xc3, 0x5b, 0x9d, 0xff, 0x9c, 0x77, 0x65, 0x25, 0xbc, + 0x21, 0xd4, 0x18, 0x21, 0x8a, 0x8d, 0xf3, 0xee, 0x08, 0x33, 0xd4, 0x35, 0x6c, 0xe2, 0xf9, 0x91, + 0x86, 0xdc, 0x72, 0x89, 0x4b, 0xf8, 0xd1, 0x08, 0x4f, 0xf1, 0xed, 0xfd, 0xd4, 0xf2, 0xc5, 0x0c, + 0xd3, 0xe8, 0x52, 0xfd, 0x59, 0x80, 0x86, 0x49, 0xdd, 0x53, 0x46, 0x02, 0x3c, 0x20, 0x0e, 0x16, + 0x0f, 0xa0, 0x46, 0xb1, 0xef, 0xe0, 0x40, 0x12, 0x3a, 0x82, 0xb6, 0x67, 0xc5, 0x92, 0xf8, 0x01, + 0xdc, 0x0b, 0xf5, 0x87, 0xa3, 0x0b, 0x86, 0x87, 0x36, 0x71, 0xb0, 0xb4, 0xd3, 0x11, 0xb4, 0x46, + 0xbf, 0xb9, 0xbc, 0x6a, 0x37, 0x9e, 0x1d, 0x9f, 0x9a, 0xfd, 0x0b, 0xc6, 0x2d, 0x58, 0x8d, 0x10, + 0x97, 0x48, 0xe2, 0x53, 0x38, 0xf0, 0x7c, 0xca, 0x90, 0xcf, 0x3c, 0xc4, 0xf0, 0x70, 0x86, 0x83, + 0xa9, 0x47, 0xa9, 0x47, 0x7c, 0xa9, 0xda, 0x11, 0xb4, 0xfd, 0x9e, 0xa2, 0xaf, 0xa7, 0xa7, 0x1f, + 0xdb, 0x36, 0xa6, 0x74, 0x40, 0xfc, 0xb1, 0xe7, 0x5a, 0x0f, 0x32, 0xda, 0x9f, 0xa5, 0xca, 0x4f, + 0x2a, 0xf5, 0x72, 0xb3, 0xf2, 0xa4, 0x52, 0xaf, 0x34, 0xab, 0xea, 0x33, 0x68, 0x65, 0x53, 0xb0, + 0x30, 0x9d, 0x11, 0x9f, 0x62, 0xf1, 0x2d, 0xd8, 0x0d, 0x03, 0x1d, 0x7a, 0x0e, 0xcf, 0xa5, 0xd2, + 0x87, 0xe5, 0x55, 0xbb, 0x16, 0x42, 0x4e, 0x3e, 0xb4, 0x6a, 0xe1, 0xa3, 0x13, 0x47, 0x94, 0xa1, + 0x6e, 0x3f, 0xc7, 0xf6, 0x0b, 0x7a, 0x36, 0x8d, 0x32, 0xb2, 0x52, 0x59, 0xfd, 0x76, 0x07, 0x0e, + 0x4c, 0xea, 0x9e, 0xdc, 0x44, 0x30, 0x20, 0x3e, 0x0b, 0x90, 0xcd, 0x0a, 0x69, 0x6a, 0x41, 0x15, + 0x39, 0x53, 0xcf, 0xe7, 0xb6, 0xf6, 0xac, 0x48, 0xc8, 0x46, 0x52, 0x2e, 0x8c, 0xa4, 0x05, 0xd5, + 0x09, 0x1a, 0xe1, 0x89, 0x54, 0x89, 0x54, 0xb9, 0x20, 0x6a, 0x50, 0x9e, 0x52, 0x97, 0x93, 0xd5, + 0xe8, 0x1f, 0xfc, 0x75, 0xd5, 0x16, 0x2d, 0x34, 0x4f, 0xc2, 0x30, 0x31, 0xa5, 0xc8, 0xc5, 0x56, + 0x08, 0x11, 0x11, 0x54, 0xc7, 0x67, 0xbe, 0x43, 0xa5, 0x5a, 0xa7, 0xac, 0xed, 0xf7, 0xde, 0xd0, + 0xa3, 0x2e, 0xd1, 0xc3, 0x2e, 0xd1, 0xe3, 0x2e, 0xd1, 0x07, 0xc4, 0xf3, 0xfb, 0x47, 0x97, 0x57, + 0xed, 0xd2, 0x0f, 0xbf, 0xb7, 0x35, 0xd7, 0x63, 0xcf, 0xcf, 0x46, 0xba, 0x4d, 0xa6, 0x46, 0xdc, + 0x52, 0xd1, 0xdf, 0x63, 0xea, 0xbc, 0x88, 0xdb, 0x24, 0x54, 0xa0, 0x56, 0x64, 0x59, 0xfd, 0x69, + 0x07, 0x0e, 0xf3, 0x09, 0xe9, 0xfd, 0x3f, 0x19, 0x11, 0x45, 0xa8, 0x50, 0x34, 0x61, 0xd2, 0x2e, + 0x6f, 0x1d, 0x7e, 0x16, 0x0f, 0x61, 0x77, 0xec, 0x2d, 0x86, 0x61, 0x90, 0xf5, 0x8e, 0xa0, 0xd5, + 0xad, 0xda, 0xd8, 0x5b, 0x98, 0xd4, 0x55, 0x3f, 0x01, 0x25, 0x9f, 0xbd, 0xb4, 0x65, 0x25, 0xd8, + 0x45, 0x8e, 0x13, 0x60, 0x4a, 0x63, 0x16, 0x13, 0x31, 0x74, 0xe4, 0x20, 0x86, 0xe2, 0x1e, 0xe5, + 0x67, 0xf5, 0x53, 0x68, 0x17, 0x54, 0xe3, 0x1f, 0x1a, 0xfc, 0x55, 0x00, 0xd1, 0xa4, 0xee, 0x47, + 0x0b, 0x6c, 0x9f, 0x6d, 0xd1, 0xec, 0xe1, 0xec, 0xc4, 0x98, 0xb8, 0xba, 0xa9, 0x9c, 0x54, 0xa9, + 0x7c, 0x87, 0x2a, 0x55, 0xff, 0xb3, 0xbe, 0x3d, 0x02, 0xf9, 0xd5, 0xb4, 0x52, 0x8e, 0x12, 0x26, + 0x84, 0x0c, 0x13, 0xdf, 0x47, 0x4c, 0x98, 0x9e, 0x1b, 0xa0, 0x7f, 0xc9, 0xc4, 0x56, 0xad, 0x1e, + 0xd3, 0x55, 0xb9, 0x95, 0xae, 0x38, 0x97, 0xb5, 0xc0, 0x36, 0xe6, 0x82, 0xe0, 0x9e, 0x49, 0xdd, + 0xa7, 0x33, 0x07, 0x31, 0x7c, 0xcc, 0xa7, 0xaf, 0x28, 0x8d, 0x37, 0x61, 0xcf, 0xc7, 0xf3, 0x61, + 0x76, 0x5e, 0xeb, 0x3e, 0x9e, 0x47, 0x4a, 0xd9, 0x1c, 0xcb, 0xab, 0x39, 0xaa, 0x12, 0x7f, 0x51, + 0x66, 0x5c, 0x24, 0x01, 0xa9, 0x03, 0x78, 0xcd, 0xa4, 0xee, 0x60, 0x82, 0x51, 0xb0, 0xd9, 0xf7, + 0x26, 0xf3, 0x87, 0xf0, 0x60, 0xc5, 0x48, 0x6a, 0xfd, 0x47, 0x81, 0xb3, 0x11, 0x39, 0x5e, 0x1d, + 0x84, 0xb1, 0xe7, 0x16, 0xfa, 0xca, 0x94, 0x64, 0xa7, 0xb0, 0x24, 0x5f, 0x81, 0x1c, 0x92, 0x51, + 0xb0, 0xbd, 0xca, 0x5b, 0x6d, 0x2f, 0xc9, 0xc7, 0xf3, 0x93, 0xbc, 0x05, 0xa6, 0x3e, 0x04, 0xb5, + 0x38, 0xf0, 0x24, 0xbf, 0xde, 0x2f, 0x35, 0x28, 0x9b, 0xd4, 0x15, 0x4f, 0x61, 0xef, 0x66, 0x45, + 0xe7, 0x38, 0xcd, 0xee, 0x3f, 0xf9, 0xed, 0xcd, 0xcf, 0xd3, 0x5e, 0xf9, 0x1a, 0xee, 0xe7, 0xad, + 0x36, 0x2d, 0x57, 0x3d, 0x07, 0x29, 0x1f, 0x6d, 0x8b, 0x4c, 0x5d, 0x32, 0x68, 0xe5, 0x2e, 0x8f, + 0x77, 0xb7, 0xb5, 0xd4, 0x93, 0xbb, 0x5b, 0x43, 0x53, 0xaf, 0x18, 0x5e, 0x5f, 0x7f, 0xa5, 0x3d, + 0xcc, 0xb5, 0xb2, 0x86, 0x92, 0x1f, 0x6d, 0x83, 0xca, 0xba, 0x59, 0x7f, 0x5f, 0xe4, 0xbb, 0x59, + 0x43, 0x15, 0xb8, 0x29, 0x1a, 0xf1, 0x2f, 0x60, 0x3f, 0x3b, 0xcb, 0x9d, 0x5c, 0xe5, 0x0c, 0x42, + 0xd6, 0x6e, 0x43, 0xa4, 0xa6, 0x3f, 0x07, 0xc8, 0x4c, 0x6a, 0x3b, 0x57, 0xef, 0x06, 0x20, 0xbf, + 0x73, 0x0b, 0x20, 0xb5, 0xfb, 0x0d, 0x1c, 0x16, 0x8d, 0xe8, 0xa3, 0x0d, 0xc1, 0xbd, 0x82, 0x96, + 0xdf, 0xbf, 0x0b, 0x3a, 0x71, 0xdf, 0xff, 0xf8, 0xf2, 0x4f, 0xa5, 0x74, 0xb9, 0x54, 0x84, 0x97, + 0x4b, 0x45, 0xf8, 0x63, 0xa9, 0x08, 0xdf, 0x5d, 0x2b, 0xa5, 0x97, 0xd7, 0x4a, 0xe9, 0xb7, 0x6b, + 0xa5, 0xf4, 0xe5, 0xca, 0x36, 0xc1, 0x81, 0xfd, 0xd8, 0x23, 0xc6, 0x04, 0xd9, 0xc4, 0xf7, 0x6c, + 0xc7, 0x58, 0x18, 0xfc, 0xab, 0x99, 0xef, 0x94, 0x51, 0x8d, 0x7f, 0x33, 0xbf, 0xf7, 0x77, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x70, 0xa3, 0x2c, 0x87, 0xa4, 0x0b, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // StoreCode to submit Wasm code to the system + StoreCode(ctx context.Context, in *MsgStoreCode, opts ...grpc.CallOption) (*MsgStoreCodeResponse, error) + // InstantiateContract creates a new smart contract instance for the given + // code id. + InstantiateContract(ctx context.Context, in *MsgInstantiateContract, opts ...grpc.CallOption) (*MsgInstantiateContractResponse, error) + // InstantiateContract2 creates a new smart contract instance for the given + // code id with a predictable address + InstantiateContract2(ctx context.Context, in *MsgInstantiateContract2, opts ...grpc.CallOption) (*MsgInstantiateContract2Response, error) + // Execute submits the given message data to a smart contract + ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error) + // Migrate runs a code upgrade/ downgrade for a smart contract + MigrateContract(ctx context.Context, in *MsgMigrateContract, opts ...grpc.CallOption) (*MsgMigrateContractResponse, error) + // UpdateAdmin sets a new admin for a smart contract + UpdateAdmin(ctx context.Context, in *MsgUpdateAdmin, opts ...grpc.CallOption) (*MsgUpdateAdminResponse, error) + // ClearAdmin removes any admin stored for a smart contract + ClearAdmin(ctx context.Context, in *MsgClearAdmin, opts ...grpc.CallOption) (*MsgClearAdminResponse, error) + // UpdateInstantiateConfig updates instantiate config for a smart contract + UpdateInstantiateConfig(ctx context.Context, in *MsgUpdateInstantiateConfig, opts ...grpc.CallOption) (*MsgUpdateInstantiateConfigResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) StoreCode(ctx context.Context, in *MsgStoreCode, opts ...grpc.CallOption) (*MsgStoreCodeResponse, error) { + out := new(MsgStoreCodeResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/StoreCode", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) InstantiateContract(ctx context.Context, in *MsgInstantiateContract, opts ...grpc.CallOption) (*MsgInstantiateContractResponse, error) { + out := new(MsgInstantiateContractResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/InstantiateContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) InstantiateContract2(ctx context.Context, in *MsgInstantiateContract2, opts ...grpc.CallOption) (*MsgInstantiateContract2Response, error) { + out := new(MsgInstantiateContract2Response) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/InstantiateContract2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ExecuteContract(ctx context.Context, in *MsgExecuteContract, opts ...grpc.CallOption) (*MsgExecuteContractResponse, error) { + out := new(MsgExecuteContractResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/ExecuteContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) MigrateContract(ctx context.Context, in *MsgMigrateContract, opts ...grpc.CallOption) (*MsgMigrateContractResponse, error) { + out := new(MsgMigrateContractResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/MigrateContract", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateAdmin(ctx context.Context, in *MsgUpdateAdmin, opts ...grpc.CallOption) (*MsgUpdateAdminResponse, error) { + out := new(MsgUpdateAdminResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/UpdateAdmin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) ClearAdmin(ctx context.Context, in *MsgClearAdmin, opts ...grpc.CallOption) (*MsgClearAdminResponse, error) { + out := new(MsgClearAdminResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/ClearAdmin", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateInstantiateConfig(ctx context.Context, in *MsgUpdateInstantiateConfig, opts ...grpc.CallOption) (*MsgUpdateInstantiateConfigResponse, error) { + out := new(MsgUpdateInstantiateConfigResponse) + err := c.cc.Invoke(ctx, "/cosmwasm.wasm.v1.Msg/UpdateInstantiateConfig", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // StoreCode to submit Wasm code to the system + StoreCode(context.Context, *MsgStoreCode) (*MsgStoreCodeResponse, error) + // InstantiateContract creates a new smart contract instance for the given + // code id. + InstantiateContract(context.Context, *MsgInstantiateContract) (*MsgInstantiateContractResponse, error) + // InstantiateContract2 creates a new smart contract instance for the given + // code id with a predictable address + InstantiateContract2(context.Context, *MsgInstantiateContract2) (*MsgInstantiateContract2Response, error) + // Execute submits the given message data to a smart contract + ExecuteContract(context.Context, *MsgExecuteContract) (*MsgExecuteContractResponse, error) + // Migrate runs a code upgrade/ downgrade for a smart contract + MigrateContract(context.Context, *MsgMigrateContract) (*MsgMigrateContractResponse, error) + // UpdateAdmin sets a new admin for a smart contract + UpdateAdmin(context.Context, *MsgUpdateAdmin) (*MsgUpdateAdminResponse, error) + // ClearAdmin removes any admin stored for a smart contract + ClearAdmin(context.Context, *MsgClearAdmin) (*MsgClearAdminResponse, error) + // UpdateInstantiateConfig updates instantiate config for a smart contract + UpdateInstantiateConfig(context.Context, *MsgUpdateInstantiateConfig) (*MsgUpdateInstantiateConfigResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) StoreCode(ctx context.Context, req *MsgStoreCode) (*MsgStoreCodeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method StoreCode not implemented") +} +func (*UnimplementedMsgServer) InstantiateContract(ctx context.Context, req *MsgInstantiateContract) (*MsgInstantiateContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract not implemented") +} +func (*UnimplementedMsgServer) InstantiateContract2(ctx context.Context, req *MsgInstantiateContract2) (*MsgInstantiateContract2Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method InstantiateContract2 not implemented") +} +func (*UnimplementedMsgServer) ExecuteContract(ctx context.Context, req *MsgExecuteContract) (*MsgExecuteContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ExecuteContract not implemented") +} +func (*UnimplementedMsgServer) MigrateContract(ctx context.Context, req *MsgMigrateContract) (*MsgMigrateContractResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MigrateContract not implemented") +} +func (*UnimplementedMsgServer) UpdateAdmin(ctx context.Context, req *MsgUpdateAdmin) (*MsgUpdateAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateAdmin not implemented") +} +func (*UnimplementedMsgServer) ClearAdmin(ctx context.Context, req *MsgClearAdmin) (*MsgClearAdminResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ClearAdmin not implemented") +} +func (*UnimplementedMsgServer) UpdateInstantiateConfig(ctx context.Context, req *MsgUpdateInstantiateConfig) (*MsgUpdateInstantiateConfigResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateInstantiateConfig not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_StoreCode_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgStoreCode) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).StoreCode(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/StoreCode", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).StoreCode(ctx, req.(*MsgStoreCode)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_InstantiateContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgInstantiateContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).InstantiateContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/InstantiateContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).InstantiateContract(ctx, req.(*MsgInstantiateContract)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_InstantiateContract2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgInstantiateContract2) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).InstantiateContract2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/InstantiateContract2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).InstantiateContract2(ctx, req.(*MsgInstantiateContract2)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ExecuteContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgExecuteContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ExecuteContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/ExecuteContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ExecuteContract(ctx, req.(*MsgExecuteContract)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_MigrateContract_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMigrateContract) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).MigrateContract(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/MigrateContract", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).MigrateContract(ctx, req.(*MsgMigrateContract)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateAdmin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/UpdateAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateAdmin(ctx, req.(*MsgUpdateAdmin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_ClearAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgClearAdmin) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).ClearAdmin(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/ClearAdmin", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).ClearAdmin(ctx, req.(*MsgClearAdmin)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateInstantiateConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateInstantiateConfig) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateInstantiateConfig(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmwasm.wasm.v1.Msg/UpdateInstantiateConfig", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateInstantiateConfig(ctx, req.(*MsgUpdateInstantiateConfig)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cosmwasm.wasm.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "StoreCode", + Handler: _Msg_StoreCode_Handler, + }, + { + MethodName: "InstantiateContract", + Handler: _Msg_InstantiateContract_Handler, + }, + { + MethodName: "InstantiateContract2", + Handler: _Msg_InstantiateContract2_Handler, + }, + { + MethodName: "ExecuteContract", + Handler: _Msg_ExecuteContract_Handler, + }, + { + MethodName: "MigrateContract", + Handler: _Msg_MigrateContract_Handler, + }, + { + MethodName: "UpdateAdmin", + Handler: _Msg_UpdateAdmin_Handler, + }, + { + MethodName: "ClearAdmin", + Handler: _Msg_ClearAdmin_Handler, + }, + { + MethodName: "UpdateInstantiateConfig", + Handler: _Msg_UpdateInstantiateConfig_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "wasm/v1/tx.proto", +} + +func (m *MsgStoreCode) 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 *MsgStoreCode) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgStoreCode) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.InstantiatePermission != nil { + { + size, err := m.InstantiatePermission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.WASMByteCode) > 0 { + i -= len(m.WASMByteCode) + copy(dAtA[i:], m.WASMByteCode) + i = encodeVarintTx(dAtA, i, uint64(len(m.WASMByteCode))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgStoreCodeResponse) 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 *MsgStoreCodeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgStoreCodeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Checksum) > 0 { + i -= len(m.Checksum) + copy(dAtA[i:], m.Checksum) + i = encodeVarintTx(dAtA, i, uint64(len(m.Checksum))) + i-- + dAtA[i] = 0x12 + } + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *MsgInstantiateContract) 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 *MsgInstantiateContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintTx(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x2a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintTx(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x22 + } + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x18 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintTx(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgInstantiateContract2) 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 *MsgInstantiateContract2) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContract2) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.FixMsg { + i-- + if m.FixMsg { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + } + if len(m.Salt) > 0 { + i -= len(m.Salt) + copy(dAtA[i:], m.Salt) + i = encodeVarintTx(dAtA, i, uint64(len(m.Salt))) + i-- + dAtA[i] = 0x3a + } + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintTx(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x2a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintTx(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x22 + } + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x18 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintTx(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgInstantiateContractResponse) 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 *MsgInstantiateContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContractResponse) 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 = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + 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 *MsgInstantiateContract2Response) 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 *MsgInstantiateContract2Response) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgInstantiateContract2Response) 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 = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + 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 *MsgExecuteContract) 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 *MsgExecuteContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Funds) > 0 { + for iNdEx := len(m.Funds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Funds[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintTx(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x1a + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintTx(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgExecuteContractResponse) 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 *MsgExecuteContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExecuteContractResponse) 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 = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMigrateContract) 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 *MsgMigrateContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMigrateContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintTx(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x22 + } + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x18 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintTx(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMigrateContractResponse) 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 *MsgMigrateContractResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMigrateContractResponse) 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 = encodeVarintTx(dAtA, i, uint64(len(m.Data))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateAdmin) 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 *MsgUpdateAdmin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateAdmin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintTx(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x1a + } + if len(m.NewAdmin) > 0 { + i -= len(m.NewAdmin) + copy(dAtA[i:], m.NewAdmin) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewAdmin))) + i-- + dAtA[i] = 0x12 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateAdminResponse) 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 *MsgUpdateAdminResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgClearAdmin) 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 *MsgClearAdmin) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgClearAdmin) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintTx(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0x1a + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgClearAdminResponse) 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 *MsgClearAdminResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgClearAdminResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateInstantiateConfig) 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 *MsgUpdateInstantiateConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateInstantiateConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.NewInstantiatePermission != nil { + { + size, err := m.NewInstantiatePermission.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.CodeID != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x10 + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintTx(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateInstantiateConfigResponse) 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 *MsgUpdateInstantiateConfigResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateInstantiateConfigResponse) 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 *MsgStoreCode) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.WASMByteCode) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.InstantiatePermission != nil { + l = m.InstantiatePermission.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgStoreCodeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) + } + l = len(m.Checksum) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgInstantiateContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) + } + l = len(m.Label) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgInstantiateContract2) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) + } + l = len(m.Label) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + l = len(m.Salt) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.FixMsg { + n += 2 + } + return n +} + +func (m *MsgInstantiateContractResponse) 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.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgInstantiateContract2Response) 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.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgExecuteContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Funds) > 0 { + for _, e := range m.Funds { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgExecuteContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMigrateContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgMigrateContractResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Data) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgUpdateAdmin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.NewAdmin) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgUpdateAdminResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgClearAdmin) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgClearAdminResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateInstantiateConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.CodeID != 0 { + n += 1 + sovTx(uint64(m.CodeID)) + } + if m.NewInstantiatePermission != nil { + l = m.NewInstantiatePermission.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgUpdateInstantiateConfigResponse) 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 *MsgStoreCode) 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: MsgStoreCode: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgStoreCode: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WASMByteCode", 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.WASMByteCode = append(m.WASMByteCode[:0], dAtA[iNdEx:postIndex]...) + if m.WASMByteCode == nil { + m.WASMByteCode = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiatePermission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.InstantiatePermission == nil { + m.InstantiatePermission = &AccessConfig{} + } + if err := m.InstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgStoreCodeResponse) 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: MsgStoreCodeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgStoreCodeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Checksum", 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.Checksum = append(m.Checksum[:0], dAtA[iNdEx:postIndex]...) + if m.Checksum == nil { + m.Checksum = []byte{} + } + 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 *MsgInstantiateContract) 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: MsgInstantiateContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", 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.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", 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.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", 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.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := 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 *MsgInstantiateContract2) 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: MsgInstantiateContract2: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContract2: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", 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.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", 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.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", 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.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Salt", 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.Salt = append(m.Salt[:0], dAtA[iNdEx:postIndex]...) + if m.Salt == nil { + m.Salt = []byte{} + } + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FixMsg", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.FixMsg = bool(v != 0) + 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 *MsgInstantiateContractResponse) 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: MsgInstantiateContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContractResponse: 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 Data", 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.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + 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 *MsgInstantiateContract2Response) 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: MsgInstantiateContract2Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgInstantiateContract2Response: 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 Data", 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.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + 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 *MsgExecuteContract) 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: MsgExecuteContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExecuteContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", 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.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", 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.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Funds", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Funds = append(m.Funds, types.Coin{}) + if err := m.Funds[len(m.Funds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := 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 *MsgExecuteContractResponse) 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: MsgExecuteContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExecuteContractResponse: 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 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.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + 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 *MsgMigrateContract) 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: MsgMigrateContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMigrateContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", 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.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", 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.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + 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 *MsgMigrateContractResponse) 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: MsgMigrateContractResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMigrateContractResponse: 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 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.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) + if m.Data == nil { + m.Data = []byte{} + } + 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 *MsgUpdateAdmin) 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: MsgUpdateAdmin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateAdmin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewAdmin", 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.NewAdmin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", 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.Contract = 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 *MsgUpdateAdminResponse) 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: MsgUpdateAdminResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateAdminResponse: 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 (m *MsgClearAdmin) 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: MsgClearAdmin: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClearAdmin: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", 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.Contract = 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 *MsgClearAdminResponse) 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: MsgClearAdminResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClearAdminResponse: 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 (m *MsgUpdateInstantiateConfig) 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: MsgUpdateInstantiateConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateInstantiateConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", 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.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewInstantiatePermission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.NewInstantiatePermission == nil { + m.NewInstantiatePermission = &AccessConfig{} + } + if err := m.NewInstantiatePermission.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateInstantiateConfigResponse) 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: MsgUpdateInstantiateConfigResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateInstantiateConfigResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/wasm/types/types.pb.go b/x/wasm/types/types.pb.go new file mode 100644 index 00000000..73c6462f --- /dev/null +++ b/x/wasm/types/types.pb.go @@ -0,0 +1,2483 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: wasm/v1/types.proto + +package types + +import ( + bytes "bytes" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/gogo/protobuf/proto" + github_com_tendermint_tendermint_libs_bytes "github.com/tendermint/tendermint/libs/bytes" + 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 + +// AccessType permission types +type AccessType int32 + +const ( + // AccessTypeUnspecified placeholder for empty value + AccessTypeUnspecified AccessType = 0 + // AccessTypeNobody forbidden + AccessTypeNobody AccessType = 1 + // AccessTypeOnlyAddress restricted to a single address + // Deprecated: use AccessTypeAnyOfAddresses instead + AccessTypeOnlyAddress AccessType = 2 + // AccessTypeEverybody unrestricted + AccessTypeEverybody AccessType = 3 + // AccessTypeAnyOfAddresses allow any of the addresses + AccessTypeAnyOfAddresses AccessType = 4 +) + +var AccessType_name = map[int32]string{ + 0: "ACCESS_TYPE_UNSPECIFIED", + 1: "ACCESS_TYPE_NOBODY", + 2: "ACCESS_TYPE_ONLY_ADDRESS", + 3: "ACCESS_TYPE_EVERYBODY", + 4: "ACCESS_TYPE_ANY_OF_ADDRESSES", +} + +var AccessType_value = map[string]int32{ + "ACCESS_TYPE_UNSPECIFIED": 0, + "ACCESS_TYPE_NOBODY": 1, + "ACCESS_TYPE_ONLY_ADDRESS": 2, + "ACCESS_TYPE_EVERYBODY": 3, + "ACCESS_TYPE_ANY_OF_ADDRESSES": 4, +} + +func (AccessType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{0} +} + +// ContractCodeHistoryOperationType actions that caused a code change +type ContractCodeHistoryOperationType int32 + +const ( + // ContractCodeHistoryOperationTypeUnspecified placeholder for empty value + ContractCodeHistoryOperationTypeUnspecified ContractCodeHistoryOperationType = 0 + // ContractCodeHistoryOperationTypeInit on chain contract instantiation + ContractCodeHistoryOperationTypeInit ContractCodeHistoryOperationType = 1 + // ContractCodeHistoryOperationTypeMigrate code migration + ContractCodeHistoryOperationTypeMigrate ContractCodeHistoryOperationType = 2 + // ContractCodeHistoryOperationTypeGenesis based on genesis data + ContractCodeHistoryOperationTypeGenesis ContractCodeHistoryOperationType = 3 +) + +var ContractCodeHistoryOperationType_name = map[int32]string{ + 0: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_UNSPECIFIED", + 1: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", + 2: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE", + 3: "CONTRACT_CODE_HISTORY_OPERATION_TYPE_GENESIS", +} + +var ContractCodeHistoryOperationType_value = map[string]int32{ + "CONTRACT_CODE_HISTORY_OPERATION_TYPE_UNSPECIFIED": 0, + "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT": 1, + "CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE": 2, + "CONTRACT_CODE_HISTORY_OPERATION_TYPE_GENESIS": 3, +} + +func (x ContractCodeHistoryOperationType) String() string { + return proto.EnumName(ContractCodeHistoryOperationType_name, int32(x)) +} + +func (ContractCodeHistoryOperationType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{1} +} + +// AccessTypeParam +type AccessTypeParam struct { + Value AccessType `protobuf:"varint,1,opt,name=value,proto3,enum=cosmwasm.wasm.v1.AccessType" json:"value,omitempty" yaml:"value"` +} + +func (m *AccessTypeParam) Reset() { *m = AccessTypeParam{} } +func (m *AccessTypeParam) String() string { return proto.CompactTextString(m) } +func (*AccessTypeParam) ProtoMessage() {} +func (*AccessTypeParam) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{0} +} +func (m *AccessTypeParam) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessTypeParam) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessTypeParam.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 *AccessTypeParam) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessTypeParam.Merge(m, src) +} +func (m *AccessTypeParam) XXX_Size() int { + return m.Size() +} +func (m *AccessTypeParam) XXX_DiscardUnknown() { + xxx_messageInfo_AccessTypeParam.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessTypeParam proto.InternalMessageInfo + +// AccessConfig access control type. +type AccessConfig struct { + Permission AccessType `protobuf:"varint,1,opt,name=permission,proto3,enum=cosmwasm.wasm.v1.AccessType" json:"permission,omitempty" yaml:"permission"` + // Address + // Deprecated: replaced by addresses + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty" yaml:"address"` + Addresses []string `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty" yaml:"addresses"` +} + +func (m *AccessConfig) Reset() { *m = AccessConfig{} } +func (m *AccessConfig) String() string { return proto.CompactTextString(m) } +func (*AccessConfig) ProtoMessage() {} +func (*AccessConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{1} +} +func (m *AccessConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccessConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccessConfig.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 *AccessConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccessConfig.Merge(m, src) +} +func (m *AccessConfig) XXX_Size() int { + return m.Size() +} +func (m *AccessConfig) XXX_DiscardUnknown() { + xxx_messageInfo_AccessConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_AccessConfig proto.InternalMessageInfo + +// Params defines the set of wasm parameters. +type Params struct { + CodeUploadAccess AccessConfig `protobuf:"bytes,1,opt,name=code_upload_access,json=codeUploadAccess,proto3" json:"code_upload_access" yaml:"code_upload_access"` + InstantiateDefaultPermission AccessType `protobuf:"varint,2,opt,name=instantiate_default_permission,json=instantiateDefaultPermission,proto3,enum=cosmwasm.wasm.v1.AccessType" json:"instantiate_default_permission,omitempty" yaml:"instantiate_default_permission"` +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{2} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +// CodeInfo is data for the uploaded contract WASM code +type CodeInfo struct { + // CodeHash is the unique identifier created by wasmvm + CodeHash []byte `protobuf:"bytes,1,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` + // Creator address who initially stored the code + Creator string `protobuf:"bytes,2,opt,name=creator,proto3" json:"creator,omitempty"` + // InstantiateConfig access control to apply on contract creation, optional + InstantiateConfig AccessConfig `protobuf:"bytes,5,opt,name=instantiate_config,json=instantiateConfig,proto3" json:"instantiate_config"` +} + +func (m *CodeInfo) Reset() { *m = CodeInfo{} } +func (m *CodeInfo) String() string { return proto.CompactTextString(m) } +func (*CodeInfo) ProtoMessage() {} +func (*CodeInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{3} +} +func (m *CodeInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *CodeInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_CodeInfo.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 *CodeInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_CodeInfo.Merge(m, src) +} +func (m *CodeInfo) XXX_Size() int { + return m.Size() +} +func (m *CodeInfo) XXX_DiscardUnknown() { + xxx_messageInfo_CodeInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_CodeInfo proto.InternalMessageInfo + +// ContractInfo stores a WASM contract instance +type ContractInfo struct { + // CodeID is the reference to the stored Wasm code + CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Creator address who initially instantiated the contract + Creator string `protobuf:"bytes,2,opt,name=creator,proto3" json:"creator,omitempty"` + // Admin is an optional address that can execute migrations + Admin string `protobuf:"bytes,3,opt,name=admin,proto3" json:"admin,omitempty"` + // Label is optional metadata to be stored with a contract instance. + Label string `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"` + // Created Tx position when the contract was instantiated. + Created *AbsoluteTxPosition `protobuf:"bytes,5,opt,name=created,proto3" json:"created,omitempty"` + IBCPortID string `protobuf:"bytes,6,opt,name=ibc_port_id,json=ibcPortId,proto3" json:"ibc_port_id,omitempty"` + // Extension is an extension point to store custom metadata within the + // persistence model. + Extension *types.Any `protobuf:"bytes,7,opt,name=extension,proto3" json:"extension,omitempty"` +} + +func (m *ContractInfo) Reset() { *m = ContractInfo{} } +func (m *ContractInfo) String() string { return proto.CompactTextString(m) } +func (*ContractInfo) ProtoMessage() {} +func (*ContractInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{4} +} +func (m *ContractInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractInfo.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 *ContractInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractInfo.Merge(m, src) +} +func (m *ContractInfo) XXX_Size() int { + return m.Size() +} +func (m *ContractInfo) XXX_DiscardUnknown() { + xxx_messageInfo_ContractInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractInfo proto.InternalMessageInfo + +// ContractCodeHistoryEntry metadata to a contract. +type ContractCodeHistoryEntry struct { + Operation ContractCodeHistoryOperationType `protobuf:"varint,1,opt,name=operation,proto3,enum=cosmwasm.wasm.v1.ContractCodeHistoryOperationType" json:"operation,omitempty"` + // CodeID is the reference to the stored WASM code + CodeID uint64 `protobuf:"varint,2,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` + // Updated Tx position when the operation was executed. + Updated *AbsoluteTxPosition `protobuf:"bytes,3,opt,name=updated,proto3" json:"updated,omitempty"` + Msg RawContractMessage `protobuf:"bytes,4,opt,name=msg,proto3,casttype=RawContractMessage" json:"msg,omitempty"` +} + +func (m *ContractCodeHistoryEntry) Reset() { *m = ContractCodeHistoryEntry{} } +func (m *ContractCodeHistoryEntry) String() string { return proto.CompactTextString(m) } +func (*ContractCodeHistoryEntry) ProtoMessage() {} +func (*ContractCodeHistoryEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{5} +} +func (m *ContractCodeHistoryEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ContractCodeHistoryEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ContractCodeHistoryEntry.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 *ContractCodeHistoryEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_ContractCodeHistoryEntry.Merge(m, src) +} +func (m *ContractCodeHistoryEntry) XXX_Size() int { + return m.Size() +} +func (m *ContractCodeHistoryEntry) XXX_DiscardUnknown() { + xxx_messageInfo_ContractCodeHistoryEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_ContractCodeHistoryEntry proto.InternalMessageInfo + +// AbsoluteTxPosition is a unique transaction position that allows for global +// ordering of transactions. +type AbsoluteTxPosition struct { + // BlockHeight is the block the contract was created at + BlockHeight uint64 `protobuf:"varint,1,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` + // TxIndex is a monotonic counter within the block (actual transaction index, + // or gas consumed) + TxIndex uint64 `protobuf:"varint,2,opt,name=tx_index,json=txIndex,proto3" json:"tx_index,omitempty"` +} + +func (m *AbsoluteTxPosition) Reset() { *m = AbsoluteTxPosition{} } +func (m *AbsoluteTxPosition) String() string { return proto.CompactTextString(m) } +func (*AbsoluteTxPosition) ProtoMessage() {} +func (*AbsoluteTxPosition) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{6} +} +func (m *AbsoluteTxPosition) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AbsoluteTxPosition) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AbsoluteTxPosition.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 *AbsoluteTxPosition) XXX_Merge(src proto.Message) { + xxx_messageInfo_AbsoluteTxPosition.Merge(m, src) +} +func (m *AbsoluteTxPosition) XXX_Size() int { + return m.Size() +} +func (m *AbsoluteTxPosition) XXX_DiscardUnknown() { + xxx_messageInfo_AbsoluteTxPosition.DiscardUnknown(m) +} + +var xxx_messageInfo_AbsoluteTxPosition proto.InternalMessageInfo + +// Model is a struct that holds a KV pair +type Model struct { + // hex-encode key to read it better (this is often ascii) + Key github_com_tendermint_tendermint_libs_bytes.HexBytes `protobuf:"bytes,1,opt,name=key,proto3,casttype=github.com/tendermint/tendermint/libs/bytes.HexBytes" json:"key,omitempty"` + // base64-encode raw value + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *Model) Reset() { *m = Model{} } +func (m *Model) String() string { return proto.CompactTextString(m) } +func (*Model) ProtoMessage() {} +func (*Model) Descriptor() ([]byte, []int) { + return fileDescriptor_c24c3aad44b115ab, []int{7} +} +func (m *Model) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Model) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Model.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 *Model) XXX_Merge(src proto.Message) { + xxx_messageInfo_Model.Merge(m, src) +} +func (m *Model) XXX_Size() int { + return m.Size() +} +func (m *Model) XXX_DiscardUnknown() { + xxx_messageInfo_Model.DiscardUnknown(m) +} + +var xxx_messageInfo_Model proto.InternalMessageInfo + +func init() { + proto.RegisterEnum("cosmwasm.wasm.v1.AccessType", AccessType_name, AccessType_value) + proto.RegisterEnum("cosmwasm.wasm.v1.ContractCodeHistoryOperationType", ContractCodeHistoryOperationType_name, ContractCodeHistoryOperationType_value) + proto.RegisterType((*AccessTypeParam)(nil), "cosmwasm.wasm.v1.AccessTypeParam") + proto.RegisterType((*AccessConfig)(nil), "cosmwasm.wasm.v1.AccessConfig") + proto.RegisterType((*Params)(nil), "cosmwasm.wasm.v1.Params") + proto.RegisterType((*CodeInfo)(nil), "cosmwasm.wasm.v1.CodeInfo") + proto.RegisterType((*ContractInfo)(nil), "cosmwasm.wasm.v1.ContractInfo") + proto.RegisterType((*ContractCodeHistoryEntry)(nil), "cosmwasm.wasm.v1.ContractCodeHistoryEntry") + proto.RegisterType((*AbsoluteTxPosition)(nil), "cosmwasm.wasm.v1.AbsoluteTxPosition") + proto.RegisterType((*Model)(nil), "cosmwasm.wasm.v1.Model") +} + +func init() { proto.RegisterFile("wasm/v1/types.proto", fileDescriptor_c24c3aad44b115ab) } + +var fileDescriptor_c24c3aad44b115ab = []byte{ + // 1180 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x56, 0xcd, 0x8f, 0xdb, 0x44, + 0x14, 0x8f, 0x93, 0xec, 0x47, 0xa6, 0x4b, 0x71, 0xa7, 0xbb, 0x34, 0x1b, 0x56, 0x49, 0x6a, 0x8a, + 0xd8, 0x7e, 0x25, 0x74, 0x41, 0x80, 0x7a, 0xa8, 0x14, 0x27, 0x6e, 0xd7, 0x2b, 0x36, 0x8e, 0x26, + 0x29, 0x68, 0x91, 0x2a, 0xcb, 0xb1, 0x67, 0xb3, 0xa3, 0x3a, 0x9e, 0xc8, 0x33, 0xd9, 0xc6, 0xff, + 0x01, 0x8a, 0x84, 0xe0, 0xc8, 0x25, 0x12, 0x02, 0x84, 0xca, 0x9d, 0x2b, 0xf7, 0x0a, 0x2e, 0x3d, + 0x72, 0x8a, 0x60, 0x7b, 0xe1, 0x9c, 0x63, 0xb9, 0x20, 0x8f, 0x93, 0xc6, 0xf4, 0x6b, 0xc3, 0x25, + 0x9a, 0x79, 0xef, 0xfd, 0x7e, 0xef, 0xbd, 0xdf, 0xbc, 0x67, 0x05, 0x9c, 0x7f, 0x60, 0xb1, 0x6e, + 0xf9, 0xf8, 0x46, 0x99, 0x07, 0x3d, 0xcc, 0x4a, 0x3d, 0x9f, 0x72, 0x0a, 0x65, 0x9b, 0xb2, 0x6e, + 0xe8, 0x28, 0x89, 0x9f, 0xe3, 0x1b, 0xb9, 0xcd, 0xd0, 0x42, 0x99, 0x29, 0xfc, 0xe5, 0xe8, 0x12, + 0x05, 0xe7, 0xd6, 0x3b, 0xb4, 0x43, 0x23, 0x7b, 0x78, 0x9a, 0x5a, 0x37, 0x3b, 0x94, 0x76, 0x5c, + 0x5c, 0x16, 0xb7, 0x76, 0xff, 0xb0, 0x6c, 0x79, 0x41, 0xe4, 0x52, 0xee, 0x81, 0x37, 0x2b, 0xb6, + 0x8d, 0x19, 0x6b, 0x05, 0x3d, 0xdc, 0xb0, 0x7c, 0xab, 0x0b, 0x6b, 0x60, 0xe9, 0xd8, 0x72, 0xfb, + 0x38, 0x2b, 0x15, 0xa5, 0xed, 0xb3, 0x3b, 0x5b, 0xa5, 0xe7, 0x0b, 0x28, 0xcd, 0x11, 0xaa, 0x3c, + 0x19, 0x17, 0xd6, 0x02, 0xab, 0xeb, 0xde, 0x54, 0x04, 0x48, 0x41, 0x11, 0xf8, 0x66, 0xfa, 0xdb, + 0xef, 0x0a, 0x92, 0xf2, 0xbb, 0x04, 0xd6, 0xa2, 0xe8, 0x2a, 0xf5, 0x0e, 0x49, 0x07, 0x36, 0x01, + 0xe8, 0x61, 0xbf, 0x4b, 0x18, 0x23, 0xd4, 0x5b, 0x28, 0xc3, 0xc6, 0x64, 0x5c, 0x38, 0x17, 0x65, + 0x98, 0x23, 0x15, 0x14, 0xa3, 0x81, 0xd7, 0xc0, 0x8a, 0xe5, 0x38, 0x3e, 0x66, 0x2c, 0x9b, 0x2c, + 0x4a, 0xdb, 0x19, 0x15, 0x4e, 0xc6, 0x85, 0xb3, 0x11, 0x66, 0xea, 0x50, 0xd0, 0x2c, 0x04, 0xee, + 0x80, 0xcc, 0xf4, 0x88, 0x59, 0x36, 0x55, 0x4c, 0x6d, 0x67, 0xd4, 0xf5, 0xc9, 0xb8, 0x20, 0xff, + 0x27, 0x1e, 0x33, 0x05, 0xcd, 0xc3, 0xa6, 0xdd, 0x7c, 0x9d, 0x04, 0xcb, 0x42, 0x23, 0x06, 0x29, + 0x80, 0x36, 0x75, 0xb0, 0xd9, 0xef, 0xb9, 0xd4, 0x72, 0x4c, 0x4b, 0xd4, 0x2b, 0xfa, 0x39, 0xb3, + 0x93, 0x7f, 0x55, 0x3f, 0x91, 0x06, 0xea, 0xc5, 0x47, 0xe3, 0x42, 0x62, 0x32, 0x2e, 0x6c, 0x46, + 0x19, 0x5f, 0xe4, 0x51, 0x90, 0x1c, 0x1a, 0xef, 0x0a, 0x5b, 0x04, 0x85, 0x5f, 0x49, 0x20, 0x4f, + 0x3c, 0xc6, 0x2d, 0x8f, 0x13, 0x8b, 0x63, 0xd3, 0xc1, 0x87, 0x56, 0xdf, 0xe5, 0x66, 0x4c, 0xcd, + 0xe4, 0x02, 0x6a, 0x5e, 0x9e, 0x8c, 0x0b, 0xef, 0x46, 0x79, 0x5f, 0xcf, 0xa6, 0xa0, 0xad, 0x58, + 0x40, 0x2d, 0xf2, 0x37, 0x9e, 0xb9, 0x85, 0x22, 0x09, 0xe5, 0x7b, 0x09, 0xac, 0x56, 0xa9, 0x83, + 0x75, 0xef, 0x90, 0xc2, 0xb7, 0x41, 0x46, 0xf4, 0x72, 0x64, 0xb1, 0x23, 0x21, 0xc5, 0x1a, 0x5a, + 0x0d, 0x0d, 0xbb, 0x16, 0x3b, 0x82, 0x59, 0xb0, 0x62, 0xfb, 0xd8, 0xe2, 0xd4, 0x8f, 0xde, 0x08, + 0xcd, 0xae, 0xb0, 0x09, 0x60, 0xbc, 0x14, 0x5b, 0x88, 0x94, 0x5d, 0x5a, 0x48, 0xca, 0x74, 0x28, + 0x25, 0x3a, 0x17, 0xc3, 0x47, 0x8e, 0xbd, 0xf4, 0x6a, 0x4a, 0x4e, 0xef, 0xa5, 0x57, 0xd3, 0xf2, + 0x92, 0xf2, 0x6b, 0x12, 0xac, 0x55, 0xa9, 0xc7, 0x7d, 0xcb, 0xe6, 0xa2, 0xd0, 0x77, 0xc0, 0x8a, + 0x28, 0x94, 0x38, 0xa2, 0xcc, 0xb4, 0x0a, 0x4e, 0xc6, 0x85, 0x65, 0xd1, 0x47, 0x0d, 0x2d, 0x87, + 0x2e, 0xdd, 0x79, 0x4d, 0xc1, 0xeb, 0x60, 0xc9, 0x72, 0xba, 0xc4, 0xcb, 0xa6, 0x84, 0x3d, 0xba, + 0x84, 0x56, 0xd7, 0x6a, 0x63, 0x37, 0x9b, 0x8e, 0xac, 0xe2, 0x02, 0x6f, 0x4d, 0x59, 0xb0, 0x33, + 0xed, 0xe8, 0xd2, 0x4b, 0x3a, 0x6a, 0x33, 0xea, 0xf6, 0x39, 0x6e, 0x0d, 0x1a, 0x94, 0x11, 0x4e, + 0xa8, 0x87, 0x66, 0x20, 0x78, 0x1d, 0x9c, 0x21, 0x6d, 0xdb, 0xec, 0x51, 0x9f, 0x87, 0xe5, 0x2e, + 0x8b, 0xf1, 0x7e, 0xe3, 0x64, 0x5c, 0xc8, 0xe8, 0x6a, 0xb5, 0x41, 0x7d, 0xae, 0xd7, 0x50, 0x86, + 0xb4, 0x6d, 0x71, 0x74, 0xe0, 0x3e, 0xc8, 0xe0, 0x01, 0xc7, 0x9e, 0x98, 0x87, 0x15, 0x91, 0x70, + 0xbd, 0x14, 0x6d, 0x7f, 0x69, 0xb6, 0xfd, 0xa5, 0x8a, 0x17, 0xa8, 0x9b, 0xbf, 0xfd, 0x72, 0x7d, + 0x23, 0x2e, 0x8a, 0x36, 0x83, 0xa1, 0x39, 0xc3, 0xcd, 0xf4, 0xdf, 0xe1, 0xd8, 0xff, 0x23, 0x81, + 0xec, 0x2c, 0x34, 0x14, 0x69, 0x97, 0x30, 0x4e, 0xfd, 0x40, 0xf3, 0xb8, 0x1f, 0xc0, 0x06, 0xc8, + 0xd0, 0x1e, 0xf6, 0x2d, 0x3e, 0xdf, 0xe7, 0x9d, 0x17, 0x5b, 0x7c, 0x09, 0xdc, 0x98, 0xa1, 0xc2, + 0xb9, 0x44, 0x73, 0x92, 0xf8, 0xeb, 0x24, 0x5f, 0xf9, 0x3a, 0xb7, 0xc0, 0x4a, 0xbf, 0xe7, 0x08, + 0x5d, 0x53, 0xff, 0x47, 0xd7, 0x29, 0x08, 0x6e, 0x83, 0x54, 0x97, 0x75, 0xc4, 0x5b, 0xad, 0xa9, + 0x6f, 0x3d, 0x1d, 0x17, 0x20, 0xb2, 0x1e, 0xcc, 0xaa, 0xdc, 0xc7, 0x8c, 0x59, 0x1d, 0x8c, 0xc2, + 0x10, 0x05, 0x01, 0xf8, 0x22, 0x11, 0xbc, 0x08, 0xd6, 0xda, 0x2e, 0xb5, 0xef, 0x9b, 0x47, 0x98, + 0x74, 0x8e, 0x78, 0x34, 0x47, 0xe8, 0x8c, 0xb0, 0xed, 0x0a, 0x13, 0xdc, 0x04, 0xab, 0x7c, 0x60, + 0x12, 0xcf, 0xc1, 0x83, 0xa8, 0x11, 0xb4, 0xc2, 0x07, 0x7a, 0x78, 0x55, 0x08, 0x58, 0xda, 0xa7, + 0x0e, 0x76, 0xe1, 0x1e, 0x48, 0xdd, 0xc7, 0x41, 0xb4, 0x2c, 0xea, 0x27, 0x4f, 0xc7, 0x85, 0x0f, + 0x3b, 0x84, 0x1f, 0xf5, 0xdb, 0x25, 0x9b, 0x76, 0xcb, 0x1c, 0x7b, 0x4e, 0xb8, 0x70, 0x1e, 0x8f, + 0x1f, 0x5d, 0xd2, 0x66, 0xe5, 0x76, 0xc0, 0x31, 0x2b, 0xed, 0xe2, 0x81, 0x1a, 0x1e, 0x50, 0x48, + 0x12, 0x0e, 0x60, 0xf4, 0xdd, 0x4e, 0x8a, 0xd5, 0x8b, 0x2e, 0x57, 0x7e, 0x4e, 0x02, 0x30, 0xdf, + 0x7f, 0xf8, 0x11, 0xb8, 0x50, 0xa9, 0x56, 0xb5, 0x66, 0xd3, 0x6c, 0x1d, 0x34, 0x34, 0xf3, 0x6e, + 0xbd, 0xd9, 0xd0, 0xaa, 0xfa, 0x6d, 0x5d, 0xab, 0xc9, 0x89, 0xdc, 0xe6, 0x70, 0x54, 0xdc, 0x98, + 0x07, 0xdf, 0xf5, 0x58, 0x0f, 0xdb, 0xe4, 0x90, 0x60, 0x07, 0x5e, 0x03, 0x30, 0x8e, 0xab, 0x1b, + 0xaa, 0x51, 0x3b, 0x90, 0xa5, 0xdc, 0xfa, 0x70, 0x54, 0x94, 0xe7, 0x90, 0x3a, 0x6d, 0x53, 0x27, + 0x80, 0x1f, 0x83, 0x6c, 0x3c, 0xda, 0xa8, 0x7f, 0x7a, 0x60, 0x56, 0x6a, 0x35, 0xa4, 0x35, 0x9b, + 0x72, 0xf2, 0xf9, 0x34, 0x86, 0xe7, 0x06, 0x95, 0x67, 0xdf, 0xe6, 0x8d, 0x38, 0x50, 0xfb, 0x4c, + 0x43, 0x07, 0x22, 0x53, 0x2a, 0x77, 0x61, 0x38, 0x2a, 0x9e, 0x9f, 0xa3, 0xb4, 0x63, 0xec, 0x07, + 0x22, 0xd9, 0x2d, 0xb0, 0x15, 0xc7, 0x54, 0xea, 0x07, 0xa6, 0x71, 0x7b, 0x96, 0x4e, 0x6b, 0xca, + 0xe9, 0xdc, 0xd6, 0x70, 0x54, 0xcc, 0xce, 0xa1, 0x15, 0x2f, 0x30, 0x0e, 0x2b, 0xb3, 0x6f, 0x7b, + 0x6e, 0xf5, 0xcb, 0x1f, 0xf2, 0x89, 0x87, 0x3f, 0xe6, 0x13, 0x57, 0x7e, 0x4a, 0x81, 0xe2, 0x69, + 0x93, 0x0a, 0x31, 0x78, 0xbf, 0x6a, 0xd4, 0x5b, 0xa8, 0x52, 0x6d, 0x99, 0x55, 0xa3, 0xa6, 0x99, + 0xbb, 0x7a, 0xb3, 0x65, 0xa0, 0x03, 0xd3, 0x68, 0x68, 0xa8, 0xd2, 0xd2, 0x8d, 0xfa, 0xcb, 0xa4, + 0x2d, 0x0f, 0x47, 0xc5, 0xab, 0xa7, 0x71, 0xc7, 0x05, 0xff, 0x1c, 0x5c, 0x5e, 0x28, 0x8d, 0x5e, + 0xd7, 0x5b, 0xb2, 0x94, 0xdb, 0x1e, 0x8e, 0x8a, 0x97, 0x4e, 0xe3, 0xd7, 0x3d, 0xc2, 0xe1, 0x3d, + 0x70, 0x6d, 0x21, 0xe2, 0x7d, 0xfd, 0x0e, 0xaa, 0xb4, 0x34, 0x39, 0x99, 0xbb, 0x3a, 0x1c, 0x15, + 0xdf, 0x3b, 0x8d, 0x7b, 0x9f, 0x74, 0x7c, 0x8b, 0xe3, 0x85, 0xe9, 0xef, 0x68, 0x75, 0xad, 0xa9, + 0x37, 0xe5, 0xd4, 0x62, 0xf4, 0x77, 0xb0, 0x87, 0x19, 0x61, 0xb9, 0x74, 0xf8, 0x58, 0xea, 0xde, + 0xa3, 0xbf, 0xf2, 0x89, 0x87, 0x27, 0x79, 0xe9, 0xd1, 0x49, 0x5e, 0x7a, 0x7c, 0x92, 0x97, 0xfe, + 0x3c, 0xc9, 0x4b, 0xdf, 0x3c, 0xc9, 0x27, 0x1e, 0x3f, 0xc9, 0x27, 0xfe, 0x78, 0x92, 0x4f, 0x7c, + 0xb1, 0x1d, 0xdb, 0x23, 0x1b, 0xfb, 0xf6, 0x75, 0x42, 0xcb, 0xae, 0x65, 0x53, 0x8f, 0xd8, 0x4e, + 0x79, 0x50, 0x16, 0x7f, 0xb4, 0xc4, 0xbf, 0xac, 0xf6, 0xb2, 0xf8, 0x2e, 0x7e, 0xf0, 0x6f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x68, 0x19, 0x25, 0x5b, 0x7d, 0x09, 0x00, 0x00, +} + +func (this *AccessTypeParam) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*AccessTypeParam) + if !ok { + that2, ok := that.(AccessTypeParam) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Value != that1.Value { + return false + } + return true +} +func (this *AccessConfig) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*AccessConfig) + if !ok { + that2, ok := that.(AccessConfig) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Permission != that1.Permission { + return false + } + if this.Address != that1.Address { + return false + } + if len(this.Addresses) != len(that1.Addresses) { + return false + } + for i := range this.Addresses { + if this.Addresses[i] != that1.Addresses[i] { + return false + } + } + return true +} +func (this *Params) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Params) + if !ok { + that2, ok := that.(Params) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !this.CodeUploadAccess.Equal(&that1.CodeUploadAccess) { + return false + } + if this.InstantiateDefaultPermission != that1.InstantiateDefaultPermission { + return false + } + return true +} +func (this *CodeInfo) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*CodeInfo) + if !ok { + that2, ok := that.(CodeInfo) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.CodeHash, that1.CodeHash) { + return false + } + if this.Creator != that1.Creator { + return false + } + if !this.InstantiateConfig.Equal(&that1.InstantiateConfig) { + return false + } + return true +} +func (this *ContractInfo) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ContractInfo) + if !ok { + that2, ok := that.(ContractInfo) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if this.Creator != that1.Creator { + return false + } + if this.Admin != that1.Admin { + return false + } + if this.Label != that1.Label { + return false + } + if !this.Created.Equal(that1.Created) { + return false + } + if this.IBCPortID != that1.IBCPortID { + return false + } + if !this.Extension.Equal(that1.Extension) { + return false + } + return true +} +func (this *ContractCodeHistoryEntry) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*ContractCodeHistoryEntry) + if !ok { + that2, ok := that.(ContractCodeHistoryEntry) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Operation != that1.Operation { + return false + } + if this.CodeID != that1.CodeID { + return false + } + if !this.Updated.Equal(that1.Updated) { + return false + } + if !bytes.Equal(this.Msg, that1.Msg) { + return false + } + return true +} +func (this *AbsoluteTxPosition) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*AbsoluteTxPosition) + if !ok { + that2, ok := that.(AbsoluteTxPosition) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.BlockHeight != that1.BlockHeight { + return false + } + if this.TxIndex != that1.TxIndex { + return false + } + return true +} +func (this *Model) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*Model) + if !ok { + that2, ok := that.(Model) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if !bytes.Equal(this.Key, that1.Key) { + return false + } + if !bytes.Equal(this.Value, that1.Value) { + return false + } + return true +} +func (m *AccessTypeParam) 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 *AccessTypeParam) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessTypeParam) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Value != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Value)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AccessConfig) 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 *AccessConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccessConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Addresses) > 0 { + for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Addresses[iNdEx]) + copy(dAtA[i:], m.Addresses[iNdEx]) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Addresses[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x12 + } + if m.Permission != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Permission)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Params) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.InstantiateDefaultPermission != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.InstantiateDefaultPermission)) + i-- + dAtA[i] = 0x10 + } + { + size, err := m.CodeUploadAccess.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *CodeInfo) 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 *CodeInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *CodeInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.InstantiateConfig.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0x12 + } + if len(m.CodeHash) > 0 { + i -= len(m.CodeHash) + copy(dAtA[i:], m.CodeHash) + i = encodeVarintTypes(dAtA, i, uint64(len(m.CodeHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ContractInfo) 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 *ContractInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Extension != nil { + { + size, err := m.Extension.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } + if len(m.IBCPortID) > 0 { + i -= len(m.IBCPortID) + copy(dAtA[i:], m.IBCPortID) + i = encodeVarintTypes(dAtA, i, uint64(len(m.IBCPortID))) + i-- + dAtA[i] = 0x32 + } + if m.Created != nil { + { + size, err := m.Created.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if len(m.Label) > 0 { + i -= len(m.Label) + copy(dAtA[i:], m.Label) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Label))) + i-- + dAtA[i] = 0x22 + } + if len(m.Admin) > 0 { + i -= len(m.Admin) + copy(dAtA[i:], m.Admin) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Admin))) + i-- + dAtA[i] = 0x1a + } + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0x12 + } + if m.CodeID != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *ContractCodeHistoryEntry) 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 *ContractCodeHistoryEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ContractCodeHistoryEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x22 + } + if m.Updated != nil { + { + size, err := m.Updated.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTypes(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.CodeID != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.CodeID)) + i-- + dAtA[i] = 0x10 + } + if m.Operation != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.Operation)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *AbsoluteTxPosition) 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 *AbsoluteTxPosition) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AbsoluteTxPosition) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TxIndex != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.TxIndex)) + i-- + dAtA[i] = 0x10 + } + if m.BlockHeight != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.BlockHeight)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Model) 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 *Model) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Model) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Value) > 0 { + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintTypes(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTypes(dAtA []byte, offset int, v uint64) int { + offset -= sovTypes(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *AccessTypeParam) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Value != 0 { + n += 1 + sovTypes(uint64(m.Value)) + } + return n +} + +func (m *AccessConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Permission != 0 { + n += 1 + sovTypes(uint64(m.Permission)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if len(m.Addresses) > 0 { + for _, s := range m.Addresses { + l = len(s) + n += 1 + l + sovTypes(uint64(l)) + } + } + return n +} + +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.CodeUploadAccess.Size() + n += 1 + l + sovTypes(uint64(l)) + if m.InstantiateDefaultPermission != 0 { + n += 1 + sovTypes(uint64(m.InstantiateDefaultPermission)) + } + return n +} + +func (m *CodeInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.CodeHash) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = m.InstantiateConfig.Size() + n += 1 + l + sovTypes(uint64(l)) + return n +} + +func (m *ContractInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CodeID != 0 { + n += 1 + sovTypes(uint64(m.CodeID)) + } + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Admin) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Label) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.Created != nil { + l = m.Created.Size() + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.IBCPortID) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + if m.Extension != nil { + l = m.Extension.Size() + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *ContractCodeHistoryEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Operation != 0 { + n += 1 + sovTypes(uint64(m.Operation)) + } + if m.CodeID != 0 { + n += 1 + sovTypes(uint64(m.CodeID)) + } + if m.Updated != nil { + l = m.Updated.Size() + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func (m *AbsoluteTxPosition) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.BlockHeight != 0 { + n += 1 + sovTypes(uint64(m.BlockHeight)) + } + if m.TxIndex != 0 { + n += 1 + sovTypes(uint64(m.TxIndex)) + } + return n +} + +func (m *Model) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + l = len(m.Value) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } + return n +} + +func sovTypes(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTypes(x uint64) (n int) { + return sovTypes(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *AccessTypeParam) 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 ErrIntOverflowTypes + } + 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: AccessTypeParam: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessTypeParam: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + m.Value = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Value |= AccessType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccessConfig) 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 ErrIntOverflowTypes + } + 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: AccessConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccessConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permission", wireType) + } + m.Permission = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permission |= AccessType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + 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 ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addresses = append(m.Addresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Params) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeUploadAccess", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.CodeUploadAccess.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiateDefaultPermission", wireType) + } + m.InstantiateDefaultPermission = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InstantiateDefaultPermission |= AccessType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *CodeInfo) 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 ErrIntOverflowTypes + } + 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: CodeInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CodeInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CodeHash = append(m.CodeHash[:0], dAtA[iNdEx:postIndex]...) + if m.CodeHash == nil { + m.CodeHash = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InstantiateConfig", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InstantiateConfig.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractInfo) 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 ErrIntOverflowTypes + } + 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: ContractInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Admin", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Admin = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Label", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Label = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Created", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Created == nil { + m.Created = &AbsoluteTxPosition{} + } + if err := m.Created.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IBCPortID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + 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 ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IBCPortID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Extension", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Extension == nil { + m.Extension = &types.Any{} + } + if err := m.Extension.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ContractCodeHistoryEntry) 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 ErrIntOverflowTypes + } + 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: ContractCodeHistoryEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ContractCodeHistoryEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Operation", wireType) + } + m.Operation = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Operation |= ContractCodeHistoryOperationType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CodeID", wireType) + } + m.CodeID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CodeID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Updated", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Updated == nil { + m.Updated = &AbsoluteTxPosition{} + } + if err := m.Updated.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = append(m.Msg[:0], dAtA[iNdEx:postIndex]...) + if m.Msg == nil { + m.Msg = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AbsoluteTxPosition) 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 ErrIntOverflowTypes + } + 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: AbsoluteTxPosition: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AbsoluteTxPosition: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field BlockHeight", wireType) + } + m.BlockHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.BlockHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TxIndex", wireType) + } + m.TxIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TxIndex |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Model) 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 ErrIntOverflowTypes + } + 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: Model: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Model: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Value = append(m.Value[:0], dAtA[iNdEx:postIndex]...) + if m.Value == nil { + m.Value = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTypes(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTypes + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTypes(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, ErrIntOverflowTypes + } + 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, ErrIntOverflowTypes + } + 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, ErrIntOverflowTypes + } + 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, ErrInvalidLengthTypes + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTypes + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTypes + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTypes = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTypes = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTypes = fmt.Errorf("proto: unexpected end of group") +) From 290c9fbf0c29011e5d1a1c932dd962152f5a35ef Mon Sep 17 00:00:00 2001 From: aleem1314 Date: Tue, 28 Feb 2023 15:05:49 +0530 Subject: [PATCH 2/3] wip: port wasm module --- x/wasm/Governance.md | 205 ++ x/wasm/IBC.md | 137 + x/wasm/README.md | 219 ++ x/wasm/alias.go | 133 + x/wasm/client/cli/gov_tx.go | 834 ++++++ x/wasm/client/cli/gov_tx_test.go | 158 ++ x/wasm/client/cli/new_tx.go | 163 ++ x/wasm/client/cli/query.go | 674 +++++ x/wasm/client/cli/tx.go | 544 ++++ x/wasm/client/cli/tx_test.go | 59 + x/wasm/client/proposal_handler.go | 25 + x/wasm/client/proposal_handler_test.go | 381 +++ x/wasm/client/rest/gov.go | 547 ++++ x/wasm/client/rest/new_tx.go | 86 + x/wasm/client/rest/query.go | 270 ++ x/wasm/client/rest/rest.go | 15 + x/wasm/client/rest/tx.go | 149 + x/wasm/common_test.go | 34 + x/wasm/genesis_test.go | 96 + x/wasm/handler.go | 77 + x/wasm/ibc.go | 357 +++ x/wasm/ibc_integration_test.go | 126 + x/wasm/ibc_reflect_test.go | 124 + x/wasm/ibc_test.go | 82 + x/wasm/ibctesting/README.md | 2 + x/wasm/ibctesting/chain.go | 594 ++++ x/wasm/ibctesting/coordinator.go | 317 +++ x/wasm/ibctesting/endpoint.go | 597 ++++ x/wasm/ibctesting/event_utils.go | 118 + x/wasm/ibctesting/faucet.go | 52 + x/wasm/ibctesting/path.go | 113 + x/wasm/ibctesting/wasm.go | 138 + x/wasm/ioutils/ioutil.go | 41 + x/wasm/ioutils/ioutil_test.go | 82 + x/wasm/ioutils/utils.go | 43 + x/wasm/ioutils/utils_test.go | 68 + x/wasm/keeper/addresses.go | 76 + x/wasm/keeper/addresses_test.go | 432 +++ x/wasm/keeper/ante.go | 96 + x/wasm/keeper/ante_test.go | 189 ++ x/wasm/keeper/api.go | 43 + x/wasm/keeper/authz_policy.go | 63 + x/wasm/keeper/authz_policy_test.go | 345 +++ x/wasm/keeper/bench_test.go | 102 + x/wasm/keeper/contract_keeper.go | 130 + x/wasm/keeper/contract_keeper_test.go | 168 ++ x/wasm/keeper/events.go | 67 + x/wasm/keeper/events_test.go | 290 ++ x/wasm/keeper/gas_register.go | 252 ++ x/wasm/keeper/gas_register_test.go | 472 ++++ x/wasm/keeper/genesis.go | 116 + x/wasm/keeper/genesis_test.go | 671 +++++ x/wasm/keeper/handler_plugin.go | 226 ++ x/wasm/keeper/handler_plugin_encoders.go | 393 +++ x/wasm/keeper/handler_plugin_encoders_test.go | 932 +++++++ x/wasm/keeper/handler_plugin_test.go | 410 +++ x/wasm/keeper/ibc.go | 56 + x/wasm/keeper/ibc_test.go | 82 + x/wasm/keeper/keeper.go | 1188 ++++++++ x/wasm/keeper/keeper_cgo.go | 69 + x/wasm/keeper/keeper_no_cgo.go | 35 + x/wasm/keeper/keeper_test.go | 2410 +++++++++++++++++ x/wasm/keeper/legacy_querier.go | 154 ++ x/wasm/keeper/legacy_querier_test.go | 364 +++ x/wasm/keeper/metrics.go | 72 + x/wasm/keeper/migrate_test.go | 61 + x/wasm/keeper/migrations.go | 27 + x/wasm/keeper/msg_dispatcher.go | 222 ++ x/wasm/keeper/msg_dispatcher_test.go | 426 +++ x/wasm/keeper/msg_server.go | 256 ++ x/wasm/keeper/msg_server_integration_test.go | 46 + x/wasm/keeper/options.go | 170 ++ x/wasm/keeper/options_test.go | 116 + x/wasm/keeper/proposal_handler.go | 326 +++ x/wasm/keeper/proposal_integration_test.go | 1001 +++++++ x/wasm/keeper/querier.go | 346 +++ x/wasm/keeper/querier_test.go | 917 +++++++ x/wasm/keeper/query_plugins.go | 614 +++++ x/wasm/keeper/query_plugins_test.go | 825 ++++++ x/wasm/keeper/recurse_test.go | 306 +++ x/wasm/keeper/reflect_test.go | 665 +++++ x/wasm/keeper/relay.go | 203 ++ x/wasm/keeper/relay_test.go | 703 +++++ x/wasm/keeper/snapshotter.go | 156 ++ x/wasm/keeper/snapshotter_integration_test.go | 124 + x/wasm/keeper/staking_test.go | 748 +++++ x/wasm/keeper/submsg_test.go | 552 ++++ x/wasm/keeper/test_common.go | 759 ++++++ x/wasm/keeper/test_fuzz.go | 76 + x/wasm/keeper/testdata/broken_crc.gzip | Bin 0 -> 809232 bytes x/wasm/keeper/testdata/burner.wasm | Bin 0 -> 127528 bytes x/wasm/keeper/testdata/download_releases.sh | 23 + x/wasm/keeper/testdata/genesis.json | 219 ++ x/wasm/keeper/testdata/hackatom.wasm | Bin 0 -> 177474 bytes x/wasm/keeper/testdata/hackatom.wasm.gzip | Bin 0 -> 64560 bytes x/wasm/keeper/testdata/ibc_reflect.wasm | Bin 0 -> 254798 bytes x/wasm/keeper/testdata/ibc_reflect_send.wasm | Bin 0 -> 269429 bytes x/wasm/keeper/testdata/reflect.go | 69 + x/wasm/keeper/testdata/reflect.wasm | Bin 0 -> 257191 bytes x/wasm/keeper/testdata/reflect.wasm.v1_0 | Bin 0 -> 262794 bytes x/wasm/keeper/testdata/reflect_1_1.wasm | Bin 0 -> 257047 bytes x/wasm/keeper/testdata/staking.wasm | Bin 0 -> 222166 bytes x/wasm/keeper/testdata/version.txt | 1 + x/wasm/keeper/wasmtesting/extension_mocks.go | 28 + x/wasm/keeper/wasmtesting/gas_register.go | 74 + x/wasm/keeper/wasmtesting/message_router.go | 27 + x/wasm/keeper/wasmtesting/messenger.go | 38 + x/wasm/keeper/wasmtesting/mock_engine.go | 401 +++ x/wasm/keeper/wasmtesting/mock_keepers.go | 120 + x/wasm/keeper/wasmtesting/msg_dispatcher.go | 17 + x/wasm/keeper/wasmtesting/query_handler.go | 17 + x/wasm/keeper/wasmtesting/store.go | 26 + x/wasm/module.go | 311 +++ x/wasm/module_integration_test.go | 31 + x/wasm/module_test.go | 587 ++++ x/wasm/relay_pingpong_test.go | 396 +++ x/wasm/relay_test.go | 808 ++++++ x/wasm/simulation/genesis.go | 27 + x/wasm/simulation/operations.go | 551 ++++ x/wasm/simulation/params.go | 32 + x/wasm/simulation/proposals.go | 406 +++ x/wasm/simulation/sim_utils.go | 53 + x/wasm/testdata/escrow_0.7.wasm | Bin 0 -> 91577 bytes x/wasm/types/ante.go | 24 + x/wasm/types/authz.go | 534 ++++ x/wasm/types/authz_test.go | 728 +++++ x/wasm/types/codec.go | 122 + x/wasm/types/errors.go | 150 + x/wasm/types/errors_test.go | 86 + x/wasm/types/events.go | 34 + x/wasm/types/expected_keepers.go | 106 + x/wasm/types/exported_keepers.go | 119 + x/wasm/types/feature_flag.go | 4 + x/wasm/types/genesis.go | 102 + x/wasm/types/genesis_test.go | 211 ++ x/wasm/types/iavl_range_test.go | 83 + x/wasm/types/json_matching.go | 34 + x/wasm/types/json_matching_test.go | 134 + x/wasm/types/keys.go | 131 + x/wasm/types/keys_test.go | 147 + x/wasm/types/params.go | 227 ++ x/wasm/types/params_test.go | 306 +++ x/wasm/types/proposal.go | 996 +++++++ x/wasm/types/proposal_test.go | 1141 ++++++++ x/wasm/types/test_fixtures.go | 443 +++ x/wasm/types/tx.go | 447 +++ x/wasm/types/tx_test.go | 751 +++++ x/wasm/types/types.go | 398 +++ x/wasm/types/types_test.go | 747 +++++ x/wasm/types/validation.go | 79 + x/wasm/types/wasmer_engine.go | 241 ++ 151 files changed, 39995 insertions(+) create mode 100644 x/wasm/Governance.md create mode 100644 x/wasm/IBC.md create mode 100644 x/wasm/README.md create mode 100644 x/wasm/alias.go create mode 100644 x/wasm/client/cli/gov_tx.go create mode 100644 x/wasm/client/cli/gov_tx_test.go create mode 100644 x/wasm/client/cli/new_tx.go create mode 100644 x/wasm/client/cli/query.go create mode 100644 x/wasm/client/cli/tx.go create mode 100644 x/wasm/client/cli/tx_test.go create mode 100644 x/wasm/client/proposal_handler.go create mode 100644 x/wasm/client/proposal_handler_test.go create mode 100644 x/wasm/client/rest/gov.go create mode 100644 x/wasm/client/rest/new_tx.go create mode 100644 x/wasm/client/rest/query.go create mode 100644 x/wasm/client/rest/rest.go create mode 100644 x/wasm/client/rest/tx.go create mode 100644 x/wasm/common_test.go create mode 100644 x/wasm/genesis_test.go create mode 100644 x/wasm/handler.go create mode 100644 x/wasm/ibc.go create mode 100644 x/wasm/ibc_integration_test.go create mode 100644 x/wasm/ibc_reflect_test.go create mode 100644 x/wasm/ibc_test.go create mode 100644 x/wasm/ibctesting/README.md create mode 100644 x/wasm/ibctesting/chain.go create mode 100644 x/wasm/ibctesting/coordinator.go create mode 100644 x/wasm/ibctesting/endpoint.go create mode 100644 x/wasm/ibctesting/event_utils.go create mode 100644 x/wasm/ibctesting/faucet.go create mode 100644 x/wasm/ibctesting/path.go create mode 100644 x/wasm/ibctesting/wasm.go create mode 100644 x/wasm/ioutils/ioutil.go create mode 100644 x/wasm/ioutils/ioutil_test.go create mode 100644 x/wasm/ioutils/utils.go create mode 100644 x/wasm/ioutils/utils_test.go create mode 100644 x/wasm/keeper/addresses.go create mode 100644 x/wasm/keeper/addresses_test.go create mode 100644 x/wasm/keeper/ante.go create mode 100644 x/wasm/keeper/ante_test.go create mode 100644 x/wasm/keeper/api.go create mode 100644 x/wasm/keeper/authz_policy.go create mode 100644 x/wasm/keeper/authz_policy_test.go create mode 100644 x/wasm/keeper/bench_test.go create mode 100644 x/wasm/keeper/contract_keeper.go create mode 100644 x/wasm/keeper/contract_keeper_test.go create mode 100644 x/wasm/keeper/events.go create mode 100644 x/wasm/keeper/events_test.go create mode 100644 x/wasm/keeper/gas_register.go create mode 100644 x/wasm/keeper/gas_register_test.go create mode 100644 x/wasm/keeper/genesis.go create mode 100644 x/wasm/keeper/genesis_test.go create mode 100644 x/wasm/keeper/handler_plugin.go create mode 100644 x/wasm/keeper/handler_plugin_encoders.go create mode 100644 x/wasm/keeper/handler_plugin_encoders_test.go create mode 100644 x/wasm/keeper/handler_plugin_test.go create mode 100644 x/wasm/keeper/ibc.go create mode 100644 x/wasm/keeper/ibc_test.go create mode 100644 x/wasm/keeper/keeper.go create mode 100644 x/wasm/keeper/keeper_cgo.go create mode 100644 x/wasm/keeper/keeper_no_cgo.go create mode 100644 x/wasm/keeper/keeper_test.go create mode 100644 x/wasm/keeper/legacy_querier.go create mode 100644 x/wasm/keeper/legacy_querier_test.go create mode 100644 x/wasm/keeper/metrics.go create mode 100644 x/wasm/keeper/migrate_test.go create mode 100644 x/wasm/keeper/migrations.go create mode 100644 x/wasm/keeper/msg_dispatcher.go create mode 100644 x/wasm/keeper/msg_dispatcher_test.go create mode 100644 x/wasm/keeper/msg_server.go create mode 100644 x/wasm/keeper/msg_server_integration_test.go create mode 100644 x/wasm/keeper/options.go create mode 100644 x/wasm/keeper/options_test.go create mode 100644 x/wasm/keeper/proposal_handler.go create mode 100644 x/wasm/keeper/proposal_integration_test.go create mode 100644 x/wasm/keeper/querier.go create mode 100644 x/wasm/keeper/querier_test.go create mode 100644 x/wasm/keeper/query_plugins.go create mode 100644 x/wasm/keeper/query_plugins_test.go create mode 100644 x/wasm/keeper/recurse_test.go create mode 100644 x/wasm/keeper/reflect_test.go create mode 100644 x/wasm/keeper/relay.go create mode 100644 x/wasm/keeper/relay_test.go create mode 100644 x/wasm/keeper/snapshotter.go create mode 100644 x/wasm/keeper/snapshotter_integration_test.go create mode 100644 x/wasm/keeper/staking_test.go create mode 100644 x/wasm/keeper/submsg_test.go create mode 100644 x/wasm/keeper/test_common.go create mode 100644 x/wasm/keeper/test_fuzz.go create mode 100644 x/wasm/keeper/testdata/broken_crc.gzip create mode 100644 x/wasm/keeper/testdata/burner.wasm create mode 100755 x/wasm/keeper/testdata/download_releases.sh create mode 100644 x/wasm/keeper/testdata/genesis.json create mode 100644 x/wasm/keeper/testdata/hackatom.wasm create mode 100644 x/wasm/keeper/testdata/hackatom.wasm.gzip create mode 100644 x/wasm/keeper/testdata/ibc_reflect.wasm create mode 100644 x/wasm/keeper/testdata/ibc_reflect_send.wasm create mode 100644 x/wasm/keeper/testdata/reflect.go create mode 100644 x/wasm/keeper/testdata/reflect.wasm create mode 100644 x/wasm/keeper/testdata/reflect.wasm.v1_0 create mode 100644 x/wasm/keeper/testdata/reflect_1_1.wasm create mode 100644 x/wasm/keeper/testdata/staking.wasm create mode 100644 x/wasm/keeper/testdata/version.txt create mode 100644 x/wasm/keeper/wasmtesting/extension_mocks.go create mode 100644 x/wasm/keeper/wasmtesting/gas_register.go create mode 100644 x/wasm/keeper/wasmtesting/message_router.go create mode 100644 x/wasm/keeper/wasmtesting/messenger.go create mode 100644 x/wasm/keeper/wasmtesting/mock_engine.go create mode 100644 x/wasm/keeper/wasmtesting/mock_keepers.go create mode 100644 x/wasm/keeper/wasmtesting/msg_dispatcher.go create mode 100644 x/wasm/keeper/wasmtesting/query_handler.go create mode 100644 x/wasm/keeper/wasmtesting/store.go create mode 100644 x/wasm/module.go create mode 100644 x/wasm/module_integration_test.go create mode 100644 x/wasm/module_test.go create mode 100644 x/wasm/relay_pingpong_test.go create mode 100644 x/wasm/relay_test.go create mode 100644 x/wasm/simulation/genesis.go create mode 100644 x/wasm/simulation/operations.go create mode 100644 x/wasm/simulation/params.go create mode 100644 x/wasm/simulation/proposals.go create mode 100644 x/wasm/simulation/sim_utils.go create mode 100644 x/wasm/testdata/escrow_0.7.wasm create mode 100644 x/wasm/types/ante.go create mode 100644 x/wasm/types/authz.go create mode 100644 x/wasm/types/authz_test.go create mode 100644 x/wasm/types/codec.go create mode 100644 x/wasm/types/errors.go create mode 100644 x/wasm/types/errors_test.go create mode 100644 x/wasm/types/events.go create mode 100644 x/wasm/types/expected_keepers.go create mode 100644 x/wasm/types/exported_keepers.go create mode 100644 x/wasm/types/feature_flag.go create mode 100644 x/wasm/types/genesis.go create mode 100644 x/wasm/types/genesis_test.go create mode 100644 x/wasm/types/iavl_range_test.go create mode 100644 x/wasm/types/json_matching.go create mode 100644 x/wasm/types/json_matching_test.go create mode 100644 x/wasm/types/keys.go create mode 100644 x/wasm/types/keys_test.go create mode 100644 x/wasm/types/params.go create mode 100644 x/wasm/types/params_test.go create mode 100644 x/wasm/types/proposal.go create mode 100644 x/wasm/types/proposal_test.go create mode 100644 x/wasm/types/test_fixtures.go create mode 100644 x/wasm/types/tx.go create mode 100644 x/wasm/types/tx_test.go create mode 100644 x/wasm/types/types.go create mode 100644 x/wasm/types/types_test.go create mode 100644 x/wasm/types/validation.go create mode 100644 x/wasm/types/wasmer_engine.go diff --git a/x/wasm/Governance.md b/x/wasm/Governance.md new file mode 100644 index 00000000..da47240c --- /dev/null +++ b/x/wasm/Governance.md @@ -0,0 +1,205 @@ +# Governance + +This document gives an overview of how the various governance +proposals interact with the CosmWasm contract lifecycle. It is +a high-level, technical introduction meant to provide context before +looking into the code, or constructing proposals. + +## Proposal Types +We have added 9 new wasm specific proposal types that cover the contract's live cycle and authorization: + +* `StoreCodeProposal` - upload a wasm binary +* `InstantiateContractProposal` - instantiate a wasm contract +* `MigrateContractProposal` - migrate a wasm contract to a new code version +* `SudoContractProposal` - call into the protected `sudo` entry point of a contract +* `ExecuteContractProposal` - execute a wasm contract as an arbitrary user +* `UpdateAdminProposal` - set a new admin for a contract +* `ClearAdminProposal` - clear admin for a contract to prevent further migrations +* `PinCodes` - pin the given code ids in cache. This trades memory for reduced startup time and lowers gas cost +* `UnpinCodes` - unpin the given code ids from the cache. This frees up memory and returns to standard speed and gas cost +* `UpdateInstantiateConfigProposal` - update instantiate permissions to a list of given code ids. +* `StoreAndInstantiateContractProposal` - upload and instantiate a wasm contract. + +For details see the proposal type [implementation](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/proposal.go) + +### Unit tests +[Proposal type validations](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/proposal_test.go) + +## Proposal Handler +The [wasmd proposal_handler](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/proposal_handler.go) implements the `gov.Handler` function +and executes the wasmd proposal types after a successful tally. + +The proposal handler uses a [`GovAuthorizationPolicy`](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/authz_policy.go#L29) to bypass the existing contract's authorization policy. + +### Tests +* [Integration: Submit and execute proposal](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/proposal_integration_test.go) + +## Gov Integration +The wasmd proposal handler can be added to the gov router in the [abci app](https://github.com/CosmWasm/wasmd/blob/master/app/app.go#L306) +to receive proposal execution calls. +```go +govRouter.AddRoute(wasm.RouterKey, wasm.NewWasmProposalHandler(app.wasmKeeper, enabledProposals)) +``` + +## Wasmd Authorization Settings + +Settings via sdk `params` module: +- `code_upload_access` - who can upload a wasm binary: `Nobody`, `Everybody`, `OnlyAddress` +- `instantiate_default_permission` - platform default, who can instantiate a wasm binary when the code owner has not set it + +See [params.go](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/params.go) + +### Init Params Via Genesis + +```json + "wasm": { + "params": { + "code_upload_access": { + "permission": "Everybody" + }, + "instantiate_default_permission": "Everybody" + } + }, +``` + +The values can be updated via gov proposal implemented in the `params` module. + +### Update Params Via [ParamChangeProposal](https://github.com/cosmos/cosmos-sdk/blob/v0.45.3/proto/cosmos/params/v1beta1/params.proto#L10) +Example to submit a parameter change gov proposal: +```sh +wasmd tx gov submit-proposal param-change --from validator --chain-id=testing -b block +``` +#### Content examples +* Disable wasm code uploads +```json +{ + "title": "Foo", + "description": "Bar", + "changes": [ + { + "subspace": "wasm", + "key": "uploadAccess", + "value": { + "permission": "Nobody" + } + } + ], + "deposit": "" +} +``` +* Allow wasm code uploads for everybody +```json +{ + "title": "Foo", + "description": "Bar", + "changes": [ + { + "subspace": "wasm", + "key": "uploadAccess", + "value": { + "permission": "Everybody" + } + } + ], + "deposit": "" +} +``` + +* Restrict code uploads to a single address +```json +{ + "title": "Foo", + "description": "Bar", + "changes": [ + { + "subspace": "wasm", + "key": "uploadAccess", + "value": { + "permission": "OnlyAddress", + "address": "cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq0fr2sh" + } + } + ], + "deposit": "" +} +``` +* Set chain **default** instantiation settings to nobody +```json +{ + "title": "Foo", + "description": "Bar", + "changes": [ + { + "subspace": "wasm", + "key": "instantiateAccess", + "value": "Nobody" + } + ], + "deposit": "" +} +``` +* Set chain **default** instantiation settings to everybody +```json +{ + "title": "Foo", + "description": "Bar", + "changes": [ + { + "subspace": "wasm", + "key": "instantiateAccess", + "value": "Everybody" + } + ], + "deposit": "" +} +``` + +### Enable gov proposals at **compile time**. +As gov proposals bypass the existing authorization policy they are disabled and require to be enabled at compile time. +``` +-X github.com/CosmWasm/wasmd/app.ProposalsEnabled=true - enable all x/wasm governance proposals (default false) +-X github.com/CosmWasm/wasmd/app.EnableSpecificProposals=MigrateContract,UpdateAdmin,ClearAdmin - enable a subset of the x/wasm governance proposal types (overrides ProposalsEnabled) +``` + +The `ParamChangeProposal` is always enabled. + +### Tests +* [params validation unit tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/params_test.go) +* [genesis validation tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/types/genesis_test.go) +* [policy integration tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/keeper/keeper_test.go) + +## CLI + +```shell script + wasmd tx gov submit-proposal [command] + +Available Commands: + wasm-store Submit a wasm binary proposal + instantiate-contract Submit an instantiate wasm contract proposal + migrate-contract Submit a migrate wasm contract to a new code version proposal + set-contract-admin Submit a new admin for a contract proposal + clear-contract-admin Submit a clear admin for a contract to prevent further migrations proposal +... +``` +## Rest +New [`ProposalHandlers`](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/client/proposal_handler.go) + +* Integration +```shell script +gov.NewAppModuleBasic(append(wasmclient.ProposalHandlers, paramsclient.ProposalHandler, distr.ProposalHandler, upgradeclient.ProposalHandler)...), +``` +In [abci app](https://github.com/CosmWasm/wasmd/blob/master/app/app.go#L109) + +### Tests +* [Rest Unit tests](https://github.com/CosmWasm/wasmd/blob/master/x/wasm/client/proposal_handler_test.go) +* [Rest smoke LCD test](https://github.com/CosmWasm/wasmd/blob/master/lcd_test/wasm_test.go) + + + +## Pull requests +* https://github.com/CosmWasm/wasmd/pull/190 +* https://github.com/CosmWasm/wasmd/pull/186 +* https://github.com/CosmWasm/wasmd/pull/183 +* https://github.com/CosmWasm/wasmd/pull/180 +* https://github.com/CosmWasm/wasmd/pull/179 +* https://github.com/CosmWasm/wasmd/pull/173 diff --git a/x/wasm/IBC.md b/x/wasm/IBC.md new file mode 100644 index 00000000..c3cd0a00 --- /dev/null +++ b/x/wasm/IBC.md @@ -0,0 +1,137 @@ +# IBC specification + +This documents how CosmWasm contracts are expected to interact with IBC. + +## General Concepts + +**IBC Enabled** - when instantiating a contract, we detect if it supports IBC messages. + We require "feature flags" in the contract/vm handshake to ensure compatibility + for features like staking or chain-specific extensions. IBC functionality will require + another "feature flag", and the list of "enabled features" can be returned to the `x/wasm` + module to control conditional IBC behavior. + + If this feature is enabled, it is considered "IBC Enabled", and that info will + be stored in the ContractInfo. (For mock, we assume all contracts are IBC enabled) + +Also, please read the [IBC Docs](https://docs.cosmos.network/master/ibc/overview.html) +for detailed descriptions of the terms *Port*, *Client*, *Connection*, +and *Channel* + +## Overview + +We use "One Port per Contract", which is the most straight-forward mapping, treating each contract +like a module. It does lead to very long portIDs however. Pay special attention to both the Channel establishment +(which should be compatible with standard ICS20 modules without changes on their part), as well +as how contracts can properly identify their counterparty. + +(We considered on port for the `x/wasm` module and multiplexing on it, but [dismissed that idea](#rejected-ideas)) + +* Upon `Instantiate`, if a contract is *IBC Enabled*, we dynamically + bind a port for this contract. The port name is `wasm.`, + eg. `wasm.cosmos1hmdudppzceg27qsuq707tjg8rkgj7g5hnvnw29` +* If a *Channel* is being established with a registered `wasm.xyz` port, + the `x/wasm.Keeper` will handle this and call into the appropriate + contract to determine supported protocol versions during the + [`ChanOpenTry` and `ChanOpenAck` phases](https://docs.cosmos.network/master/ibc/overview.html#channels). + (See [Channel Handshake Version Negotiation](https://docs.cosmos.network/master/ibc/custom.html#channel-handshake-version-negotiation)) +* Both the *Port* and the *Channel* are fully owned by one contract. +* `x/wasm` will allow both *ORDERED* and *UNORDERED* channels and pass that mode + down to the contract in `OnChanOpenTry`, so the contract can decide if it accepts + the mode. We will recommend the contract developers stick with *ORDERED* channels + for custom protocols unless they can reason about async packet timing. +* When sending a packet, the CosmWasm contract must specify the local *ChannelID*. + As there is a unique *PortID* per contract, that is filled in by `x/wasm` + to produce the globally unique `(PortID, ChannelID)` +* When receiving a Packet (or Ack or Timeout), the contracts receives the local + *ChannelID* it came from, as well as the packet that was sent by the counterparty. +* When receiving an Ack or Timeout packet, the contract also receives the + original packet that it sent earlier. +* We do not support multihop packets in this model (they are rejected by `x/wasm`). + They are currently not fully specified nor implemented in IBC 1.0, so let us + simplify our model until this is well established + +## Workflow + +Establishing *Clients* and *Connections* is out of the scope of this +module and must be created by the same means as for `ibc-transfer` +(via the [go cli](https://github.com/cosmos/relayer) or better [ts-relayer](https://github.com/confio/ts-relayer)). +`x/wasm` will bind a unique *Port* for each "IBC Enabled" contract. + +For mocks, all the Packet Handling and Channel Lifecycle Hooks are routed +to some Golang stub handler, but containing the contract address, so we +can perform contract-specific actions for each packet. In a real setting, +we route to the contract that owns the port/channel and call one of it's various +entry points. + +Please refer to the CosmWasm repo for all +[details on the IBC API from the point of view of a CosmWasm contract](https://github.com/CosmWasm/cosmwasm/blob/main/IBC.md). + +## Future Ideas + +Here are some ideas we may add in the future + +### Dynamic Ports and Channels + +* multiple ports per contract +* elastic ports that can be assigned to different contracts +* transfer of channels to another contract + +This is inspired by the Agoric design, but also adds considerable complexity to both the `x/wasm` +implementation as well as the correctness reasoning of any given contract. This will not be +available in the first version of our "IBC Enabled contracts", but we can consider it for later, +if there are concrete user cases that would significantly benefit from this added complexity. + +### Add multihop support + +Once the ICS and IBC specs fully establish how multihop packets work, we should add support for that. +Both on setting up the routes with OpenChannel, as well as acting as an intermediate relayer (if that is possible) + +## Rejected Ideas + +### One Port per Module + +We decided on "one port per contract", especially after the IBC team raised +the max length on port names to allow `wasm-` to be a valid port. +Here are the arguments for "one port for x/wasm" vs "one port per contract". Here +was an alternate proposal: + +In this approach, the `x/wasm` module just binds one port to handle all +modules. This can be well defined name like `wasm`. Since we always +have `(ChannelID, PortID)` for routing messages, we can reuse one port +for all contracts as long as we have a clear way to map the `ChannelID` +to a specific contract when it is being established. + + +* On genesis we bind the port `wasm` for all communication with the `x/wasm` + module. +* The *Port* is fully owned by `x/wasm` +* Each *Channel* is fully owned by one contract. +* `x/wasm` only accepts *ORDERED Channels* for simplicity of contract + correctness. + +To clarify: + +* When a *Channel* is being established with port `wasm`, the + `x/wasm.Keeper` must be able to identify for which contract this + is destined. **how to do so**?? + * One idea: the channel name must be the contract address. This means + (`wasm`, `cosmos13d...`) will map to the given contract in the wasm module. + The problem with this is that if two contracts from chainA want to + connect to the same contracts on chainB, they will want to claim the + same *ChannelID* and *PortID*. Not sure how to differentiate multiple + parties in this way. + * Other ideas: have a special field we send on `OnChanOpenInit` that + specifies the destination contract, and allow any *ChannelID*. + However, looking at [`OnChanOpenInit` function signature](https://docs.cosmos.network/master/ibc/custom.html#implement-ibcmodule-interface-and-callbacks), + I don't see a place to put this extra info, without abusing the version field, + which is a [specified field](https://docs.cosmos.network/master/ibc/custom.html#channel-handshake-version-negotiation): + ``` + Versions must be strings but can implement any versioning structure. + If your application plans to have linear releases then semantic versioning is recommended. + ... + Valid version selection includes selecting a compatible version identifier with a subset + of features supported by your application for that version. + ... + ICS20 currently implements basic string matching with a + single supported version. + ``` \ No newline at end of file diff --git a/x/wasm/README.md b/x/wasm/README.md new file mode 100644 index 00000000..cba9c5cf --- /dev/null +++ b/x/wasm/README.md @@ -0,0 +1,219 @@ +# Wasm Module + +This should be a brief overview of the functionality + +## Configuration + +You can add the following section to `config/app.toml`: + +```toml +[wasm] +# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries +query_gas_limit = 300000 +# This defines the memory size for Wasm modules that we can keep cached to speed-up instantiation +# The value is in MiB not bytes +memory_cache_size = 300 +``` + +The values can also be set via CLI flags on with the `start` command: +```shell script +--wasm.memory_cache_size uint32 Sets the size in MiB (NOT bytes) of an in-memory cache for wasm modules. Set to 0 to disable. (default 100) +--wasm.query_gas_limit uint Set the max gas that can be spent on executing a query with a Wasm contract (default 3000000) +``` + +## Events + +A number of events are returned to allow good indexing of the transactions from smart contracts. + +Every call to Instantiate or Execute will be tagged with the info on the contract that was executed and who executed it. +It should look something like this (with different addresses). The module is always `wasm`, and `code_id` is only present +when Instantiating a contract, so you can subscribe to new instances, it is omitted on Execute. There is also an `action` tag +which is auto-added by the Cosmos SDK and has a value of either `store-code`, `instantiate` or `execute` depending on which message +was sent: + +```json +{ + "Type": "message", + "Attr": [ + { + "key": "module", + "value": "wasm" + }, + { + "key": "action", + "value": "instantiate" + }, + { + "key": "signer", + "value": "cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x" + }, + { + "key": "code_id", + "value": "1" + }, + { + "key": "_contract_address", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + } + ] +} +``` + +If any funds were transferred to the contract as part of the message, or if the contract released funds as part of it's executions, +it will receive the typical events associated with sending tokens from bank. In this case, we instantiate the contract and +provide a initial balance in the same `MsgInstantiateContract`. We see the following events in addition to the above one: + +```json +[ + { + "Type": "transfer", + "Attr": [ + { + "key": "recipient", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + }, + { + "key": "sender", + "value": "cosmos1ffnqn02ft2psvyv4dyr56nnv6plllf9pm2kpmv" + }, + { + "key": "amount", + "value": "100000denom" + } + ] + } +] +``` + +Finally, the contract itself can emit a "custom event" on Execute only (not on Init). +There is one event per contract, so if one contract calls a second contract, you may receive +one event for the original contract and one for the re-invoked contract. All attributes from the contract are passed through verbatim, +and we add a `_contract_address` attribute that contains the actual contract that emitted that event. +Here is an example from the escrow contract successfully releasing funds to the destination address: + +```json +{ + "Type": "wasm", + "Attr": [ + { + "key": "_contract_address", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + }, + { + "key": "action", + "value": "release" + }, + { + "key": "destination", + "value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq" + } + ] +} +``` + +### Pulling this all together + +We will invoke an escrow contract to release to the designated beneficiary. +The escrow was previously loaded with `100000denom` (from the above example). +In this transaction, we send `5000denom` along with the `MsgExecuteContract` +and the contract releases the entire funds (`105000denom`) to the beneficiary. + +We will see all the following events, where you should be able to reconstruct the actions +(remember there are two events for each transfer). We see (1) the initial transfer of funds +to the contract, (2) the contract custom event that it released funds (3) the transfer of funds +from the contract to the beneficiary and (4) the generic x/wasm event stating that the contract +was executed (which always appears, while 2 is optional and has information as reliable as the contract): + +```json +[ + { + "Type": "transfer", + "Attr": [ + { + "key": "recipient", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + }, + { + "key": "sender", + "value": "cosmos1zm074khx32hqy20hlshlsd423n07pwlu9cpt37" + }, + { + "key": "amount", + "value": "5000denom" + } + ] + }, + { + "Type": "wasm", + "Attr": [ + { + "key": "_contract_address", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + }, + { + "key": "action", + "value": "release" + }, + { + "key": "destination", + "value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq" + } + ] + }, + { + "Type": "transfer", + "Attr": [ + { + "key": "recipient", + "value": "cosmos14k7v7ms4jxkk2etmg9gljxjm4ru3qjdugfsflq" + }, + { + "key": "sender", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + }, + { + "key": "amount", + "value": "105000denom" + } + ] + }, + { + "Type": "message", + "Attr": [ + { + "key": "module", + "value": "wasm" + }, + { + "key": "action", + "value": "execute" + }, + { + "key": "signer", + "value": "cosmos1zm074khx32hqy20hlshlsd423n07pwlu9cpt37" + }, + { + "key": "_contract_address", + "value": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr" + } + ] + } +] +``` + +A note on this format. This is what we return from our module. However, it seems to me that many events with the same `Type` +get merged together somewhere along the stack, so in this case, you *may* end up with one "transfer" event with the info for +both transfers. Double check when evaluating the event logs, I will document better with more experience, especially when I +find out the entire path for the events. + +## Messages + +TODO + +## CLI + +TODO - working, but not the nicest interface (json + bash = bleh). Use to upload, but I suggest to focus on frontend / js tooling + +## Rest + +TODO - main supported interface, under rapid change diff --git a/x/wasm/alias.go b/x/wasm/alias.go new file mode 100644 index 00000000..b7e60d22 --- /dev/null +++ b/x/wasm/alias.go @@ -0,0 +1,133 @@ +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cerc-io/laconicd/x/wasm/types +// ALIASGEN: github.com/cerc-io/laconicd/x/wasm/keeper +package wasm + +import ( + "github.com/cerc-io/laconicd/x/wasm/keeper" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +const ( + firstCodeID = 1 + ModuleName = types.ModuleName + StoreKey = types.StoreKey + TStoreKey = types.TStoreKey + QuerierRoute = types.QuerierRoute + RouterKey = types.RouterKey + WasmModuleEventType = types.WasmModuleEventType + AttributeKeyContractAddr = types.AttributeKeyContractAddr + ProposalTypeStoreCode = types.ProposalTypeStoreCode + ProposalTypeInstantiateContract = types.ProposalTypeInstantiateContract + ProposalTypeMigrateContract = types.ProposalTypeMigrateContract + ProposalTypeUpdateAdmin = types.ProposalTypeUpdateAdmin + ProposalTypeClearAdmin = types.ProposalTypeClearAdmin + QueryListContractByCode = keeper.QueryListContractByCode + QueryGetContract = keeper.QueryGetContract + QueryGetContractState = keeper.QueryGetContractState + QueryGetCode = keeper.QueryGetCode + QueryListCode = keeper.QueryListCode + QueryMethodContractStateSmart = keeper.QueryMethodContractStateSmart + QueryMethodContractStateAll = keeper.QueryMethodContractStateAll + QueryMethodContractStateRaw = keeper.QueryMethodContractStateRaw +) + +var ( + // functions aliases + RegisterCodec = types.RegisterLegacyAminoCodec + RegisterInterfaces = types.RegisterInterfaces + ValidateGenesis = types.ValidateGenesis + ConvertToProposals = types.ConvertToProposals + GetCodeKey = types.GetCodeKey + GetContractAddressKey = types.GetContractAddressKey + GetContractStorePrefixKey = types.GetContractStorePrefix + NewCodeInfo = types.NewCodeInfo + NewAbsoluteTxPosition = types.NewAbsoluteTxPosition + NewContractInfo = types.NewContractInfo + NewEnv = types.NewEnv + NewWasmCoins = types.NewWasmCoins + DefaultWasmConfig = types.DefaultWasmConfig + DefaultParams = types.DefaultParams + InitGenesis = keeper.InitGenesis + ExportGenesis = keeper.ExportGenesis + NewMessageHandler = keeper.NewDefaultMessageHandler + DefaultEncoders = keeper.DefaultEncoders + EncodeBankMsg = keeper.EncodeBankMsg + NoCustomMsg = keeper.NoCustomMsg + EncodeStakingMsg = keeper.EncodeStakingMsg + EncodeWasmMsg = keeper.EncodeWasmMsg + NewKeeper = keeper.NewKeeper + DefaultQueryPlugins = keeper.DefaultQueryPlugins + BankQuerier = keeper.BankQuerier + NoCustomQuerier = keeper.NoCustomQuerier + StakingQuerier = keeper.StakingQuerier + WasmQuerier = keeper.WasmQuerier + CreateTestInput = keeper.CreateTestInput + TestHandler = keeper.TestHandler + NewWasmProposalHandler = keeper.NewWasmProposalHandler + NewQuerier = keeper.Querier + ContractFromPortID = keeper.ContractFromPortID + WithWasmEngine = keeper.WithWasmEngine + NewCountTXDecorator = keeper.NewCountTXDecorator + + // variable aliases + ModuleCdc = types.ModuleCdc + DefaultCodespace = types.DefaultCodespace + ErrCreateFailed = types.ErrCreateFailed + ErrAccountExists = types.ErrAccountExists + ErrInstantiateFailed = types.ErrInstantiateFailed + ErrExecuteFailed = types.ErrExecuteFailed + ErrGasLimit = types.ErrGasLimit + ErrInvalidGenesis = types.ErrInvalidGenesis + ErrNotFound = types.ErrNotFound + ErrQueryFailed = types.ErrQueryFailed + ErrInvalidMsg = types.ErrInvalidMsg + KeyLastCodeID = types.KeyLastCodeID + KeyLastInstanceID = types.KeyLastInstanceID + CodeKeyPrefix = types.CodeKeyPrefix + ContractKeyPrefix = types.ContractKeyPrefix + ContractStorePrefix = types.ContractStorePrefix + EnableAllProposals = types.EnableAllProposals + DisableAllProposals = types.DisableAllProposals +) + +type ( + ProposalType = types.ProposalType + GenesisState = types.GenesisState + Code = types.Code + Contract = types.Contract + MsgStoreCode = types.MsgStoreCode + MsgStoreCodeResponse = types.MsgStoreCodeResponse + MsgInstantiateContract = types.MsgInstantiateContract + MsgInstantiateContract2 = types.MsgInstantiateContract2 + MsgInstantiateContractResponse = types.MsgInstantiateContractResponse + MsgExecuteContract = types.MsgExecuteContract + MsgExecuteContractResponse = types.MsgExecuteContractResponse + MsgMigrateContract = types.MsgMigrateContract + MsgMigrateContractResponse = types.MsgMigrateContractResponse + MsgUpdateAdmin = types.MsgUpdateAdmin + MsgUpdateAdminResponse = types.MsgUpdateAdminResponse + MsgClearAdmin = types.MsgClearAdmin + MsgWasmIBCCall = types.MsgIBCSend + MsgClearAdminResponse = types.MsgClearAdminResponse + MsgServer = types.MsgServer + Model = types.Model + CodeInfo = types.CodeInfo + ContractInfo = types.ContractInfo + CreatedAt = types.AbsoluteTxPosition + Config = types.WasmConfig + CodeInfoResponse = types.CodeInfoResponse + MessageHandler = keeper.SDKMessageHandler + BankEncoder = keeper.BankEncoder + CustomEncoder = keeper.CustomEncoder + StakingEncoder = keeper.StakingEncoder + WasmEncoder = keeper.WasmEncoder + MessageEncoders = keeper.MessageEncoders + Keeper = keeper.Keeper + QueryHandler = keeper.QueryHandler + CustomQuerier = keeper.CustomQuerier + QueryPlugins = keeper.QueryPlugins + Option = keeper.Option +) diff --git a/x/wasm/client/cli/gov_tx.go b/x/wasm/client/cli/gov_tx.go new file mode 100644 index 00000000..4cff5963 --- /dev/null +++ b/x/wasm/client/cli/gov_tx.go @@ -0,0 +1,834 @@ +package cli + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "fmt" + "net/url" + "strconv" + "strings" + + "github.com/docker/distribution/reference" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/pkg/errors" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func ProposalStoreCodeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "wasm-store [wasm file] --title [text] --description [text] --run-as [address] --unpin-code [unpin_code] --source [source] --builder [builder] --code-hash [code_hash]", + Short: "Submit a wasm binary proposal", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + src, err := parseStoreCodeArgs(args[0], clientCtx.FromAddress, cmd.Flags()) + if err != nil { + return err + } + runAs, err := cmd.Flags().GetString(flagRunAs) + if err != nil { + return fmt.Errorf("run-as: %s", err) + } + if len(runAs) == 0 { + return errors.New("run-as address is required") + } + + unpinCode, err := cmd.Flags().GetBool(flagUnpinCode) + if err != nil { + return err + } + + source, builder, codeHash, err := parseVerificationFlags(src.WASMByteCode, cmd.Flags()) + if err != nil { + return err + } + content := types.StoreCodeProposal{ + Title: proposalTitle, + Description: proposalDescr, + RunAs: runAs, + WASMByteCode: src.WASMByteCode, + InstantiatePermission: src.InstantiatePermission, + UnpinCode: unpinCode, + Source: source, + Builder: builder, + CodeHash: codeHash, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + cmd.Flags().String(flagRunAs, "", "The address that is stored as code creator") + cmd.Flags().Bool(flagUnpinCode, false, "Unpin code on upload, optional") + cmd.Flags().String(flagSource, "", "Code Source URL is a valid absolute HTTPS URI to the contract's source code,") + cmd.Flags().String(flagBuilder, "", "Builder is a valid docker image name with tag, such as \"cosmwasm/workspace-optimizer:0.12.9\"") + cmd.Flags().BytesHex(flagCodeHash, nil, "CodeHash is the sha256 hash of the wasm code") + addInstantiatePermissionFlags(cmd) + + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func parseVerificationFlags(wasm []byte, flags *flag.FlagSet) (string, string, []byte, error) { + source, err := flags.GetString(flagSource) + if err != nil { + return "", "", nil, fmt.Errorf("source: %s", err) + } + builder, err := flags.GetString(flagBuilder) + if err != nil { + return "", "", nil, fmt.Errorf("builder: %s", err) + } + codeHash, err := flags.GetBytesHex(flagCodeHash) + if err != nil { + return "", "", nil, fmt.Errorf("codeHash: %s", err) + } + + // if any set require others to be set + if len(source) != 0 || len(builder) != 0 || len(codeHash) != 0 { + if source == "" { + return "", "", nil, fmt.Errorf("source is required") + } + if _, err = url.ParseRequestURI(source); err != nil { + return "", "", nil, fmt.Errorf("source: %s", err) + } + if builder == "" { + return "", "", nil, fmt.Errorf("builder is required") + } + if _, err := reference.ParseDockerRef(builder); err != nil { + return "", "", nil, fmt.Errorf("builder: %s", err) + } + if len(codeHash) == 0 { + return "", "", nil, fmt.Errorf("code hash is required") + } + // wasm is unzipped in parseStoreCodeArgs + // checksum generation will be decoupled here + // reference https://github.com/CosmWasm/wasmvm/issues/359 + checksum := sha256.Sum256(wasm) + if !bytes.Equal(checksum[:], codeHash) { + return "", "", nil, fmt.Errorf("code-hash mismatch: %X, checksum: %X", codeHash, checksum) + } + } + return source, builder, codeHash, nil +} + +func ProposalInstantiateContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "instantiate-contract [code_id_int64] [json_encoded_init_args] --label [text] --title [text] --description [text] --run-as [address] --admin [address,optional] --amount [coins,optional]", + Short: "Submit an instantiate wasm contract proposal", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + src, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.FromAddress, cmd.Flags()) + if err != nil { + return err + } + + runAs, err := cmd.Flags().GetString(flagRunAs) + if err != nil { + return fmt.Errorf("run-as: %s", err) + } + if len(runAs) == 0 { + return errors.New("run-as address is required") + } + + content := types.InstantiateContractProposal{ + Title: proposalTitle, + Description: proposalDescr, + RunAs: runAs, + Admin: src.Admin, + CodeID: src.CodeID, + Label: src.Label, + Msg: src.Msg, + Funds: src.Funds, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists") + cmd.Flags().String(flagAdmin, "", "Address or key name of an admin") + cmd.Flags().String(flagRunAs, "", "The address that pays the init funds. It is the creator of the contract and passed to the contract as sender on proposal execution") + cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin") + + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalInstantiateContract2Cmd() *cobra.Command { + decoder := newArgDecoder(hex.DecodeString) + cmd := &cobra.Command{ + Use: "instantiate-contract-2 [code_id_int64] [json_encoded_init_args] [salt] --label [text] --title [text] --description [text] --run-as [address] --admin [address,optional] --amount [coins,optional] --fix-msg [bool,optional]", + Short: "Submit an instantiate wasm contract proposal with predictable address", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + src, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.FromAddress, cmd.Flags()) + if err != nil { + return err + } + + runAs, err := cmd.Flags().GetString(flagRunAs) + if err != nil { + return fmt.Errorf("run-as: %s", err) + } + if len(runAs) == 0 { + return errors.New("run-as address is required") + } + + salt, err := decoder.DecodeString(args[2]) + if err != nil { + return fmt.Errorf("salt: %w", err) + } + + fixMsg, err := cmd.Flags().GetBool(flagFixMsg) + if err != nil { + return fmt.Errorf("fix msg: %w", err) + } + + content := types.NewInstantiateContract2Proposal(proposalTitle, proposalDescr, runAs, src.Admin, src.CodeID, src.Label, src.Msg, src.Funds, salt, fixMsg) + + msg, err := govtypes.NewMsgSubmitProposal(content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists") + cmd.Flags().String(flagAdmin, "", "Address of an admin") + cmd.Flags().String(flagRunAs, "", "The address that pays the init funds. It is the creator of the contract and passed to the contract as sender on proposal execution") + cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin") + cmd.Flags().Bool(flagFixMsg, false, "An optional flag to include the json_encoded_init_args for the predictable address generation mode") + decoder.RegisterFlags(cmd.PersistentFlags(), "salt") + + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalStoreAndInstantiateContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "store-instantiate [wasm file] [json_encoded_init_args] --label [text] --title [text] --description [text] --run-as [address]" + + "--unpin-code [unpin_code,optional] --source [source,optional] --builder [builder,optional] --code-hash [code_hash,optional] --admin [address,optional] --amount [coins,optional]", + Short: "Submit and instantiate a wasm contract proposal", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + src, err := parseStoreCodeArgs(args[0], clientCtx.FromAddress, cmd.Flags()) + if err != nil { + return err + } + runAs, err := cmd.Flags().GetString(flagRunAs) + if err != nil { + return fmt.Errorf("run-as: %s", err) + } + if len(runAs) == 0 { + return errors.New("run-as address is required") + } + + unpinCode, err := cmd.Flags().GetBool(flagUnpinCode) + if err != nil { + return err + } + + source, builder, codeHash, err := parseVerificationFlags(src.WASMByteCode, cmd.Flags()) + if err != nil { + return err + } + + amountStr, err := cmd.Flags().GetString(flagAmount) + if err != nil { + return fmt.Errorf("amount: %s", err) + } + amount, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return fmt.Errorf("amount: %s", err) + } + label, err := cmd.Flags().GetString(flagLabel) + if err != nil { + return fmt.Errorf("label: %s", err) + } + if label == "" { + return errors.New("label is required on all contracts") + } + adminStr, err := cmd.Flags().GetString(flagAdmin) + if err != nil { + return fmt.Errorf("admin: %s", err) + } + noAdmin, err := cmd.Flags().GetBool(flagNoAdmin) + if err != nil { + return fmt.Errorf("no-admin: %s", err) + } + + // ensure sensible admin is set (or explicitly immutable) + if adminStr == "" && !noAdmin { + return fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)") + } + if adminStr != "" && noAdmin { + return fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true") + } + + if adminStr != "" { + addr, err := sdk.AccAddressFromBech32(adminStr) + if err != nil { + info, err := clientCtx.Keyring.Key(adminStr) + if err != nil { + return fmt.Errorf("admin %s", err) + } + adminStr = info.GetAddress().String() + } else { + adminStr = addr.String() + } + } + + content := types.StoreAndInstantiateContractProposal{ + Title: proposalTitle, + Description: proposalDescr, + RunAs: runAs, + WASMByteCode: src.WASMByteCode, + InstantiatePermission: src.InstantiatePermission, + UnpinCode: unpinCode, + Source: source, + Builder: builder, + CodeHash: codeHash, + Admin: adminStr, + Label: label, + Msg: []byte(args[1]), + Funds: amount, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + cmd.Flags().String(flagRunAs, "", "The address that is stored as code creator. It is the creator of the contract and passed to the contract as sender on proposal execution") + cmd.Flags().Bool(flagUnpinCode, false, "Unpin code on upload, optional") + cmd.Flags().String(flagSource, "", "Code Source URL is a valid absolute HTTPS URI to the contract's source code,") + cmd.Flags().String(flagBuilder, "", "Builder is a valid docker image name with tag, such as \"cosmwasm/workspace-optimizer:0.12.9\"") + cmd.Flags().BytesHex(flagCodeHash, nil, "CodeHash is the sha256 hash of the wasm code") + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists") + cmd.Flags().String(flagAdmin, "", "Address or key name of an admin") + cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin") + addInstantiatePermissionFlags(cmd) + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalMigrateContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "migrate-contract [contract_addr_bech32] [new_code_id_int64] [json_encoded_migration_args]", + Short: "Submit a migrate wasm contract to a new code version proposal", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + src, err := parseMigrateContractArgs(args, clientCtx) + if err != nil { + return err + } + + content := types.MigrateContractProposal{ + Title: proposalTitle, + Description: proposalDescr, + Contract: src.Contract, + CodeID: src.CodeID, + Msg: src.Msg, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalExecuteContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "execute-contract [contract_addr_bech32] [json_encoded_migration_args]", + Short: "Submit a execute wasm contract proposal (run by any address)", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + contract := args[0] + execMsg := []byte(args[1]) + amountStr, err := cmd.Flags().GetString(flagAmount) + if err != nil { + return fmt.Errorf("amount: %s", err) + } + funds, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return fmt.Errorf("amount: %s", err) + } + runAs, err := cmd.Flags().GetString(flagRunAs) + if err != nil { + return fmt.Errorf("run-as: %s", err) + } + + if len(runAs) == 0 { + return errors.New("run-as address is required") + } + + content := types.ExecuteContractProposal{ + Title: proposalTitle, + Description: proposalDescr, + Contract: contract, + Msg: execMsg, + RunAs: runAs, + Funds: funds, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + cmd.Flags().String(flagRunAs, "", "The address that is passed as sender to the contract on proposal execution") + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalSudoContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "sudo-contract [contract_addr_bech32] [json_encoded_migration_args]", + Short: "Submit a sudo wasm contract proposal (to call privileged commands)", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + contract := args[0] + sudoMsg := []byte(args[1]) + + content := types.SudoContractProposal{ + Title: proposalTitle, + Description: proposalDescr, + Contract: contract, + Msg: sudoMsg, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + // proposal flagsExecute + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalUpdateContractAdminCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-contract-admin [contract_addr_bech32] [new_admin_addr_bech32]", + Short: "Submit a new admin for a contract proposal", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + src, err := parseUpdateContractAdminArgs(args, clientCtx) + if err != nil { + return err + } + + content := types.UpdateAdminProposal{ + Title: proposalTitle, + Description: proposalDescr, + Contract: src.Contract, + NewAdmin: src.NewAdmin, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalClearContractAdminCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "clear-contract-admin [contract_addr_bech32]", + Short: "Submit a clear admin for a contract to prevent further migrations proposal", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + content := types.ClearAdminProposal{ + Title: proposalTitle, + Description: proposalDescr, + Contract: args[0], + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func ProposalPinCodesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "pin-codes [code-ids]", + Short: "Submit a pin code proposal for pinning a code to cache", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + codeIds, err := parsePinCodesArgs(args) + if err != nil { + return err + } + + content := types.PinCodesProposal{ + Title: proposalTitle, + Description: proposalDescr, + CodeIDs: codeIds, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func parsePinCodesArgs(args []string) ([]uint64, error) { + codeIDs := make([]uint64, len(args)) + for i, c := range args { + codeID, err := strconv.ParseUint(c, 10, 64) + if err != nil { + return codeIDs, fmt.Errorf("code IDs: %s", err) + } + codeIDs[i] = codeID + } + return codeIDs, nil +} + +func ProposalUnpinCodesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "unpin-codes [code-ids]", + Short: "Submit a unpin code proposal for unpinning a code to cache", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + + codeIds, err := parsePinCodesArgs(args) + if err != nil { + return err + } + + content := types.UnpinCodesProposal{ + Title: proposalTitle, + Description: proposalDescr, + CodeIDs: codeIds, + } + + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func parseAccessConfig(raw string) (c types.AccessConfig, err error) { + switch raw { + case "nobody": + return types.AllowNobody, nil + case "everybody": + return types.AllowEverybody, nil + default: + parts := strings.Split(raw, ",") + addrs := make([]sdk.AccAddress, len(parts)) + for i, v := range parts { + addr, err := sdk.AccAddressFromBech32(v) + if err != nil { + return types.AccessConfig{}, fmt.Errorf("unable to parse address %q: %s", v, err) + } + addrs[i] = addr + } + defer func() { // convert panic in ".With" to error for better output + if r := recover(); r != nil { + err = r.(error) + } + }() + cfg := types.AccessTypeAnyOfAddresses.With(addrs...) + return cfg, cfg.ValidateBasic() + } +} + +func parseAccessConfigUpdates(args []string) ([]types.AccessConfigUpdate, error) { + updates := make([]types.AccessConfigUpdate, len(args)) + for i, c := range args { + // format: code_id:access_config + // access_config: nobody|everybody|address(es) + parts := strings.Split(c, ":") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid format") + } + + codeID, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid code ID: %s", err) + } + + accessConfig, err := parseAccessConfig(parts[1]) + if err != nil { + return nil, err + } + updates[i] = types.AccessConfigUpdate{ + CodeID: codeID, + InstantiatePermission: accessConfig, + } + } + return updates, nil +} + +func ProposalUpdateInstantiateConfigCmd() *cobra.Command { + bech32Prefix := sdk.GetConfig().GetBech32AccountAddrPrefix() + cmd := &cobra.Command{ + Use: "update-instantiate-config [code-id:permission]...", + Short: "Submit an update instantiate config proposal.", + Args: cobra.MinimumNArgs(1), + Long: strings.TrimSpace( + fmt.Sprintf(`Submit an update instantiate config proposal for multiple code ids. + +Example: +$ %s tx gov submit-proposal update-instantiate-config 1:nobody 2:everybody 3:%s1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm,%s1vx8knpllrj7n963p9ttd80w47kpacrhuts497x +`, version.AppName, bech32Prefix, bech32Prefix)), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, proposalDescr, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + updates, err := parseAccessConfigUpdates(args) + if err != nil { + return err + } + + content := types.UpdateInstantiateConfigProposal{ + Title: proposalTitle, + Description: proposalDescr, + AccessConfigUpdates: updates, + } + msg, err := govtypes.NewMsgSubmitProposal(&content, deposit, clientCtx.GetFromAddress()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + // proposal flags + cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "Description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "Deposit of proposal") + return cmd +} + +func getProposalInfo(cmd *cobra.Command) (client.Context, string, string, sdk.Coins, error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return client.Context{}, "", "", nil, err + } + + proposalTitle, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return clientCtx, proposalTitle, "", nil, err + } + + proposalDescr, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return client.Context{}, proposalTitle, proposalDescr, nil, err + } + + depositArg, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return client.Context{}, proposalTitle, proposalDescr, nil, err + } + + deposit, err := sdk.ParseCoinsNormalized(depositArg) + if err != nil { + return client.Context{}, proposalTitle, proposalDescr, deposit, err + } + + return clientCtx, proposalTitle, proposalDescr, deposit, nil +} diff --git a/x/wasm/client/cli/gov_tx_test.go b/x/wasm/client/cli/gov_tx_test.go new file mode 100644 index 00000000..672e203c --- /dev/null +++ b/x/wasm/client/cli/gov_tx_test.go @@ -0,0 +1,158 @@ +package cli + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestParseAccessConfigUpdates(t *testing.T) { + specs := map[string]struct { + src []string + exp []types.AccessConfigUpdate + expErr bool + }{ + "nobody": { + src: []string{"1:nobody"}, + exp: []types.AccessConfigUpdate{{ + CodeID: 1, + InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeNobody}, + }}, + }, + "everybody": { + src: []string{"1:everybody"}, + exp: []types.AccessConfigUpdate{{ + CodeID: 1, + InstantiatePermission: types.AccessConfig{Permission: types.AccessTypeEverybody}, + }}, + }, + "any of addresses - single": { + src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"}, + exp: []types.AccessConfigUpdate{ + { + CodeID: 1, + InstantiatePermission: types.AccessConfig{ + Permission: types.AccessTypeAnyOfAddresses, + Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"}, + }, + }, + }, + }, + "any of addresses - multiple": { + src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}, + exp: []types.AccessConfigUpdate{ + { + CodeID: 1, + InstantiatePermission: types.AccessConfig{ + Permission: types.AccessTypeAnyOfAddresses, + Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}, + }, + }, + }, + }, + "multiple code ids with different permissions": { + src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", "2:nobody"}, + exp: []types.AccessConfigUpdate{ + { + CodeID: 1, + InstantiatePermission: types.AccessConfig{ + Permission: types.AccessTypeAnyOfAddresses, + Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}, + }, + }, { + CodeID: 2, + InstantiatePermission: types.AccessConfig{ + Permission: types.AccessTypeNobody, + }, + }, + }, + }, + "any of addresses - empty list": { + src: []string{"1:"}, + expErr: true, + }, + "any of addresses - invalid address": { + src: []string{"1:foo"}, + expErr: true, + }, + "any of addresses - duplicate address": { + src: []string{"1:cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"}, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got, gotErr := parseAccessConfigUpdates(spec.src) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestParseCodeInfoFlags(t *testing.T) { + correctSource := "https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/testdata/hackatom.wasm" + correctBuilderRef := "cosmwasm/workspace-optimizer:0.12.9" + + wasmBin, err := os.ReadFile("../../keeper/testdata/hackatom.wasm") + require.NoError(t, err) + + checksumStr := "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b" + + specs := map[string]struct { + args []string + expErr bool + }{ + "source missing": { + args: []string{"--builder=" + correctBuilderRef, "--code-hash=" + checksumStr}, + expErr: true, + }, + "builder missing": { + args: []string{"--code-source-url=" + correctSource, "--code-hash=" + checksumStr}, + expErr: true, + }, + "code hash missing": { + args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef}, + expErr: true, + }, + "source format wrong": { + args: []string{"--code-source-url=" + "format_wrong", "--builder=" + correctBuilderRef, "--code-hash=" + checksumStr}, + expErr: true, + }, + "builder format wrong": { + args: []string{"--code-source-url=" + correctSource, "--builder=" + "format//", "--code-hash=" + checksumStr}, + expErr: true, + }, + "code hash wrong": { + args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef, "--code-hash=" + "AA"}, + expErr: true, + }, + "happy path, none set": { + args: []string{}, + expErr: false, + }, + "happy path all set": { + args: []string{"--code-source-url=" + correctSource, "--builder=" + correctBuilderRef, "--code-hash=" + checksumStr}, + expErr: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + flags := ProposalStoreCodeCmd().Flags() + require.NoError(t, flags.Parse(spec.args)) + _, _, _, gotErr := parseVerificationFlags(wasmBin, flags) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} diff --git a/x/wasm/client/cli/new_tx.go b/x/wasm/client/cli/new_tx.go new file mode 100644 index 00000000..0c742de6 --- /dev/null +++ b/x/wasm/client/cli/new_tx.go @@ -0,0 +1,163 @@ +package cli + +import ( + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/spf13/cobra" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// MigrateContractCmd will migrate a contract to a new code version +func MigrateContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "migrate [contract_addr_bech32] [new_code_id_int64] [json_encoded_migration_args]", + Short: "Migrate a wasm contract to a new code version", + Aliases: []string{"update", "mig", "m"}, + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg, err := parseMigrateContractArgs(args, clientCtx) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return nil + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + SilenceUsage: true, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func parseMigrateContractArgs(args []string, cliCtx client.Context) (types.MsgMigrateContract, error) { + // get the id of the code to instantiate + codeID, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return types.MsgMigrateContract{}, sdkerrors.Wrap(err, "code id") + } + + migrateMsg := args[2] + + msg := types.MsgMigrateContract{ + Sender: cliCtx.GetFromAddress().String(), + Contract: args[0], + CodeID: codeID, + Msg: []byte(migrateMsg), + } + return msg, nil +} + +// UpdateContractAdminCmd sets an new admin for a contract +func UpdateContractAdminCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "set-contract-admin [contract_addr_bech32] [new_admin_addr_bech32]", + Short: "Set new admin for a contract", + Aliases: []string{"new-admin", "admin", "set-adm", "sa"}, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg, err := parseUpdateContractAdminArgs(args, clientCtx) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + SilenceUsage: true, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func parseUpdateContractAdminArgs(args []string, cliCtx client.Context) (types.MsgUpdateAdmin, error) { + msg := types.MsgUpdateAdmin{ + Sender: cliCtx.GetFromAddress().String(), + Contract: args[0], + NewAdmin: args[1], + } + return msg, nil +} + +// ClearContractAdminCmd clears an admin for a contract +func ClearContractAdminCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "clear-contract-admin [contract_addr_bech32]", + Short: "Clears admin for a contract to prevent further migrations", + Aliases: []string{"clear-admin", "clr-adm"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.MsgClearAdmin{ + Sender: clientCtx.GetFromAddress().String(), + Contract: args[0], + } + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + SilenceUsage: true, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// UpdateInstantiateConfigCmd updates instantiate config for a smart contract. +func UpdateInstantiateConfigCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-instantiate-config [code_id_int64]", + Short: "Update instantiate config for a codeID", + Aliases: []string{"update-instantiate-config"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + codeID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + perm, err := parseAccessConfigFlags(cmd.Flags()) + if err != nil { + return err + } + + msg := types.MsgUpdateInstantiateConfig{ + Sender: string(clientCtx.GetFromAddress()), + CodeID: codeID, + NewInstantiatePermission: perm, + } + if err = msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + SilenceUsage: true, + } + + addInstantiatePermissionFlags(cmd) + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/x/wasm/client/cli/query.go b/x/wasm/client/cli/query.go new file mode 100644 index 00000000..55b4694a --- /dev/null +++ b/x/wasm/client/cli/query.go @@ -0,0 +1,674 @@ +package cli + +import ( + "context" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "os" + "strconv" + + wasmvm "github.com/CosmWasm/wasmvm" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + + "github.com/cerc-io/laconicd/x/wasm/keeper" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func GetQueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the wasm module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + SilenceUsage: true, + } + queryCmd.AddCommand( + GetCmdListCode(), + GetCmdListContractByCode(), + GetCmdQueryCode(), + GetCmdQueryCodeInfo(), + GetCmdGetContractInfo(), + GetCmdGetContractHistory(), + GetCmdGetContractState(), + GetCmdListPinnedCode(), + GetCmdLibVersion(), + GetCmdQueryParams(), + GetCmdBuildAddress(), + GetCmdListContractsByCreator(), + ) + return queryCmd +} + +// GetCmdLibVersion gets current libwasmvm version. +func GetCmdLibVersion() *cobra.Command { + cmd := &cobra.Command{ + Use: "libwasmvm-version", + Short: "Get libwasmvm version", + Long: "Get libwasmvm version", + Aliases: []string{"lib-version"}, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + version, err := wasmvm.LibwasmvmVersion() + if err != nil { + return fmt.Errorf("error retrieving libwasmvm version: %w", err) + } + fmt.Println(version) + return nil + }, + SilenceUsage: true, + } + return cmd +} + +// GetCmdBuildAddress build a contract address +func GetCmdBuildAddress() *cobra.Command { + decoder := newArgDecoder(hex.DecodeString) + cmd := &cobra.Command{ + Use: "build-address [code-hash] [creator-address] [salt-hex-encoded] [json_encoded_init_args (required when set as fixed)]", + Short: "build contract address", + Aliases: []string{"address"}, + Args: cobra.RangeArgs(3, 4), + RunE: func(cmd *cobra.Command, args []string) error { + codeHash, err := hex.DecodeString(args[0]) + if err != nil { + return fmt.Errorf("code-hash: %s", err) + } + creator, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return fmt.Errorf("creator: %s", err) + } + salt, err := hex.DecodeString(args[2]) + switch { + case err != nil: + return fmt.Errorf("salt: %s", err) + case len(salt) == 0: + return errors.New("empty salt") + } + + if len(args) == 3 { + cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, []byte{}).String()) + return nil + } + msg := types.RawContractMessage(args[3]) + if err := msg.ValidateBasic(); err != nil { + return fmt.Errorf("init message: %s", err) + } + cmd.Println(keeper.BuildContractAddressPredictable(codeHash, creator, salt, msg).String()) + return nil + }, + SilenceUsage: true, + } + decoder.RegisterFlags(cmd.PersistentFlags(), "salt") + return cmd +} + +// GetCmdListCode lists all wasm code uploaded +func GetCmdListCode() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-code", + Short: "List all wasm bytecode on the chain", + Long: "List all wasm bytecode on the chain", + Aliases: []string{"list-codes", "codes", "lco"}, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Codes( + context.Background(), + &types.QueryCodesRequest{ + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "list codes") + return cmd +} + +// GetCmdListContractByCode lists all wasm code uploaded for given code id +func GetCmdListContractByCode() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-contract-by-code [code_id]", + Short: "List wasm all bytecode on the chain for given code id", + Long: "List wasm all bytecode on the chain for given code id", + Aliases: []string{"list-contracts-by-code", "list-contracts", "contracts", "lca"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + codeID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + if codeID == 0 { + return errors.New("empty code id") + } + + pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.ContractsByCode( + context.Background(), + &types.QueryContractsByCodeRequest{ + CodeId: codeID, + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "list contracts by code") + return cmd +} + +// GetCmdQueryCode returns the bytecode for a given contract +func GetCmdQueryCode() *cobra.Command { + cmd := &cobra.Command{ + Use: "code [code_id] [output filename]", + Short: "Downloads wasm bytecode for given code id", + Long: "Downloads wasm bytecode for given code id", + Aliases: []string{"source-code", "source"}, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + codeID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Code( + context.Background(), + &types.QueryCodeRequest{ + CodeId: codeID, + }, + ) + if err != nil { + return err + } + if len(res.Data) == 0 { + return fmt.Errorf("contract not found") + } + + fmt.Printf("Downloading wasm code to %s\n", args[1]) + return os.WriteFile(args[1], res.Data, 0o600) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdQueryCodeInfo returns the code info for a given code id +func GetCmdQueryCodeInfo() *cobra.Command { + cmd := &cobra.Command{ + Use: "code-info [code_id]", + Short: "Prints out metadata of a code id", + Long: "Prints out metadata of a code id", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + codeID, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.Code( + context.Background(), + &types.QueryCodeRequest{ + CodeId: codeID, + }, + ) + if err != nil { + return err + } + if res.CodeInfoResponse == nil { + return fmt.Errorf("contract not found") + } + + return clientCtx.PrintProto(res.CodeInfoResponse) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdGetContractInfo gets details about a given contract +func GetCmdGetContractInfo() *cobra.Command { + cmd := &cobra.Command{ + Use: "contract [bech32_address]", + Short: "Prints out metadata of a contract given its address", + Long: "Prints out metadata of a contract given its address", + Aliases: []string{"meta", "c"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.ContractInfo( + context.Background(), + &types.QueryContractInfoRequest{ + Address: args[0], + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdGetContractState dumps full internal state of a given contract +func GetCmdGetContractState() *cobra.Command { + cmd := &cobra.Command{ + Use: "contract-state", + Short: "Querying commands for the wasm module", + Aliases: []string{"state", "cs", "s"}, + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + SilenceUsage: true, + } + cmd.AddCommand( + GetCmdGetContractStateAll(), + GetCmdGetContractStateRaw(), + GetCmdGetContractStateSmart(), + ) + return cmd +} + +func GetCmdGetContractStateAll() *cobra.Command { + cmd := &cobra.Command{ + Use: "all [bech32_address]", + Short: "Prints out all internal state of a contract given its address", + Long: "Prints out all internal state of a contract given its address", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.AllContractState( + context.Background(), + &types.QueryAllContractStateRequest{ + Address: args[0], + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "contract state") + return cmd +} + +func GetCmdGetContractStateRaw() *cobra.Command { + decoder := newArgDecoder(hex.DecodeString) + cmd := &cobra.Command{ + Use: "raw [bech32_address] [key]", + Short: "Prints out internal state for key of a contract given its address", + Long: "Prints out internal state for of a contract given its address", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + queryData, err := decoder.DecodeString(args[1]) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.RawContractState( + context.Background(), + &types.QueryRawContractStateRequest{ + Address: args[0], + QueryData: queryData, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + decoder.RegisterFlags(cmd.PersistentFlags(), "key argument") + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +func GetCmdGetContractStateSmart() *cobra.Command { + decoder := newArgDecoder(asciiDecodeString) + cmd := &cobra.Command{ + Use: "smart [bech32_address] [query]", + Short: "Calls contract with given address with query data and prints the returned result", + Long: "Calls contract with given address with query data and prints the returned result", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + if args[1] == "" { + return errors.New("query data must not be empty") + } + + queryData, err := decoder.DecodeString(args[1]) + if err != nil { + return fmt.Errorf("decode query: %s", err) + } + if !json.Valid(queryData) { + return errors.New("query data must be json") + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.SmartContractState( + context.Background(), + &types.QuerySmartContractStateRequest{ + Address: args[0], + QueryData: queryData, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + decoder.RegisterFlags(cmd.PersistentFlags(), "query argument") + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +// GetCmdGetContractHistory prints the code history for a given contract +func GetCmdGetContractHistory() *cobra.Command { + cmd := &cobra.Command{ + Use: "contract-history [bech32_address]", + Short: "Prints out the code history for a contract given its address", + Long: "Prints out the code history for a contract given its address", + Aliases: []string{"history", "hist", "ch"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.ContractHistory( + context.Background(), + &types.QueryContractHistoryRequest{ + Address: args[0], + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "contract history") + return cmd +} + +// GetCmdListPinnedCode lists all wasm code ids that are pinned +func GetCmdListPinnedCode() *cobra.Command { + cmd := &cobra.Command{ + Use: "pinned", + Short: "List all pinned code ids", + Long: "List all pinned code ids", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.PinnedCodes( + context.Background(), + &types.QueryPinnedCodesRequest{ + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "list codes") + return cmd +} + +// GetCmdListContractsByCreator lists all contracts by creator +func GetCmdListContractsByCreator() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-contracts-by-creator [creator]", + Short: "List all contracts by creator", + Long: "List all contracts by creator", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + pageReq, err := client.ReadPageRequest(withPageKeyDecoded(cmd.Flags())) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + res, err := queryClient.ContractsByCreator( + context.Background(), + &types.QueryContractsByCreatorRequest{ + CreatorAddress: args[0], + Pagination: pageReq, + }, + ) + if err != nil { + return err + } + return clientCtx.PrintProto(res) + }, + SilenceUsage: true, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +type argumentDecoder struct { + // dec is the default decoder + dec func(string) ([]byte, error) + asciiF, hexF, b64F bool +} + +func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder { + return &argumentDecoder{dec: def} +} + +func (a *argumentDecoder) RegisterFlags(f *flag.FlagSet, argName string) { + f.BoolVar(&a.asciiF, "ascii", false, "ascii encoded "+argName) + f.BoolVar(&a.hexF, "hex", false, "hex encoded "+argName) + f.BoolVar(&a.b64F, "b64", false, "base64 encoded "+argName) +} + +func (a *argumentDecoder) DecodeString(s string) ([]byte, error) { + found := -1 + for i, v := range []*bool{&a.asciiF, &a.hexF, &a.b64F} { + if !*v { + continue + } + if found != -1 { + return nil, errors.New("multiple decoding flags used") + } + found = i + } + switch found { + case 0: + return asciiDecodeString(s) + case 1: + return hex.DecodeString(s) + case 2: + return base64.StdEncoding.DecodeString(s) + default: + return a.dec(s) + } +} + +func asciiDecodeString(s string) ([]byte, error) { + return []byte(s), nil +} + +// sdk ReadPageRequest expects binary but we encoded to base64 in our marshaller +func withPageKeyDecoded(flagSet *flag.FlagSet) *flag.FlagSet { + encoded, err := flagSet.GetString(flags.FlagPageKey) + if err != nil { + panic(err.Error()) + } + raw, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + panic(err.Error()) + } + err = flagSet.Set(flags.FlagPageKey, string(raw)) + if err != nil { + panic(err.Error()) + } + return flagSet +} + +// GetCmdQueryParams implements a command to return the current wasm +// parameters. +func GetCmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query the current wasm parameters", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryParamsRequest{} + res, err := queryClient.Params(cmd.Context(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(&res.Params) + }, + SilenceUsage: true, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/wasm/client/cli/tx.go b/x/wasm/client/cli/tx.go new file mode 100644 index 00000000..092d4288 --- /dev/null +++ b/x/wasm/client/cli/tx.go @@ -0,0 +1,544 @@ +package cli + +import ( + "encoding/hex" + "errors" + "fmt" + "os" + "strconv" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/authz" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + + "github.com/cerc-io/laconicd/x/wasm/ioutils" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +const ( + flagAmount = "amount" + flagLabel = "label" + flagSource = "code-source-url" + flagBuilder = "builder" + flagCodeHash = "code-hash" + flagAdmin = "admin" + flagNoAdmin = "no-admin" + flagFixMsg = "fix-msg" + flagRunAs = "run-as" + flagInstantiateByEverybody = "instantiate-everybody" + flagInstantiateNobody = "instantiate-nobody" + flagInstantiateByAddress = "instantiate-only-address" + flagInstantiateByAnyOfAddress = "instantiate-anyof-addresses" + flagUnpinCode = "unpin-code" + flagAllowedMsgKeys = "allow-msg-keys" + flagAllowedRawMsgs = "allow-raw-msgs" + flagExpiration = "expiration" + flagMaxCalls = "max-calls" + flagMaxFunds = "max-funds" + flagAllowAllMsgs = "allow-all-messages" + flagNoTokenTransfer = "no-token-transfer" //nolint:gosec +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Wasm transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + SilenceUsage: true, + } + txCmd.AddCommand( + StoreCodeCmd(), + InstantiateContractCmd(), + InstantiateContract2Cmd(), + ExecuteContractCmd(), + MigrateContractCmd(), + UpdateContractAdminCmd(), + ClearContractAdminCmd(), + GrantAuthorizationCmd(), + UpdateInstantiateConfigCmd(), + ) + return txCmd +} + +// StoreCodeCmd will upload code to be reused. +func StoreCodeCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "store [wasm file]", + Short: "Upload a wasm binary", + Aliases: []string{"upload", "st", "s"}, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg, err := parseStoreCodeArgs(args[0], clientCtx.GetFromAddress(), cmd.Flags()) + if err != nil { + return err + } + if err = msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + SilenceUsage: true, + } + + addInstantiatePermissionFlags(cmd) + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgStoreCode, error) { + wasm, err := os.ReadFile(file) + if err != nil { + return types.MsgStoreCode{}, err + } + + // gzip the wasm file + if ioutils.IsWasm(wasm) { + wasm, err = ioutils.GzipIt(wasm) + + if err != nil { + return types.MsgStoreCode{}, err + } + } else if !ioutils.IsGzip(wasm) { + return types.MsgStoreCode{}, fmt.Errorf("invalid input file. Use wasm binary or gzip") + } + + perm, err := parseAccessConfigFlags(flags) + if err != nil { + return types.MsgStoreCode{}, err + } + + msg := types.MsgStoreCode{ + Sender: sender.String(), + WASMByteCode: wasm, + InstantiatePermission: perm, + } + return msg, nil +} + +func parseAccessConfigFlags(flags *flag.FlagSet) (*types.AccessConfig, error) { + addrs, err := flags.GetStringSlice(flagInstantiateByAnyOfAddress) + if err != nil { + return nil, fmt.Errorf("flag any of: %s", err) + } + if len(addrs) != 0 { + acceptedAddrs := make([]sdk.AccAddress, len(addrs)) + for i, v := range addrs { + acceptedAddrs[i], err = sdk.AccAddressFromBech32(v) + if err != nil { + return nil, fmt.Errorf("parse %q: %w", v, err) + } + } + x := types.AccessTypeAnyOfAddresses.With(acceptedAddrs...) + return &x, nil + } + + onlyAddrStr, err := flags.GetString(flagInstantiateByAddress) + if err != nil { + return nil, fmt.Errorf("instantiate by address: %s", err) + } + if onlyAddrStr != "" { + return nil, fmt.Errorf("not supported anymore. Use: %s", flagInstantiateByAnyOfAddress) + } + everybodyStr, err := flags.GetString(flagInstantiateByEverybody) + if err != nil { + return nil, fmt.Errorf("instantiate by everybody: %s", err) + } + if everybodyStr != "" { + ok, err := strconv.ParseBool(everybodyStr) + if err != nil { + return nil, fmt.Errorf("boolean value expected for instantiate by everybody: %s", err) + } + if ok { + return &types.AllowEverybody, nil + } + } + + nobodyStr, err := flags.GetString(flagInstantiateNobody) + if err != nil { + return nil, fmt.Errorf("instantiate by nobody: %s", err) + } + if nobodyStr != "" { + ok, err := strconv.ParseBool(nobodyStr) + if err != nil { + return nil, fmt.Errorf("boolean value expected for instantiate by nobody: %s", err) + } + if ok { + return &types.AllowNobody, nil + } + } + return nil, nil +} + +func addInstantiatePermissionFlags(cmd *cobra.Command) { + cmd.Flags().String(flagInstantiateByEverybody, "", "Everybody can instantiate a contract from the code, optional") + cmd.Flags().String(flagInstantiateNobody, "", "Nobody except the governance process can instantiate a contract from the code, optional") + cmd.Flags().String(flagInstantiateByAddress, "", fmt.Sprintf("Removed: use %s instead", flagInstantiateByAnyOfAddress)) + cmd.Flags().StringSlice(flagInstantiateByAnyOfAddress, []string{}, "Any of the addresses can instantiate a contract from the code, optional") +} + +// InstantiateContractCmd will instantiate a contract from previously uploaded code. +func InstantiateContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "instantiate [code_id_int64] [json_encoded_init_args] --label [text] --admin [address,optional] --amount [coins,optional] ", + Short: "Instantiate a wasm contract", + Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message. +Each contract instance has a unique address assigned. +Example: +$ %s tx wasm instantiate 1 '{"foo":"bar"}' --admin="$(%s keys show mykey -a)" \ + --from mykey --amount="100ustake" --label "local0.1.0" +`, version.AppName, version.AppName), + Aliases: []string{"start", "init", "inst", "i"}, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.GetFromAddress(), cmd.Flags()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists") + cmd.Flags().String(flagAdmin, "", "Address or key name of an admin") + cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin") + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +// InstantiateContract2Cmd will instantiate a contract from previously uploaded code with predicable address generated +func InstantiateContract2Cmd() *cobra.Command { + decoder := newArgDecoder(hex.DecodeString) + cmd := &cobra.Command{ + Use: "instantiate2 [code_id_int64] [json_encoded_init_args] [salt] --label [text] --admin [address,optional] --amount [coins,optional] " + + "--fix-msg [bool,optional]", + Short: "Instantiate a wasm contract with predictable address", + Long: fmt.Sprintf(`Creates a new instance of an uploaded wasm code with the given 'constructor' message. +Each contract instance has a unique address assigned. They are assigned automatically but in order to have predictable addresses +for special use cases, the given 'salt' argument and '--fix-msg' parameters can be used to generate a custom address. + +Predictable address example (also see '%s query wasm build-address -h'): +$ %s tx wasm instantiate2 1 '{"foo":"bar"}' $(echo -n "testing" | xxd -ps) --admin="$(%s keys show mykey -a)" \ + --from mykey --amount="100ustake" --label "local0.1.0" \ + --fix-msg +`, version.AppName, version.AppName, version.AppName), + Aliases: []string{"start", "init", "inst", "i"}, + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + salt, err := decoder.DecodeString(args[2]) + if err != nil { + return fmt.Errorf("salt: %w", err) + } + fixMsg, err := cmd.Flags().GetBool(flagFixMsg) + if err != nil { + return fmt.Errorf("fix msg: %w", err) + } + data, err := parseInstantiateArgs(args[0], args[1], clientCtx.Keyring, clientCtx.GetFromAddress(), cmd.Flags()) + if err != nil { + return err + } + msg := &types.MsgInstantiateContract2{ + Sender: data.Sender, + Admin: data.Admin, + CodeID: data.CodeID, + Label: data.Label, + Msg: data.Msg, + Funds: data.Funds, + Salt: salt, + FixMsg: fixMsg, + } + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + SilenceUsage: true, + } + + cmd.Flags().String(flagAmount, "", "Coins to send to the contract during instantiation") + cmd.Flags().String(flagLabel, "", "A human-readable name for this contract in lists") + cmd.Flags().String(flagAdmin, "", "Address or key name of an admin") + cmd.Flags().Bool(flagNoAdmin, false, "You must set this explicitly if you don't want an admin") + cmd.Flags().Bool(flagFixMsg, false, "An optional flag to include the json_encoded_init_args for the predictable address generation mode") + decoder.RegisterFlags(cmd.PersistentFlags(), "salt") + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func parseInstantiateArgs(rawCodeID, initMsg string, kr keyring.Keyring, sender sdk.AccAddress, flags *flag.FlagSet) (*types.MsgInstantiateContract, error) { + // get the id of the code to instantiate + codeID, err := strconv.ParseUint(rawCodeID, 10, 64) + if err != nil { + return nil, err + } + + amountStr, err := flags.GetString(flagAmount) + if err != nil { + return nil, fmt.Errorf("amount: %s", err) + } + amount, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return nil, fmt.Errorf("amount: %s", err) + } + label, err := flags.GetString(flagLabel) + if err != nil { + return nil, fmt.Errorf("label: %s", err) + } + if label == "" { + return nil, errors.New("label is required on all contracts") + } + adminStr, err := flags.GetString(flagAdmin) + if err != nil { + return nil, fmt.Errorf("admin: %s", err) + } + + noAdmin, err := flags.GetBool(flagNoAdmin) + if err != nil { + return nil, fmt.Errorf("no-admin: %s", err) + } + + // ensure sensible admin is set (or explicitly immutable) + if adminStr == "" && !noAdmin { + return nil, fmt.Errorf("you must set an admin or explicitly pass --no-admin to make it immutible (wasmd issue #719)") + } + if adminStr != "" && noAdmin { + return nil, fmt.Errorf("you set an admin and passed --no-admin, those cannot both be true") + } + + if adminStr != "" { + addr, err := sdk.AccAddressFromBech32(adminStr) + if err != nil { + info, err := kr.Key(adminStr) + if err != nil { + return nil, fmt.Errorf("admin %s", err) + } + adminStr = info.GetAddress().String() + } else { + adminStr = addr.String() + } + } + + // build and sign the transaction, then broadcast to Tendermint + msg := types.MsgInstantiateContract{ + Sender: sender.String(), + CodeID: codeID, + Label: label, + Funds: amount, + Msg: []byte(initMsg), + Admin: adminStr, + } + return &msg, nil +} + +// ExecuteContractCmd will instantiate a contract from previously uploaded code. +func ExecuteContractCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "execute [contract_addr_bech32] [json_encoded_send_args] --amount [coins,optional]", + Short: "Execute a command on a wasm contract", + Aliases: []string{"run", "call", "exec", "ex", "e"}, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg, err := parseExecuteArgs(args[0], args[1], clientCtx.GetFromAddress(), cmd.Flags()) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg) + }, + SilenceUsage: true, + } + + cmd.Flags().String(flagAmount, "", "Coins to send to the contract along with command") + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func parseExecuteArgs(contractAddr string, execMsg string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgExecuteContract, error) { + amountStr, err := flags.GetString(flagAmount) + if err != nil { + return types.MsgExecuteContract{}, fmt.Errorf("amount: %s", err) + } + + amount, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return types.MsgExecuteContract{}, err + } + + return types.MsgExecuteContract{ + Sender: sender.String(), + Contract: contractAddr, + Funds: amount, + Msg: []byte(execMsg), + }, nil +} + +func GrantAuthorizationCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "grant [grantee] [message_type=\"execution\"|\"migration\"] [contract_addr_bech32] --allow-raw-msgs [msg1,msg2,...] --allow-msg-keys [key1,key2,...] --allow-all-messages", + Short: "Grant authorization to an address", + Long: fmt.Sprintf(`Grant authorization to an address. +Examples: +$ %s tx grant execution --allow-all-messages --max-calls 1 --no-token-transfer --expiration 1667979596 + +$ %s tx grant execution --allow-all-messages --max-funds 100000uwasm --expiration 1667979596 + +$ %s tx grant execution --allow-all-messages --max-calls 5 --max-funds 100000uwasm --expiration 1667979596 +`, version.AppName, version.AppName, version.AppName), + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + grantee, err := sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + + contract, err := sdk.AccAddressFromBech32(args[2]) + if err != nil { + return err + } + + msgKeys, err := cmd.Flags().GetStringSlice(flagAllowedMsgKeys) + if err != nil { + return err + } + + rawMsgs, err := cmd.Flags().GetStringSlice(flagAllowedRawMsgs) + if err != nil { + return err + } + + maxFundsStr, err := cmd.Flags().GetString(flagMaxFunds) + if err != nil { + return fmt.Errorf("max funds: %s", err) + } + + maxCalls, err := cmd.Flags().GetUint64(flagMaxCalls) + if err != nil { + return err + } + + exp, err := cmd.Flags().GetInt64(flagExpiration) + if err != nil { + return err + } + if exp == 0 { + return errors.New("expiration must be set") + } + + allowAllMsgs, err := cmd.Flags().GetBool(flagAllowAllMsgs) + if err != nil { + return err + } + + noTokenTransfer, err := cmd.Flags().GetBool(flagNoTokenTransfer) + if err != nil { + return err + } + + var limit types.ContractAuthzLimitX + switch { + case maxFundsStr != "" && maxCalls != 0 && !noTokenTransfer: + maxFunds, err := sdk.ParseCoinsNormalized(maxFundsStr) + if err != nil { + return fmt.Errorf("max funds: %s", err) + } + limit = types.NewCombinedLimit(maxCalls, maxFunds...) + case maxFundsStr != "" && maxCalls == 0 && !noTokenTransfer: + maxFunds, err := sdk.ParseCoinsNormalized(maxFundsStr) + if err != nil { + return fmt.Errorf("max funds: %s", err) + } + limit = types.NewMaxFundsLimit(maxFunds...) + case maxCalls != 0 && noTokenTransfer && maxFundsStr == "": + limit = types.NewMaxCallsLimit(maxCalls) + default: + return errors.New("invalid limit setup") + } + + var filter types.ContractAuthzFilterX + switch { + case allowAllMsgs && len(msgKeys) != 0 || allowAllMsgs && len(rawMsgs) != 0 || len(msgKeys) != 0 && len(rawMsgs) != 0: + return errors.New("cannot set more than one filter within one grant") + case allowAllMsgs: + filter = types.NewAllowAllMessagesFilter() + case len(msgKeys) != 0: + filter = types.NewAcceptedMessageKeysFilter(msgKeys...) + case len(rawMsgs) != 0: + msgs := make([]types.RawContractMessage, len(rawMsgs)) + for i, msg := range rawMsgs { + msgs[i] = types.RawContractMessage(msg) + } + filter = types.NewAcceptedMessagesFilter(msgs...) + default: + return errors.New("invalid filter setup") + } + + grant, err := types.NewContractGrant(contract, limit, filter) + if err != nil { + return err + } + + var authorization authz.Authorization + switch args[1] { + case "execution": + authorization = types.NewContractExecutionAuthorization(*grant) + case "migration": + authorization = types.NewContractMigrationAuthorization(*grant) + default: + return fmt.Errorf("%s authorization type not supported", args[1]) + } + + grantMsg, err := authz.NewMsgGrant(clientCtx.GetFromAddress(), grantee, authorization, time.Unix(0, exp)) + if err != nil { + return err + } + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), grantMsg) + }, + } + flags.AddTxFlagsToCmd(cmd) + cmd.Flags().StringSlice(flagAllowedMsgKeys, []string{}, "Allowed msg keys") + cmd.Flags().StringSlice(flagAllowedRawMsgs, []string{}, "Allowed raw msgs") + cmd.Flags().Uint64(flagMaxCalls, 0, "Maximal number of calls to the contract") + cmd.Flags().String(flagMaxFunds, "", "Maximal amount of tokens transferable to the contract.") + cmd.Flags().Int64(flagExpiration, 0, "The Unix timestamp.") + cmd.Flags().Bool(flagAllowAllMsgs, false, "Allow all messages") + cmd.Flags().Bool(flagNoTokenTransfer, false, "Don't allow token transfer") + return cmd +} diff --git a/x/wasm/client/cli/tx_test.go b/x/wasm/client/cli/tx_test.go new file mode 100644 index 00000000..15bbc15a --- /dev/null +++ b/x/wasm/client/cli/tx_test.go @@ -0,0 +1,59 @@ +package cli + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestParseAccessConfigFlags(t *testing.T) { + specs := map[string]struct { + args []string + expCfg *types.AccessConfig + expErr bool + }{ + "nobody": { + args: []string{"--instantiate-nobody=true"}, + expCfg: &types.AccessConfig{Permission: types.AccessTypeNobody}, + }, + "everybody": { + args: []string{"--instantiate-everybody=true"}, + expCfg: &types.AccessConfig{Permission: types.AccessTypeEverybody}, + }, + "only address": { + args: []string{"--instantiate-only-address=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x"}, + expErr: true, + }, + "only address - invalid": { + args: []string{"--instantiate-only-address=foo"}, + expErr: true, + }, + "any of address": { + args: []string{"--instantiate-anyof-addresses=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}, + expCfg: &types.AccessConfig{Permission: types.AccessTypeAnyOfAddresses, Addresses: []string{"cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x", "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr"}}, + }, + "any of address - invalid": { + args: []string{"--instantiate-anyof-addresses=cosmos1vx8knpllrj7n963p9ttd80w47kpacrhuts497x,foo"}, + expErr: true, + }, + "not set": { + args: []string{}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + flags := StoreCodeCmd().Flags() + require.NoError(t, flags.Parse(spec.args)) + gotCfg, gotErr := parseAccessConfigFlags(flags) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expCfg, gotCfg) + }) + } +} diff --git a/x/wasm/client/proposal_handler.go b/x/wasm/client/proposal_handler.go new file mode 100644 index 00000000..cf7b3d4e --- /dev/null +++ b/x/wasm/client/proposal_handler.go @@ -0,0 +1,25 @@ +package client + +import ( + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + + "github.com/cerc-io/laconicd/x/wasm/client/cli" + "github.com/cerc-io/laconicd/x/wasm/client/rest" //nolint:staticcheck +) + +// ProposalHandlers define the wasm cli proposal types and rest handler. +// Deprecated: the rest package will be removed. You can use the GRPC gateway instead +var ProposalHandlers = []govclient.ProposalHandler{ + govclient.NewProposalHandler(cli.ProposalStoreCodeCmd, rest.StoreCodeProposalHandler), + govclient.NewProposalHandler(cli.ProposalInstantiateContractCmd, rest.InstantiateProposalHandler), + govclient.NewProposalHandler(cli.ProposalMigrateContractCmd, rest.MigrateProposalHandler), + govclient.NewProposalHandler(cli.ProposalExecuteContractCmd, rest.ExecuteProposalHandler), + govclient.NewProposalHandler(cli.ProposalSudoContractCmd, rest.SudoProposalHandler), + govclient.NewProposalHandler(cli.ProposalUpdateContractAdminCmd, rest.UpdateContractAdminProposalHandler), + govclient.NewProposalHandler(cli.ProposalClearContractAdminCmd, rest.ClearContractAdminProposalHandler), + govclient.NewProposalHandler(cli.ProposalPinCodesCmd, rest.PinCodeProposalHandler), + govclient.NewProposalHandler(cli.ProposalUnpinCodesCmd, rest.UnpinCodeProposalHandler), + govclient.NewProposalHandler(cli.ProposalUpdateInstantiateConfigCmd, rest.UpdateInstantiateConfigProposalHandler), + govclient.NewProposalHandler(cli.ProposalStoreAndInstantiateContractCmd, rest.EmptyRestHandler), + govclient.NewProposalHandler(cli.ProposalInstantiateContract2Cmd, rest.EmptyRestHandler), +} diff --git a/x/wasm/client/proposal_handler_test.go b/x/wasm/client/proposal_handler_test.go new file mode 100644 index 00000000..dd4099da --- /dev/null +++ b/x/wasm/client/proposal_handler_test.go @@ -0,0 +1,381 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/gorilla/mux" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper" +) + +func TestGovRestHandlers(t *testing.T) { + type dict map[string]interface{} + var ( + anyAddress = "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz" + aBaseReq = dict{ + "from": anyAddress, + "memo": "rest test", + "chain_id": "testing", + "account_number": "1", + "sequence": "1", + "fees": []dict{{"denom": "ustake", "amount": "1000000"}}, + } + ) + encodingConfig := keeper.MakeEncodingConfig(t) + clientCtx := client.Context{}. + WithCodec(encodingConfig.Marshaler). + WithTxConfig(encodingConfig.TxConfig). + WithLegacyAmino(encodingConfig.Amino). + WithInput(os.Stdin). + WithAccountRetriever(authtypes.AccountRetriever{}). + WithBroadcastMode(flags.BroadcastBlock). + WithChainID("testing") + + // router setup as in gov/client/rest/tx.go + propSubRtr := mux.NewRouter().PathPrefix("/gov/proposals").Subrouter() + for _, ph := range ProposalHandlers { + r := ph.RESTHandler(clientCtx) + propSubRtr.HandleFunc(fmt.Sprintf("/%s", r.SubRoute), r.Handler).Methods("POST") + } + + specs := map[string]struct { + srcBody dict + srcPath string + expCode int + }{ + "store-code": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": []byte("valid wasm byte code"), + "source": "https://example.com/", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "store-code without verification info": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": []byte("valid wasm byte code"), + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "store-code without permission": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": []byte("valid wasm byte code"), + "source": "https://example.com/", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "store-code invalid permission": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": []byte("valid wasm byte code"), + "source": "https://example.com/", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "instantiate_permission": dict{ + "permission": "Nobody", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "store-code with incomplete proposal data: blank title": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": []byte("valid wasm byte code"), + "source": "https://example.com/", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "store-code with incomplete content data: no wasm_byte_code": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": "", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "source": "https://example.com/", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "store-code with incomplete content data: no builder": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": "", + "source": "https://example.com/", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "store-code with incomplete content data: no code hash": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": "", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "source": "https://example.com/", + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "store-code with incomplete content data: no source": { + srcPath: "/gov/proposals/wasm_store_code", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "store-code", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "wasm_byte_code": "", + "builder": "cosmwasm/workspace-optimizer:v0.12.9", + "code_hash": "79F174F09BFE3F83398BF7C147929D5F735161BD46D645E85216BB13BF91D42D", + "instantiate_permission": dict{ + "permission": "OnlyAddress", + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + }, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "instantiate contract": { + srcPath: "/gov/proposals/wasm_instantiate", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "instantiate", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "admin": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "code_id": "1", + "label": "https://example.com/", + "msg": dict{"recipient": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz"}, + "funds": []dict{{"denom": "ustake", "amount": "100"}}, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "migrate contract": { + srcPath: "/gov/proposals/wasm_migrate", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "code_id": "1", + "msg": dict{"foo": "bar"}, + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "execute contract": { + srcPath: "/gov/proposals/wasm_execute", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "msg": dict{"foo": "bar"}, + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "execute contract fails with no run_as": { + srcPath: "/gov/proposals/wasm_execute", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "msg": dict{"foo": "bar"}, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "execute contract fails with no message": { + srcPath: "/gov/proposals/wasm_execute", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "run_as": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "sudo contract": { + srcPath: "/gov/proposals/wasm_sudo", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "msg": dict{"foo": "bar"}, + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "sudo contract fails with no message": { + srcPath: "/gov/proposals/wasm_sudo", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusBadRequest, + }, + "update contract admin": { + srcPath: "/gov/proposals/wasm_update_admin", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "new_admin": "cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + "clear contract admin": { + srcPath: "/gov/proposals/wasm_clear_admin", + srcBody: dict{ + "title": "Test Proposal", + "description": "My proposal", + "type": "migrate", + "contract": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "deposit": []dict{{"denom": "ustake", "amount": "10"}}, + "proposer": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "base_req": aBaseReq, + }, + expCode: http.StatusOK, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + src, err := json.Marshal(spec.srcBody) + require.NoError(t, err) + + // when + r := httptest.NewRequest("POST", spec.srcPath, bytes.NewReader(src)) + w := httptest.NewRecorder() + propSubRtr.ServeHTTP(w, r) + + // then + require.Equal(t, spec.expCode, w.Code, w.Body.String()) + }) + } +} diff --git a/x/wasm/client/rest/gov.go b/x/wasm/client/rest/gov.go new file mode 100644 index 00000000..b048cf87 --- /dev/null +++ b/x/wasm/client/rest/gov.go @@ -0,0 +1,547 @@ +package rest + +import ( + "encoding/json" + "net/http" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +type StoreCodeProposalJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + RunAs string `json:"run_as" yaml:"run_as"` + // WASMByteCode can be raw or gzip compressed + WASMByteCode []byte `json:"wasm_byte_code" yaml:"wasm_byte_code"` + // InstantiatePermission to apply on contract creation, optional + InstantiatePermission *types.AccessConfig `json:"instantiate_permission" yaml:"instantiate_permission"` + + // UnpinCode indicates if the code should not be pinned as part of the proposal. + UnpinCode bool `json:"unpin_code" yaml:"unpin_code"` + + // Source is the URL where the code is hosted + Source string `json:"source" yaml:"source"` + // Builder is the docker image used to build the code deterministically, used for smart + // contract verification + Builder string `json:"builder" yaml:"builder"` + // CodeHash is the SHA256 sum of the code outputted by optimizer, used for smart contract verification + CodeHash []byte `json:"code_hash" yaml:"code_hash"` +} + +func (s StoreCodeProposalJSONReq) Content() govtypes.Content { + return &types.StoreCodeProposal{ + Title: s.Title, + Description: s.Description, + RunAs: s.RunAs, + WASMByteCode: s.WASMByteCode, + InstantiatePermission: s.InstantiatePermission, + UnpinCode: s.UnpinCode, + Source: s.Source, + Builder: s.Builder, + CodeHash: s.CodeHash, + } +} + +func (s StoreCodeProposalJSONReq) GetProposer() string { + return s.Proposer +} + +func (s StoreCodeProposalJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s StoreCodeProposalJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func StoreCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_store_code", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req StoreCodeProposalJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type InstantiateProposalJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + RunAs string `json:"run_as" yaml:"run_as"` + // Admin is an optional address that can execute migrations + Admin string `json:"admin,omitempty" yaml:"admin"` + Code uint64 `json:"code_id" yaml:"code_id"` + Label string `json:"label" yaml:"label"` + Msg json.RawMessage `json:"msg" yaml:"msg"` + Funds sdk.Coins `json:"funds" yaml:"funds"` +} + +func (s InstantiateProposalJSONReq) Content() govtypes.Content { + return &types.InstantiateContractProposal{ + Title: s.Title, + Description: s.Description, + RunAs: s.RunAs, + Admin: s.Admin, + CodeID: s.Code, + Label: s.Label, + Msg: types.RawContractMessage(s.Msg), + Funds: s.Funds, + } +} + +func (s InstantiateProposalJSONReq) GetProposer() string { + return s.Proposer +} + +func (s InstantiateProposalJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s InstantiateProposalJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func InstantiateProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_instantiate", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req InstantiateProposalJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type MigrateProposalJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + Contract string `json:"contract" yaml:"contract"` + Code uint64 `json:"code_id" yaml:"code_id"` + Msg json.RawMessage `json:"msg" yaml:"msg"` +} + +func (s MigrateProposalJSONReq) Content() govtypes.Content { + return &types.MigrateContractProposal{ + Title: s.Title, + Description: s.Description, + Contract: s.Contract, + CodeID: s.Code, + Msg: types.RawContractMessage(s.Msg), + } +} + +func (s MigrateProposalJSONReq) GetProposer() string { + return s.Proposer +} + +func (s MigrateProposalJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s MigrateProposalJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func MigrateProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_migrate", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req MigrateProposalJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type ExecuteProposalJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + Contract string `json:"contract" yaml:"contract"` + Msg json.RawMessage `json:"msg" yaml:"msg"` + // RunAs is the role that is passed to the contract's environment + RunAs string `json:"run_as" yaml:"run_as"` + Funds sdk.Coins `json:"funds" yaml:"funds"` +} + +func (s ExecuteProposalJSONReq) Content() govtypes.Content { + return &types.ExecuteContractProposal{ + Title: s.Title, + Description: s.Description, + Contract: s.Contract, + Msg: types.RawContractMessage(s.Msg), + RunAs: s.RunAs, + Funds: s.Funds, + } +} + +func (s ExecuteProposalJSONReq) GetProposer() string { + return s.Proposer +} + +func (s ExecuteProposalJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s ExecuteProposalJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func ExecuteProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_execute", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req ExecuteProposalJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type SudoProposalJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + Contract string `json:"contract" yaml:"contract"` + Msg json.RawMessage `json:"msg" yaml:"msg"` +} + +func (s SudoProposalJSONReq) Content() govtypes.Content { + return &types.SudoContractProposal{ + Title: s.Title, + Description: s.Description, + Contract: s.Contract, + Msg: types.RawContractMessage(s.Msg), + } +} + +func (s SudoProposalJSONReq) GetProposer() string { + return s.Proposer +} + +func (s SudoProposalJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s SudoProposalJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func SudoProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_sudo", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req SudoProposalJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type UpdateAdminJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + NewAdmin string `json:"new_admin" yaml:"new_admin"` + Contract string `json:"contract" yaml:"contract"` +} + +func (s UpdateAdminJSONReq) Content() govtypes.Content { + return &types.UpdateAdminProposal{ + Title: s.Title, + Description: s.Description, + Contract: s.Contract, + NewAdmin: s.NewAdmin, + } +} + +func (s UpdateAdminJSONReq) GetProposer() string { + return s.Proposer +} + +func (s UpdateAdminJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s UpdateAdminJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func UpdateContractAdminProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_update_admin", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req UpdateAdminJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type ClearAdminJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + Contract string `json:"contract" yaml:"contract"` +} + +func (s ClearAdminJSONReq) Content() govtypes.Content { + return &types.ClearAdminProposal{ + Title: s.Title, + Description: s.Description, + Contract: s.Contract, + } +} + +func (s ClearAdminJSONReq) GetProposer() string { + return s.Proposer +} + +func (s ClearAdminJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s ClearAdminJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func ClearContractAdminProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "wasm_clear_admin", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req ClearAdminJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type PinCodeJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + CodeIDs []uint64 `json:"code_ids" yaml:"code_ids"` +} + +func (s PinCodeJSONReq) Content() govtypes.Content { + return &types.PinCodesProposal{ + Title: s.Title, + Description: s.Description, + CodeIDs: s.CodeIDs, + } +} + +func (s PinCodeJSONReq) GetProposer() string { + return s.Proposer +} + +func (s PinCodeJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s PinCodeJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func PinCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "pin_code", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req PinCodeJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type UnpinCodeJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + + CodeIDs []uint64 `json:"code_ids" yaml:"code_ids"` +} + +func (s UnpinCodeJSONReq) Content() govtypes.Content { + return &types.UnpinCodesProposal{ + Title: s.Title, + Description: s.Description, + CodeIDs: s.CodeIDs, + } +} + +func (s UnpinCodeJSONReq) GetProposer() string { + return s.Proposer +} + +func (s UnpinCodeJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s UnpinCodeJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func UnpinCodeProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "unpin_code", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req UnpinCodeJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type UpdateInstantiateConfigProposalJSONReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + Proposer string `json:"proposer" yaml:"proposer"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + AccessConfigUpdates []types.AccessConfigUpdate `json:"access_config_updates" yaml:"access_config_updates"` +} + +func (s UpdateInstantiateConfigProposalJSONReq) Content() govtypes.Content { + return &types.UpdateInstantiateConfigProposal{ + Title: s.Title, + Description: s.Description, + AccessConfigUpdates: s.AccessConfigUpdates, + } +} + +func (s UpdateInstantiateConfigProposalJSONReq) GetProposer() string { + return s.Proposer +} + +func (s UpdateInstantiateConfigProposalJSONReq) GetDeposit() sdk.Coins { + return s.Deposit +} + +func (s UpdateInstantiateConfigProposalJSONReq) GetBaseReq() rest.BaseReq { + return s.BaseReq +} + +func UpdateInstantiateConfigProposalHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "update_instantiate_config", + Handler: func(w http.ResponseWriter, r *http.Request) { + var req UpdateInstantiateConfigProposalJSONReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + toStdTxResponse(cliCtx, w, req) + }, + } +} + +type wasmProposalData interface { + Content() govtypes.Content + GetProposer() string + GetDeposit() sdk.Coins + GetBaseReq() rest.BaseReq +} + +func toStdTxResponse(cliCtx client.Context, w http.ResponseWriter, data wasmProposalData) { + proposerAddr, err := sdk.AccAddressFromBech32(data.GetProposer()) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + msg, err := govtypes.NewMsgSubmitProposal(data.Content(), data.GetDeposit(), proposerAddr) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + baseReq := data.GetBaseReq().Sanitize() + if !baseReq.ValidateBasic(w) { + return + } + tx.WriteGeneratedTxResponse(cliCtx, w, baseReq, msg) +} + +func EmptyRestHandler(cliCtx client.Context) govrest.ProposalRESTHandler { + return govrest.ProposalRESTHandler{ + SubRoute: "unsupported", + Handler: func(w http.ResponseWriter, r *http.Request) { + rest.WriteErrorResponse(w, http.StatusBadRequest, "Legacy REST Routes are not supported for gov proposals") + }, + } +} diff --git a/x/wasm/client/rest/new_tx.go b/x/wasm/client/rest/new_tx.go new file mode 100644 index 00000000..89ebaf48 --- /dev/null +++ b/x/wasm/client/rest/new_tx.go @@ -0,0 +1,86 @@ +package rest + +import ( + "net/http" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/gorilla/mux" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func registerNewTxRoutes(cliCtx client.Context, r *mux.Router) { + r.HandleFunc("/wasm/contract/{contractAddr}/admin", setContractAdminHandlerFn(cliCtx)).Methods("PUT") + r.HandleFunc("/wasm/contract/{contractAddr}/code", migrateContractHandlerFn(cliCtx)).Methods("PUT") +} + +type migrateContractReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Admin string `json:"admin,omitempty" yaml:"admin"` + CodeID uint64 `json:"code_id" yaml:"code_id"` + Msg []byte `json:"msg,omitempty" yaml:"msg"` +} + +type updateContractAdministrateReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Admin string `json:"admin,omitempty" yaml:"admin"` +} + +func setContractAdminHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req updateContractAdministrateReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + vars := mux.Vars(r) + contractAddr := vars["contractAddr"] + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + msg := &types.MsgUpdateAdmin{ + Sender: req.BaseReq.From, + NewAdmin: req.Admin, + Contract: contractAddr, + } + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) + } +} + +func migrateContractHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req migrateContractReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + vars := mux.Vars(r) + contractAddr := vars["contractAddr"] + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + msg := &types.MsgMigrateContract{ + Sender: req.BaseReq.From, + Contract: contractAddr, + CodeID: req.CodeID, + Msg: req.Msg, + } + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, msg) + } +} diff --git a/x/wasm/client/rest/query.go b/x/wasm/client/rest/query.go new file mode 100644 index 00000000..42c074e3 --- /dev/null +++ b/x/wasm/client/rest/query.go @@ -0,0 +1,270 @@ +package rest + +import ( + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/gorilla/mux" + + "github.com/cerc-io/laconicd/x/wasm/keeper" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func registerQueryRoutes(cliCtx client.Context, r *mux.Router) { + r.HandleFunc("/wasm/code", listCodesHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/wasm/code/{codeID}", queryCodeHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/wasm/code/{codeID}/contracts", listContractsByCodeHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/wasm/contract/{contractAddr}", queryContractHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/wasm/contract/{contractAddr}/state", queryContractStateAllHandlerFn(cliCtx)).Methods("GET") + r.HandleFunc("/wasm/contract/{contractAddr}/history", queryContractHistoryFn(cliCtx)).Methods("GET") + r.HandleFunc("/wasm/contract/{contractAddr}/smart/{query}", queryContractStateSmartHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET") + r.HandleFunc("/wasm/contract/{contractAddr}/raw/{key}", queryContractStateRawHandlerFn(cliCtx)).Queries("encoding", "{encoding}").Methods("GET") +} + +func listCodesHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, keeper.QueryListCode) + res, height, err := cliCtx.Query(route) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) + } +} + +func queryCodeHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryGetCode, codeID) + res, height, err := cliCtx.Query(route) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + if len(res) == 0 { + rest.WriteErrorResponse(w, http.StatusNotFound, "contract not found") + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) + } +} + +func listContractsByCodeHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + codeID, err := strconv.ParseUint(mux.Vars(r)["codeID"], 10, 64) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%d", types.QuerierRoute, keeper.QueryListContractByCode, codeID) + res, height, err := cliCtx.Query(route) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) + } +} + +func queryContractHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContract, addr.String()) + res, height, err := cliCtx.Query(route) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) + } +} + +func queryContractStateAllHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateAll) + res, height, err := cliCtx.Query(route) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + // parse res + var resultData []types.Model + err = json.Unmarshal(res, &resultData) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, resultData) + } +} + +func queryContractStateRawHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + decoder := newArgDecoder(hex.DecodeString) + addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + decoder.encoding = mux.Vars(r)["encoding"] + queryData, err := decoder.DecodeString(mux.Vars(r)["key"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateRaw) + res, height, err := cliCtx.QueryWithData(route, queryData) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx = cliCtx.WithHeight(height) + // ensure this is base64 encoded + encoded := base64.StdEncoding.EncodeToString(res) + rest.PostProcessResponse(w, cliCtx, encoded) + } +} + +type smartResponse struct { + Smart []byte `json:"smart"` +} + +func queryContractStateSmartHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + decoder := newArgDecoder(hex.DecodeString) + addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + decoder.encoding = mux.Vars(r)["encoding"] + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%s/%s", types.QuerierRoute, keeper.QueryGetContractState, addr.String(), keeper.QueryMethodContractStateSmart) + + queryData, err := decoder.DecodeString(mux.Vars(r)["query"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + res, height, err := cliCtx.QueryWithData(route, queryData) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + // return as raw bytes (to be base64-encoded) + responseData := smartResponse{Smart: res} + + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, responseData) + } +} + +func queryContractHistoryFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + addr, err := sdk.AccAddressFromBech32(mux.Vars(r)["contractAddr"]) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r) + if !ok { + return + } + + route := fmt.Sprintf("custom/%s/%s/%s", types.QuerierRoute, keeper.QueryContractHistory, addr.String()) + res, height, err := cliCtx.Query(route) + if err != nil { + rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error()) + return + } + cliCtx = cliCtx.WithHeight(height) + rest.PostProcessResponse(w, cliCtx, json.RawMessage(res)) + } +} + +type argumentDecoder struct { + // dec is the default decoder + dec func(string) ([]byte, error) + encoding string +} + +func newArgDecoder(def func(string) ([]byte, error)) *argumentDecoder { + return &argumentDecoder{dec: def} +} + +func (a *argumentDecoder) DecodeString(s string) ([]byte, error) { + switch a.encoding { + case "hex": + return hex.DecodeString(s) + case "base64": + return base64.StdEncoding.DecodeString(s) + default: + return a.dec(s) + } +} diff --git a/x/wasm/client/rest/rest.go b/x/wasm/client/rest/rest.go new file mode 100644 index 00000000..95339d3a --- /dev/null +++ b/x/wasm/client/rest/rest.go @@ -0,0 +1,15 @@ +// Deprecated: the rest package will be removed. You can use the GRPC gateway instead +package rest + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/gorilla/mux" +) + +// RegisterRoutes registers staking-related REST handlers to a router +// Deprecated: the rest package will be removed. You can use the GRPC gateway instead +func RegisterRoutes(cliCtx client.Context, r *mux.Router) { + registerQueryRoutes(cliCtx, r) + registerTxRoutes(cliCtx, r) + registerNewTxRoutes(cliCtx, r) +} diff --git a/x/wasm/client/rest/tx.go b/x/wasm/client/rest/tx.go new file mode 100644 index 00000000..7be7d67d --- /dev/null +++ b/x/wasm/client/rest/tx.go @@ -0,0 +1,149 @@ +package rest + +import ( + "net/http" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/rest" + "github.com/gorilla/mux" + + "github.com/cerc-io/laconicd/x/wasm/ioutils" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func registerTxRoutes(cliCtx client.Context, r *mux.Router) { + r.HandleFunc("/wasm/code", storeCodeHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/wasm/code/{codeId}", instantiateContractHandlerFn(cliCtx)).Methods("POST") + r.HandleFunc("/wasm/contract/{contractAddr}", executeContractHandlerFn(cliCtx)).Methods("POST") +} + +type storeCodeReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + WasmBytes []byte `json:"wasm_bytes"` +} + +type instantiateContractReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + Label string `json:"label" yaml:"label"` + Deposit sdk.Coins `json:"deposit" yaml:"deposit"` + Admin string `json:"admin,omitempty" yaml:"admin"` + Msg []byte `json:"msg" yaml:"msg"` +} + +type executeContractReq struct { + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ExecMsg []byte `json:"exec_msg" yaml:"exec_msg"` + Amount sdk.Coins `json:"coins" yaml:"coins"` +} + +func storeCodeHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req storeCodeReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + var err error + wasm := req.WasmBytes + + // gzip the wasm file + if ioutils.IsWasm(wasm) { + wasm, err = ioutils.GzipIt(wasm) + if err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + } else if !ioutils.IsGzip(wasm) { + rest.WriteErrorResponse(w, http.StatusBadRequest, "Invalid input file, use wasm binary or zip") + return + } + + // build and sign the transaction, then broadcast to Tendermint + msg := types.MsgStoreCode{ + Sender: req.BaseReq.From, + WASMByteCode: wasm, + } + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, &msg) + } +} + +func instantiateContractHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req instantiateContractReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + vars := mux.Vars(r) + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + // get the id of the code to instantiate + codeID, err := strconv.ParseUint(vars["codeId"], 10, 64) + if err != nil { + return + } + + msg := types.MsgInstantiateContract{ + Sender: req.BaseReq.From, + CodeID: codeID, + Label: req.Label, + Funds: req.Deposit, + Msg: req.Msg, + Admin: req.Admin, + } + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, &msg) + } +} + +func executeContractHandlerFn(cliCtx client.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req executeContractReq + if !rest.ReadRESTReq(w, r, cliCtx.LegacyAmino, &req) { + return + } + vars := mux.Vars(r) + contractAddr := vars["contractAddr"] + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + msg := types.MsgExecuteContract{ + Sender: req.BaseReq.From, + Contract: contractAddr, + Msg: req.ExecMsg, + Funds: req.Amount, + } + + if err := msg.ValidateBasic(); err != nil { + rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error()) + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, req.BaseReq, &msg) + } +} diff --git a/x/wasm/common_test.go b/x/wasm/common_test.go new file mode 100644 index 00000000..ce232a5e --- /dev/null +++ b/x/wasm/common_test.go @@ -0,0 +1,34 @@ +package wasm + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +// ensure store code returns the expected response +func assertStoreCodeResponse(t *testing.T, data []byte, expected uint64) { + var pStoreResp MsgStoreCodeResponse + require.NoError(t, pStoreResp.Unmarshal(data)) + require.Equal(t, pStoreResp.CodeID, expected) +} + +// ensure execution returns the expected data +func assertExecuteResponse(t *testing.T, data []byte, expected []byte) { + var pExecResp MsgExecuteContractResponse + require.NoError(t, pExecResp.Unmarshal(data)) + require.Equal(t, pExecResp.Data, expected) +} + +// ensures this returns a valid bech32 address and returns it +func parseInitResponse(t *testing.T, data []byte) string { + var pInstResp MsgInstantiateContractResponse + require.NoError(t, pInstResp.Unmarshal(data)) + require.NotEmpty(t, pInstResp.Address) + addr := pInstResp.Address + // ensure this is a valid sdk address + _, err := sdk.AccAddressFromBech32(addr) + require.NoError(t, err) + return addr +} diff --git a/x/wasm/genesis_test.go b/x/wasm/genesis_test.go new file mode 100644 index 00000000..9d968f87 --- /dev/null +++ b/x/wasm/genesis_test.go @@ -0,0 +1,96 @@ +package wasm + +import ( + "encoding/json" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" +) + +func TestInitGenesis(t *testing.T) { + data := setupTest(t) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := data.faucet.NewFundedRandomAccount(data.ctx, deposit.Add(deposit...)...) + fred := data.faucet.NewFundedRandomAccount(data.ctx, topUp...) + + h := data.module.Route().Handler() + q := data.module.LegacyQuerierHandler(nil) + + msg := MsgStoreCode{ + Sender: creator.String(), + WASMByteCode: testContract, + } + err := msg.ValidateBasic() + require.NoError(t, err) + + res, err := h(data.ctx, &msg) + require.NoError(t, err) + assertStoreCodeResponse(t, res.Data, 1) + + _, _, bob := keyPubAddr() + initMsg := initMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + initCmd := MsgInstantiateContract{ + Sender: creator.String(), + CodeID: firstCodeID, + Msg: initMsgBz, + Funds: deposit, + Label: "testing", + } + res, err = h(data.ctx, &initCmd) + require.NoError(t, err) + contractBech32Addr := parseInitResponse(t, res.Data) + + execCmd := MsgExecuteContract{ + Sender: fred.String(), + Contract: contractBech32Addr, + Msg: []byte(`{"release":{}}`), + Funds: topUp, + } + res, err = h(data.ctx, &execCmd) + require.NoError(t, err) + // from https://github.com/CosmWasm/cosmwasm/blob/master/contracts/hackatom/src/contract.rs#L167 + assertExecuteResponse(t, res.Data, []byte{0xf0, 0x0b, 0xaa}) + + // ensure all contract state is as after init + assertCodeList(t, q, data.ctx, 1) + assertCodeBytes(t, q, data.ctx, 1, testContract) + + assertContractList(t, q, data.ctx, 1, []string{contractBech32Addr}) + assertContractInfo(t, q, data.ctx, contractBech32Addr, 1, creator) + assertContractState(t, q, data.ctx, contractBech32Addr, state{ + Verifier: fred.String(), + Beneficiary: bob.String(), + Funder: creator.String(), + }) + + // export into genstate + genState := ExportGenesis(data.ctx, &data.keeper) + + // create new app to import genstate into + newData := setupTest(t) + q2 := newData.module.LegacyQuerierHandler(nil) + + // initialize new app with genstate + InitGenesis(newData.ctx, &newData.keeper, *genState) + + // run same checks again on newdata, to make sure it was reinitialized correctly + assertCodeList(t, q2, newData.ctx, 1) + assertCodeBytes(t, q2, newData.ctx, 1, testContract) + + assertContractList(t, q2, newData.ctx, 1, []string{contractBech32Addr}) + assertContractInfo(t, q2, newData.ctx, contractBech32Addr, 1, creator) + assertContractState(t, q2, newData.ctx, contractBech32Addr, state{ + Verifier: fred.String(), + Beneficiary: bob.String(), + Funder: creator.String(), + }) +} diff --git a/x/wasm/handler.go b/x/wasm/handler.go new file mode 100644 index 00000000..75cd080f --- /dev/null +++ b/x/wasm/handler.go @@ -0,0 +1,77 @@ +package wasm + +import ( + "fmt" + + "github.com/gogo/protobuf/proto" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/keeper" + "github.com/cerc-io/laconicd/x/wasm/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// NewHandler returns a handler for "wasm" type messages. +func NewHandler(k types.ContractOpsKeeper) sdk.Handler { + msgServer := keeper.NewMsgServerImpl(k) + + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + var ( + res proto.Message + err error + ) + switch msg := msg.(type) { + case *MsgStoreCode: //nolint:typecheck + res, err = msgServer.StoreCode(sdk.WrapSDKContext(ctx), msg) + case *MsgInstantiateContract: + res, err = msgServer.InstantiateContract(sdk.WrapSDKContext(ctx), msg) + case *MsgInstantiateContract2: + res, err = msgServer.InstantiateContract2(sdk.WrapSDKContext(ctx), msg) + case *MsgExecuteContract: + res, err = msgServer.ExecuteContract(sdk.WrapSDKContext(ctx), msg) + case *MsgMigrateContract: + res, err = msgServer.MigrateContract(sdk.WrapSDKContext(ctx), msg) + case *MsgUpdateAdmin: + res, err = msgServer.UpdateAdmin(sdk.WrapSDKContext(ctx), msg) + case *MsgClearAdmin: + res, err = msgServer.ClearAdmin(sdk.WrapSDKContext(ctx), msg) + case *types.MsgUpdateInstantiateConfig: + res, err = msgServer.UpdateInstantiateConfig(sdk.WrapSDKContext(ctx), msg) + default: + errMsg := fmt.Sprintf("unrecognized wasm message type: %T", msg) + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) + } + + ctx = ctx.WithEventManager(filterMessageEvents(ctx)) + return sdk.WrapServiceResult(ctx, res, err) + } +} + +// filterMessageEvents returns the same events with all of type == EventTypeMessage removed except +// for wasm message types. +// this is so only our top-level message event comes through +func filterMessageEvents(ctx sdk.Context) *sdk.EventManager { + m := sdk.NewEventManager() + for _, e := range ctx.EventManager().Events() { + if e.Type == sdk.EventTypeMessage && + !hasWasmModuleAttribute(e.Attributes) { + continue + } + m.EmitEvent(e) + } + return m +} + +func hasWasmModuleAttribute(attrs []abci.EventAttribute) bool { + for _, a := range attrs { + if sdk.AttributeKeyModule == string(a.Key) && + types.ModuleName == string(a.Value) { + return true + } + } + return false +} diff --git a/x/wasm/ibc.go b/x/wasm/ibc.go new file mode 100644 index 00000000..a20f6890 --- /dev/null +++ b/x/wasm/ibc.go @@ -0,0 +1,357 @@ +package wasm + +import ( + "math" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + 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/v4/modules/core/04-channel/types" + porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var _ porttypes.IBCModule = IBCHandler{} + +// internal interface that is implemented by ibc middleware +type appVersionGetter interface { + // GetAppVersion returns the application level version with all middleware data stripped out + GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) +} + +type IBCHandler struct { + keeper types.IBCContractKeeper + channelKeeper types.ChannelKeeper + appVersionGetter appVersionGetter +} + +func NewIBCHandler(k types.IBCContractKeeper, ck types.ChannelKeeper, vg appVersionGetter) IBCHandler { + return IBCHandler{keeper: k, channelKeeper: ck, appVersionGetter: vg} +} + +// OnChanOpenInit implements the IBCModule interface +func (i IBCHandler) OnChanOpenInit( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + chanCap *capabilitytypes.Capability, + counterParty channeltypes.Counterparty, + version string, +) (string, error) { + // ensure port, version, capability + if err := ValidateChannelParams(channelID); err != nil { + return "", err + } + contractAddr, err := ContractFromPortID(portID) + if err != nil { + return "", sdkerrors.Wrapf(err, "contract port id") + } + + msg := wasmvmtypes.IBCChannelOpenMsg{ + OpenInit: &wasmvmtypes.IBCOpenInit{ + Channel: wasmvmtypes.IBCChannel{ + Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID}, + CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: counterParty.PortId, ChannelID: counterParty.ChannelId}, + Order: order.String(), + // DESIGN V3: this may be "" ?? + Version: version, + ConnectionID: connectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported. + }, + }, + } + + // Allow contracts to return a version (or default to proposed version if unset) + acceptedVersion, err := i.keeper.OnOpenChannel(ctx, contractAddr, msg) + if err != nil { + return "", err + } + if acceptedVersion == "" { + acceptedVersion = version + } + + // Claim channel capability passed back by IBC module + if err := i.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", sdkerrors.Wrap(err, "claim capability") + } + return acceptedVersion, nil +} + +// OnChanOpenTry implements the IBCModule interface +func (i IBCHandler) OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, channelID string, + chanCap *capabilitytypes.Capability, + counterParty channeltypes.Counterparty, + counterpartyVersion string, +) (string, error) { + // ensure port, version, capability + if err := ValidateChannelParams(channelID); err != nil { + return "", err + } + + contractAddr, err := ContractFromPortID(portID) + if err != nil { + return "", sdkerrors.Wrapf(err, "contract port id") + } + + msg := wasmvmtypes.IBCChannelOpenMsg{ + OpenTry: &wasmvmtypes.IBCOpenTry{ + Channel: wasmvmtypes.IBCChannel{ + Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID}, + CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: counterParty.PortId, ChannelID: counterParty.ChannelId}, + Order: order.String(), + Version: counterpartyVersion, + ConnectionID: connectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported. + }, + CounterpartyVersion: counterpartyVersion, + }, + } + + // Allow contracts to return a version (or default to counterpartyVersion if unset) + version, err := i.keeper.OnOpenChannel(ctx, contractAddr, msg) + if err != nil { + return "", err + } + if version == "" { + version = counterpartyVersion + } + + // 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 !i.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 := i.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil { + return "", sdkerrors.Wrap(err, "claim capability") + } + } + + return version, nil +} + +// OnChanOpenAck implements the IBCModule interface +func (i IBCHandler) OnChanOpenAck( + ctx sdk.Context, + portID, channelID string, + counterpartyChannelID string, + counterpartyVersion string, +) error { + contractAddr, err := ContractFromPortID(portID) + if err != nil { + return sdkerrors.Wrapf(err, "contract port id") + } + channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + channelInfo.Counterparty.ChannelId = counterpartyChannelID + + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } + + msg := wasmvmtypes.IBCChannelConnectMsg{ + OpenAck: &wasmvmtypes.IBCOpenAck{ + Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion), + CounterpartyVersion: counterpartyVersion, + }, + } + return i.keeper.OnConnectChannel(ctx, contractAddr, msg) +} + +// OnChanOpenConfirm implements the IBCModule interface +func (i IBCHandler) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { + contractAddr, err := ContractFromPortID(portID) + if err != nil { + return sdkerrors.Wrapf(err, "contract port id") + } + channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } + msg := wasmvmtypes.IBCChannelConnectMsg{ + OpenConfirm: &wasmvmtypes.IBCOpenConfirm{ + Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion), + }, + } + return i.keeper.OnConnectChannel(ctx, contractAddr, msg) +} + +// OnChanCloseInit implements the IBCModule interface +func (i IBCHandler) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { + contractAddr, err := ContractFromPortID(portID) + if err != nil { + return sdkerrors.Wrapf(err, "contract port id") + } + channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } + + msg := wasmvmtypes.IBCChannelCloseMsg{ + CloseInit: &wasmvmtypes.IBCCloseInit{Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion)}, + } + err = i.keeper.OnCloseChannel(ctx, contractAddr, msg) + if err != nil { + return err + } + // emit events? + + return err +} + +// OnChanCloseConfirm implements the IBCModule interface +func (i IBCHandler) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { + // counterparty has closed the channel + contractAddr, err := ContractFromPortID(portID) + if err != nil { + return sdkerrors.Wrapf(err, "contract port id") + } + channelInfo, ok := i.channelKeeper.GetChannel(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", portID, channelID) + } + appVersion, ok := i.appVersionGetter.GetAppVersion(ctx, portID, channelID) + if !ok { + return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "port ID (%s) channel ID (%s)", portID, channelID) + } + + msg := wasmvmtypes.IBCChannelCloseMsg{ + CloseConfirm: &wasmvmtypes.IBCCloseConfirm{Channel: toWasmVMChannel(portID, channelID, channelInfo, appVersion)}, + } + err = i.keeper.OnCloseChannel(ctx, contractAddr, msg) + if err != nil { + return err + } + // emit events? + + return err +} + +func toWasmVMChannel(portID, channelID string, channelInfo channeltypes.Channel, appVersion string) wasmvmtypes.IBCChannel { + return wasmvmtypes.IBCChannel{ + Endpoint: wasmvmtypes.IBCEndpoint{PortID: portID, ChannelID: channelID}, + CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{PortID: channelInfo.Counterparty.PortId, ChannelID: channelInfo.Counterparty.ChannelId}, + Order: channelInfo.Ordering.String(), + Version: appVersion, + ConnectionID: channelInfo.ConnectionHops[0], // At the moment this list must be of length 1. In the future multi-hop channels may be supported. + } +} + +// OnRecvPacket implements the IBCModule interface +func (i IBCHandler) OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, + relayer sdk.AccAddress, +) ibcexported.Acknowledgement { + contractAddr, err := ContractFromPortID(packet.DestinationPort) + if err != nil { + return channeltypes.NewErrorAcknowledgement(sdkerrors.Wrapf(err, "contract port id")) + } + msg := wasmvmtypes.IBCPacketReceiveMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()} + ack, err := i.keeper.OnRecvPacket(ctx, contractAddr, msg) + if err != nil { + return channeltypes.NewErrorAcknowledgement(err) + } + return ContractConfirmStateAck(ack) +} + +var _ ibcexported.Acknowledgement = ContractConfirmStateAck{} + +type ContractConfirmStateAck []byte + +func (w ContractConfirmStateAck) Success() bool { + return true // always commit state +} + +func (w ContractConfirmStateAck) Acknowledgement() []byte { + return w +} + +// OnAcknowledgementPacket implements the IBCModule interface +func (i IBCHandler) OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, + relayer sdk.AccAddress, +) error { + contractAddr, err := ContractFromPortID(packet.SourcePort) + if err != nil { + return sdkerrors.Wrapf(err, "contract port id") + } + + err = i.keeper.OnAckPacket(ctx, contractAddr, wasmvmtypes.IBCPacketAckMsg{ + Acknowledgement: wasmvmtypes.IBCAcknowledgement{Data: acknowledgement}, + OriginalPacket: newIBCPacket(packet), + Relayer: relayer.String(), + }) + if err != nil { + return sdkerrors.Wrap(err, "on ack") + } + return nil +} + +// OnTimeoutPacket implements the IBCModule interface +func (i IBCHandler) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, relayer sdk.AccAddress) error { + contractAddr, err := ContractFromPortID(packet.SourcePort) + if err != nil { + return sdkerrors.Wrapf(err, "contract port id") + } + msg := wasmvmtypes.IBCPacketTimeoutMsg{Packet: newIBCPacket(packet), Relayer: relayer.String()} + err = i.keeper.OnTimeoutPacket(ctx, contractAddr, msg) + if err != nil { + return sdkerrors.Wrap(err, "on timeout") + } + return nil +} + +func newIBCPacket(packet channeltypes.Packet) wasmvmtypes.IBCPacket { + timeout := wasmvmtypes.IBCTimeout{ + Timestamp: packet.TimeoutTimestamp, + } + if !packet.TimeoutHeight.IsZero() { + timeout.Block = &wasmvmtypes.IBCTimeoutBlock{ + Height: packet.TimeoutHeight.RevisionHeight, + Revision: packet.TimeoutHeight.RevisionNumber, + } + } + + return wasmvmtypes.IBCPacket{ + Data: packet.Data, + Src: wasmvmtypes.IBCEndpoint{ChannelID: packet.SourceChannel, PortID: packet.SourcePort}, + Dest: wasmvmtypes.IBCEndpoint{ChannelID: packet.DestinationChannel, PortID: packet.DestinationPort}, + Sequence: packet.Sequence, + Timeout: timeout, + } +} + +func ValidateChannelParams(channelID string) error { + // NOTE: for escrow address security only 2^32 channels are allowed to be created + // Issue: https://github.com/cosmos/cosmos-sdk/issues/7737 + channelSequence, err := channeltypes.ParseChannelSequence(channelID) + if err != nil { + return err + } + if channelSequence > math.MaxUint32 { + return sdkerrors.Wrapf(types.ErrMaxIBCChannels, "channel sequence %d is greater than max allowed transfer channels %d", channelSequence, math.MaxUint32) + } + return nil +} diff --git a/x/wasm/ibc_integration_test.go b/x/wasm/ibc_integration_test.go new file mode 100644 index 00000000..2cdf0193 --- /dev/null +++ b/x/wasm/ibc_integration_test.go @@ -0,0 +1,126 @@ +package wasm_test + +import ( + "testing" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + wasmibctesting "github.com/cerc-io/laconicd/x/wasm/ibctesting" + wasmkeeper "github.com/cerc-io/laconicd/x/wasm/keeper" + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" +) + +func TestOnChanOpenInitVersion(t *testing.T) { + const startVersion = "v1" + specs := map[string]struct { + contractRsp *wasmvmtypes.IBC3ChannelOpenResponse + expVersion string + }{ + "different version": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{Version: "v2"}, + expVersion: "v2", + }, + "no response": { + expVersion: startVersion, + }, + "empty result": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{}, + expVersion: startVersion, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myContract := &wasmtesting.MockIBCContractCallbacks{ + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { + return spec.contractRsp, 0, nil + }, + } + var ( + chainAOpts = []wasmkeeper.Option{ + wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(myContract)), + } + coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts) + chainA = coordinator.GetChain(wasmibctesting.GetChainID(0)) + chainB = coordinator.GetChain(wasmibctesting.GetChainID(1)) + myContractAddr = chainA.SeedNewContractInstance() + contractInfo = chainA.App.WasmKeeper.GetContractInfo(chainA.GetContext(), myContractAddr) + ) + + path := wasmibctesting.NewPath(chainA, chainB) + coordinator.SetupConnections(path) + + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: contractInfo.IBCPortID, + Version: startVersion, + Order: channeltypes.UNORDERED, + } + require.NoError(t, path.EndpointA.ChanOpenInit()) + assert.Equal(t, spec.expVersion, path.EndpointA.ChannelConfig.Version) + }) + } +} + +func TestOnChanOpenTryVersion(t *testing.T) { + const startVersion = ibctransfertypes.Version + specs := map[string]struct { + contractRsp *wasmvmtypes.IBC3ChannelOpenResponse + expVersion string + }{ + "different version": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{Version: "v2"}, + expVersion: "v2", + }, + "no response": { + expVersion: startVersion, + }, + "empty result": { + contractRsp: &wasmvmtypes.IBC3ChannelOpenResponse{}, + expVersion: startVersion, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myContract := &wasmtesting.MockIBCContractCallbacks{ + IBCChannelOpenFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { + return spec.contractRsp, 0, nil + }, + } + var ( + chainAOpts = []wasmkeeper.Option{ + wasmkeeper.WithWasmEngine( + wasmtesting.NewIBCContractMockWasmer(myContract)), + } + coordinator = wasmibctesting.NewCoordinator(t, 2, chainAOpts) + chainA = coordinator.GetChain(wasmibctesting.GetChainID(0)) + chainB = coordinator.GetChain(wasmibctesting.GetChainID(1)) + myContractAddr = chainA.SeedNewContractInstance() + contractInfo = chainA.ContractInfo(myContractAddr) + ) + + path := wasmibctesting.NewPath(chainA, chainB) + coordinator.SetupConnections(path) + + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: contractInfo.IBCPortID, + Version: startVersion, + Order: channeltypes.UNORDERED, + } + path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: ibctransfertypes.PortID, + Version: ibctransfertypes.Version, + Order: channeltypes.UNORDERED, + } + + require.NoError(t, path.EndpointB.ChanOpenInit()) + require.NoError(t, path.EndpointA.ChanOpenTry()) + assert.Equal(t, spec.expVersion, path.EndpointA.ChannelConfig.Version) + }) + } +} diff --git a/x/wasm/ibc_reflect_test.go b/x/wasm/ibc_reflect_test.go new file mode 100644 index 00000000..31e3e465 --- /dev/null +++ b/x/wasm/ibc_reflect_test.go @@ -0,0 +1,124 @@ +package wasm_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/stretchr/testify/require" + + wasmibctesting "github.com/cerc-io/laconicd/x/wasm/ibctesting" + wasmkeeper "github.com/cerc-io/laconicd/x/wasm/keeper" +) + +func TestIBCReflectContract(t *testing.T) { + // scenario: + // chain A: ibc_reflect_send.wasm + // chain B: reflect.wasm + ibc_reflect.wasm + // + // Chain A "ibc_reflect_send" sends a IBC packet "on channel connect" event to chain B "ibc_reflect" + // "ibc_reflect" sends a submessage to "reflect" which is returned as submessage. + + var ( + coordinator = wasmibctesting.NewCoordinator(t, 2) + chainA = coordinator.GetChain(wasmibctesting.GetChainID(0)) + chainB = coordinator.GetChain(wasmibctesting.GetChainID(1)) + ) + coordinator.CommitBlock(chainA, chainB) + + initMsg := []byte(`{}`) + codeID := chainA.StoreCodeFile("./keeper/testdata/ibc_reflect_send.wasm").CodeID + sendContractAddr := chainA.InstantiateContract(codeID, initMsg) + + reflectID := chainB.StoreCodeFile("./keeper/testdata/reflect.wasm").CodeID + initMsg = wasmkeeper.IBCReflectInitMsg{ + ReflectCodeID: reflectID, + }.GetBytes(t) + codeID = chainB.StoreCodeFile("./keeper/testdata/ibc_reflect.wasm").CodeID + + reflectContractAddr := chainB.InstantiateContract(codeID, initMsg) + var ( + sourcePortID = chainA.ContractInfo(sendContractAddr).IBCPortID + counterpartPortID = chainB.ContractInfo(reflectContractAddr).IBCPortID + ) + coordinator.CommitBlock(chainA, chainB) + coordinator.UpdateTime() + + require.Equal(t, chainA.CurrentHeader.Time, chainB.CurrentHeader.Time) + path := wasmibctesting.NewPath(chainA, chainB) + path.EndpointA.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: sourcePortID, + Version: "ibc-reflect-v1", + Order: channeltypes.ORDERED, + } + path.EndpointB.ChannelConfig = &ibctesting.ChannelConfig{ + PortID: counterpartPortID, + Version: "ibc-reflect-v1", + Order: channeltypes.ORDERED, + } + + coordinator.SetupConnections(path) + coordinator.CreateChannels(path) + + // TODO: query both contracts directly to ensure they have registered the proper connection + // (and the chainB has created a reflect contract) + + // there should be one packet to relay back and forth (whoami) + // TODO: how do I find the packet that was previously sent by the smart contract? + // Coordinator.RecvPacket requires channeltypes.Packet as input? + // Given the source (portID, channelID), we should be able to count how many packets are pending, query the data + // and submit them to the other side (same with acks). This is what the real relayer does. I guess the test framework doesn't? + + // Update: I dug through the code, especially channel.Keeper.SendPacket, and it only writes a commitment + // only writes I see: https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/keeper/packet.go#L115-L116 + // commitment is hashed packet: https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/types/packet.go#L14-L34 + // how is the relayer supposed to get the original packet data?? + // eg. ibctransfer doesn't store the packet either: https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc/applications/transfer/keeper/relay.go#L145-L162 + // ... or I guess the original packet data is only available in the event logs???? + // https://github.com/cosmos/cosmos-sdk/blob/31fdee0228bd6f3e787489c8e4434aabc8facb7d/x/ibc/core/04-channel/keeper/packet.go#L121-L132 + + // ensure the expected packet was prepared, and relay it + require.Equal(t, 1, len(chainA.PendingSendPackets)) + require.Equal(t, 0, len(chainB.PendingSendPackets)) + err := coordinator.RelayAndAckPendingPackets(path) + require.NoError(t, err) + require.Equal(t, 0, len(chainA.PendingSendPackets)) + require.Equal(t, 0, len(chainB.PendingSendPackets)) + + // let's query the source contract and make sure it registered an address + query := ReflectSendQueryMsg{Account: &AccountQuery{ChannelID: path.EndpointA.ChannelID}} + var account AccountResponse + err = chainA.SmartQuery(sendContractAddr.String(), query, &account) + require.NoError(t, err) + require.NotEmpty(t, account.RemoteAddr) + require.Empty(t, account.RemoteBalance) + + // close channel + coordinator.CloseChannel(path) + + // let's query the source contract and make sure it registered an address + account = AccountResponse{} + err = chainA.SmartQuery(sendContractAddr.String(), query, &account) + require.Error(t, err) + assert.Contains(t, err.Error(), "not found") +} + +type ReflectSendQueryMsg struct { + Admin *struct{} `json:"admin,omitempty"` + ListAccounts *struct{} `json:"list_accounts,omitempty"` + Account *AccountQuery `json:"account,omitempty"` +} + +type AccountQuery struct { + ChannelID string `json:"channel_id"` +} + +type AccountResponse struct { + LastUpdateTime uint64 `json:"last_update_time,string"` + RemoteAddr string `json:"remote_addr"` + RemoteBalance wasmvmtypes.Coins `json:"remote_balance"` +} diff --git a/x/wasm/ibc_test.go b/x/wasm/ibc_test.go new file mode 100644 index 00000000..ee63c7fb --- /dev/null +++ b/x/wasm/ibc_test.go @@ -0,0 +1,82 @@ +package wasm + +import ( + "testing" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/stretchr/testify/assert" +) + +func TestMapToWasmVMIBCPacket(t *testing.T) { + var myTimestamp uint64 = 1 + specs := map[string]struct { + src channeltypes.Packet + exp wasmvmtypes.IBCPacket + }{ + "with height timeout": { + src: IBCPacketFixture(), + exp: wasmvmtypes.IBCPacket{ + Data: []byte("myData"), + Src: wasmvmtypes.IBCEndpoint{PortID: "srcPort", ChannelID: "channel-1"}, + Dest: wasmvmtypes.IBCEndpoint{PortID: "destPort", ChannelID: "channel-2"}, + Sequence: 1, + Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Height: 1, Revision: 2}}, + }, + }, + "with time timeout": { + src: IBCPacketFixture(func(p *channeltypes.Packet) { + p.TimeoutTimestamp = myTimestamp + p.TimeoutHeight = clienttypes.Height{} + }), + exp: wasmvmtypes.IBCPacket{ + Data: []byte("myData"), + Src: wasmvmtypes.IBCEndpoint{PortID: "srcPort", ChannelID: "channel-1"}, + Dest: wasmvmtypes.IBCEndpoint{PortID: "destPort", ChannelID: "channel-2"}, + Sequence: 1, + Timeout: wasmvmtypes.IBCTimeout{Timestamp: myTimestamp}, + }, + }, "with time and height timeout": { + src: IBCPacketFixture(func(p *channeltypes.Packet) { + p.TimeoutTimestamp = myTimestamp + }), + exp: wasmvmtypes.IBCPacket{ + Data: []byte("myData"), + Src: wasmvmtypes.IBCEndpoint{PortID: "srcPort", ChannelID: "channel-1"}, + Dest: wasmvmtypes.IBCEndpoint{PortID: "destPort", ChannelID: "channel-2"}, + Sequence: 1, + Timeout: wasmvmtypes.IBCTimeout{ + Block: &wasmvmtypes.IBCTimeoutBlock{Height: 1, Revision: 2}, + Timestamp: myTimestamp, + }, + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + got := newIBCPacket(spec.src) + assert.Equal(t, spec.exp, got) + }) + } +} + +func IBCPacketFixture(mutators ...func(p *channeltypes.Packet)) channeltypes.Packet { + r := channeltypes.Packet{ + Sequence: 1, + SourcePort: "srcPort", + SourceChannel: "channel-1", + DestinationPort: "destPort", + DestinationChannel: "channel-2", + Data: []byte("myData"), + TimeoutHeight: clienttypes.Height{ + RevisionHeight: 1, + RevisionNumber: 2, + }, + TimeoutTimestamp: 0, + } + for _, m := range mutators { + m(&r) + } + return r +} diff --git a/x/wasm/ibctesting/README.md b/x/wasm/ibctesting/README.md new file mode 100644 index 00000000..1c928699 --- /dev/null +++ b/x/wasm/ibctesting/README.md @@ -0,0 +1,2 @@ +# testing package for ibc +Customized version of cosmos-sdk x/ibc/testing \ No newline at end of file diff --git a/x/wasm/ibctesting/chain.go b/x/wasm/ibctesting/chain.go new file mode 100644 index 00000000..e127a9db --- /dev/null +++ b/x/wasm/ibctesting/chain.go @@ -0,0 +1,594 @@ +package ibctesting + +import ( + "fmt" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/staking/teststaking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/cosmos/ibc-go/v4/modules/core/types" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/cosmos/ibc-go/v4/testing/mock" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/tmhash" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmprotoversion "github.com/tendermint/tendermint/proto/tendermint/version" + tmtypes "github.com/tendermint/tendermint/types" + tmversion "github.com/tendermint/tendermint/version" + + "github.com/cerc-io/laconicd/app" + "github.com/cerc-io/laconicd/app/params" + "github.com/cerc-io/laconicd/x/wasm" +) + +var MaxAccounts = 10 + +type SenderAccount struct { + SenderPrivKey cryptotypes.PrivKey + SenderAccount authtypes.AccountI +} + +// TestChain is a testing struct that wraps a simapp with the last TM Header, the current ABCI +// header and the validators of the TestChain. It also contains a field called ChainID. This +// is the clientID that *other* chains use to refer to this TestChain. The SenderAccount +// is used for delivering transactions through the application state. +// NOTE: the actual application uses an empty chain-id for ease of testing. +type TestChain struct { + t *testing.T + + Coordinator *Coordinator + App *app.WasmApp + ChainID string + LastHeader *ibctmtypes.Header // header for last block height committed + CurrentHeader tmproto.Header // header for current block height + QueryServer types.QueryServer + TxConfig client.TxConfig + Codec codec.BinaryCodec + + Vals *tmtypes.ValidatorSet + NextVals *tmtypes.ValidatorSet + + // Signers is a map from validator address to the PrivValidator + // The map is converted into an array that is the same order as the validators right before signing commit + // This ensures that signers will always be in correct order even as validator powers change. + // If a test adds a new validator after chain creation, then the signer map must be updated to include + // the new PrivValidator entry. + Signers map[string]tmtypes.PrivValidator + + // autogenerated sender private key + SenderPrivKey cryptotypes.PrivKey + SenderAccount authtypes.AccountI + SenderAccounts []SenderAccount + + PendingSendPackets []channeltypes.Packet +} + +type PacketAck struct { + Packet channeltypes.Packet + Ack []byte +} + +// NewTestChain initializes a new test chain with a default of 4 validators +// Use this function if the tests do not need custom control over the validator set +func NewTestChain(t *testing.T, coord *Coordinator, chainID string, opts ...wasm.Option) *TestChain { + // generate validators private/public key + var ( + validatorsPerChain = 4 + validators = make([]*tmtypes.Validator, 0, validatorsPerChain) + signersByAddress = make(map[string]tmtypes.PrivValidator, validatorsPerChain) + ) + + for i := 0; i < validatorsPerChain; i++ { + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + validators = append(validators, tmtypes.NewValidator(pubKey, 1)) + signersByAddress[pubKey.Address().String()] = privVal + } + + // construct validator set; + // Note that the validators are sorted by voting power + // or, if equal, by address lexical order + valSet := tmtypes.NewValidatorSet(validators) + + return NewTestChainWithValSet(t, coord, chainID, valSet, signersByAddress, opts...) +} + +// NewTestChainWithValSet initializes a new TestChain instance with the given validator set +// and signer array. It also initializes 10 Sender accounts with a balance of 10000000000000000000 coins of +// bond denom to use for tests. +// +// The first block height is committed to state in order to allow for client creations on +// counterparty chains. The TestChain will return with a block height starting at 2. +// +// Time management is handled by the Coordinator in order to ensure synchrony between chains. +// Each update of any chain increments the block header time for all chains by 5 seconds. +// +// NOTE: to use a custom sender privkey and account for testing purposes, replace and modify this +// constructor function. +// +// CONTRACT: Validator array must be provided in the order expected by Tendermint. +// i.e. sorted first by power and then lexicographically by address. +func NewTestChainWithValSet(t *testing.T, coord *Coordinator, chainID string, valSet *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator, opts ...wasm.Option) *TestChain { + genAccs := []authtypes.GenesisAccount{} + genBals := []banktypes.Balance{} + senderAccs := []SenderAccount{} + + // generate genesis accounts + for i := 0; i < MaxAccounts; i++ { + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), uint64(i), 0) + amount, ok := sdk.NewIntFromString("10000000000000000000") + require.True(t, ok) + + // add sender account + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + } + + genAccs = append(genAccs, acc) + genBals = append(genBals, balance) + + senderAcc := SenderAccount{ + SenderAccount: acc, + SenderPrivKey: senderPrivKey, + } + + senderAccs = append(senderAccs, senderAcc) + } + + wasmApp := app.SetupWithGenesisValSet(t, valSet, genAccs, chainID, opts, genBals...) + + // create current header and call begin block + header := tmproto.Header{ + ChainID: chainID, + Height: 1, + Time: coord.CurrentTime.UTC(), + } + + txConfig := params.MakeEncodingConfig().TxConfig + + // create an account to send transactions from + chain := &TestChain{ + t: t, + Coordinator: coord, + ChainID: chainID, + App: wasmApp, + CurrentHeader: header, + QueryServer: wasmApp.IBCKeeper, + TxConfig: txConfig, + Codec: wasmApp.AppCodec(), + Vals: valSet, + NextVals: valSet, + Signers: signers, + SenderPrivKey: senderAccs[0].SenderPrivKey, + SenderAccount: senderAccs[0].SenderAccount, + SenderAccounts: senderAccs, + } + + coord.CommitBlock(chain) + + return chain +} + +// GetContext returns the current context for the application. +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, chain.CurrentHeader) +} + +// QueryProof performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) { + return chain.QueryProofAtHeight(key, chain.App.LastBlockHeight()) +} + +// QueryProofAtHeight performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryProofAtHeight(key []byte, height int64) ([]byte, clienttypes.Height) { + res := chain.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", host.StoreKey), + Height: height - 1, + Data: key, + Prove: true, + }) + + merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) + require.NoError(chain.t, err) + + proof, err := chain.App.AppCodec().Marshal(&merkleProof) + require.NoError(chain.t, err) + + revision := clienttypes.ParseChainID(chain.ChainID) + + // proof height + 1 is returned as the proof created corresponds to the height the proof + // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it + // have heights 1 above the IAVL tree. Thus we return proof height + 1 + return proof, clienttypes.NewHeight(revision, uint64(res.Height)+1) +} + +// QueryUpgradeProof performs an abci query with the given key and returns the proto encoded merkle proof +// for the query and the height at which the proof will succeed on a tendermint verifier. +func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, clienttypes.Height) { + res := chain.App.Query(abci.RequestQuery{ + Path: "store/upgrade/key", + Height: int64(height - 1), + Data: key, + Prove: true, + }) + + merkleProof, err := commitmenttypes.ConvertProofs(res.ProofOps) + require.NoError(chain.t, err) + + proof, err := chain.App.AppCodec().Marshal(&merkleProof) + require.NoError(chain.t, err) + + revision := clienttypes.ParseChainID(chain.ChainID) + + // proof height + 1 is returned as the proof created corresponds to the height the proof + // was created in the IAVL tree. Tendermint and subsequently the clients that rely on it + // have heights 1 above the IAVL tree. Thus we return proof height + 1 + return proof, clienttypes.NewHeight(revision, uint64(res.Height+1)) +} + +// QueryConsensusStateProof performs an abci query for a consensus state +// stored on the given clientID. The proof and consensusHeight are returned. +func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) { + clientState := chain.GetClientState(clientID) + + consensusHeight := clientState.GetLatestHeight().(clienttypes.Height) + consensusKey := host.FullConsensusStateKey(clientID, consensusHeight) + proofConsensus, _ := chain.QueryProof(consensusKey) + + return proofConsensus, consensusHeight +} + +// NextBlock sets the last header to the current header and increments the current header to be +// at the next block height. It does not update the time as that is handled by the Coordinator. +// It will call Endblock and Commit and apply the validator set changes to the next validators +// of the next block being created. This follows the Tendermint protocol of applying valset changes +// returned on block `n` to the validators of block `n+2`. +// It calls BeginBlock with the new block created before returning. +func (chain *TestChain) NextBlock() { + res := chain.App.EndBlock(abci.RequestEndBlock{Height: chain.CurrentHeader.Height}) + + chain.App.Commit() + + // set the last header to the current header + // use nil trusted fields + chain.LastHeader = chain.CurrentTMClientHeader() + + // val set changes returned from previous block get applied to the next validators + // of this block. See tendermint spec for details. + chain.Vals = chain.NextVals + chain.NextVals = ibctesting.ApplyValSetChanges(chain.t, chain.Vals, res.ValidatorUpdates) + + // increment the current header + chain.CurrentHeader = tmproto.Header{ + ChainID: chain.ChainID, + Height: chain.App.LastBlockHeight() + 1, + AppHash: chain.App.LastCommitID().Hash, + // NOTE: the time is increased by the coordinator to maintain time synchrony amongst + // chains. + Time: chain.CurrentHeader.Time, + ValidatorsHash: chain.Vals.Hash(), + NextValidatorsHash: chain.NextVals.Hash(), + } + + chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) +} + +// sendMsgs delivers a transaction through the application without returning the result. +func (chain *TestChain) sendMsgs(msgs ...sdk.Msg) error { + _, err := chain.SendMsgs(msgs...) + return err +} + +// SendMsgs delivers a transaction through the application. It updates the senders sequence +// number and updates the TestChain's headers. It returns the result and error if one +// occurred. +func (chain *TestChain) SendMsgs(msgs ...sdk.Msg) (*sdk.Result, error) { + // ensure the chain has the latest time + chain.Coordinator.UpdateTimeForChain(chain) + + _, r, err := app.SignAndDeliver( + chain.t, + chain.TxConfig, + chain.App.BaseApp, + chain.GetContext().BlockHeader(), + msgs, + chain.ChainID, + []uint64{chain.SenderAccount.GetAccountNumber()}, + []uint64{chain.SenderAccount.GetSequence()}, + chain.SenderPrivKey, + ) + + // NextBlock calls app.Commit() + chain.NextBlock() + if err != nil { + return r, err + } + + // increment sequence for successful transaction execution + err = chain.SenderAccount.SetSequence(chain.SenderAccount.GetSequence() + 1) + if err != nil { + return nil, err + } + + chain.Coordinator.IncrementTime() + + chain.captureIBCEvents(r) + + return r, nil +} + +func (chain *TestChain) captureIBCEvents(r *sdk.Result) { + toSend := getSendPackets(r.Events) + if len(toSend) > 0 { + // Keep a queue on the chain that we can relay in tests + chain.PendingSendPackets = append(chain.PendingSendPackets, toSend...) + } +} + +// GetClientState retrieves the client state for the provided clientID. The client is +// expected to exist otherwise testing will fail. +func (chain *TestChain) GetClientState(clientID string) exported.ClientState { + clientState, found := chain.App.IBCKeeper.ClientKeeper.GetClientState(chain.GetContext(), clientID) + require.True(chain.t, found) + + return clientState +} + +// GetConsensusState retrieves the consensus state for the provided clientID and height. +// It will return a success boolean depending on if consensus state exists or not. +func (chain *TestChain) GetConsensusState(clientID string, height exported.Height) (exported.ConsensusState, bool) { + return chain.App.IBCKeeper.ClientKeeper.GetClientConsensusState(chain.GetContext(), clientID, height) +} + +// GetValsAtHeight will return the validator set of the chain at a given height. It will return +// a success boolean depending on if the validator set exists or not at that height. +func (chain *TestChain) GetValsAtHeight(height int64) (*tmtypes.ValidatorSet, bool) { + histInfo, ok := chain.App.StakingKeeper.GetHistoricalInfo(chain.GetContext(), height) + if !ok { + return nil, false + } + + valSet := stakingtypes.Validators(histInfo.Valset) + + tmValidators, err := teststaking.ToTmValidators(valSet, sdk.DefaultPowerReduction) + if err != nil { + panic(err) + } + return tmtypes.NewValidatorSet(tmValidators), true +} + +// GetAcknowledgement retrieves an acknowledgement for the provided packet. If the +// acknowledgement does not exist then testing will fail. +func (chain *TestChain) GetAcknowledgement(packet exported.PacketI) []byte { + ack, found := chain.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(chain.GetContext(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + require.True(chain.t, found) + + return ack +} + +// GetPrefix returns the prefix for used by a chain in connection creation +func (chain *TestChain) GetPrefix() commitmenttypes.MerklePrefix { + return commitmenttypes.NewMerklePrefix(chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix().Bytes()) +} + +// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the +// light client on the source chain. +func (chain *TestChain) ConstructUpdateTMClientHeader(counterparty *TestChain, clientID string) (*ibctmtypes.Header, error) { + return chain.ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty, clientID, clienttypes.ZeroHeight()) +} + +// ConstructUpdateTMClientHeader will construct a valid 07-tendermint Header to update the +// light client on the source chain. +func (chain *TestChain) ConstructUpdateTMClientHeaderWithTrustedHeight(counterparty *TestChain, clientID string, trustedHeight clienttypes.Height) (*ibctmtypes.Header, error) { + header := counterparty.LastHeader + // Relayer must query for LatestHeight on client to get TrustedHeight if the trusted height is not set + if trustedHeight.IsZero() { + trustedHeight = chain.GetClientState(clientID).GetLatestHeight().(clienttypes.Height) + } + var ( + tmTrustedVals *tmtypes.ValidatorSet + ok bool + ) + // Once we get TrustedHeight from client, we must query the validators from the counterparty chain + // If the LatestHeight == LastHeader.Height, then TrustedValidators are current validators + // If LatestHeight < LastHeader.Height, we can query the historical validator set from HistoricalInfo + if trustedHeight == counterparty.LastHeader.GetHeight() { + tmTrustedVals = counterparty.Vals + } else { + // NOTE: We need to get validators from counterparty at height: trustedHeight+1 + // since the last trusted validators for a header at height h + // is the NextValidators at h+1 committed to in header h by + // NextValidatorsHash + tmTrustedVals, ok = counterparty.GetValsAtHeight(int64(trustedHeight.RevisionHeight + 1)) + if !ok { + return nil, sdkerrors.Wrapf(ibctmtypes.ErrInvalidHeaderHeight, "could not retrieve trusted validators at trustedHeight: %d", trustedHeight) + } + } + // inject trusted fields into last header + // for now assume revision number is 0 + header.TrustedHeight = trustedHeight + + trustedVals, err := tmTrustedVals.ToProto() + if err != nil { + return nil, err + } + header.TrustedValidators = trustedVals + + return header, nil +} + +// ExpireClient fast forwards the chain's block time by the provided amount of time which will +// expire any clients with a trusting period less than or equal to this amount of time. +func (chain *TestChain) ExpireClient(amount time.Duration) { + chain.Coordinator.IncrementTimeBy(amount) +} + +// CurrentTMClientHeader creates a TM header using the current header parameters +// on the chain. The trusted fields in the header are set to nil. +func (chain *TestChain) CurrentTMClientHeader() *ibctmtypes.Header { + return chain.CreateTMClientHeader(chain.ChainID, chain.CurrentHeader.Height, clienttypes.Height{}, chain.CurrentHeader.Time, chain.Vals, chain.NextVals, nil, chain.Signers) +} + +// CreateTMClientHeader creates a TM header to update the TM client. Args are passed in to allow +// caller flexibility to use params that differ from the chain. +func (chain *TestChain) CreateTMClientHeader(chainID string, blockHeight int64, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, nextVals, tmTrustedVals *tmtypes.ValidatorSet, signers map[string]tmtypes.PrivValidator) *ibctmtypes.Header { + var ( + valSet *tmproto.ValidatorSet + trustedVals *tmproto.ValidatorSet + ) + require.NotNil(chain.t, tmValSet) + + vsetHash := tmValSet.Hash() + nextValHash := nextVals.Hash() + + tmHeader := tmtypes.Header{ + Version: tmprotoversion.Consensus{Block: tmversion.BlockProtocol, App: 2}, + ChainID: chainID, + Height: blockHeight, + Time: timestamp, + LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)), + LastCommitHash: chain.App.LastCommitID().Hash, + DataHash: tmhash.Sum([]byte("data_hash")), + ValidatorsHash: vsetHash, + NextValidatorsHash: nextValHash, + ConsensusHash: tmhash.Sum([]byte("consensus_hash")), + AppHash: chain.CurrentHeader.AppHash, + LastResultsHash: tmhash.Sum([]byte("last_results_hash")), + EvidenceHash: tmhash.Sum([]byte("evidence_hash")), + ProposerAddress: tmValSet.Proposer.Address, //nolint:staticcheck + } + + hhash := tmHeader.Hash() + blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set"))) + voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet) + + // MakeCommit expects a signer array in the same order as the validator array. + // Thus we iterate over the ordered validator set and construct a signer array + // from the signer map in the same order. + signerArr := make([]tmtypes.PrivValidator, len(tmValSet.Validators)) + for i, v := range tmValSet.Validators { + signerArr[i] = signers[v.Address.String()] + } + + commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signerArr, timestamp) + require.NoError(chain.t, err) + + signedHeader := &tmproto.SignedHeader{ + Header: tmHeader.ToProto(), + Commit: commit.ToProto(), + } + + valSet, err = tmValSet.ToProto() + require.NoError(chain.t, err) + + if tmTrustedVals != nil { + trustedVals, err = tmTrustedVals.ToProto() + require.NoError(chain.t, err) + } + + // The trusted fields may be nil. They may be filled before relaying messages to a client. + // The relayer is responsible for querying client and injecting appropriate trusted fields. + return &ibctmtypes.Header{ + SignedHeader: signedHeader, + ValidatorSet: valSet, + TrustedHeight: trustedHeight, + TrustedValidators: trustedVals, + } +} + +// MakeBlockID copied unimported test functions from tmtypes to use them here +func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.BlockID { + return tmtypes.BlockID{ + Hash: hash, + PartSetHeader: tmtypes.PartSetHeader{ + Total: partSetSize, + Hash: partSetHash, + }, + } +} + +// CreatePortCapability binds and claims a capability for the given portID if it does not +// already exist. This function will fail testing on any resulting error. +// NOTE: only creation of a capability for a transfer or mock port is supported +// Other applications must bind to the port in InitGenesis or modify this code. +func (chain *TestChain) CreatePortCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID string) { + // check if the portId is already binded, if not bind it + _, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.PortPath(portID)) + if !ok { + // create capability using the IBC capability keeper + cap, err := chain.App.ScopedIBCKeeper.NewCapability(chain.GetContext(), host.PortPath(portID)) + require.NoError(chain.t, err) + + // claim capability using the scopedKeeper + err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, host.PortPath(portID)) + require.NoError(chain.t, err) + } + + chain.NextBlock() +} + +// GetPortCapability returns the port capability for the given portID. The capability must +// exist, otherwise testing will fail. +func (chain *TestChain) GetPortCapability(portID string) *capabilitytypes.Capability { + cap, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.PortPath(portID)) + require.True(chain.t, ok) + + return cap +} + +// CreateChannelCapability binds and claims a capability for the given portID and channelID +// if it does not already exist. This function will fail testing on any resulting error. The +// scoped keeper passed in will claim the new capability. +func (chain *TestChain) CreateChannelCapability(scopedKeeper capabilitykeeper.ScopedKeeper, portID, channelID string) { + capName := host.ChannelCapabilityPath(portID, channelID) + // check if the portId is already binded, if not bind it + _, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), capName) + if !ok { + cap, err := chain.App.ScopedIBCKeeper.NewCapability(chain.GetContext(), capName) + require.NoError(chain.t, err) + err = scopedKeeper.ClaimCapability(chain.GetContext(), cap, capName) + require.NoError(chain.t, err) + } + + chain.NextBlock() +} + +// GetChannelCapability returns the channel capability for the given portID and channelID. +// The capability must exist, otherwise testing will fail. +func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabilitytypes.Capability { + cap, ok := chain.App.ScopedIBCKeeper.GetCapability(chain.GetContext(), host.ChannelCapabilityPath(portID, channelID)) + require.True(chain.t, ok) + + return cap +} + +func (chain *TestChain) Balance(acc sdk.AccAddress, denom string) sdk.Coin { + return chain.App.BankKeeper.GetBalance(chain.GetContext(), acc, denom) +} + +func (chain *TestChain) AllBalances(acc sdk.AccAddress) sdk.Coins { + return chain.App.BankKeeper.GetAllBalances(chain.GetContext(), acc) +} diff --git a/x/wasm/ibctesting/coordinator.go b/x/wasm/ibctesting/coordinator.go new file mode 100644 index 00000000..5e30d139 --- /dev/null +++ b/x/wasm/ibctesting/coordinator.go @@ -0,0 +1,317 @@ +package ibctesting + +import ( + "fmt" + "strconv" + "testing" + "time" + + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + wasmkeeper "github.com/cerc-io/laconicd/x/wasm/keeper" +) + +const ChainIDPrefix = "testchain" + +var ( + globalStartTime = time.Date(2020, 12, 4, 10, 30, 0, 0, time.UTC) + TimeIncrement = time.Second * 5 +) + +// Coordinator is a testing struct which contains N TestChain's. It handles keeping all chains +// in sync with regards to time. +type Coordinator struct { + t *testing.T + + CurrentTime time.Time + Chains map[string]*TestChain +} + +// NewCoordinator initializes Coordinator with N TestChain's +func NewCoordinator(t *testing.T, n int, opts ...[]wasmkeeper.Option) *Coordinator { + chains := make(map[string]*TestChain) + coord := &Coordinator{ + t: t, + CurrentTime: globalStartTime, + } + + for i := 0; i < n; i++ { + chainID := GetChainID(i) + var x []wasmkeeper.Option + if len(opts) > i { + x = opts[i] + } + chains[chainID] = NewTestChain(t, coord, chainID, x...) + } + coord.Chains = chains + + return coord +} + +// IncrementTime iterates through all the TestChain's and increments their current header time +// by 5 seconds. +// +// CONTRACT: this function must be called after every Commit on any TestChain. +func (coord *Coordinator) IncrementTime() { + coord.IncrementTimeBy(TimeIncrement) +} + +// IncrementTimeBy iterates through all the TestChain's and increments their current header time +// by specified time. +func (coord *Coordinator) IncrementTimeBy(increment time.Duration) { + coord.CurrentTime = coord.CurrentTime.Add(increment).UTC() + coord.UpdateTime() +} + +// UpdateTime updates all clocks for the TestChains to the current global time. +func (coord *Coordinator) UpdateTime() { + for _, chain := range coord.Chains { + coord.UpdateTimeForChain(chain) + } +} + +// UpdateTimeForChain updates the clock for a specific chain. +func (coord *Coordinator) UpdateTimeForChain(chain *TestChain) { + chain.CurrentHeader.Time = coord.CurrentTime.UTC() + chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) +} + +// Setup constructs a TM client, connection, and channel on both chains provided. It will +// fail if any error occurs. The clientID's, TestConnections, and TestChannels are returned +// for both chains. The channels created are connected to the ibc-transfer application. +func (coord *Coordinator) Setup(path *Path) { + coord.SetupConnections(path) + + // channels can also be referenced through the returned connections + coord.CreateChannels(path) +} + +// SetupClients is a helper function to create clients on both chains. It assumes the +// caller does not anticipate any errors. +func (coord *Coordinator) SetupClients(path *Path) { + err := path.EndpointA.CreateClient() + require.NoError(coord.t, err) + + err = path.EndpointB.CreateClient() + require.NoError(coord.t, err) +} + +// SetupClientConnections is a helper function to create clients and the appropriate +// connections on both the source and counterparty chain. It assumes the caller does not +// anticipate any errors. +func (coord *Coordinator) SetupConnections(path *Path) { + coord.SetupClients(path) + + coord.CreateConnections(path) +} + +// CreateConnection constructs and executes connection handshake messages in order to create +// OPEN channels on chainA and chainB. The connection information of for chainA and chainB +// are returned within a TestConnection struct. The function expects the connections to be +// successfully opened otherwise testing will fail. +func (coord *Coordinator) CreateConnections(path *Path) { + err := path.EndpointA.ConnOpenInit() + require.NoError(coord.t, err) + + err = path.EndpointB.ConnOpenTry() + require.NoError(coord.t, err) + + err = path.EndpointA.ConnOpenAck() + require.NoError(coord.t, err) + + err = path.EndpointB.ConnOpenConfirm() + require.NoError(coord.t, err) + + // ensure counterparty is up to date + err = path.EndpointA.UpdateClient() + require.NoError(coord.t, err) +} + +// CreateMockChannels constructs and executes channel handshake messages to create OPEN +// channels that use a mock application module that returns nil on all callbacks. This +// function is expects the channels to be successfully opened otherwise testing will +// fail. +func (coord *Coordinator) CreateMockChannels(path *Path) { + path.EndpointA.ChannelConfig.PortID = ibctesting.MockPort + path.EndpointB.ChannelConfig.PortID = ibctesting.MockPort + + coord.CreateChannels(path) +} + +// CreateTransferChannels constructs and executes channel handshake messages to create OPEN +// ibc-transfer channels on chainA and chainB. The function expects the channels to be +// successfully opened otherwise testing will fail. +func (coord *Coordinator) CreateTransferChannels(path *Path) { + path.EndpointA.ChannelConfig.PortID = ibctesting.TransferPort + path.EndpointB.ChannelConfig.PortID = ibctesting.TransferPort + + coord.CreateChannels(path) +} + +// CreateChannel constructs and executes channel handshake messages in order to create +// OPEN channels on chainA and chainB. The function expects the channels to be successfully +// opened otherwise testing will fail. +func (coord *Coordinator) CreateChannels(path *Path) { + err := path.EndpointA.ChanOpenInit() + require.NoError(coord.t, err) + + err = path.EndpointB.ChanOpenTry() + require.NoError(coord.t, err) + + err = path.EndpointA.ChanOpenAck() + require.NoError(coord.t, err) + + err = path.EndpointB.ChanOpenConfirm() + require.NoError(coord.t, err) + + // ensure counterparty is up to date + err = path.EndpointA.UpdateClient() + require.NoError(coord.t, err) +} + +// GetChain returns the TestChain using the given chainID and returns an error if it does +// not exist. +func (coord *Coordinator) GetChain(chainID string) *TestChain { + chain, found := coord.Chains[chainID] + require.True(coord.t, found, fmt.Sprintf("%s chain does not exist", chainID)) + return chain +} + +// GetChainID returns the chainID used for the provided index. +func GetChainID(index int) string { + return ChainIDPrefix + strconv.Itoa(index) +} + +// CommitBlock commits a block on the provided indexes and then increments the global time. +// +// CONTRACT: the passed in list of indexes must not contain duplicates +func (coord *Coordinator) CommitBlock(chains ...*TestChain) { + for _, chain := range chains { + chain.NextBlock() + } + coord.IncrementTime() +} + +// CommitNBlocks commits n blocks to state and updates the block height by 1 for each commit. +func (coord *Coordinator) CommitNBlocks(chain *TestChain, n uint64) { + for i := uint64(0); i < n; i++ { + chain.App.BeginBlock(abci.RequestBeginBlock{Header: chain.CurrentHeader}) + chain.NextBlock() + coord.IncrementTime() + } +} + +// ConnOpenInitOnBothChains initializes a connection on both endpoints with the state INIT +// using the OpenInit handshake call. +func (coord *Coordinator) ConnOpenInitOnBothChains(path *Path) error { + if err := path.EndpointA.ConnOpenInit(); err != nil { + return err + } + + if err := path.EndpointB.ConnOpenInit(); err != nil { + return err + } + + if err := path.EndpointA.UpdateClient(); err != nil { + return err + } + + if err := path.EndpointB.UpdateClient(); err != nil { + return err + } + + return nil +} + +// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain +// with the state INIT using the OpenInit handshake call. +func (coord *Coordinator) ChanOpenInitOnBothChains(path *Path) error { + // NOTE: only creation of a capability for a transfer or mock port is supported + // Other applications must bind to the port in InitGenesis or modify this code. + + if err := path.EndpointA.ChanOpenInit(); err != nil { + return err + } + + if err := path.EndpointB.ChanOpenInit(); err != nil { + return err + } + + if err := path.EndpointA.UpdateClient(); err != nil { + return err + } + + if err := path.EndpointB.UpdateClient(); err != nil { + return err + } + + return nil +} + +// RelayAndAckPendingPackets sends pending packages from path.EndpointA to the counterparty chain and acks +func (coord *Coordinator) RelayAndAckPendingPackets(path *Path) error { + // get all the packet to relay src->dest + src := path.EndpointA + coord.t.Logf("Relay: %d Packets A->B, %d Packets B->A\n", len(src.Chain.PendingSendPackets), len(path.EndpointB.Chain.PendingSendPackets)) + for i, v := range src.Chain.PendingSendPackets { + err := path.RelayPacket(v, nil) + if err != nil { + return err + } + src.Chain.PendingSendPackets = append(src.Chain.PendingSendPackets[0:i], src.Chain.PendingSendPackets[i+1:]...) + } + + src = path.EndpointB + for i, v := range src.Chain.PendingSendPackets { + err := path.RelayPacket(v, nil) + if err != nil { + return err + } + src.Chain.PendingSendPackets = append(src.Chain.PendingSendPackets[0:i], src.Chain.PendingSendPackets[i+1:]...) + } + return nil +} + +// TimeoutPendingPackets returns the package to source chain to let the IBC app revert any operation. +// from A to A +func (coord *Coordinator) TimeoutPendingPackets(path *Path) error { + src := path.EndpointA + dest := path.EndpointB + + toSend := src.Chain.PendingSendPackets + coord.t.Logf("Timeout %d Packets A->A\n", len(toSend)) + + if err := src.UpdateClient(); err != nil { + return err + } + // Increment time and commit block so that 5 second delay period passes between send and receive + coord.IncrementTime() + coord.CommitBlock(src.Chain, dest.Chain) + for _, packet := range toSend { + // get proof of packet unreceived on dest + packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + proofUnreceived, proofHeight := dest.QueryProof(packetKey) + timeoutMsg := channeltypes.NewMsgTimeout(packet, packet.Sequence, proofUnreceived, proofHeight, src.Chain.SenderAccount.GetAddress().String()) + err := src.Chain.sendMsgs(timeoutMsg) + if err != nil { + return err + } + } + src.Chain.PendingSendPackets = nil + return nil +} + +// CloseChannel close channel on both sides +func (coord *Coordinator) CloseChannel(path *Path) { + err := path.EndpointA.ChanCloseInit() + require.NoError(coord.t, err) + coord.IncrementTime() + err = path.EndpointB.UpdateClient() + require.NoError(coord.t, err) + err = path.EndpointB.ChanCloseConfirm() + require.NoError(coord.t, err) +} diff --git a/x/wasm/ibctesting/endpoint.go b/x/wasm/ibctesting/endpoint.go new file mode 100644 index 00000000..e56c5d06 --- /dev/null +++ b/x/wasm/ibctesting/endpoint.go @@ -0,0 +1,597 @@ +package ibctesting + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v4/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v4/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + "github.com/cosmos/ibc-go/v4/modules/core/exported" + ibctmtypes "github.com/cosmos/ibc-go/v4/modules/light-clients/07-tendermint/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" + "github.com/stretchr/testify/require" +) + +// Endpoint is a which represents a channel endpoint and its associated +// client and connections. It contains client, connection, and channel +// configuration parameters. Endpoint functions will utilize the parameters +// set in the configuration structs when executing IBC messages. +type Endpoint struct { + Chain *TestChain + Counterparty *Endpoint + ClientID string + ConnectionID string + ChannelID string + + ClientConfig ibctesting.ClientConfig + ConnectionConfig *ibctesting.ConnectionConfig + ChannelConfig *ibctesting.ChannelConfig +} + +// NewEndpoint constructs a new endpoint without the counterparty. +// CONTRACT: the counterparty endpoint must be set by the caller. +func NewEndpoint( + chain *TestChain, clientConfig ibctesting.ClientConfig, + connectionConfig *ibctesting.ConnectionConfig, channelConfig *ibctesting.ChannelConfig, +) *Endpoint { + return &Endpoint{ + Chain: chain, + ClientConfig: clientConfig, + ConnectionConfig: connectionConfig, + ChannelConfig: channelConfig, + } +} + +// NewDefaultEndpoint constructs a new endpoint using default values. +// CONTRACT: the counterparty endpoitn must be set by the caller. +func NewDefaultEndpoint(chain *TestChain) *Endpoint { + return &Endpoint{ + Chain: chain, + ClientConfig: ibctesting.NewTendermintConfig(), + ConnectionConfig: ibctesting.NewConnectionConfig(), + ChannelConfig: ibctesting.NewChannelConfig(), + } +} + +// QueryProof queries proof associated with this endpoint using the lastest client state +// height on the counterparty chain. +func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { + // obtain the counterparty client representing the chain associated with the endpoint + clientState := endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) + + // query proof on the counterparty using the latest height of the IBC client + return endpoint.QueryProofAtHeight(key, clientState.GetLatestHeight().GetRevisionHeight()) +} + +// QueryProofAtHeight queries proof associated with this endpoint using the proof height +// provided +func (endpoint *Endpoint) QueryProofAtHeight(key []byte, height uint64) ([]byte, clienttypes.Height) { + // query proof on the counterparty using the latest height of the IBC client + return endpoint.Chain.QueryProofAtHeight(key, int64(height)) +} + +// CreateClient creates an IBC client on the endpoint. It will update the +// clientID for the endpoint if the message is successfully executed. +// NOTE: a solo machine client will be created with an empty diversifier. +func (endpoint *Endpoint) CreateClient() (err error) { + // ensure counterparty has committed state + endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) + + var ( + clientState exported.ClientState + consensusState exported.ConsensusState + ) + + switch endpoint.ClientConfig.GetClientType() { + case exported.Tendermint: + tmConfig, ok := endpoint.ClientConfig.(*ibctesting.TendermintConfig) + require.True(endpoint.Chain.t, ok) + + height := endpoint.Counterparty.Chain.LastHeader.GetHeight().(clienttypes.Height) + clientState = ibctmtypes.NewClientState( + endpoint.Counterparty.Chain.ChainID, tmConfig.TrustLevel, tmConfig.TrustingPeriod, tmConfig.UnbondingPeriod, tmConfig.MaxClockDrift, + height, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, tmConfig.AllowUpdateAfterExpiry, tmConfig.AllowUpdateAfterMisbehaviour, + ) + consensusState = endpoint.Counterparty.Chain.LastHeader.ConsensusState() + case exported.Solomachine: + // TODO + // solo := NewSolomachine(chain.t, endpoint.Chain.Codec, clientID, "", 1) + // clientState = solo.ClientState() + // consensusState = solo.ConsensusState() + + default: + err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) + } + + if err != nil { + return err + } + + msg, err := clienttypes.NewMsgCreateClient( + clientState, consensusState, endpoint.Chain.SenderAccount.GetAddress().String(), + ) + require.NoError(endpoint.Chain.t, err) + + res, err := endpoint.Chain.SendMsgs(msg) + if err != nil { + return err + } + + endpoint.ClientID, err = ibctesting.ParseClientIDFromEvents(res.GetEvents()) + require.NoError(endpoint.Chain.t, err) + + return nil +} + +// UpdateClient updates the IBC client associated with the endpoint. +func (endpoint *Endpoint) UpdateClient() (err error) { + // ensure counterparty has committed state + endpoint.Chain.Coordinator.CommitBlock(endpoint.Counterparty.Chain) + + var header exported.Header + + switch endpoint.ClientConfig.GetClientType() { + case exported.Tendermint: + header, err = endpoint.Chain.ConstructUpdateTMClientHeader(endpoint.Counterparty.Chain, endpoint.ClientID) + + default: + err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) + } + + if err != nil { + return err + } + + msg, err := clienttypes.NewMsgUpdateClient( + endpoint.ClientID, header, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + require.NoError(endpoint.Chain.t, err) + + return endpoint.Chain.sendMsgs(msg) +} + +// ConnOpenInit will construct and execute a MsgConnectionOpenInit on the associated endpoint. +func (endpoint *Endpoint) ConnOpenInit() error { + msg := connectiontypes.NewMsgConnectionOpenInit( + endpoint.ClientID, + endpoint.Counterparty.ClientID, + endpoint.Counterparty.Chain.GetPrefix(), ibctesting.DefaultOpenInitVersion, endpoint.ConnectionConfig.DelayPeriod, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + res, err := endpoint.Chain.SendMsgs(msg) + if err != nil { + return err + } + + endpoint.ConnectionID, err = ibctesting.ParseConnectionIDFromEvents(res.GetEvents()) + require.NoError(endpoint.Chain.t, err) + + return nil +} + +// ConnOpenTry will construct and execute a MsgConnectionOpenTry on the associated endpoint. +func (endpoint *Endpoint) ConnOpenTry() error { + if err := endpoint.UpdateClient(); err != nil { + return err + } + + counterpartyClient, proofClient, proofConsensus, consensusHeight, proofInit, proofHeight := endpoint.QueryConnectionHandshakeProof() + + msg := connectiontypes.NewMsgConnectionOpenTry( + endpoint.ClientID, endpoint.Counterparty.ConnectionID, endpoint.Counterparty.ClientID, + counterpartyClient, endpoint.Counterparty.Chain.GetPrefix(), []*connectiontypes.Version{ibctesting.ConnectionVersion}, endpoint.ConnectionConfig.DelayPeriod, + proofInit, proofClient, proofConsensus, + proofHeight, consensusHeight, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + res, err := endpoint.Chain.SendMsgs(msg) + if err != nil { + return err + } + + if endpoint.ConnectionID == "" { + endpoint.ConnectionID, err = ibctesting.ParseConnectionIDFromEvents(res.GetEvents()) + require.NoError(endpoint.Chain.t, err) + } + + return nil +} + +// ConnOpenAck will construct and execute a MsgConnectionOpenAck on the associated endpoint. +func (endpoint *Endpoint) ConnOpenAck() error { + if err := endpoint.UpdateClient(); err != nil { + return err + } + + counterpartyClient, proofClient, proofConsensus, consensusHeight, proofTry, proofHeight := endpoint.QueryConnectionHandshakeProof() + + msg := connectiontypes.NewMsgConnectionOpenAck( + endpoint.ConnectionID, endpoint.Counterparty.ConnectionID, counterpartyClient, // testing doesn't use flexible selection + proofTry, proofClient, proofConsensus, + proofHeight, consensusHeight, + ibctesting.ConnectionVersion, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + return endpoint.Chain.sendMsgs(msg) +} + +// ConnOpenConfirm will construct and execute a MsgConnectionOpenConfirm on the associated endpoint. +func (endpoint *Endpoint) ConnOpenConfirm() error { + if err := endpoint.UpdateClient(); err != nil { + return err + } + + connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) + proof, height := endpoint.Counterparty.Chain.QueryProof(connectionKey) + + msg := connectiontypes.NewMsgConnectionOpenConfirm( + endpoint.ConnectionID, + proof, height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + return endpoint.Chain.sendMsgs(msg) +} + +// QueryConnectionHandshakeProof returns all the proofs necessary to execute OpenTry or Open Ack of +// the connection handshakes. It returns the counterparty client state, proof of the counterparty +// client state, proof of the counterparty consensus state, the consensus state height, proof of +// the counterparty connection, and the proof height for all the proofs returned. +func (endpoint *Endpoint) QueryConnectionHandshakeProof() ( + clientState exported.ClientState, proofClient, + proofConsensus []byte, consensusHeight clienttypes.Height, + proofConnection []byte, proofHeight clienttypes.Height, +) { + // obtain the client state on the counterparty chain + clientState = endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) + + // query proof for the client state on the counterparty + clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID) + proofClient, proofHeight = endpoint.Counterparty.QueryProof(clientKey) + + consensusHeight = clientState.GetLatestHeight().(clienttypes.Height) + + // query proof for the consensus state on the counterparty + consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight) + proofConsensus, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) + + // query proof for the connection on the counterparty + connectionKey := host.ConnectionKey(endpoint.Counterparty.ConnectionID) + proofConnection, _ = endpoint.Counterparty.QueryProofAtHeight(connectionKey, proofHeight.GetRevisionHeight()) + + return +} + +// ChanOpenInit will construct and execute a MsgChannelOpenInit on the associated endpoint. +func (endpoint *Endpoint) ChanOpenInit() error { + msg := channeltypes.NewMsgChannelOpenInit( + endpoint.ChannelConfig.PortID, + endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID}, + endpoint.Counterparty.ChannelConfig.PortID, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + res, err := endpoint.Chain.SendMsgs(msg) + if err != nil { + return err + } + + endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents()) + require.NoError(endpoint.Chain.t, err) + + // update version to selected app version + // NOTE: this update must be performed after SendMsgs() + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + + return nil +} + +// ChanOpenTry will construct and execute a MsgChannelOpenTry on the associated endpoint. +func (endpoint *Endpoint) ChanOpenTry() error { + if err := endpoint.UpdateClient(); err != nil { + return err + } + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelOpenTry( + endpoint.ChannelConfig.PortID, + endpoint.ChannelConfig.Version, endpoint.ChannelConfig.Order, []string{endpoint.ConnectionID}, + endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version, + proof, height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + res, err := endpoint.Chain.SendMsgs(msg) + if err != nil { + return err + } + + if endpoint.ChannelID == "" { + endpoint.ChannelID, err = ibctesting.ParseChannelIDFromEvents(res.GetEvents()) + require.NoError(endpoint.Chain.t, err) + } + + // update version to selected app version + // NOTE: this update must be performed after the endpoint channelID is set + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + + return nil +} + +// ChanOpenAck will construct and execute a MsgChannelOpenAck on the associated endpoint. +func (endpoint *Endpoint) ChanOpenAck() error { + if err := endpoint.UpdateClient(); err != nil { + return err + } + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelOpenAck( + endpoint.ChannelConfig.PortID, endpoint.ChannelID, + endpoint.Counterparty.ChannelID, endpoint.Counterparty.ChannelConfig.Version, // testing doesn't use flexible selection + proof, height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + if err := endpoint.Chain.sendMsgs(msg); err != nil { + return err + } + + endpoint.ChannelConfig.Version = endpoint.GetChannel().Version + return nil +} + +// ChanOpenConfirm will construct and execute a MsgChannelOpenConfirm on the associated endpoint. +func (endpoint *Endpoint) ChanOpenConfirm() error { + if err := endpoint.UpdateClient(); err != nil { + return err + } + + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + proof, height := endpoint.Counterparty.Chain.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelOpenConfirm( + endpoint.ChannelConfig.PortID, endpoint.ChannelID, + proof, height, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + return endpoint.Chain.sendMsgs(msg) +} + +// ChanCloseInit will construct and execute a MsgChannelCloseInit on the associated endpoint. +// +// NOTE: does not work with ibc-transfer module +func (endpoint *Endpoint) ChanCloseInit() error { + msg := channeltypes.NewMsgChannelCloseInit( + endpoint.ChannelConfig.PortID, endpoint.ChannelID, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + return endpoint.Chain.sendMsgs(msg) +} + +// ChanCloseConfirm will construct and execute a NewMsgChannelCloseConfirm on the associated endpoint. +func (endpoint *Endpoint) ChanCloseConfirm() error { + channelKey := host.ChannelKey(endpoint.Counterparty.ChannelConfig.PortID, endpoint.Counterparty.ChannelID) + proof, proofHeight := endpoint.Counterparty.QueryProof(channelKey) + + msg := channeltypes.NewMsgChannelCloseConfirm( + endpoint.ChannelConfig.PortID, endpoint.ChannelID, + proof, proofHeight, + endpoint.Chain.SenderAccount.GetAddress().String(), + ) + return endpoint.Chain.sendMsgs(msg) +} + +// SendPacket sends a packet through the channel keeper using the associated endpoint +// The counterparty client is updated so proofs can be sent to the counterparty chain. +func (endpoint *Endpoint) SendPacket(packet exported.PacketI) error { + channelCap := endpoint.Chain.GetChannelCapability(packet.GetSourcePort(), packet.GetSourceChannel()) + + // no need to send message, acting as a module + err := endpoint.Chain.App.IBCKeeper.ChannelKeeper.SendPacket(endpoint.Chain.GetContext(), channelCap, packet) + if err != nil { + return err + } + + // commit changes since no message was sent + endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) + + return endpoint.Counterparty.UpdateClient() +} + +// RecvPacket receives a packet on the associated endpoint. +// The counterparty client is updated. +func (endpoint *Endpoint) RecvPacket(packet channeltypes.Packet) error { + _, err := endpoint.RecvPacketWithResult(packet) + if err != nil { + return err + } + + return nil +} + +// RecvPacketWithResult receives a packet on the associated endpoint and the result +// of the transaction is returned. The counterparty client is updated. +func (endpoint *Endpoint) RecvPacketWithResult(packet channeltypes.Packet) (*sdk.Result, error) { + // get proof of packet commitment on source + packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + proof, proofHeight := endpoint.Counterparty.Chain.QueryProof(packetKey) + + recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) + + // receive on counterparty and update source client + res, err := endpoint.Chain.SendMsgs(recvMsg) + if err != nil { + return nil, err + } + + if err := endpoint.Counterparty.UpdateClient(); err != nil { + return nil, err + } + + return res, nil +} + +// WriteAcknowledgement writes an acknowledgement on the channel associated with the endpoint. +// The counterparty client is updated. +func (endpoint *Endpoint) WriteAcknowledgement(ack exported.Acknowledgement, packet exported.PacketI) error { + channelCap := endpoint.Chain.GetChannelCapability(packet.GetDestPort(), packet.GetDestChannel()) + + // no need to send message, acting as a handler + err := endpoint.Chain.App.IBCKeeper.ChannelKeeper.WriteAcknowledgement(endpoint.Chain.GetContext(), channelCap, packet, ack) + if err != nil { + return err + } + + // commit changes since no message was sent + endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) + + return endpoint.Counterparty.UpdateClient() +} + +// AcknowledgePacket sends a MsgAcknowledgement to the channel associated with the endpoint. +func (endpoint *Endpoint) AcknowledgePacket(packet channeltypes.Packet, ack []byte) error { + // get proof of acknowledgement on counterparty + packetKey := host.PacketAcknowledgementKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + ackMsg := channeltypes.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String()) + + return endpoint.Chain.sendMsgs(ackMsg) +} + +// TimeoutPacket sends a MsgTimeout to the channel associated with the endpoint. +func (endpoint *Endpoint) TimeoutPacket(packet channeltypes.Packet) error { + // get proof for timeout based on channel order + var packetKey []byte + + switch endpoint.ChannelConfig.Order { + case channeltypes.ORDERED: + packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) + case channeltypes.UNORDERED: + packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + default: + return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) + } + + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + nextSeqRecv, found := endpoint.Counterparty.Chain.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.t, found) + + timeoutMsg := channeltypes.NewMsgTimeout( + packet, nextSeqRecv, + proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(timeoutMsg) +} + +// TimeoutOnClose sends a MsgTimeoutOnClose to the channel associated with the endpoint. +func (endpoint *Endpoint) TimeoutOnClose(packet channeltypes.Packet) error { + // get proof for timeout based on channel order + var packetKey []byte + + switch endpoint.ChannelConfig.Order { + case channeltypes.ORDERED: + packetKey = host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel()) + case channeltypes.UNORDERED: + packetKey = host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + default: + return fmt.Errorf("unsupported order type %s", endpoint.ChannelConfig.Order) + } + + proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey) + + channelKey := host.ChannelKey(packet.GetDestPort(), packet.GetDestChannel()) + proofClosed, _ := endpoint.Counterparty.QueryProof(channelKey) + + nextSeqRecv, found := endpoint.Counterparty.Chain.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(endpoint.Counterparty.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.t, found) + + timeoutOnCloseMsg := channeltypes.NewMsgTimeoutOnClose( + packet, nextSeqRecv, + proof, proofClosed, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return endpoint.Chain.sendMsgs(timeoutOnCloseMsg) +} + +// SetChannelClosed sets a channel state to CLOSED. +func (endpoint *Endpoint) SetChannelClosed() error { + channel := endpoint.GetChannel() + + channel.State = channeltypes.CLOSED + endpoint.Chain.App.IBCKeeper.ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) + + endpoint.Chain.Coordinator.CommitBlock(endpoint.Chain) + + return endpoint.Counterparty.UpdateClient() +} + +// GetClientState retrieves the Client State for this endpoint. The +// client state is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetClientState() exported.ClientState { + return endpoint.Chain.GetClientState(endpoint.ClientID) +} + +// SetClientState sets the client state for this endpoint. +func (endpoint *Endpoint) SetClientState(clientState exported.ClientState) { + endpoint.Chain.App.IBCKeeper.ClientKeeper.SetClientState(endpoint.Chain.GetContext(), endpoint.ClientID, clientState) +} + +// GetConsensusState retrieves the Consensus State for this endpoint at the provided height. +// The consensus state is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetConsensusState(height exported.Height) exported.ConsensusState { + consensusState, found := endpoint.Chain.GetConsensusState(endpoint.ClientID, height) + require.True(endpoint.Chain.t, found) + + return consensusState +} + +// SetConsensusState sets the consensus state for this endpoint. +func (endpoint *Endpoint) SetConsensusState(consensusState exported.ConsensusState, height exported.Height) { + endpoint.Chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState(endpoint.Chain.GetContext(), endpoint.ClientID, height, consensusState) +} + +// GetConnection retrieves an IBC Connection for the endpoint. The +// connection is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetConnection() connectiontypes.ConnectionEnd { + connection, found := endpoint.Chain.App.IBCKeeper.ConnectionKeeper.GetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID) + require.True(endpoint.Chain.t, found) + + return connection +} + +// SetConnection sets the connection for this endpoint. +func (endpoint *Endpoint) SetConnection(connection connectiontypes.ConnectionEnd) { + endpoint.Chain.App.IBCKeeper.ConnectionKeeper.SetConnection(endpoint.Chain.GetContext(), endpoint.ConnectionID, connection) +} + +// GetChannel retrieves an IBC Channel for the endpoint. The channel +// is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetChannel() channeltypes.Channel { + channel, found := endpoint.Chain.App.IBCKeeper.ChannelKeeper.GetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID) + require.True(endpoint.Chain.t, found) + + return channel +} + +// SetChannel sets the channel for this endpoint. +func (endpoint *Endpoint) SetChannel(channel channeltypes.Channel) { + endpoint.Chain.App.IBCKeeper.ChannelKeeper.SetChannel(endpoint.Chain.GetContext(), endpoint.ChannelConfig.PortID, endpoint.ChannelID, channel) +} + +// QueryClientStateProof performs and abci query for a client stat associated +// with this endpoint and returns the ClientState along with the proof. +func (endpoint *Endpoint) QueryClientStateProof() (exported.ClientState, []byte) { + // retrieve client state to provide proof for + clientState := endpoint.GetClientState() + + clientKey := host.FullClientStateKey(endpoint.ClientID) + proofClient, _ := endpoint.QueryProof(clientKey) + + return clientState, proofClient +} diff --git a/x/wasm/ibctesting/event_utils.go b/x/wasm/ibctesting/event_utils.go new file mode 100644 index 00000000..0933dadd --- /dev/null +++ b/x/wasm/ibctesting/event_utils.go @@ -0,0 +1,118 @@ +package ibctesting + +import ( + "encoding/hex" + "fmt" + "strconv" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + abci "github.com/tendermint/tendermint/abci/types" +) + +func getSendPackets(evts []abci.Event) []channeltypes.Packet { + var res []channeltypes.Packet + for _, evt := range evts { + if evt.Type == channeltypes.EventTypeSendPacket { + packet := parsePacketFromEvent(evt) + res = append(res, packet) + } + } + return res +} + +// Used for various debug statements above when needed... do not remove +// func showEvent(evt abci.Event) { +// fmt.Printf("evt.Type: %s\n", evt.Type) +// for _, attr := range evt.Attributes { +// fmt.Printf(" %s = %s\n", string(attr.Key), string(attr.Value)) +// } +//} + +func parsePacketFromEvent(evt abci.Event) channeltypes.Packet { + return channeltypes.Packet{ + Sequence: getUintField(evt, channeltypes.AttributeKeySequence), + SourcePort: getField(evt, channeltypes.AttributeKeySrcPort), + SourceChannel: getField(evt, channeltypes.AttributeKeySrcChannel), + DestinationPort: getField(evt, channeltypes.AttributeKeyDstPort), + DestinationChannel: getField(evt, channeltypes.AttributeKeyDstChannel), + Data: getHexField(evt, channeltypes.AttributeKeyDataHex), + TimeoutHeight: parseTimeoutHeight(getField(evt, channeltypes.AttributeKeyTimeoutHeight)), + TimeoutTimestamp: getUintField(evt, channeltypes.AttributeKeyTimeoutTimestamp), + } +} + +func getHexField(evt abci.Event, key string) []byte { + got := getField(evt, key) + if got == "" { + return nil + } + bz, err := hex.DecodeString(got) + if err != nil { + panic(err) + } + return bz +} + +// return the value for the attribute with the given name +func getField(evt abci.Event, key string) string { + for _, attr := range evt.Attributes { + if string(attr.Key) == key { + return string(attr.Value) + } + } + return "" +} + +func getUintField(evt abci.Event, key string) uint64 { + raw := getField(evt, key) + return toUint64(raw) +} + +func toUint64(raw string) uint64 { + if raw == "" { + return 0 + } + i, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + panic(err) + } + return i +} + +func parseTimeoutHeight(raw string) clienttypes.Height { + chunks := strings.Split(raw, "-") + return clienttypes.Height{ + RevisionNumber: toUint64(chunks[0]), + RevisionHeight: toUint64(chunks[1]), + } +} + +func ParsePortIDFromEvents(events sdk.Events) (string, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { + for _, attr := range ev.Attributes { + if string(attr.Key) == channeltypes.AttributeKeyPortID { + return string(attr.Value), nil + } + } + } + } + return "", fmt.Errorf("port id event attribute not found") +} + +func ParseChannelVersionFromEvents(events sdk.Events) (string, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeChannelOpenInit || ev.Type == channeltypes.EventTypeChannelOpenTry { + for _, attr := range ev.Attributes { + if string(attr.Key) == channeltypes.AttributeVersion { + return string(attr.Value), nil + } + } + } + } + return "", fmt.Errorf("version event attribute not found") +} diff --git a/x/wasm/ibctesting/faucet.go b/x/wasm/ibctesting/faucet.go new file mode 100644 index 00000000..d72d4437 --- /dev/null +++ b/x/wasm/ibctesting/faucet.go @@ -0,0 +1,52 @@ +package ibctesting + +import ( + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/app" +) + +// Fund an address with the given amount in default denom +func (chain *TestChain) Fund(addr sdk.AccAddress, amount sdk.Int) { + require.NoError(chain.t, chain.sendMsgs(&banktypes.MsgSend{ + FromAddress: chain.SenderAccount.GetAddress().String(), + ToAddress: addr.String(), + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + })) +} + +// SendNonDefaultSenderMsgs delivers a transaction through the application. It returns the result and error if one +// occurred. +func (chain *TestChain) SendNonDefaultSenderMsgs(senderPrivKey cryptotypes.PrivKey, msgs ...sdk.Msg) (*sdk.Result, error) { + require.NotEqual(chain.t, chain.SenderPrivKey, senderPrivKey, "use SendMsgs method") + + // ensure the chain has the latest time + chain.Coordinator.UpdateTimeForChain(chain) + + addr := sdk.AccAddress(senderPrivKey.PubKey().Address().Bytes()) + account := chain.App.AccountKeeper.GetAccount(chain.GetContext(), addr) + require.NotNil(chain.t, account) + _, r, err := app.SignAndDeliver( + chain.t, + chain.TxConfig, + chain.App.BaseApp, + chain.GetContext().BlockHeader(), + msgs, + chain.ChainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + senderPrivKey, + ) + + // SignAndDeliver calls app.Commit() + chain.NextBlock() + chain.Coordinator.IncrementTime() + if err != nil { + return r, err + } + chain.captureIBCEvents(r) + return r, nil +} diff --git a/x/wasm/ibctesting/path.go b/x/wasm/ibctesting/path.go new file mode 100644 index 00000000..5e861325 --- /dev/null +++ b/x/wasm/ibctesting/path.go @@ -0,0 +1,113 @@ +package ibctesting + +import ( + "bytes" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibctesting "github.com/cosmos/ibc-go/v4/testing" +) + +// Path contains two endpoints representing two chains connected over IBC +type Path struct { + EndpointA *Endpoint + EndpointB *Endpoint +} + +// NewPath constructs an endpoint for each chain using the default values +// for the endpoints. Each endpoint is updated to have a pointer to the +// counterparty endpoint. +func NewPath(chainA, chainB *TestChain) *Path { + endpointA := NewDefaultEndpoint(chainA) + endpointB := NewDefaultEndpoint(chainB) + + endpointA.Counterparty = endpointB + endpointB.Counterparty = endpointA + + return &Path{ + EndpointA: endpointA, + EndpointB: endpointB, + } +} + +// SetChannelOrdered sets the channel order for both endpoints to ORDERED. +func (path *Path) SetChannelOrdered() { + path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED +} + +// RelayPacket attempts to relay the packet first on EndpointA and then on EndpointB +// if EndpointA does not contain a packet commitment for that packet. An error is returned +// if a relay step fails or the packet commitment does not exist on either endpoint. +func (path *Path) RelayPacket(packet channeltypes.Packet, ack []byte) error { + pc := path.EndpointA.Chain.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(path.EndpointA.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointA.Chain.App.AppCodec(), packet)) { + + // packet found, relay from A to B + if err := path.EndpointB.UpdateClient(); err != nil { + return err + } + + res, err := path.EndpointB.RecvPacketWithResult(packet) + if err != nil { + return err + } + + ack, err := ibctesting.ParseAckFromEvents(res.GetEvents()) + if err != nil { + return err + } + + if err := path.EndpointA.AcknowledgePacket(packet, ack); err != nil { + return err + } + + return nil + } + + pc = path.EndpointB.Chain.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(path.EndpointB.Chain.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + if bytes.Equal(pc, channeltypes.CommitPacket(path.EndpointB.Chain.App.AppCodec(), packet)) { + + // packet found, relay B to A + if err := path.EndpointA.UpdateClient(); err != nil { + return err + } + + res, err := path.EndpointA.RecvPacketWithResult(packet) + if err != nil { + return err + } + + ack, err := ibctesting.ParseAckFromEvents(res.GetEvents()) + if err != nil { + return err + } + + if err := path.EndpointB.AcknowledgePacket(packet, ack); err != nil { + return err + } + return nil + } + + return fmt.Errorf("packet commitment does not exist on either endpoint for provided packet") +} + +// SendMsg delivers the provided messages to the chain. The counterparty +// client is updated with the new source consensus state. +func (path *Path) SendMsg(msgs ...sdk.Msg) error { + if err := path.EndpointA.Chain.sendMsgs(msgs...); err != nil { + return err + } + if err := path.EndpointA.UpdateClient(); err != nil { + return err + } + return path.EndpointB.UpdateClient() +} + +func (path *Path) Invert() *Path { + return &Path{ + EndpointA: path.EndpointB, + EndpointB: path.EndpointA, + } +} diff --git a/x/wasm/ibctesting/wasm.go b/x/wasm/ibctesting/wasm.go new file mode 100644 index 00000000..80eb87e2 --- /dev/null +++ b/x/wasm/ibctesting/wasm.go @@ -0,0 +1,138 @@ +package ibctesting + +import ( + "bytes" + "compress/gzip" + "encoding/json" + "fmt" + "os" + "strings" + + ibctesting "github.com/cosmos/ibc-go/v4/testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/protobuf/proto" //nolint + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/rand" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var wasmIdent = []byte("\x00\x61\x73\x6D") + +// SeedNewContractInstance stores some wasm code and instantiates a new contract on this chain. +// This method can be called to prepare the store with some valid CodeInfo and ContractInfo. The returned +// Address is the contract address for this instance. Test should make use of this data and/or use NewIBCContractMockWasmer +// for using a contract mock in Go. +func (chain *TestChain) SeedNewContractInstance() sdk.AccAddress { + pInstResp := chain.StoreCode(append(wasmIdent, rand.Bytes(10)...)) + codeID := pInstResp.CodeID + + anyAddressStr := chain.SenderAccount.GetAddress().String() + initMsg := []byte(fmt.Sprintf(`{"verifier": %q, "beneficiary": %q}`, anyAddressStr, anyAddressStr)) + return chain.InstantiateContract(codeID, initMsg) +} + +func (chain *TestChain) StoreCodeFile(filename string) types.MsgStoreCodeResponse { + wasmCode, err := os.ReadFile(filename) + require.NoError(chain.t, err) + if strings.HasSuffix(filename, "wasm") { // compress for gas limit + var buf bytes.Buffer + gz := gzip.NewWriter(&buf) + _, err := gz.Write(wasmCode) + require.NoError(chain.t, err) + err = gz.Close() + require.NoError(chain.t, err) + wasmCode = buf.Bytes() + } + return chain.StoreCode(wasmCode) +} + +func (chain *TestChain) StoreCode(byteCode []byte) types.MsgStoreCodeResponse { + storeMsg := &types.MsgStoreCode{ + Sender: chain.SenderAccount.GetAddress().String(), + WASMByteCode: byteCode, + } + r, err := chain.SendMsgs(storeMsg) + require.NoError(chain.t, err) + protoResult := chain.parseSDKResultData(r) + require.Len(chain.t, protoResult.Data, 1) + // unmarshal protobuf response from data + var pInstResp types.MsgStoreCodeResponse + require.NoError(chain.t, pInstResp.Unmarshal(protoResult.Data[0].Data)) + require.NotEmpty(chain.t, pInstResp.CodeID) + require.NotEmpty(chain.t, pInstResp.Checksum) + return pInstResp +} + +func (chain *TestChain) InstantiateContract(codeID uint64, initMsg []byte) sdk.AccAddress { + instantiateMsg := &types.MsgInstantiateContract{ + Sender: chain.SenderAccount.GetAddress().String(), + Admin: chain.SenderAccount.GetAddress().String(), + CodeID: codeID, + Label: "ibc-test", + Msg: initMsg, + Funds: sdk.Coins{ibctesting.TestCoin}, + } + + r, err := chain.SendMsgs(instantiateMsg) + require.NoError(chain.t, err) + protoResult := chain.parseSDKResultData(r) + require.Len(chain.t, protoResult.Data, 1) + + var pExecResp types.MsgInstantiateContractResponse + require.NoError(chain.t, pExecResp.Unmarshal(protoResult.Data[0].Data)) + a, err := sdk.AccAddressFromBech32(pExecResp.Address) + require.NoError(chain.t, err) + return a +} + +// SmartQuery This will serialize the query message and submit it to the contract. +// The response is parsed into the provided interface. +// Usage: SmartQuery(addr, QueryMsg{Foo: 1}, &response) +func (chain *TestChain) SmartQuery(contractAddr string, queryMsg interface{}, response interface{}) error { + msg, err := json.Marshal(queryMsg) + if err != nil { + return err + } + + req := types.QuerySmartContractStateRequest{ + Address: contractAddr, + QueryData: msg, + } + reqBin, err := proto.Marshal(&req) + if err != nil { + return err + } + + // TODO: what is the query? + res := chain.App.Query(abci.RequestQuery{ + Path: "/cosmwasm.wasm.v1.Query/SmartContractState", + Data: reqBin, + }) + + if res.Code != 0 { + return fmt.Errorf("query failed: (%d) %s", res.Code, res.Log) + } + + // unpack protobuf + var resp types.QuerySmartContractStateResponse + err = proto.Unmarshal(res.Value, &resp) + if err != nil { + return err + } + // unpack json content + return json.Unmarshal(resp.Data, response) +} + +func (chain *TestChain) parseSDKResultData(r *sdk.Result) sdk.TxMsgData { + var protoResult sdk.TxMsgData + require.NoError(chain.t, proto.Unmarshal(r.Data, &protoResult)) + return protoResult +} + +// ContractInfo is a helper function to returns the ContractInfo for the given contract address +func (chain *TestChain) ContractInfo(contractAddr sdk.AccAddress) *types.ContractInfo { + return chain.App.WasmKeeper.GetContractInfo(chain.GetContext(), contractAddr) +} diff --git a/x/wasm/ioutils/ioutil.go b/x/wasm/ioutils/ioutil.go new file mode 100644 index 00000000..890f3ab2 --- /dev/null +++ b/x/wasm/ioutils/ioutil.go @@ -0,0 +1,41 @@ +package ioutils + +import ( + "bytes" + "compress/gzip" + "io" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// Uncompress expects a valid gzip source to unpack or fails. See IsGzip +func Uncompress(gzipSrc []byte, limit uint64) ([]byte, error) { + if uint64(len(gzipSrc)) > limit { + return nil, types.ErrLimit + } + zr, err := gzip.NewReader(bytes.NewReader(gzipSrc)) + if err != nil { + return nil, err + } + zr.Multistream(false) + defer zr.Close() + return io.ReadAll(LimitReader(zr, int64(limit))) +} + +// LimitReader returns a Reader that reads from r +// but stops with types.ErrLimit after n bytes. +// The underlying implementation is a *io.LimitedReader. +func LimitReader(r io.Reader, n int64) io.Reader { + return &LimitedReader{r: &io.LimitedReader{R: r, N: n}} +} + +type LimitedReader struct { + r *io.LimitedReader +} + +func (l *LimitedReader) Read(p []byte) (n int, err error) { + if l.r.N <= 0 { + return 0, types.ErrLimit + } + return l.r.Read(p) +} diff --git a/x/wasm/ioutils/ioutil_test.go b/x/wasm/ioutils/ioutil_test.go new file mode 100644 index 00000000..c57ecaa5 --- /dev/null +++ b/x/wasm/ioutils/ioutil_test.go @@ -0,0 +1,82 @@ +package ioutils + +import ( + "bytes" + "compress/gzip" + "errors" + "io" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestUncompress(t *testing.T) { + wasmRaw, err := os.ReadFile("../keeper/testdata/hackatom.wasm") + require.NoError(t, err) + + wasmGzipped, err := os.ReadFile("../keeper/testdata/hackatom.wasm.gzip") + require.NoError(t, err) + + const maxSize = 400_000 + + specs := map[string]struct { + src []byte + expError error + expResult []byte + }{ + "handle wasm compressed": { + src: wasmGzipped, + expResult: wasmRaw, + }, + "handle gzip identifier only": { + src: gzipIdent, + expError: io.ErrUnexpectedEOF, + }, + "handle broken gzip": { + src: append(gzipIdent, byte(0x1)), + expError: io.ErrUnexpectedEOF, + }, + "handle incomplete gzip": { + src: wasmGzipped[:len(wasmGzipped)-5], + expError: io.ErrUnexpectedEOF, + }, + "handle limit gzip output": { + src: asGzip(bytes.Repeat([]byte{0x1}, maxSize)), + expResult: bytes.Repeat([]byte{0x1}, maxSize), + }, + "handle big gzip output": { + src: asGzip(bytes.Repeat([]byte{0x1}, maxSize+1)), + expError: types.ErrLimit, + }, + "handle other big gzip output": { + src: asGzip(bytes.Repeat([]byte{0x1}, 2*maxSize)), + expError: types.ErrLimit, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + r, err := Uncompress(spec.src, maxSize) + require.True(t, errors.Is(spec.expError, err), "exp %v got %+v", spec.expError, err) + if spec.expError != nil { + return + } + assert.Equal(t, spec.expResult, r) + }) + } +} + +func asGzip(src []byte) []byte { + var buf bytes.Buffer + zipper := gzip.NewWriter(&buf) + if _, err := io.Copy(zipper, bytes.NewReader(src)); err != nil { + panic(err) + } + if err := zipper.Close(); err != nil { + panic(err) + } + return buf.Bytes() +} diff --git a/x/wasm/ioutils/utils.go b/x/wasm/ioutils/utils.go new file mode 100644 index 00000000..197c44c3 --- /dev/null +++ b/x/wasm/ioutils/utils.go @@ -0,0 +1,43 @@ +package ioutils + +import ( + "bytes" + "compress/gzip" +) + +// Note: []byte can never be const as they are inherently mutable +var ( + // magic bytes to identify gzip. + // See https://www.ietf.org/rfc/rfc1952.txt + // and https://github.com/golang/go/blob/master/src/net/http/sniff.go#L186 + gzipIdent = []byte("\x1F\x8B\x08") + + wasmIdent = []byte("\x00\x61\x73\x6D") +) + +// IsGzip returns checks if the file contents are gzip compressed +func IsGzip(input []byte) bool { + return len(input) >= 3 && bytes.Equal(gzipIdent, input[0:3]) +} + +// IsWasm checks if the file contents are of wasm binary +func IsWasm(input []byte) bool { + return bytes.Equal(input[:4], wasmIdent) +} + +// GzipIt compresses the input ([]byte) +func GzipIt(input []byte) ([]byte, error) { + // Create gzip writer. + var b bytes.Buffer + w := gzip.NewWriter(&b) + _, err := w.Write(input) + if err != nil { + return nil, err + } + err = w.Close() // You must close this first to flush the bytes to the buffer. + if err != nil { + return nil, err + } + + return b.Bytes(), nil +} diff --git a/x/wasm/ioutils/utils_test.go b/x/wasm/ioutils/utils_test.go new file mode 100644 index 00000000..2dea0c5c --- /dev/null +++ b/x/wasm/ioutils/utils_test.go @@ -0,0 +1,68 @@ +package ioutils + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func GetTestData() ([]byte, []byte, []byte, error) { + wasmCode, err := os.ReadFile("../keeper/testdata/hackatom.wasm") + if err != nil { + return nil, nil, nil, err + } + + gzipData, err := GzipIt(wasmCode) + if err != nil { + return nil, nil, nil, err + } + + someRandomStr := []byte("hello world") + + return wasmCode, someRandomStr, gzipData, nil +} + +func TestIsWasm(t *testing.T) { + wasmCode, someRandomStr, gzipData, err := GetTestData() + require.NoError(t, err) + + t.Log("should return false for some random string data") + require.False(t, IsWasm(someRandomStr)) + t.Log("should return false for gzip data") + require.False(t, IsWasm(gzipData)) + t.Log("should return true for exact wasm") + require.True(t, IsWasm(wasmCode)) +} + +func TestIsGzip(t *testing.T) { + wasmCode, someRandomStr, gzipData, err := GetTestData() + require.NoError(t, err) + + require.False(t, IsGzip(wasmCode)) + require.False(t, IsGzip(someRandomStr)) + require.False(t, IsGzip(nil)) + require.True(t, IsGzip(gzipData[0:3])) + require.True(t, IsGzip(gzipData)) +} + +func TestGzipIt(t *testing.T) { + wasmCode, someRandomStr, _, err := GetTestData() + originalGzipData := []byte{ + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 202, 72, 205, 201, 201, 87, 40, 207, 47, 202, 73, 1, + 4, 0, 0, 255, 255, 133, 17, 74, 13, 11, 0, 0, 0, + } + + require.NoError(t, err) + + t.Log("gzip wasm with no error") + _, err = GzipIt(wasmCode) + require.NoError(t, err) + + t.Log("gzip of a string should return exact gzip data") + strToGzip, err := GzipIt(someRandomStr) + + require.True(t, IsGzip(strToGzip)) + require.NoError(t, err) + require.Equal(t, originalGzipData, strToGzip) +} diff --git a/x/wasm/keeper/addresses.go b/x/wasm/keeper/addresses.go new file mode 100644 index 00000000..390a24f6 --- /dev/null +++ b/x/wasm/keeper/addresses.go @@ -0,0 +1,76 @@ +package keeper + +import ( + "encoding/binary" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// AddressGenerator abstract address generator to be used for a single contract address +type AddressGenerator func(ctx sdk.Context, codeID uint64, checksum []byte) sdk.AccAddress + +// ClassicAddressGenerator generates a contract address using codeID and instanceID sequence +func (k Keeper) ClassicAddressGenerator() AddressGenerator { + return func(ctx sdk.Context, codeID uint64, _ []byte) sdk.AccAddress { + instanceID := k.autoIncrementID(ctx, types.KeyLastInstanceID) + return BuildContractAddressClassic(codeID, instanceID) + } +} + +// PredicableAddressGenerator generates a predictable contract address +func PredicableAddressGenerator(creator sdk.AccAddress, salt []byte, msg []byte, fixMsg bool) AddressGenerator { + return func(ctx sdk.Context, _ uint64, checksum []byte) sdk.AccAddress { + if !fixMsg { // clear msg to not be included in the address generation + msg = []byte{} + } + return BuildContractAddressPredictable(checksum, creator, salt, msg) + } +} + +// BuildContractAddressClassic builds an sdk account address for a contract. +func BuildContractAddressClassic(codeID, instanceID uint64) sdk.AccAddress { + contractID := make([]byte, 16) + binary.BigEndian.PutUint64(contractID[:8], codeID) + binary.BigEndian.PutUint64(contractID[8:], instanceID) + return address.Module(types.ModuleName, contractID)[:types.ContractAddrLen] +} + +// BuildContractAddressPredictable generates a contract address for the wasm module with len = types.ContractAddrLen using the +// Cosmos SDK address.Module function. +// Internally a key is built containing: +// (len(checksum) | checksum | len(sender_address) | sender_address | len(salt) | salt| len(initMsg) | initMsg). +// +// All method parameter values must be valid and not nil. +func BuildContractAddressPredictable(checksum []byte, creator sdk.AccAddress, salt, initMsg types.RawContractMessage) sdk.AccAddress { + if len(checksum) != 32 { + panic("invalid checksum") + } + if err := sdk.VerifyAddressFormat(creator); err != nil { + panic(fmt.Sprintf("creator: %s", err)) + } + if err := types.ValidateSalt(salt); err != nil { + panic(fmt.Sprintf("salt: %s", err)) + } + if err := initMsg.ValidateBasic(); len(initMsg) != 0 && err != nil { + panic(fmt.Sprintf("initMsg: %s", err)) + } + checksum = UInt64LengthPrefix(checksum) + creator = UInt64LengthPrefix(creator) + salt = UInt64LengthPrefix(salt) + initMsg = UInt64LengthPrefix(initMsg) + key := make([]byte, len(checksum)+len(creator)+len(salt)+len(initMsg)) + copy(key[0:], checksum) + copy(key[len(checksum):], creator) + copy(key[len(checksum)+len(creator):], salt) + copy(key[len(checksum)+len(creator)+len(salt):], initMsg) + return address.Module(types.ModuleName, key)[:types.ContractAddrLen] +} + +// UInt64LengthPrefix prepend big endian encoded byte length +func UInt64LengthPrefix(bz []byte) []byte { + return append(sdk.Uint64ToBigEndian(uint64(len(bz))), bz...) +} diff --git a/x/wasm/keeper/addresses_test.go b/x/wasm/keeper/addresses_test.go new file mode 100644 index 00000000..fbcc607f --- /dev/null +++ b/x/wasm/keeper/addresses_test.go @@ -0,0 +1,432 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + tmbytes "github.com/tendermint/tendermint/libs/bytes" +) + +func TestBuildContractAddress(t *testing.T) { + x, y := sdk.GetConfig().GetBech32AccountAddrPrefix(), sdk.GetConfig().GetBech32AccountPubPrefix() + t.Cleanup(func() { + sdk.GetConfig().SetBech32PrefixForAccount(x, y) + }) + sdk.GetConfig().SetBech32PrefixForAccount("purple", "purple") + + // test vectors generated via cosmjs: https://github.com/cosmos/cosmjs/pull/1253/files + type Spec struct { + In struct { + Checksum tmbytes.HexBytes `json:"checksum"` + Creator sdk.AccAddress `json:"creator"` + Salt tmbytes.HexBytes `json:"salt"` + Msg string `json:"msg"` + } `json:"in"` + Out struct { + Address sdk.AccAddress `json:"address"` + } `json:"out"` + } + var specs []Spec + require.NoError(t, json.Unmarshal([]byte(goldenMasterPredictableContractAddr), &specs)) + require.NotEmpty(t, specs) + for i, spec := range specs { + t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) { + // when + gotAddr := BuildContractAddressPredictable(spec.In.Checksum, spec.In.Creator, spec.In.Salt.Bytes(), []byte(spec.In.Msg)) + + require.Equal(t, spec.Out.Address.String(), gotAddr.String()) + require.NoError(t, sdk.VerifyAddressFormat(gotAddr)) + }) + } +} + +const goldenMasterPredictableContractAddr = `[ + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000", + "addressData": "5e865d3e45ad3e961f77fd77d46543417ced44d924dc3e079b5415ff6775f847" + }, + "out": { + "address": "purple1t6r960j945lfv8mhl4mage2rg97w63xeynwrupum2s2l7em4lprs9ce5hk" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d", + "addressData": "0995499608947a5281e2c7ebd71bdb26a1ad981946dad57f6c4d3ee35de77835" + }, + "out": { + "address": "purple1px25n9sgj3a99q0zcl4awx7my6s6mxqegmdd2lmvf5lwxh080q6suttktr" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "83326e554723b15bac664ceabc8a5887e27003abe9fbd992af8c7bcea4745167" + }, + "out": { + "address": "purple1svexu428ywc4htrxfn4tezjcsl38qqata8aany4033auafr529ns4v254c" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "9384c6248c0bb171e306fd7da0993ec1e20eba006452a3a9e078883eb3594564" + }, + "out": { + "address": "purple1jwzvvfyvpwchrccxl476pxf7c83qawsqv3f2820q0zyrav6eg4jqdcq7gc" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "9a8d5f98fb186825401a26206158e7a1213311a9b6a87944469913655af52ffb" + }, + "out": { + "address": "purple1n2x4lx8mrp5z2sq6ycsxzk885ysnxydfk658j3zxnyfk2kh49lasesxf6j" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "932f07bc53f7d0b0b43cb5a54ac3e245b205e6ae6f7c1d991dc6af4a2ff9ac18" + }, + "out": { + "address": "purple1jvhs00zn7lgtpdpukkj54slzgkeqte4wda7pmxgac6h55tle4svq8cmp60" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000", + "addressData": "9725e94f528d8b78d33c25f3dfcd60e6142d8be60ab36f6a5b59036fd51560db" + }, + "out": { + "address": "purple1juj7jn6j3k9h35euyhealntquc2zmzlxp2ek76jmtypkl4g4vrdsfwmwxk" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d", + "addressData": "b056e539bbaf447ba18f3f13b792970111fc78933eb6700f4d227b5216d63658" + }, + "out": { + "address": "purple1kptw2wdm4az8hgv08ufm0y5hqyglc7yn86m8qr6dyfa4y9kkxevqmkm9q3" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "6c98434180f052294ff89fb6d2dae34f9f4468b0b8e6e7c002b2a44adee39abd" + }, + "out": { + "address": "purple1djvyxsvq7pfzjnlcn7md9khrf705g69shrnw0sqzk2jy4hhrn27sjh2ysy" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "0aaf1c31c5d529d21d898775bc35b3416f47bfd99188c334c6c716102cbd3101" + }, + "out": { + "address": "purple1p2h3cvw9655ay8vfsa6mcddng9h5007ejxyvxdxxcutpqt9axyqsagmmay" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "36fe6ab732187cdfed46290b448b32eb7f4798e7a4968b0537de8a842cbf030e" + }, + "out": { + "address": "purple1xmlx4dejrp7dlm2x9y95fzejadl50x885jtgkpfhm69ggt9lqv8qk3vn4f" + } + }, + { + "in": { + "checksum": "13a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a5", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d00000000000000002013a1fc994cc6d1c81b746ee0c0ff6f90043875e0bf1d9be6b7d779fc978dc2a500000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "a0d0c942adac6f3e5e7c23116c4c42a24e96e0ab75f53690ec2d3de16067c751" + }, + "out": { + "address": "purple15rgvjs4d43hnuhnuyvgkcnzz5f8fdc9twh6ndy8v9577zcr8cags40l9dt" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000001610000000000000000", + "addressData": "b95c467218d408a0f93046f227b6ece7fe18133ff30113db4d2a7becdfeca141" + }, + "out": { + "address": "purple1h9wyvusc6sy2p7fsgmez0dhvullpsyel7vq38k6d9fa7ehlv59qsvnyh36" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc00000000000000016100000000000000027b7d", + "addressData": "23fe45dbbd45dc6cd25244a74b6e99e7a65bf0bac2f2842a05049d37555a3ae6" + }, + "out": { + "address": "purple1y0lytkaaghwxe5jjgjn5km5eu7n9hu96ctegg2s9qjwnw4268tnqxhg60a" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "6faea261ed63baa65b05726269e83b217fa6205dc7d9fb74f9667d004a69c082" + }, + "out": { + "address": "purple1d7h2yc0dvwa2vkc9wf3xn6pmy9l6vgzaclvlka8eve7sqjnfczpqqsdnwu" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "67a3ab6384729925fdb144574628ce96836fe098d2c6be4e84ac106b2728d96c" + }, + "out": { + "address": "purple1v736kcuyw2vjtld3g3t5v2xwj6pklcyc6trtun5y4sgxkfegm9kq7vgpnt" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "23a121263bfce05c144f4af86f3d8a9f87dc56f9dc48dbcffc8c5a614da4c661" + }, + "out": { + "address": "purple1ywsjzf3mlns9c9z0ftux70v2n7rac4hem3ydhnlu33dxzndycesssc7x2m" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvhxf2py", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbcccccccccc", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000149999999999aaaaaaaaaabbbbbbbbbbcccccccccc0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "dd90dba6d6fcd5fb9c9c8f536314eb1bb29cb5aa084b633c5806b926a5636b58" + }, + "out": { + "address": "purple1mkgdhfkkln2lh8yu3afkx98trwefedd2pp9kx0zcq6ujdftrddvq50esay" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000001610000000000000000", + "addressData": "547a743022f4f1af05b102f57bf1c1c7d7ee81bae427dc20d36b2c4ec57612ae" + }, + "out": { + "address": "purple123a8gvpz7nc67pd3qt6hhuwpclt7aqd6usnacgxndvkya3tkz2hq5hz38f" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff00000000000000016100000000000000027b7d", + "addressData": "416e169110e4b411bc53162d7503b2bbf14d6b36b1413a4f4c9af622696e9665" + }, + "out": { + "address": "purple1g9hpdygsuj6pr0znzckh2qajh0c566ekk9qn5n6vntmzy6twjejsrl9alk" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "61", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff000000000000000161000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "619a0988b92d8796cea91dea63cbb1f1aefa4a6b6ee5c5d1e937007252697220" + }, + "out": { + "address": "purple1vxdqnz9e9kredn4frh4x8ja37xh05jntdmjut50fxuq8y5nfwgsquu9mxh" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": null + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae0000000000000000", + "addressData": "d8af856a6a04852d19b647ad6d4336eb26e077f740aef1a0331db34d299a885a" + }, + "out": { + "address": "purple1mzhc26n2qjzj6xdkg7kk6sekavnwqalhgzh0rgpnrke562v63pdq8grp8q" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae00000000000000027b7d", + "addressData": "c7fb7bea96daab23e416c4fcf328215303005e1d0d5424257335568e5381e33c" + }, + "out": { + "address": "purple1clahh65km24j8eqkcn70x2pp2vpsqhsap42zgftnx4tgu5upuv7q9ywjws" + } + }, + { + "in": { + "checksum": "1da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b", + "creator": "purple1nxvenxve42424242hwamhwamenxvenxvmhwamhwaamhwamhwlllsatsy6m", + "creatorData": "9999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff", + "salt": "aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae", + "msg": "{\"some\":123,\"structure\":{\"nested\":[\"ok\",true]}}" + }, + "intermediate": { + "key": "7761736d0000000000000000201da6c16de2cbaf7ad8cbb66f0925ba33f5c278cb2491762d04658c1480ea229b00000000000000209999999999aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeeeffff0000000000000040aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbccddeeffffeeddbbccddaa66551155aaaabbcc787878789900aabbbbcc221100acadae000000000000002f7b22736f6d65223a3132332c22737472756374757265223a7b226e6573746564223a5b226f6b222c747275655d7d7d", + "addressData": "ccdf9dea141a6c2475870529ab38fae9dec30df28e005894fe6578b66133ab4a" + }, + "out": { + "address": "purple1en0em6s5rfkzgav8q556kw86a80vxr0j3cq93987v4utvcfn4d9q0tql4w" + } + } +] +` diff --git a/x/wasm/keeper/ante.go b/x/wasm/keeper/ante.go new file mode 100644 index 00000000..e291233e --- /dev/null +++ b/x/wasm/keeper/ante.go @@ -0,0 +1,96 @@ +package keeper + +import ( + "encoding/binary" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// CountTXDecorator ante handler to count the tx position in a block. +type CountTXDecorator struct { + storeKey sdk.StoreKey +} + +// NewCountTXDecorator constructor +func NewCountTXDecorator(storeKey sdk.StoreKey) *CountTXDecorator { + return &CountTXDecorator{storeKey: storeKey} +} + +// AnteHandle handler stores a tx counter with current height encoded in the store to let the app handle +// global rollback behavior instead of keeping state in the handler itself. +// The ante handler passes the counter value via sdk.Context upstream. See `types.TXCounter(ctx)` to read the value. +// Simulations don't get a tx counter value assigned. +func (a CountTXDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + if simulate { + return next(ctx, tx, simulate) + } + store := ctx.KVStore(a.storeKey) + currentHeight := ctx.BlockHeight() + + var txCounter uint32 // start with 0 + // load counter when exists + if bz := store.Get(types.TXCounterPrefix); bz != nil { + lastHeight, val := decodeHeightCounter(bz) + if currentHeight == lastHeight { + // then use stored counter + txCounter = val + } // else use `0` from above to start with + } + // store next counter value for current height + store.Set(types.TXCounterPrefix, encodeHeightCounter(currentHeight, txCounter+1)) + + return next(types.WithTXCounter(ctx, txCounter), tx, simulate) +} + +func encodeHeightCounter(height int64, counter uint32) []byte { + b := make([]byte, 4) + binary.BigEndian.PutUint32(b, counter) + return append(sdk.Uint64ToBigEndian(uint64(height)), b...) +} + +func decodeHeightCounter(bz []byte) (int64, uint32) { + return int64(sdk.BigEndianToUint64(bz[0:8])), binary.BigEndian.Uint32(bz[8:]) +} + +// LimitSimulationGasDecorator ante decorator to limit gas in simulation calls +type LimitSimulationGasDecorator struct { + gasLimit *sdk.Gas +} + +// NewLimitSimulationGasDecorator constructor accepts nil value to fallback to block gas limit. +func NewLimitSimulationGasDecorator(gasLimit *sdk.Gas) *LimitSimulationGasDecorator { + if gasLimit != nil && *gasLimit == 0 { + panic("gas limit must not be zero") + } + return &LimitSimulationGasDecorator{gasLimit: gasLimit} +} + +// AnteHandle that limits the maximum gas available in simulations only. +// A custom max value can be configured and will be applied when set. The value should not +// exceed the max block gas limit. +// Different values on nodes are not consensus breaking as they affect only +// simulations but may have effect on client user experience. +// +// When no custom value is set then the max block gas is used as default limit. +func (d LimitSimulationGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + if !simulate { + // Wasm code is not executed in checkTX so that we don't need to limit it further. + // Tendermint rejects the TX afterwards when the tx.gas > max block gas. + // On deliverTX we rely on the tendermint/sdk mechanics that ensure + // tx has gas set and gas < max block gas + return next(ctx, tx, simulate) + } + + // apply custom node gas limit + if d.gasLimit != nil { + return next(ctx.WithGasMeter(sdk.NewGasMeter(*d.gasLimit)), tx, simulate) + } + + // default to max block gas when set, to be on the safe side + if maxGas := ctx.ConsensusParams().GetBlock().MaxGas; maxGas > 0 { + return next(ctx.WithGasMeter(sdk.NewGasMeter(sdk.Gas(maxGas))), tx, simulate) + } + return next(ctx, tx, simulate) +} diff --git a/x/wasm/keeper/ante_test.go b/x/wasm/keeper/ante_test.go new file mode 100644 index 00000000..5c3d7701 --- /dev/null +++ b/x/wasm/keeper/ante_test.go @@ -0,0 +1,189 @@ +package keeper_test + +import ( + "testing" + "time" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/keeper" + + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestCountTxDecorator(t *testing.T) { + keyWasm := sdk.NewKVStoreKey(types.StoreKey) + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyWasm, sdk.StoreTypeIAVL, db) + require.NoError(t, ms.LoadLatestVersion()) + const myCurrentBlockHeight = 100 + + specs := map[string]struct { + setupDB func(t *testing.T, ctx sdk.Context) + simulate bool + nextAssertAnte func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) + expErr bool + }{ + "no initial counter set": { + setupDB: func(t *testing.T, ctx sdk.Context) {}, + nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + gotCounter, ok := types.TXCounter(ctx) + require.True(t, ok) + assert.Equal(t, uint32(0), gotCounter) + // and stored +1 + bz := ctx.MultiStore().GetKVStore(keyWasm).Get(types.TXCounterPrefix) + assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 0, 0, 0, 1}, bz) + return ctx, nil + }, + }, + "persistent counter incremented - big endian": { + setupDB: func(t *testing.T, ctx sdk.Context) { + bz := []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 1, 0, 0, 2} + ctx.MultiStore().GetKVStore(keyWasm).Set(types.TXCounterPrefix, bz) + }, + nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + gotCounter, ok := types.TXCounter(ctx) + require.True(t, ok) + assert.Equal(t, uint32(1<<24+2), gotCounter) + // and stored +1 + bz := ctx.MultiStore().GetKVStore(keyWasm).Get(types.TXCounterPrefix) + assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 1, 0, 0, 3}, bz) + return ctx, nil + }, + }, + "old height counter replaced": { + setupDB: func(t *testing.T, ctx sdk.Context) { + previousHeight := byte(myCurrentBlockHeight - 1) + bz := []byte{0, 0, 0, 0, 0, 0, 0, previousHeight, 0, 0, 0, 1} + ctx.MultiStore().GetKVStore(keyWasm).Set(types.TXCounterPrefix, bz) + }, + nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + gotCounter, ok := types.TXCounter(ctx) + require.True(t, ok) + assert.Equal(t, uint32(0), gotCounter) + // and stored +1 + bz := ctx.MultiStore().GetKVStore(keyWasm).Get(types.TXCounterPrefix) + assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, myCurrentBlockHeight, 0, 0, 0, 1}, bz) + return ctx, nil + }, + }, + "simulation not persisted": { + setupDB: func(t *testing.T, ctx sdk.Context) { + }, + simulate: true, + nextAssertAnte: func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + _, ok := types.TXCounter(ctx) + assert.False(t, ok) + require.True(t, simulate) + // and not stored + assert.False(t, ctx.MultiStore().GetKVStore(keyWasm).Has(types.TXCounterPrefix)) + return ctx, nil + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx := sdk.NewContext(ms.CacheMultiStore(), tmproto.Header{ + Height: myCurrentBlockHeight, + Time: time.Date(2021, time.September, 27, 12, 0, 0, 0, time.UTC), + }, false, log.NewNopLogger()) + + spec.setupDB(t, ctx) + var anyTx sdk.Tx + + // when + ante := keeper.NewCountTXDecorator(keyWasm) + _, gotErr := ante.AnteHandle(ctx, anyTx, spec.simulate, spec.nextAssertAnte) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestLimitSimulationGasDecorator(t *testing.T) { + var ( + hundred sdk.Gas = 100 + zero sdk.Gas = 0 + ) + specs := map[string]struct { + customLimit *sdk.Gas + consumeGas sdk.Gas + maxBlockGas int64 + simulation bool + expErr interface{} + }{ + "custom limit set": { + customLimit: &hundred, + consumeGas: hundred + 1, + maxBlockGas: -1, + simulation: true, + expErr: sdk.ErrorOutOfGas{Descriptor: "testing"}, + }, + "block limit set": { + maxBlockGas: 100, + consumeGas: hundred + 1, + simulation: true, + expErr: sdk.ErrorOutOfGas{Descriptor: "testing"}, + }, + "no limits set": { + maxBlockGas: -1, + consumeGas: hundred + 1, + simulation: true, + }, + "both limits set, custom applies": { + customLimit: &hundred, + consumeGas: hundred - 1, + maxBlockGas: 10, + simulation: true, + }, + "not a simulation": { + customLimit: &hundred, + consumeGas: hundred + 1, + simulation: false, + }, + "zero custom limit": { + customLimit: &zero, + simulation: true, + expErr: "gas limit must not be zero", + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + nextAnte := consumeGasAnteHandler(spec.consumeGas) + ctx := sdk.Context{}. + WithGasMeter(sdk.NewInfiniteGasMeter()). + WithConsensusParams(&abci.ConsensusParams{ + Block: &abci.BlockParams{MaxGas: spec.maxBlockGas}, + }) + // when + if spec.expErr != nil { + require.PanicsWithValue(t, spec.expErr, func() { + ante := keeper.NewLimitSimulationGasDecorator(spec.customLimit) + ante.AnteHandle(ctx, nil, spec.simulation, nextAnte) + }) + return + } + ante := keeper.NewLimitSimulationGasDecorator(spec.customLimit) + ante.AnteHandle(ctx, nil, spec.simulation, nextAnte) + }) + } +} + +func consumeGasAnteHandler(gasToConsume sdk.Gas) sdk.AnteHandler { + return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + ctx.GasMeter().ConsumeGas(gasToConsume, "testing") + return ctx, nil + } +} diff --git a/x/wasm/keeper/api.go b/x/wasm/keeper/api.go new file mode 100644 index 00000000..3b39b34d --- /dev/null +++ b/x/wasm/keeper/api.go @@ -0,0 +1,43 @@ +package keeper + +import ( + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // DefaultGasCostHumanAddress is how moch SDK gas we charge to convert to a human address format + DefaultGasCostHumanAddress = 5 + // DefaultGasCostCanonicalAddress is how moch SDK gas we charge to convert to a canonical address format + DefaultGasCostCanonicalAddress = 4 + + // DefaultDeserializationCostPerByte The formular should be `len(data) * deserializationCostPerByte` + DefaultDeserializationCostPerByte = 1 +) + +var ( + costHumanize = DefaultGasCostHumanAddress * DefaultGasMultiplier + costCanonical = DefaultGasCostCanonicalAddress * DefaultGasMultiplier + costJSONDeserialization = wasmvmtypes.UFraction{ + Numerator: DefaultDeserializationCostPerByte * DefaultGasMultiplier, + Denominator: 1, + } +) + +func humanAddress(canon []byte) (string, uint64, error) { + if err := sdk.VerifyAddressFormat(canon); err != nil { + return "", costHumanize, err + } + return sdk.AccAddress(canon).String(), costHumanize, nil +} + +func canonicalAddress(human string) ([]byte, uint64, error) { + bz, err := sdk.AccAddressFromBech32(human) + return bz, costCanonical, err +} + +var cosmwasmAPI = wasmvm.GoAPI{ + HumanAddress: humanAddress, + CanonicalAddress: canonicalAddress, +} diff --git a/x/wasm/keeper/authz_policy.go b/x/wasm/keeper/authz_policy.go new file mode 100644 index 00000000..0c5fb77f --- /dev/null +++ b/x/wasm/keeper/authz_policy.go @@ -0,0 +1,63 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// ChainAccessConfigs chain settings +type ChainAccessConfigs struct { + Upload types.AccessConfig + Instantiate types.AccessConfig +} + +// NewChainAccessConfigs constructor +func NewChainAccessConfigs(upload types.AccessConfig, instantiate types.AccessConfig) ChainAccessConfigs { + return ChainAccessConfigs{Upload: upload, Instantiate: instantiate} +} + +type AuthorizationPolicy interface { + CanCreateCode(chainConfigs ChainAccessConfigs, actor sdk.AccAddress, contractConfig types.AccessConfig) bool + CanInstantiateContract(c types.AccessConfig, actor sdk.AccAddress) bool + CanModifyContract(admin, actor sdk.AccAddress) bool + CanModifyCodeAccessConfig(creator, actor sdk.AccAddress, isSubset bool) bool +} + +type DefaultAuthorizationPolicy struct{} + +func (p DefaultAuthorizationPolicy) CanCreateCode(chainConfigs ChainAccessConfigs, actor sdk.AccAddress, contractConfig types.AccessConfig) bool { + return chainConfigs.Upload.Allowed(actor) && + contractConfig.IsSubset(chainConfigs.Instantiate) +} + +func (p DefaultAuthorizationPolicy) CanInstantiateContract(config types.AccessConfig, actor sdk.AccAddress) bool { + return config.Allowed(actor) +} + +func (p DefaultAuthorizationPolicy) CanModifyContract(admin, actor sdk.AccAddress) bool { + return admin != nil && admin.Equals(actor) +} + +func (p DefaultAuthorizationPolicy) CanModifyCodeAccessConfig(creator, actor sdk.AccAddress, isSubset bool) bool { + return creator != nil && creator.Equals(actor) && isSubset +} + +type GovAuthorizationPolicy struct{} + +// CanCreateCode implements AuthorizationPolicy.CanCreateCode to allow gov actions. Always returns true. +func (p GovAuthorizationPolicy) CanCreateCode(ChainAccessConfigs, sdk.AccAddress, types.AccessConfig) bool { + return true +} + +func (p GovAuthorizationPolicy) CanInstantiateContract(types.AccessConfig, sdk.AccAddress) bool { + return true +} + +func (p GovAuthorizationPolicy) CanModifyContract(sdk.AccAddress, sdk.AccAddress) bool { + return true +} + +func (p GovAuthorizationPolicy) CanModifyCodeAccessConfig(sdk.AccAddress, sdk.AccAddress, bool) bool { + return true +} diff --git a/x/wasm/keeper/authz_policy_test.go b/x/wasm/keeper/authz_policy_test.go new file mode 100644 index 00000000..d7fccbdd --- /dev/null +++ b/x/wasm/keeper/authz_policy_test.go @@ -0,0 +1,345 @@ +package keeper + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestDefaultAuthzPolicyCanCreateCode(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + specs := map[string]struct { + chainConfigs ChainAccessConfigs + contractInstConf types.AccessConfig + actor sdk.AccAddress + exp bool + panics bool + }{ + "upload nobody": { + chainConfigs: NewChainAccessConfigs(types.AllowNobody, types.AllowEverybody), + contractInstConf: types.AllowEverybody, + exp: false, + }, + "upload everybody": { + chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody), + contractInstConf: types.AllowEverybody, + exp: true, + }, + "upload only address - same": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(myActorAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + exp: true, + }, + "upload only address - different": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(otherAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + exp: false, + }, + "upload any address - included": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + exp: true, + }, + "upload any address - not included": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + exp: false, + }, + "contract config - subtype": { + chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody), + contractInstConf: types.AccessTypeAnyOfAddresses.With(myActorAddress), + exp: true, + }, + "contract config - not subtype": { + chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowNobody), + contractInstConf: types.AllowEverybody, + exp: false, + }, + "upload undefined config - panics": { + chainConfigs: NewChainAccessConfigs(types.AccessConfig{}, types.AllowEverybody), + contractInstConf: types.AllowEverybody, + panics: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := DefaultAuthorizationPolicy{} + if !spec.panics { + got := policy.CanCreateCode(spec.chainConfigs, myActorAddress, spec.contractInstConf) + assert.Equal(t, spec.exp, got) + return + } + assert.Panics(t, func() { + policy.CanCreateCode(spec.chainConfigs, myActorAddress, spec.contractInstConf) + }) + }) + } +} + +func TestDefaultAuthzPolicyCanInstantiateContract(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + specs := map[string]struct { + config types.AccessConfig + actor sdk.AccAddress + exp bool + panics bool + }{ + "nobody": { + config: types.AllowNobody, + exp: false, + }, + "everybody": { + config: types.AllowEverybody, + exp: true, + }, + "only address - same": { + config: types.AccessTypeOnlyAddress.With(myActorAddress), + exp: true, + }, + "only address - different": { + config: types.AccessTypeOnlyAddress.With(otherAddress), + exp: false, + }, + "any address - included": { + config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress), + exp: true, + }, + "any address - not included": { + config: types.AccessTypeAnyOfAddresses.With(otherAddress), + exp: false, + }, + "undefined config - panics": { + config: types.AccessConfig{}, + panics: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := DefaultAuthorizationPolicy{} + if !spec.panics { + got := policy.CanInstantiateContract(spec.config, myActorAddress) + assert.Equal(t, spec.exp, got) + return + } + assert.Panics(t, func() { + policy.CanInstantiateContract(spec.config, myActorAddress) + }) + }) + } +} + +func TestDefaultAuthzPolicyCanModifyContract(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + + specs := map[string]struct { + admin sdk.AccAddress + exp bool + }{ + "same as actor": { + admin: myActorAddress, + exp: true, + }, + "different admin": { + admin: otherAddress, + exp: false, + }, + "no admin": { + exp: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := DefaultAuthorizationPolicy{} + got := policy.CanModifyContract(spec.admin, myActorAddress) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestDefaultAuthzPolicyCanModifyCodeAccessConfig(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + + specs := map[string]struct { + admin sdk.AccAddress + subset bool + exp bool + }{ + "same as actor - subset": { + admin: myActorAddress, + subset: true, + exp: true, + }, + "same as actor - not subset": { + admin: myActorAddress, + subset: false, + exp: false, + }, + "different admin": { + admin: otherAddress, + exp: false, + }, + "no admin": { + exp: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := DefaultAuthorizationPolicy{} + got := policy.CanModifyCodeAccessConfig(spec.admin, myActorAddress, spec.subset) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestGovAuthzPolicyCanCreateCode(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + specs := map[string]struct { + chainConfigs ChainAccessConfigs + contractInstConf types.AccessConfig + actor sdk.AccAddress + }{ + "upload nobody": { + chainConfigs: NewChainAccessConfigs(types.AllowNobody, types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + "upload everybody": { + chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + "upload only address - same": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(myActorAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + "upload only address - different": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeOnlyAddress.With(otherAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + "upload any address - included": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + "upload any address - not included": { + chainConfigs: NewChainAccessConfigs(types.AccessTypeAnyOfAddresses.With(otherAddress), types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + "contract config - subtype": { + chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowEverybody), + contractInstConf: types.AccessTypeAnyOfAddresses.With(myActorAddress), + }, + "contract config - not subtype": { + chainConfigs: NewChainAccessConfigs(types.AllowEverybody, types.AllowNobody), + contractInstConf: types.AllowEverybody, + }, + "upload undefined config - not panics": { + chainConfigs: NewChainAccessConfigs(types.AccessConfig{}, types.AllowEverybody), + contractInstConf: types.AllowEverybody, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := GovAuthorizationPolicy{} + got := policy.CanCreateCode(spec.chainConfigs, myActorAddress, spec.contractInstConf) + assert.True(t, got) + }) + } +} + +func TestGovAuthzPolicyCanInstantiateContract(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + specs := map[string]struct { + config types.AccessConfig + actor sdk.AccAddress + }{ + "nobody": { + config: types.AllowNobody, + }, + "everybody": { + config: types.AllowEverybody, + }, + "only address - same": { + config: types.AccessTypeOnlyAddress.With(myActorAddress), + }, + "only address - different": { + config: types.AccessTypeOnlyAddress.With(otherAddress), + }, + "any address - included": { + config: types.AccessTypeAnyOfAddresses.With(otherAddress, myActorAddress), + }, + "any address - not included": { + config: types.AccessTypeAnyOfAddresses.With(otherAddress), + }, + "undefined config - panics": { + config: types.AccessConfig{}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := GovAuthorizationPolicy{} + got := policy.CanInstantiateContract(spec.config, myActorAddress) + assert.True(t, got) + }) + } +} + +func TestGovAuthzPolicyCanModifyContract(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + + specs := map[string]struct { + admin sdk.AccAddress + }{ + "same as actor": { + admin: myActorAddress, + }, + "different admin": { + admin: otherAddress, + }, + "no admin": {}, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := GovAuthorizationPolicy{} + got := policy.CanModifyContract(spec.admin, myActorAddress) + assert.True(t, got) + }) + } +} + +func TestGovAuthzPolicyCanModifyCodeAccessConfig(t *testing.T) { + myActorAddress := RandomAccountAddress(t) + otherAddress := RandomAccountAddress(t) + + specs := map[string]struct { + admin sdk.AccAddress + subset bool + }{ + "same as actor - subset": { + admin: myActorAddress, + subset: true, + }, + "same as actor - not subset": { + admin: myActorAddress, + subset: false, + }, + "different admin": { + admin: otherAddress, + }, + "no admin": {}, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + policy := GovAuthorizationPolicy{} + got := policy.CanModifyCodeAccessConfig(spec.admin, myActorAddress, spec.subset) + assert.True(t, got) + }) + } +} diff --git a/x/wasm/keeper/bench_test.go b/x/wasm/keeper/bench_test.go new file mode 100644 index 00000000..3e850e61 --- /dev/null +++ b/x/wasm/keeper/bench_test.go @@ -0,0 +1,102 @@ +package keeper + +import ( + "os" + "testing" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/stretchr/testify/require" + dbm "github.com/tendermint/tm-db" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// BenchmarkVerification benchmarks secp256k1 verification which is 1000 gas based on cpu time. +// +// Just this function is copied from +// https://github.com/cosmos/cosmos-sdk/blob/90e9370bd80d9a3d41f7203ddb71166865561569/crypto/keys/internal/benchmarking/bench.go#L48-L62 +// And thus under the GO license (BSD style) +func BenchmarkGasNormalization(b *testing.B) { + priv := secp256k1.GenPrivKey() + pub := priv.PubKey() + + // use a short message, so this time doesn't get dominated by hashing. + message := []byte("Hello, world!") + signature, err := priv.Sign(message) + if err != nil { + b.Fatal(err) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + pub.VerifySignature(message, signature) + } +} + +// By comparing the timing for queries on pinned vs unpinned, the difference gives us the overhead of +// instantiating an unpinned contract. That value can be used to determine a reasonable gas price +// for the InstantiationCost +func BenchmarkInstantiationOverhead(b *testing.B) { + specs := map[string]struct { + pinned bool + db func() dbm.DB + }{ + "unpinned, memory db": { + db: func() dbm.DB { return dbm.NewMemDB() }, + }, + "pinned, memory db": { + db: func() dbm.DB { return dbm.NewMemDB() }, + pinned: true, + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + wasmConfig := types.WasmConfig{MemoryCacheSize: 0} + ctx, keepers := createTestInput(b, false, AvailableCapabilities, wasmConfig, spec.db()) + example := InstantiateHackatomExampleContract(b, ctx, keepers) + if spec.pinned { + require.NoError(b, keepers.ContractKeeper.PinCode(ctx, example.CodeID)) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := keepers.WasmKeeper.QuerySmart(ctx, example.Contract, []byte(`{"verifier":{}}`)) + require.NoError(b, err) + } + }) + } +} + +// Calculate the time it takes to compile some wasm code the first time. +// This will help us adjust pricing for UploadCode +func BenchmarkCompilation(b *testing.B) { + specs := map[string]struct { + wasmFile string + }{ + "hackatom": { + wasmFile: "./testdata/hackatom.wasm", + }, + "burner": { + wasmFile: "./testdata/burner.wasm", + }, + "ibc_reflect": { + wasmFile: "./testdata/ibc_reflect.wasm", + }, + } + + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + wasmConfig := types.WasmConfig{MemoryCacheSize: 0} + db := dbm.NewMemDB() + ctx, keepers := createTestInput(b, false, AvailableCapabilities, wasmConfig, db) + + // print out code size for comparisons + code, err := os.ReadFile(spec.wasmFile) + require.NoError(b, err) + b.Logf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b(size: %d) ", len(code)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = StoreExampleContract(b, ctx, keepers, spec.wasmFile) + } + }) + } +} diff --git a/x/wasm/keeper/contract_keeper.go b/x/wasm/keeper/contract_keeper.go new file mode 100644 index 00000000..efd0038d --- /dev/null +++ b/x/wasm/keeper/contract_keeper.go @@ -0,0 +1,130 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var _ types.ContractOpsKeeper = PermissionedKeeper{} + +// decoratedKeeper contains a subset of the wasm keeper that are already or can be guarded by an authorization policy in the future +type decoratedKeeper interface { + create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig, authZ AuthorizationPolicy) (codeID uint64, checksum []byte, err error) + + instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + addressGenerator AddressGenerator, + authZ AuthorizationPolicy, + ) (sdk.AccAddress, []byte, error) + + migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) ([]byte, error) + setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error + pinCode(ctx sdk.Context, codeID uint64) error + unpinCode(ctx sdk.Context, codeID uint64) error + execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) + Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) + setContractInfoExtension(ctx sdk.Context, contract sdk.AccAddress, extra types.ContractInfoExtension) error + setAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig, autz AuthorizationPolicy) error + ClassicAddressGenerator() AddressGenerator +} + +type PermissionedKeeper struct { + authZPolicy AuthorizationPolicy + nested decoratedKeeper +} + +func NewPermissionedKeeper(nested decoratedKeeper, authZPolicy AuthorizationPolicy) *PermissionedKeeper { + return &PermissionedKeeper{authZPolicy: authZPolicy, nested: nested} +} + +func NewGovPermissionKeeper(nested decoratedKeeper) *PermissionedKeeper { + return NewPermissionedKeeper(nested, GovAuthorizationPolicy{}) +} + +func NewDefaultPermissionKeeper(nested decoratedKeeper) *PermissionedKeeper { + return NewPermissionedKeeper(nested, DefaultAuthorizationPolicy{}) +} + +func (p PermissionedKeeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig) (codeID uint64, checksum []byte, err error) { + return p.nested.create(ctx, creator, wasmCode, instantiateAccess, p.authZPolicy) +} + +// Instantiate creates an instance of a WASM contract using the classic sequence based address generator +func (p PermissionedKeeper) Instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, +) (sdk.AccAddress, []byte, error) { + return p.nested.instantiate(ctx, codeID, creator, admin, initMsg, label, deposit, p.nested.ClassicAddressGenerator(), p.authZPolicy) +} + +// Instantiate2 creates an instance of a WASM contract using the predictable address generator +func (p PermissionedKeeper) Instantiate2( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + salt []byte, + fixMsg bool, +) (sdk.AccAddress, []byte, error) { + return p.nested.instantiate( + ctx, + codeID, + creator, + admin, + initMsg, + label, + deposit, + PredicableAddressGenerator(creator, salt, initMsg, fixMsg), + p.authZPolicy, + ) +} + +func (p PermissionedKeeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) { + return p.nested.execute(ctx, contractAddress, caller, msg, coins) +} + +func (p PermissionedKeeper) Migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte) ([]byte, error) { + return p.nested.migrate(ctx, contractAddress, caller, newCodeID, msg, p.authZPolicy) +} + +func (p PermissionedKeeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) { + return p.nested.Sudo(ctx, contractAddress, msg) +} + +func (p PermissionedKeeper) UpdateContractAdmin(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newAdmin sdk.AccAddress) error { + return p.nested.setContractAdmin(ctx, contractAddress, caller, newAdmin, p.authZPolicy) +} + +func (p PermissionedKeeper) ClearContractAdmin(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress) error { + return p.nested.setContractAdmin(ctx, contractAddress, caller, nil, p.authZPolicy) +} + +func (p PermissionedKeeper) PinCode(ctx sdk.Context, codeID uint64) error { + return p.nested.pinCode(ctx, codeID) +} + +func (p PermissionedKeeper) UnpinCode(ctx sdk.Context, codeID uint64) error { + return p.nested.unpinCode(ctx, codeID) +} + +// SetContractInfoExtension updates the extra attributes that can be stored with the contract info +func (p PermissionedKeeper) SetContractInfoExtension(ctx sdk.Context, contract sdk.AccAddress, extra types.ContractInfoExtension) error { + return p.nested.setContractInfoExtension(ctx, contract, extra) +} + +// SetAccessConfig updates the access config of a code id. +func (p PermissionedKeeper) SetAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig) error { + return p.nested.setAccessConfig(ctx, codeID, caller, newConfig, p.authZPolicy) +} diff --git a/x/wasm/keeper/contract_keeper_test.go b/x/wasm/keeper/contract_keeper_test.go new file mode 100644 index 00000000..a146a346 --- /dev/null +++ b/x/wasm/keeper/contract_keeper_test.go @@ -0,0 +1,168 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "math" + "strings" + "testing" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestInstantiate2(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example := StoreHackatomExampleContract(t, parentCtx, keepers) + otherExample := StoreReflectContract(t, parentCtx, keepers) + mock := &wasmtesting.MockWasmer{} + wasmtesting.MakeInstantiable(mock) + keepers.WasmKeeper.wasmVM = mock // set mock to not fail on contract init message + + verifierAddr := RandomAccountAddress(t) + beneficiaryAddr := RandomAccountAddress(t) + initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: verifierAddr, Beneficiary: beneficiaryAddr}) + + otherAddr := keepers.Faucet.NewFundedRandomAccount(parentCtx, sdk.NewInt64Coin("denom", 1_000_000_000)) + + const ( + mySalt = "my salt" + myLabel = "my label" + ) + // create instances for duplicate checks + exampleContract := func(t *testing.T, ctx sdk.Context, fixMsg bool) { + _, _, err := keepers.ContractKeeper.Instantiate2( + ctx, + example.CodeID, + example.CreatorAddr, + nil, + initMsg, + myLabel, + sdk.NewCoins(sdk.NewInt64Coin("denom", 1)), + []byte(mySalt), + fixMsg, + ) + require.NoError(t, err) + } + exampleWithFixMsg := func(t *testing.T, ctx sdk.Context) { + exampleContract(t, ctx, true) + } + exampleWithoutFixMsg := func(t *testing.T, ctx sdk.Context) { + exampleContract(t, ctx, false) + } + specs := map[string]struct { + setup func(t *testing.T, ctx sdk.Context) + codeID uint64 + sender sdk.AccAddress + salt []byte + initMsg json.RawMessage + fixMsg bool + expErr error + }{ + "fix msg - generates different address than without fixMsg": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: initMsg, + fixMsg: true, + }, + "fix msg - different sender": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: otherAddr, + salt: []byte(mySalt), + initMsg: initMsg, + fixMsg: true, + }, + "fix msg - different code": { + setup: exampleWithFixMsg, + codeID: otherExample.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: []byte(`{}`), + fixMsg: true, + }, + "fix msg - different salt": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte("other salt"), + initMsg: initMsg, + fixMsg: true, + }, + "fix msg - different init msg": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}), + fixMsg: true, + }, + "different sender": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: otherAddr, + salt: []byte(mySalt), + initMsg: initMsg, + }, + "different code": { + setup: exampleWithoutFixMsg, + codeID: otherExample.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: []byte(`{}`), + }, + "different salt": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(`other salt`), + initMsg: initMsg, + }, + "different init msg - reject same address": { + setup: exampleWithoutFixMsg, + codeID: example.CodeID, + sender: example.CreatorAddr, + salt: []byte(mySalt), + initMsg: mustMarshal(t, HackatomExampleInitMsg{Verifier: otherAddr, Beneficiary: beneficiaryAddr}), + expErr: types.ErrDuplicate, + }, + "fix msg - long msg": { + setup: exampleWithFixMsg, + codeID: example.CodeID, + sender: otherAddr, + salt: []byte(mySalt), + initMsg: []byte(fmt.Sprintf(`{"foo":%q}`, strings.Repeat("b", math.MaxInt16+1))), // too long kills CI + fixMsg: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + spec.setup(t, ctx) + gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2( + ctx, + spec.codeID, + spec.sender, + nil, + spec.initMsg, + myLabel, + sdk.NewCoins(sdk.NewInt64Coin("denom", 2)), + spec.salt, + spec.fixMsg, + ) + if spec.expErr != nil { + assert.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.NotEmpty(t, gotAddr) + }) + } +} diff --git a/x/wasm/keeper/events.go b/x/wasm/keeper/events.go new file mode 100644 index 00000000..25cf14f9 --- /dev/null +++ b/x/wasm/keeper/events.go @@ -0,0 +1,67 @@ +package keeper + +import ( + "fmt" + "strings" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// newWasmModuleEvent creates with wasm module event for interacting with the given contract. Adds custom attributes +// to this event. +func newWasmModuleEvent(customAttributes []wasmvmtypes.EventAttribute, contractAddr sdk.AccAddress) (sdk.Events, error) { + attrs, err := contractSDKEventAttributes(customAttributes, contractAddr) + if err != nil { + return nil, err + } + + // each wasm invocation always returns one sdk.Event + return sdk.Events{sdk.NewEvent(types.WasmModuleEventType, attrs...)}, nil +} + +const eventTypeMinLength = 2 + +// newCustomEvents converts wasmvm events from a contract response to sdk type events +func newCustomEvents(evts wasmvmtypes.Events, contractAddr sdk.AccAddress) (sdk.Events, error) { + events := make(sdk.Events, 0, len(evts)) + for _, e := range evts { + typ := strings.TrimSpace(e.Type) + if len(typ) <= eventTypeMinLength { + return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Event type too short: '%s'", typ)) + } + attributes, err := contractSDKEventAttributes(e.Attributes, contractAddr) + if err != nil { + return nil, err + } + events = append(events, sdk.NewEvent(fmt.Sprintf("%s%s", types.CustomContractEventPrefix, typ), attributes...)) + } + return events, nil +} + +// convert and add contract address issuing this event +func contractSDKEventAttributes(customAttributes []wasmvmtypes.EventAttribute, contractAddr sdk.AccAddress) ([]sdk.Attribute, error) { + attrs := []sdk.Attribute{sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String())} + // append attributes from wasm to the sdk.Event + for _, l := range customAttributes { + // ensure key and value are non-empty (and trim what is there) + key := strings.TrimSpace(l.Key) + if len(key) == 0 { + return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Empty attribute key. Value: %s", l.Value)) + } + value := strings.TrimSpace(l.Value) + // TODO: check if this is legal in the SDK - if it is, we can remove this check + if len(value) == 0 { + return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Empty attribute value. Key: %s", key)) + } + // and reserve all _* keys for our use (not contract) + if strings.HasPrefix(key, types.AttributeReservedPrefix) { + return nil, sdkerrors.Wrap(types.ErrInvalidEvent, fmt.Sprintf("Attribute key starts with reserved prefix %s: '%s'", types.AttributeReservedPrefix, key)) + } + attrs = append(attrs, sdk.NewAttribute(key, value)) + } + return attrs, nil +} diff --git a/x/wasm/keeper/events_test.go b/x/wasm/keeper/events_test.go new file mode 100644 index 00000000..0e6de87b --- /dev/null +++ b/x/wasm/keeper/events_test.go @@ -0,0 +1,290 @@ +package keeper + +import ( + "context" + "testing" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestHasWasmModuleEvent(t *testing.T) { + myContractAddr := RandomAccountAddress(t) + specs := map[string]struct { + srcEvents []sdk.Event + exp bool + }{ + "event found": { + srcEvents: []sdk.Event{ + sdk.NewEvent(types.WasmModuleEventType, sdk.NewAttribute("_contract_address", myContractAddr.String())), + }, + exp: true, + }, + "different event: not found": { + srcEvents: []sdk.Event{ + sdk.NewEvent(types.CustomContractEventPrefix, sdk.NewAttribute("_contract_address", myContractAddr.String())), + }, + exp: false, + }, + "event with different address: not found": { + srcEvents: []sdk.Event{ + sdk.NewEvent(types.WasmModuleEventType, sdk.NewAttribute("_contract_address", RandomBech32AccountAddress(t))), + }, + exp: false, + }, + "no event": { + srcEvents: []sdk.Event{}, + exp: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + em := sdk.NewEventManager() + em.EmitEvents(spec.srcEvents) + ctx := sdk.Context{}.WithContext(context.Background()).WithEventManager(em) + + got := hasWasmModuleEvent(ctx, myContractAddr) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestNewCustomEvents(t *testing.T) { + myContract := RandomAccountAddress(t) + specs := map[string]struct { + src wasmvmtypes.Events + exp sdk.Events + isError bool + }{ + "all good": { + src: wasmvmtypes.Events{{ + Type: "foo", + Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, + }}, + exp: sdk.Events{sdk.NewEvent("wasm-foo", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("myKey", "myVal"))}, + }, + "multiple attributes": { + src: wasmvmtypes.Events{{ + Type: "foo", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "myKey", Value: "myVal"}, + {Key: "myOtherKey", Value: "myOtherVal"}, + }, + }}, + exp: sdk.Events{sdk.NewEvent("wasm-foo", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("myKey", "myVal"), + sdk.NewAttribute("myOtherKey", "myOtherVal"))}, + }, + "multiple events": { + src: wasmvmtypes.Events{{ + Type: "foo", + Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, + }, { + Type: "bar", + Attributes: []wasmvmtypes.EventAttribute{{Key: "otherKey", Value: "otherVal"}}, + }}, + exp: sdk.Events{ + sdk.NewEvent("wasm-foo", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("myKey", "myVal")), + sdk.NewEvent("wasm-bar", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("otherKey", "otherVal")), + }, + }, + "without attributes": { + src: wasmvmtypes.Events{{ + Type: "foo", + }}, + exp: sdk.Events{sdk.NewEvent("wasm-foo", + sdk.NewAttribute("_contract_address", myContract.String()))}, + }, + "error on short event type": { + src: wasmvmtypes.Events{{ + Type: "f", + }}, + isError: true, + }, + "error on _contract_address": { + src: wasmvmtypes.Events{{ + Type: "foo", + Attributes: []wasmvmtypes.EventAttribute{{Key: "_contract_address", Value: RandomBech32AccountAddress(t)}}, + }}, + isError: true, + }, + "error on reserved prefix": { + src: wasmvmtypes.Events{{ + Type: "wasm", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "_reserved", Value: "is skipped"}, + {Key: "normal", Value: "is used"}, + }, + }}, + isError: true, + }, + "error on empty value": { + src: wasmvmtypes.Events{{ + Type: "boom", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "some", Value: "data"}, + {Key: "key", Value: ""}, + }, + }}, + isError: true, + }, + "error on empty key": { + src: wasmvmtypes.Events{{ + Type: "boom", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "some", Value: "data"}, + {Key: "", Value: "value"}, + }, + }}, + isError: true, + }, + "error on whitespace type": { + src: wasmvmtypes.Events{{ + Type: " f ", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "some", Value: "data"}, + }, + }}, + isError: true, + }, + "error on only whitespace key": { + src: wasmvmtypes.Events{{ + Type: "boom", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "some", Value: "data"}, + {Key: "\n\n\n\n", Value: "value"}, + }, + }}, + isError: true, + }, + "error on only whitespace value": { + src: wasmvmtypes.Events{{ + Type: "boom", + Attributes: []wasmvmtypes.EventAttribute{ + {Key: "some", Value: "data"}, + {Key: "myKey", Value: " \t\r\n"}, + }, + }}, + isError: true, + }, + "strip out whitespace": { + src: wasmvmtypes.Events{{ + Type: " food\n", + Attributes: []wasmvmtypes.EventAttribute{{Key: "my Key", Value: "\tmyVal"}}, + }}, + exp: sdk.Events{sdk.NewEvent("wasm-food", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("my Key", "myVal"))}, + }, + "empty event elements": { + src: make(wasmvmtypes.Events, 10), + isError: true, + }, + "nil": { + exp: sdk.Events{}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotEvent, err := newCustomEvents(spec.src, myContract) + if spec.isError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, spec.exp, gotEvent) + } + }) + } +} + +func TestNewWasmModuleEvent(t *testing.T) { + myContract := RandomAccountAddress(t) + specs := map[string]struct { + src []wasmvmtypes.EventAttribute + exp sdk.Events + isError bool + }{ + "all good": { + src: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myVal"}}, + exp: sdk.Events{sdk.NewEvent("wasm", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("myKey", "myVal"))}, + }, + "multiple attributes": { + src: []wasmvmtypes.EventAttribute{ + {Key: "myKey", Value: "myVal"}, + {Key: "myOtherKey", Value: "myOtherVal"}, + }, + exp: sdk.Events{sdk.NewEvent("wasm", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("myKey", "myVal"), + sdk.NewAttribute("myOtherKey", "myOtherVal"))}, + }, + "without attributes": { + exp: sdk.Events{sdk.NewEvent("wasm", + sdk.NewAttribute("_contract_address", myContract.String()))}, + }, + "error on _contract_address": { + src: []wasmvmtypes.EventAttribute{{Key: "_contract_address", Value: RandomBech32AccountAddress(t)}}, + isError: true, + }, + "error on whitespace key": { + src: []wasmvmtypes.EventAttribute{{Key: " ", Value: "value"}}, + isError: true, + }, + "error on whitespace value": { + src: []wasmvmtypes.EventAttribute{{Key: "key", Value: "\n\n\n"}}, + isError: true, + }, + "strip whitespace": { + src: []wasmvmtypes.EventAttribute{{Key: " my-real-key ", Value: "\n\n\nsome-val\t\t\t"}}, + exp: sdk.Events{sdk.NewEvent("wasm", + sdk.NewAttribute("_contract_address", myContract.String()), + sdk.NewAttribute("my-real-key", "some-val"))}, + }, + "empty elements": { + src: make([]wasmvmtypes.EventAttribute, 10), + isError: true, + }, + "nil": { + exp: sdk.Events{sdk.NewEvent("wasm", + sdk.NewAttribute("_contract_address", myContract.String()), + )}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotEvent, err := newWasmModuleEvent(spec.src, myContract) + if spec.isError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + assert.Equal(t, spec.exp, gotEvent) + } + }) + } +} + +// returns true when a wasm module event was emitted for this contract already +func hasWasmModuleEvent(ctx sdk.Context, contractAddr sdk.AccAddress) bool { + for _, e := range ctx.EventManager().Events() { + if e.Type == types.WasmModuleEventType { + for _, a := range e.Attributes { + if string(a.Key) == types.AttributeKeyContractAddr && string(a.Value) == contractAddr.String() { + return true + } + } + } + } + return false +} diff --git a/x/wasm/keeper/gas_register.go b/x/wasm/keeper/gas_register.go new file mode 100644 index 00000000..8ebbd180 --- /dev/null +++ b/x/wasm/keeper/gas_register.go @@ -0,0 +1,252 @@ +package keeper + +import ( + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +const ( + // DefaultGasMultiplier is how many CosmWasm gas points = 1 Cosmos SDK gas point. + // + // CosmWasm gas strategy is documented in https://github.com/CosmWasm/cosmwasm/blob/v1.0.0-beta/docs/GAS.md. + // Cosmos SDK reference costs can be found here: https://github.com/cosmos/cosmos-sdk/blob/v0.42.10/store/types/gas.go#L198-L209. + // + // The original multiplier of 100 up to CosmWasm 0.16 was based on + // "A write at ~3000 gas and ~200us = 10 gas per us (microsecond) cpu/io + // Rough timing have 88k gas at 90us, which is equal to 1k sdk gas... (one read)" + // as well as manual Wasmer benchmarks from 2019. This was then multiplied by 150_000 + // in the 0.16 -> 1.0 upgrade (https://github.com/CosmWasm/cosmwasm/pull/1120). + // + // The multiplier deserves more reproducible benchmarking and a strategy that allows easy adjustments. + // This is tracked in https://github.com/CosmWasm/wasmd/issues/566 and https://github.com/CosmWasm/wasmd/issues/631. + // Gas adjustments are consensus breaking but may happen in any release marked as consensus breaking. + // Do not make assumptions on how much gas an operation will consume in places that are hard to adjust, + // such as hardcoding them in contracts. + // + // Please note that all gas prices returned to wasmvm should have this multiplied. + // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938055852 + DefaultGasMultiplier uint64 = 140_000_000 + // DefaultInstanceCost is how much SDK gas we charge each time we load a WASM instance. + // Creating a new instance is costly, and this helps put a recursion limit to contracts calling contracts. + // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803 + DefaultInstanceCost uint64 = 60_000 + // DefaultCompileCost is how much SDK gas is charged *per byte* for compiling WASM code. + // Benchmarks and numbers were discussed in: https://github.com/CosmWasm/wasmd/pull/634#issuecomment-938056803 + DefaultCompileCost uint64 = 3 + // DefaultEventAttributeDataCost is how much SDK gas is charged *per byte* for attribute data in events. + // This is used with len(key) + len(value) + DefaultEventAttributeDataCost uint64 = 1 + // DefaultContractMessageDataCost is how much SDK gas is charged *per byte* of the message that goes to the contract + // This is used with len(msg). Note that the message is deserialized in the receiving contract and this is charged + // with wasm gas already. The derserialization of results is also charged in wasmvm. I am unsure if we need to add + // additional costs here. + // Note: also used for error fields on reply, and data on reply. Maybe these should be pulled out to a different (non-zero) field + DefaultContractMessageDataCost uint64 = 0 + // DefaultPerAttributeCost is how much SDK gas we charge per attribute count. + DefaultPerAttributeCost uint64 = 10 + // DefaultPerCustomEventCost is how much SDK gas we charge per event count. + DefaultPerCustomEventCost uint64 = 20 + // DefaultEventAttributeDataFreeTier number of bytes of total attribute data we do not charge. + DefaultEventAttributeDataFreeTier = 100 +) + +// default: 0.15 gas. +// see https://github.com/CosmWasm/wasmd/pull/898#discussion_r937727200 +var defaultPerByteUncompressCost = wasmvmtypes.UFraction{ + Numerator: 15, + Denominator: 100, +} + +// DefaultPerByteUncompressCost is how much SDK gas we charge per source byte to unpack +func DefaultPerByteUncompressCost() wasmvmtypes.UFraction { + return defaultPerByteUncompressCost +} + +// GasRegister abstract source for gas costs +type GasRegister interface { + // NewContractInstanceCosts costs to crate a new contract instance from code + NewContractInstanceCosts(pinned bool, msgLen int) sdk.Gas + // CompileCosts costs to persist and "compile" a new wasm contract + CompileCosts(byteLength int) sdk.Gas + // UncompressCosts costs to unpack a new wasm contract + UncompressCosts(byteLength int) sdk.Gas + // InstantiateContractCosts costs when interacting with a wasm contract + InstantiateContractCosts(pinned bool, msgLen int) sdk.Gas + // ReplyCosts costs to to handle a message reply + ReplyCosts(pinned bool, reply wasmvmtypes.Reply) sdk.Gas + // EventCosts costs to persist an event + EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) sdk.Gas + // ToWasmVMGas converts from sdk gas to wasmvm gas + ToWasmVMGas(source sdk.Gas) uint64 + // FromWasmVMGas converts from wasmvm gas to sdk gas + FromWasmVMGas(source uint64) sdk.Gas +} + +// WasmGasRegisterConfig config type +type WasmGasRegisterConfig struct { + // InstanceCost costs when interacting with a wasm contract + InstanceCost sdk.Gas + // CompileCosts costs to persist and "compile" a new wasm contract + CompileCost sdk.Gas + // UncompressCost costs per byte to unpack a contract + UncompressCost wasmvmtypes.UFraction + // GasMultiplier is how many cosmwasm gas points = 1 sdk gas point + // SDK reference costs can be found here: https://github.com/cosmos/cosmos-sdk/blob/02c6c9fafd58da88550ab4d7d494724a477c8a68/store/types/gas.go#L153-L164 + GasMultiplier sdk.Gas + // EventPerAttributeCost is how much SDK gas is charged *per byte* for attribute data in events. + // This is used with len(key) + len(value) + EventPerAttributeCost sdk.Gas + // EventAttributeDataCost is how much SDK gas is charged *per byte* for attribute data in events. + // This is used with len(key) + len(value) + EventAttributeDataCost sdk.Gas + // EventAttributeDataFreeTier number of bytes of total attribute data that is free of charge + EventAttributeDataFreeTier uint64 + // ContractMessageDataCost SDK gas charged *per byte* of the message that goes to the contract + // This is used with len(msg) + ContractMessageDataCost sdk.Gas + // CustomEventCost cost per custom event + CustomEventCost uint64 +} + +// DefaultGasRegisterConfig default values +func DefaultGasRegisterConfig() WasmGasRegisterConfig { + return WasmGasRegisterConfig{ + InstanceCost: DefaultInstanceCost, + CompileCost: DefaultCompileCost, + GasMultiplier: DefaultGasMultiplier, + EventPerAttributeCost: DefaultPerAttributeCost, + CustomEventCost: DefaultPerCustomEventCost, + EventAttributeDataCost: DefaultEventAttributeDataCost, + EventAttributeDataFreeTier: DefaultEventAttributeDataFreeTier, + ContractMessageDataCost: DefaultContractMessageDataCost, + UncompressCost: DefaultPerByteUncompressCost(), + } +} + +// WasmGasRegister implements GasRegister interface +type WasmGasRegister struct { + c WasmGasRegisterConfig +} + +// NewDefaultWasmGasRegister creates instance with default values +func NewDefaultWasmGasRegister() WasmGasRegister { + return NewWasmGasRegister(DefaultGasRegisterConfig()) +} + +// NewWasmGasRegister constructor +func NewWasmGasRegister(c WasmGasRegisterConfig) WasmGasRegister { + if c.GasMultiplier == 0 { + panic(sdkerrors.Wrap(sdkerrors.ErrLogic, "GasMultiplier can not be 0")) + } + return WasmGasRegister{ + c: c, + } +} + +// NewContractInstanceCosts costs to crate a new contract instance from code +func (g WasmGasRegister) NewContractInstanceCosts(pinned bool, msgLen int) storetypes.Gas { + return g.InstantiateContractCosts(pinned, msgLen) +} + +// CompileCosts costs to persist and "compile" a new wasm contract +func (g WasmGasRegister) CompileCosts(byteLength int) storetypes.Gas { + if byteLength < 0 { + panic(sdkerrors.Wrap(types.ErrInvalid, "negative length")) + } + return g.c.CompileCost * uint64(byteLength) +} + +// UncompressCosts costs to unpack a new wasm contract +func (g WasmGasRegister) UncompressCosts(byteLength int) sdk.Gas { + if byteLength < 0 { + panic(sdkerrors.Wrap(types.ErrInvalid, "negative length")) + } + return g.c.UncompressCost.Mul(uint64(byteLength)).Floor() +} + +// InstantiateContractCosts costs when interacting with a wasm contract +func (g WasmGasRegister) InstantiateContractCosts(pinned bool, msgLen int) sdk.Gas { + if msgLen < 0 { + panic(sdkerrors.Wrap(types.ErrInvalid, "negative length")) + } + dataCosts := sdk.Gas(msgLen) * g.c.ContractMessageDataCost + if pinned { + return dataCosts + } + return g.c.InstanceCost + dataCosts +} + +// ReplyCosts costs to to handle a message reply +func (g WasmGasRegister) ReplyCosts(pinned bool, reply wasmvmtypes.Reply) sdk.Gas { + var eventGas sdk.Gas + msgLen := len(reply.Result.Err) + if reply.Result.Ok != nil { + msgLen += len(reply.Result.Ok.Data) + var attrs []wasmvmtypes.EventAttribute + for _, e := range reply.Result.Ok.Events { + eventGas += sdk.Gas(len(e.Type)) * g.c.EventAttributeDataCost + attrs = append(attrs, e.Attributes...) + } + // apply free tier on the whole set not per event + eventGas += g.EventCosts(attrs, nil) + } + return eventGas + g.InstantiateContractCosts(pinned, msgLen) +} + +// EventCosts costs to persist an event +func (g WasmGasRegister) EventCosts(attrs []wasmvmtypes.EventAttribute, events wasmvmtypes.Events) sdk.Gas { + gas, remainingFreeTier := g.eventAttributeCosts(attrs, g.c.EventAttributeDataFreeTier) + for _, e := range events { + gas += g.c.CustomEventCost + gas += sdk.Gas(len(e.Type)) * g.c.EventAttributeDataCost // no free tier with event type + var attrCost sdk.Gas + attrCost, remainingFreeTier = g.eventAttributeCosts(e.Attributes, remainingFreeTier) + gas += attrCost + } + return gas +} + +func (g WasmGasRegister) eventAttributeCosts(attrs []wasmvmtypes.EventAttribute, freeTier uint64) (sdk.Gas, uint64) { + if len(attrs) == 0 { + return 0, freeTier + } + var storedBytes uint64 + for _, l := range attrs { + storedBytes += uint64(len(l.Key)) + uint64(len(l.Value)) + } + storedBytes, freeTier = calcWithFreeTier(storedBytes, freeTier) + // total Length * costs + attribute count * costs + r := sdk.NewIntFromUint64(g.c.EventAttributeDataCost).Mul(sdk.NewIntFromUint64(storedBytes)). + Add(sdk.NewIntFromUint64(g.c.EventPerAttributeCost).Mul(sdk.NewIntFromUint64(uint64(len(attrs))))) + if !r.IsUint64() { + panic(sdk.ErrorOutOfGas{Descriptor: "overflow"}) + } + return r.Uint64(), freeTier +} + +// apply free tier +func calcWithFreeTier(storedBytes uint64, freeTier uint64) (uint64, uint64) { + if storedBytes <= freeTier { + return 0, freeTier - storedBytes + } + storedBytes -= freeTier + return storedBytes, 0 +} + +// ToWasmVMGas convert to wasmVM contract runtime gas unit +func (g WasmGasRegister) ToWasmVMGas(source storetypes.Gas) uint64 { + x := source * g.c.GasMultiplier + if x < source { + panic(sdk.ErrorOutOfGas{Descriptor: "overflow"}) + } + return x +} + +// FromWasmVMGas converts to SDK gas unit +func (g WasmGasRegister) FromWasmVMGas(source uint64) sdk.Gas { + return source / g.c.GasMultiplier +} diff --git a/x/wasm/keeper/gas_register_test.go b/x/wasm/keeper/gas_register_test.go new file mode 100644 index 00000000..f6d4b12e --- /dev/null +++ b/x/wasm/keeper/gas_register_test.go @@ -0,0 +1,472 @@ +package keeper + +import ( + "math" + "strings" + "testing" + + "github.com/cerc-io/laconicd/x/wasm/types" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" +) + +func TestCompileCosts(t *testing.T) { + specs := map[string]struct { + srcLen int + srcConfig WasmGasRegisterConfig + exp sdk.Gas + expPanic bool + }{ + "one byte": { + srcLen: 1, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(3), // DefaultCompileCost + }, + "zero byte": { + srcLen: 0, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(0), + }, + "negative len": { + srcLen: -1, + srcConfig: DefaultGasRegisterConfig(), + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { + NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) + }) + return + } + gotGas := NewWasmGasRegister(spec.srcConfig).CompileCosts(spec.srcLen) + assert.Equal(t, spec.exp, gotGas) + }) + } +} + +func TestNewContractInstanceCosts(t *testing.T) { + specs := map[string]struct { + srcLen int + srcConfig WasmGasRegisterConfig + pinned bool + exp sdk.Gas + expPanic bool + }{ + "small msg - pinned": { + srcLen: 1, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: DefaultContractMessageDataCost, + }, + "big msg - pinned": { + srcLen: math.MaxUint32, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: DefaultContractMessageDataCost * sdk.Gas(math.MaxUint32), + }, + "empty msg - pinned": { + srcLen: 0, + pinned: true, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(0), + }, + "small msg - unpinned": { + srcLen: 1, + srcConfig: DefaultGasRegisterConfig(), + exp: DefaultContractMessageDataCost + DefaultInstanceCost, + }, + "big msg - unpinned": { + srcLen: math.MaxUint32, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultContractMessageDataCost*math.MaxUint32 + DefaultInstanceCost), + }, + "empty msg - unpinned": { + srcLen: 0, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultInstanceCost), + }, + + "negative len": { + srcLen: -1, + srcConfig: DefaultGasRegisterConfig(), + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { + NewWasmGasRegister(spec.srcConfig).NewContractInstanceCosts(spec.pinned, spec.srcLen) + }) + return + } + gotGas := NewWasmGasRegister(spec.srcConfig).NewContractInstanceCosts(spec.pinned, spec.srcLen) + assert.Equal(t, spec.exp, gotGas) + }) + } +} + +func TestContractInstanceCosts(t *testing.T) { + // same as TestNewContractInstanceCosts currently + specs := map[string]struct { + srcLen int + srcConfig WasmGasRegisterConfig + pinned bool + exp sdk.Gas + expPanic bool + }{ + "small msg - pinned": { + srcLen: 1, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: DefaultContractMessageDataCost, + }, + "big msg - pinned": { + srcLen: math.MaxUint32, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: sdk.Gas(DefaultContractMessageDataCost * math.MaxUint32), + }, + "empty msg - pinned": { + srcLen: 0, + pinned: true, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(0), + }, + "small msg - unpinned": { + srcLen: 1, + srcConfig: DefaultGasRegisterConfig(), + exp: DefaultContractMessageDataCost + DefaultInstanceCost, + }, + "big msg - unpinned": { + srcLen: math.MaxUint32, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultContractMessageDataCost*math.MaxUint32 + DefaultInstanceCost), + }, + "empty msg - unpinned": { + srcLen: 0, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultInstanceCost), + }, + + "negative len": { + srcLen: -1, + srcConfig: DefaultGasRegisterConfig(), + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { + NewWasmGasRegister(spec.srcConfig).InstantiateContractCosts(spec.pinned, spec.srcLen) + }) + return + } + gotGas := NewWasmGasRegister(spec.srcConfig).InstantiateContractCosts(spec.pinned, spec.srcLen) + assert.Equal(t, spec.exp, gotGas) + }) + } +} + +func TestReplyCost(t *testing.T) { + specs := map[string]struct { + src wasmvmtypes.Reply + srcConfig WasmGasRegisterConfig + pinned bool + exp sdk.Gas + expPanic bool + }{ + "subcall response with events and data - pinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: []wasmvmtypes.Event{ + {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, + }, + Data: []byte{0x1}, + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: sdk.Gas(3*DefaultEventAttributeDataCost + DefaultPerAttributeCost + DefaultContractMessageDataCost), // 3 == len("foo") + }, + "subcall response with events - pinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: []wasmvmtypes.Event{ + {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, + }, + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: sdk.Gas(3*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo") + }, + "subcall response with events exceeds free tier- pinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: []wasmvmtypes.Event{ + {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: strings.Repeat("x", DefaultEventAttributeDataFreeTier), Value: "myData"}}}, + }, + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: sdk.Gas((3+6)*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo"), 6 == len("myData") + }, + "subcall response error - pinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Err: "foo", + }, + }, + srcConfig: DefaultGasRegisterConfig(), + pinned: true, + exp: 3 * DefaultContractMessageDataCost, + }, + "subcall response with events and data - unpinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: []wasmvmtypes.Event{ + {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, + }, + Data: []byte{0x1}, + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultInstanceCost + 3*DefaultEventAttributeDataCost + DefaultPerAttributeCost + DefaultContractMessageDataCost), + }, + "subcall response with events - unpinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: []wasmvmtypes.Event{ + {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: "myKey", Value: "myData"}}}, + }, + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultInstanceCost + 3*DefaultEventAttributeDataCost + DefaultPerAttributeCost), + }, + "subcall response with events exceeds free tier- unpinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: []wasmvmtypes.Event{ + {Type: "foo", Attributes: []wasmvmtypes.EventAttribute{{Key: strings.Repeat("x", DefaultEventAttributeDataFreeTier), Value: "myData"}}}, + }, + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultInstanceCost + (3+6)*DefaultEventAttributeDataCost + DefaultPerAttributeCost), // 3 == len("foo"), 6 == len("myData") + }, + "subcall response error - unpinned": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Err: "foo", + }, + }, + srcConfig: DefaultGasRegisterConfig(), + exp: sdk.Gas(DefaultInstanceCost + 3*DefaultContractMessageDataCost), + }, + "subcall response with empty events": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: make([]wasmvmtypes.Event, 10), + }, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + exp: DefaultInstanceCost, + }, + "subcall response with events unset": { + src: wasmvmtypes.Reply{ + Result: wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{}, + }, + }, + srcConfig: DefaultGasRegisterConfig(), + exp: DefaultInstanceCost, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { + NewWasmGasRegister(spec.srcConfig).ReplyCosts(spec.pinned, spec.src) + }) + return + } + gotGas := NewWasmGasRegister(spec.srcConfig).ReplyCosts(spec.pinned, spec.src) + assert.Equal(t, spec.exp, gotGas) + }) + } +} + +func TestEventCosts(t *testing.T) { + // most cases are covered in TestReplyCost already. This ensures some edge cases + specs := map[string]struct { + srcAttrs []wasmvmtypes.EventAttribute + srcEvents wasmvmtypes.Events + expGas sdk.Gas + }{ + "empty events": { + srcEvents: make([]wasmvmtypes.Event, 1), + expGas: DefaultPerCustomEventCost, + }, + "empty attributes": { + srcAttrs: make([]wasmvmtypes.EventAttribute, 1), + expGas: DefaultPerAttributeCost, + }, + "both nil": { + expGas: 0, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotGas := NewDefaultWasmGasRegister().EventCosts(spec.srcAttrs, spec.srcEvents) + assert.Equal(t, spec.expGas, gotGas) + }) + } +} + +func TestToWasmVMGasConversion(t *testing.T) { + specs := map[string]struct { + src storetypes.Gas + srcConfig WasmGasRegisterConfig + exp uint64 + expPanic bool + }{ + "0": { + src: 0, + exp: 0, + srcConfig: DefaultGasRegisterConfig(), + }, + "max": { + srcConfig: WasmGasRegisterConfig{ + GasMultiplier: 1, + }, + src: math.MaxUint64, + exp: math.MaxUint64, + }, + "overflow": { + srcConfig: WasmGasRegisterConfig{ + GasMultiplier: 2, + }, + src: math.MaxUint64, + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { + r := NewWasmGasRegister(spec.srcConfig) + _ = r.ToWasmVMGas(spec.src) + }) + return + } + r := NewWasmGasRegister(spec.srcConfig) + got := r.ToWasmVMGas(spec.src) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestFromWasmVMGasConversion(t *testing.T) { + specs := map[string]struct { + src uint64 + exp storetypes.Gas + srcConfig WasmGasRegisterConfig + expPanic bool + }{ + "0": { + src: 0, + exp: 0, + srcConfig: DefaultGasRegisterConfig(), + }, + "max": { + srcConfig: WasmGasRegisterConfig{ + GasMultiplier: 1, + }, + src: math.MaxUint64, + exp: math.MaxUint64, + }, + "missconfigured": { + srcConfig: WasmGasRegisterConfig{ + GasMultiplier: 0, + }, + src: 1, + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { + r := NewWasmGasRegister(spec.srcConfig) + _ = r.FromWasmVMGas(spec.src) + }) + return + } + r := NewWasmGasRegister(spec.srcConfig) + got := r.FromWasmVMGas(spec.src) + assert.Equal(t, spec.exp, got) + }) + } +} + +func TestUncompressCosts(t *testing.T) { + specs := map[string]struct { + lenIn int + exp sdk.Gas + expPanic bool + }{ + "0": { + exp: 0, + }, + "even": { + lenIn: 100, + exp: 15, + }, + "round down when uneven": { + lenIn: 19, + exp: 2, + }, + "max len": { + lenIn: types.MaxWasmSize, + exp: 122880, + }, + "invalid len": { + lenIn: -1, + expPanic: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + if spec.expPanic { + assert.Panics(t, func() { NewDefaultWasmGasRegister().UncompressCosts(spec.lenIn) }) + return + } + got := NewDefaultWasmGasRegister().UncompressCosts(spec.lenIn) + assert.Equal(t, spec.exp, got) + }) + } +} diff --git a/x/wasm/keeper/genesis.go b/x/wasm/keeper/genesis.go new file mode 100644 index 00000000..84a113ef --- /dev/null +++ b/x/wasm/keeper/genesis.go @@ -0,0 +1,116 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// ValidatorSetSource is a subset of the staking keeper +type ValidatorSetSource interface { + ApplyAndReturnValidatorSetUpdates(sdk.Context) (updates []abci.ValidatorUpdate, err error) +} + +// InitGenesis sets supply information for genesis. +// +// CONTRACT: all types of accounts must have been already initialized/created +func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) ([]abci.ValidatorUpdate, error) { + contractKeeper := NewGovPermissionKeeper(keeper) + keeper.SetParams(ctx, data.Params) + var maxCodeID uint64 + for i, code := range data.Codes { + err := keeper.importCode(ctx, code.CodeID, code.CodeInfo, code.CodeBytes) + if err != nil { + return nil, sdkerrors.Wrapf(err, "code %d with id: %d", i, code.CodeID) + } + if code.CodeID > maxCodeID { + maxCodeID = code.CodeID + } + if code.Pinned { + if err := contractKeeper.PinCode(ctx, code.CodeID); err != nil { + return nil, sdkerrors.Wrapf(err, "contract number %d", i) + } + } + } + + var maxContractID int + for i, contract := range data.Contracts { + contractAddr, err := sdk.AccAddressFromBech32(contract.ContractAddress) + if err != nil { + return nil, sdkerrors.Wrapf(err, "address in contract number %d", i) + } + err = keeper.importContract(ctx, contractAddr, &contract.ContractInfo, contract.ContractState, contract.ContractCodeHistory) + if err != nil { + return nil, sdkerrors.Wrapf(err, "contract number %d", i) + } + maxContractID = i + 1 // not ideal but max(contractID) is not persisted otherwise + } + + for i, seq := range data.Sequences { + err := keeper.importAutoIncrementID(ctx, seq.IDKey, seq.Value) + if err != nil { + return nil, sdkerrors.Wrapf(err, "sequence number %d", i) + } + } + + // sanity check seq values + seqVal := keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID) + if seqVal <= maxCodeID { + return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastCodeID), seqVal, maxCodeID) + } + seqVal = keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID) + if seqVal <= uint64(maxContractID) { + return nil, sdkerrors.Wrapf(types.ErrInvalid, "seq %s with value: %d must be greater than: %d ", string(types.KeyLastInstanceID), seqVal, maxContractID) + } + return nil, nil +} + +// ExportGenesis returns a GenesisState for a given context and keeper. +func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState { + var genState types.GenesisState + + genState.Params = keeper.GetParams(ctx) + + keeper.IterateCodeInfos(ctx, func(codeID uint64, info types.CodeInfo) bool { + bytecode, err := keeper.GetByteCode(ctx, codeID) + if err != nil { + panic(err) + } + genState.Codes = append(genState.Codes, types.Code{ + CodeID: codeID, + CodeInfo: info, + CodeBytes: bytecode, + Pinned: keeper.IsPinnedCode(ctx, codeID), + }) + return false + }) + + keeper.IterateContractInfo(ctx, func(addr sdk.AccAddress, contract types.ContractInfo) bool { + var state []types.Model + keeper.IterateContractState(ctx, addr, func(key, value []byte) bool { + state = append(state, types.Model{Key: key, Value: value}) + return false + }) + + contractCodeHistory := keeper.GetContractHistory(ctx, addr) + + genState.Contracts = append(genState.Contracts, types.Contract{ + ContractAddress: addr.String(), + ContractInfo: contract, + ContractState: state, + ContractCodeHistory: contractCodeHistory, + }) + return false + }) + + for _, k := range [][]byte{types.KeyLastCodeID, types.KeyLastInstanceID} { + genState.Sequences = append(genState.Sequences, types.Sequence{ + IDKey: k, + Value: keeper.PeekAutoIncrementID(ctx, k), + }) + } + + return &genState +} diff --git a/x/wasm/keeper/genesis_test.go b/x/wasm/keeper/genesis_test.go new file mode 100644 index 00000000..7d9ecab6 --- /dev/null +++ b/x/wasm/keeper/genesis_test.go @@ -0,0 +1,671 @@ +package keeper + +import ( + "crypto/sha256" + "encoding/base64" + "fmt" + "math/rand" + "os" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + fuzz "github.com/google/gofuzz" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cerc-io/laconicd/x/wasm/types" + wasmTypes "github.com/cerc-io/laconicd/x/wasm/types" +) + +const firstCodeID = 1 + +func TestGenesisExportImport(t *testing.T) { + wasmKeeper, srcCtx, srcStoreKeys := setupKeeper(t) + contractKeeper := NewGovPermissionKeeper(wasmKeeper) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + // store some test data + f := fuzz.New().Funcs(ModelFuzzers...) + + wasmKeeper.SetParams(srcCtx, types.DefaultParams()) + + for i := 0; i < 25; i++ { + var ( + codeInfo types.CodeInfo + contract types.ContractInfo + stateModels []types.Model + history []types.ContractCodeHistoryEntry + pinned bool + contractExtension bool + ) + f.Fuzz(&codeInfo) + f.Fuzz(&contract) + f.Fuzz(&stateModels) + f.NilChance(0).Fuzz(&history) + f.Fuzz(&pinned) + f.Fuzz(&contractExtension) + + creatorAddr, err := sdk.AccAddressFromBech32(codeInfo.Creator) + require.NoError(t, err) + codeID, _, err := contractKeeper.Create(srcCtx, creatorAddr, wasmCode, &codeInfo.InstantiateConfig) + require.NoError(t, err) + if pinned { + contractKeeper.PinCode(srcCtx, codeID) + } + if contractExtension { + anyTime := time.Now().UTC() + var nestedType govtypes.TextProposal + f.NilChance(0).Fuzz(&nestedType) + myExtension, err := govtypes.NewProposal(&nestedType, 1, anyTime, anyTime) + require.NoError(t, err) + contract.SetExtension(&myExtension) + } + + contract.CodeID = codeID + contractAddr := wasmKeeper.ClassicAddressGenerator()(srcCtx, codeID, nil) + wasmKeeper.storeContractInfo(srcCtx, contractAddr, &contract) + wasmKeeper.appendToContractHistory(srcCtx, contractAddr, history...) + wasmKeeper.importContractState(srcCtx, contractAddr, stateModels) + } + var wasmParams types.Params + f.NilChance(0).Fuzz(&wasmParams) + wasmKeeper.SetParams(srcCtx, wasmParams) + + // export + exportedState := ExportGenesis(srcCtx, wasmKeeper) + // order should not matter + rand.Shuffle(len(exportedState.Codes), func(i, j int) { + exportedState.Codes[i], exportedState.Codes[j] = exportedState.Codes[j], exportedState.Codes[i] + }) + rand.Shuffle(len(exportedState.Contracts), func(i, j int) { + exportedState.Contracts[i], exportedState.Contracts[j] = exportedState.Contracts[j], exportedState.Contracts[i] + }) + rand.Shuffle(len(exportedState.Sequences), func(i, j int) { + exportedState.Sequences[i], exportedState.Sequences[j] = exportedState.Sequences[j], exportedState.Sequences[i] + }) + exportedGenesis, err := wasmKeeper.cdc.MarshalJSON(exportedState) + require.NoError(t, err) + + // setup new instances + dstKeeper, dstCtx, dstStoreKeys := setupKeeper(t) + + // reset contract code index in source DB for comparison with dest DB + wasmKeeper.IterateContractInfo(srcCtx, func(address sdk.AccAddress, info wasmTypes.ContractInfo) bool { + creatorAddress := sdk.MustAccAddressFromBech32(info.Creator) + history := wasmKeeper.GetContractHistory(srcCtx, address) + + wasmKeeper.addToContractCodeSecondaryIndex(srcCtx, address, history[len(history)-1]) + wasmKeeper.addToContractCreatorSecondaryIndex(srcCtx, creatorAddress, history[0].Updated, address) + return false + }) + + // re-import + var importState wasmTypes.GenesisState + err = dstKeeper.cdc.UnmarshalJSON(exportedGenesis, &importState) + require.NoError(t, err) + InitGenesis(dstCtx, dstKeeper, importState) + + // compare whole DB + for j := range srcStoreKeys { + srcIT := srcCtx.KVStore(srcStoreKeys[j]).Iterator(nil, nil) + dstIT := dstCtx.KVStore(dstStoreKeys[j]).Iterator(nil, nil) + + for i := 0; srcIT.Valid(); i++ { + require.True(t, dstIT.Valid(), "[%s] destination DB has less elements than source. Missing: %x", srcStoreKeys[j].Name(), srcIT.Key()) + require.Equal(t, srcIT.Key(), dstIT.Key(), i) + require.Equal(t, srcIT.Value(), dstIT.Value(), "[%s] element (%d): %X", srcStoreKeys[j].Name(), i, srcIT.Key()) + dstIT.Next() + srcIT.Next() + } + if !assert.False(t, dstIT.Valid()) { + t.Fatalf("dest Iterator still has key :%X", dstIT.Key()) + } + srcIT.Close() + dstIT.Close() + } +} + +func TestGenesisInit(t *testing.T) { + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + myCodeInfo := wasmTypes.CodeInfoFixture(wasmTypes.WithSHA256CodeHash(wasmCode)) + specs := map[string]struct { + src types.GenesisState + expSuccess bool + }{ + "happy path: code info correct": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 1}, + }, + Params: types.DefaultParams(), + }, + expSuccess: true, + }, + "happy path: code ids can contain gaps": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }, { + CodeID: 3, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 10}, + {IDKey: types.KeyLastInstanceID, Value: 1}, + }, + Params: types.DefaultParams(), + }, + expSuccess: true, + }, + "happy path: code order does not matter": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: 2, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }, { + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: nil, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 3}, + {IDKey: types.KeyLastInstanceID, Value: 1}, + }, + Params: types.DefaultParams(), + }, + expSuccess: true, + }, + "prevent code hash mismatch": {src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: wasmTypes.CodeInfoFixture(func(i *wasmTypes.CodeInfo) { i.CodeHash = make([]byte, sha256.Size) }), + CodeBytes: wasmCode, + }}, + Params: types.DefaultParams(), + }}, + "prevent duplicate codeIDs": {src: types.GenesisState{ + Codes: []types.Code{ + { + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }, + { + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }, + }, + Params: types.DefaultParams(), + }}, + "codes with same checksum can be pinned": { + src: types.GenesisState{ + Codes: []types.Code{ + { + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + Pinned: true, + }, + { + CodeID: 2, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + Pinned: true, + }, + }, + Params: types.DefaultParams(), + }, + }, + "happy path: code id in info and contract do match": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{}`), + }, + }, + }, + }, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 2}, + }, + Params: types.DefaultParams(), + }, + expSuccess: true, + }, + "happy path: code info with two contracts": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{}`), + }, + }, + }, { + ContractAddress: BuildContractAddressClassic(1, 2).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{"foo":"bar"}`), + }, + }, + }, + }, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 3}, + }, + Params: types.DefaultParams(), + }, + expSuccess: true, + }, + "prevent contracts that points to non existing codeID": { + src: types.GenesisState{ + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{"foo":"bar"}`), + }, + }, + }, + }, + Params: types.DefaultParams(), + }, + }, + "prevent duplicate contract address": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{"foo":"bar"}`), + }, + }, + }, { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{"other":"value"}`), + }, + }, + }, + }, + Params: types.DefaultParams(), + }, + }, + "prevent duplicate contract model keys": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractState: []types.Model{ + { + Key: []byte{0x1}, + Value: []byte("foo"), + }, + { + Key: []byte{0x1}, + Value: []byte("bar"), + }, + }, + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{"foo":"bar"}`), + }, + }, + }, + }, + Params: types.DefaultParams(), + }, + }, + "prevent duplicate sequences": { + src: types.GenesisState{ + Sequences: []types.Sequence{ + {IDKey: []byte("foo"), Value: 1}, + {IDKey: []byte("foo"), Value: 9999}, + }, + Params: types.DefaultParams(), + }, + }, + "prevent code id seq init value == max codeID used": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: 2, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 1}, + }, + Params: types.DefaultParams(), + }, + }, + "prevent contract id seq init value == count contracts": { + src: types.GenesisState{ + Codes: []types.Code{{ + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + }}, + Contracts: []types.Contract{ + { + ContractAddress: BuildContractAddressClassic(1, 1).String(), + ContractInfo: types.ContractInfoFixture(func(c *wasmTypes.ContractInfo) { c.CodeID = 1 }, types.RandCreatedFields), + ContractCodeHistory: []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 1, + Updated: &types.AbsoluteTxPosition{BlockHeight: rand.Uint64(), TxIndex: rand.Uint64()}, + Msg: []byte(`{}`), + }, + }, + }, + }, + Sequences: []types.Sequence{ + {IDKey: types.KeyLastCodeID, Value: 2}, + {IDKey: types.KeyLastInstanceID, Value: 1}, + }, + Params: types.DefaultParams(), + }, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + keeper, ctx, _ := setupKeeper(t) + + require.NoError(t, types.ValidateGenesis(spec.src)) + _, gotErr := InitGenesis(ctx, keeper, spec.src) + if !spec.expSuccess { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + + for _, c := range spec.src.Codes { + assert.Equal(t, c.Pinned, keeper.IsPinnedCode(ctx, c.CodeID)) + } + }) + } +} + +func TestImportContractWithCodeHistoryPreserved(t *testing.T) { + genesisTemplate := ` +{ + "params":{ + "code_upload_access": { + "permission": "Everybody" + }, + "instantiate_default_permission": "Everybody" + }, + "codes": [ + { + "code_id": "1", + "code_info": { + "code_hash": %q, + "creator": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx", + "instantiate_config": { + "permission": "OnlyAddress", + "address": "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx" + } + }, + "code_bytes": %q + } + ], + "contracts": [ + { + "contract_address": "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", + "contract_info": { + "code_id": "1", + "creator": "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x", + "admin": "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn", + "label": "ȀĴnZV芢毤", + "created": { + "block_height" : "100", + "tx_index" : "10" + } + }, + "contract_code_history": [ + { + "operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT", + "code_id": "1", + "updated": { + "block_height" : "100", + "tx_index" : "10" + }, + "msg": {"foo": "bar"} + }, + { + "operation": "CONTRACT_CODE_HISTORY_OPERATION_TYPE_MIGRATE", + "code_id": "1", + "updated": { + "block_height" : "200", + "tx_index" : "10" + }, + "msg": {"other": "msg"} + } + ] + } + ], + "sequences": [ + {"id_key": "BGxhc3RDb2RlSWQ=", "value": "2"}, + {"id_key": "BGxhc3RDb250cmFjdElk", "value": "3"} + ] +}` + keeper, ctx, _ := setupKeeper(t) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + wasmCodeHash := sha256.Sum256(wasmCode) + enc64 := base64.StdEncoding.EncodeToString + genesisStr := fmt.Sprintf(genesisTemplate, enc64(wasmCodeHash[:]), enc64(wasmCode)) + + var importState wasmTypes.GenesisState + err = keeper.cdc.UnmarshalJSON([]byte(genesisStr), &importState) + require.NoError(t, err) + require.NoError(t, importState.ValidateBasic(), genesisStr) + + ctx = ctx.WithBlockHeight(0).WithGasMeter(sdk.NewInfiniteGasMeter()) + + // when + _, err = InitGenesis(ctx, keeper, importState) + require.NoError(t, err) + + // verify wasm code + gotWasmCode, err := keeper.GetByteCode(ctx, 1) + require.NoError(t, err) + assert.Equal(t, wasmCode, gotWasmCode, "byte code does not match") + + // verify code info + gotCodeInfo := keeper.GetCodeInfo(ctx, 1) + require.NotNil(t, gotCodeInfo) + codeCreatorAddr := "cosmos1qtu5n0cnhfkjj6l2rq97hmky9fd89gwca9yarx" + expCodeInfo := types.CodeInfo{ + CodeHash: wasmCodeHash[:], + Creator: codeCreatorAddr, + InstantiateConfig: wasmTypes.AccessConfig{ + Permission: types.AccessTypeOnlyAddress, + Address: codeCreatorAddr, + }, + } + assert.Equal(t, expCodeInfo, *gotCodeInfo) + + // verify contract + contractAddr, _ := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + gotContractInfo := keeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, gotContractInfo) + contractCreatorAddr := "cosmos13x849jzd03vne42ynpj25hn8npjecxqrjghd8x" + adminAddr := "cosmos1h5t8zxmjr30e9dqghtlpl40f2zz5cgey6esxtn" + + expContractInfo := types.ContractInfo{ + CodeID: firstCodeID, + Creator: contractCreatorAddr, + Admin: adminAddr, + Label: "ȀĴnZV芢毤", + Created: &types.AbsoluteTxPosition{BlockHeight: 100, TxIndex: 10}, + } + assert.Equal(t, expContractInfo, *gotContractInfo) + + expHistory := []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Updated: &types.AbsoluteTxPosition{ + BlockHeight: 100, + TxIndex: 10, + }, + Msg: []byte(`{"foo": "bar"}`), + }, + { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: firstCodeID, + Updated: &types.AbsoluteTxPosition{ + BlockHeight: 200, + TxIndex: 10, + }, + Msg: []byte(`{"other": "msg"}`), + }, + } + assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr)) + assert.Equal(t, uint64(2), keeper.PeekAutoIncrementID(ctx, types.KeyLastCodeID)) + assert.Equal(t, uint64(3), keeper.PeekAutoIncrementID(ctx, types.KeyLastInstanceID)) +} + +func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) { + t.Helper() + tempDir, err := os.MkdirTemp("", "wasm") + require.NoError(t, err) + t.Cleanup(func() { os.RemoveAll(tempDir) }) + var ( + keyParams = sdk.NewKVStoreKey(paramtypes.StoreKey) + tkeyParams = sdk.NewTransientStoreKey(paramtypes.TStoreKey) + keyWasm = sdk.NewKVStoreKey(wasmTypes.StoreKey) + ) + + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + ms.MountStoreWithDB(keyWasm, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db) + require.NoError(t, ms.LoadLatestVersion()) + + ctx := sdk.NewContext(ms, tmproto.Header{ + Height: 1234567, + Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC), + }, false, log.NewNopLogger()) + + encodingConfig := MakeEncodingConfig(t) + // register an example extension. must be protobuf + encodingConfig.InterfaceRegistry.RegisterImplementations( + (*types.ContractInfoExtension)(nil), + &govtypes.Proposal{}, + ) + // also registering gov interfaces for nested Any type + govtypes.RegisterInterfaces(encodingConfig.InterfaceRegistry) + + wasmConfig := wasmTypes.DefaultWasmConfig() + pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams) + + srcKeeper := NewKeeper( + encodingConfig.Marshaler, + keyWasm, + pk.Subspace(wasmTypes.ModuleName), + authkeeper.AccountKeeper{}, + &bankkeeper.BaseKeeper{}, + stakingkeeper.Keeper{}, + distributionkeeper.Keeper{}, + nil, + nil, + nil, + nil, + nil, + nil, + tempDir, + wasmConfig, + AvailableCapabilities, + ) + return &srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams} +} diff --git a/x/wasm/keeper/handler_plugin.go b/x/wasm/keeper/handler_plugin.go new file mode 100644 index 00000000..14aa4ec5 --- /dev/null +++ b/x/wasm/keeper/handler_plugin.go @@ -0,0 +1,226 @@ +package keeper + +import ( + "errors" + "fmt" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/baseapp" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// msgEncoder is an extension point to customize encodings +type msgEncoder interface { + // Encode converts wasmvm message to n cosmos message types + Encode(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Msg, error) +} + +// MessageRouter ADR 031 request type routing +type MessageRouter interface { + Handler(msg sdk.Msg) baseapp.MsgServiceHandler +} + +// SDKMessageHandler can handles messages that can be encoded into sdk.Message types and routed. +type SDKMessageHandler struct { + router MessageRouter + encoders msgEncoder +} + +func NewDefaultMessageHandler( + router MessageRouter, + channelKeeper types.ChannelKeeper, + capabilityKeeper types.CapabilityKeeper, + bankKeeper types.Burner, + unpacker codectypes.AnyUnpacker, + portSource types.ICS20TransferPortSource, + customEncoders ...*MessageEncoders, +) Messenger { + encoders := DefaultEncoders(unpacker, portSource) + for _, e := range customEncoders { + encoders = encoders.Merge(e) + } + return NewMessageHandlerChain( + NewSDKMessageHandler(router, encoders), + NewIBCRawPacketHandler(channelKeeper, capabilityKeeper), + NewBurnCoinMessageHandler(bankKeeper), + ) +} + +func NewSDKMessageHandler(router MessageRouter, encoders msgEncoder) SDKMessageHandler { + return SDKMessageHandler{ + router: router, + encoders: encoders, + } +} + +func (h SDKMessageHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + sdkMsgs, err := h.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg) + if err != nil { + return nil, nil, err + } + for _, sdkMsg := range sdkMsgs { + res, err := h.handleSdkMessage(ctx, contractAddr, sdkMsg) + if err != nil { + return nil, nil, err + } + // append data + data = append(data, res.Data) + // append events + sdkEvents := make([]sdk.Event, len(res.Events)) + for i := range res.Events { + sdkEvents[i] = sdk.Event(res.Events[i]) + } + events = append(events, sdkEvents...) + } + return +} + +func (h SDKMessageHandler) handleSdkMessage(ctx sdk.Context, contractAddr sdk.Address, msg sdk.Msg) (*sdk.Result, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + // make sure this account can send it + for _, acct := range msg.GetSigners() { + if !acct.Equals(contractAddr) { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "contract doesn't have permission") + } + } + + // find the handler and execute it + if handler := h.router.Handler(msg); handler != nil { + // ADR 031 request type routing + msgResult, err := handler(ctx, msg) + return msgResult, err + } + // legacy sdk.Msg routing + // Assuming that the app developer has migrated all their Msgs to + // proto messages and has registered all `Msg services`, then this + // path should never be called, because all those Msgs should be + // registered within the `msgServiceRouter` already. + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", msg) +} + +// MessageHandlerChain defines a chain of handlers that are called one by one until it can be handled. +type MessageHandlerChain struct { + handlers []Messenger +} + +func NewMessageHandlerChain(first Messenger, others ...Messenger) *MessageHandlerChain { + r := &MessageHandlerChain{handlers: append([]Messenger{first}, others...)} + for i := range r.handlers { + if r.handlers[i] == nil { + panic(fmt.Sprintf("handler must not be nil at position : %d", i)) + } + } + return r +} + +// DispatchMsg dispatch message and calls chained handlers one after another in +// order to find the right one to process given message. If a handler cannot +// process given message (returns ErrUnknownMsg), its result is ignored and the +// next handler is executed. +func (m MessageHandlerChain) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) { + for _, h := range m.handlers { + events, data, err := h.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + switch { + case err == nil: + return events, data, nil + case errors.Is(err, types.ErrUnknownMsg): + continue + default: + return events, data, err + } + } + return nil, nil, sdkerrors.Wrap(types.ErrUnknownMsg, "no handler found") +} + +// IBCRawPacketHandler handels IBC.SendPacket messages which are published to an IBC channel. +type IBCRawPacketHandler struct { + channelKeeper types.ChannelKeeper + capabilityKeeper types.CapabilityKeeper +} + +func NewIBCRawPacketHandler(chk types.ChannelKeeper, cak types.CapabilityKeeper) IBCRawPacketHandler { + return IBCRawPacketHandler{channelKeeper: chk, capabilityKeeper: cak} +} + +// DispatchMsg publishes a raw IBC packet onto the channel. +func (h IBCRawPacketHandler) DispatchMsg(ctx sdk.Context, _ sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + if msg.IBC == nil || msg.IBC.SendPacket == nil { + return nil, nil, types.ErrUnknownMsg + } + if contractIBCPortID == "" { + return nil, nil, sdkerrors.Wrapf(types.ErrUnsupportedForContract, "ibc not supported") + } + contractIBCChannelID := msg.IBC.SendPacket.ChannelID + if contractIBCChannelID == "" { + return nil, nil, sdkerrors.Wrapf(types.ErrEmpty, "ibc channel") + } + + sequence, found := h.channelKeeper.GetNextSequenceSend(ctx, contractIBCPortID, contractIBCChannelID) + if !found { + return nil, nil, sdkerrors.Wrapf(channeltypes.ErrSequenceSendNotFound, + "source port: %s, source channel: %s", contractIBCPortID, contractIBCChannelID, + ) + } + + channelInfo, ok := h.channelKeeper.GetChannel(ctx, contractIBCPortID, contractIBCChannelID) + if !ok { + return nil, nil, sdkerrors.Wrap(channeltypes.ErrInvalidChannel, "not found") + } + channelCap, ok := h.capabilityKeeper.GetCapability(ctx, host.ChannelCapabilityPath(contractIBCPortID, contractIBCChannelID)) + if !ok { + return nil, nil, sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability") + } + packet := channeltypes.NewPacket( + msg.IBC.SendPacket.Data, + sequence, + contractIBCPortID, + contractIBCChannelID, + channelInfo.Counterparty.PortId, + channelInfo.Counterparty.ChannelId, + ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.IBC.SendPacket.Timeout.Block), + msg.IBC.SendPacket.Timeout.Timestamp, + ) + return nil, nil, h.channelKeeper.SendPacket(ctx, channelCap, packet) +} + +var _ Messenger = MessageHandlerFunc(nil) + +// MessageHandlerFunc is a helper to construct a function based message handler. +type MessageHandlerFunc func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) + +// DispatchMsg delegates dispatching of provided message into the MessageHandlerFunc. +func (m MessageHandlerFunc) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return m(ctx, contractAddr, contractIBCPortID, msg) +} + +// NewBurnCoinMessageHandler handles wasmvm.BurnMsg messages +func NewBurnCoinMessageHandler(burner types.Burner) MessageHandlerFunc { + return func(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + if msg.Bank != nil && msg.Bank.Burn != nil { + coins, err := ConvertWasmCoinsToSdkCoins(msg.Bank.Burn.Amount) + if err != nil { + return nil, nil, err + } + if coins.IsZero() { + return nil, nil, types.ErrEmpty.Wrap("amount") + } + if err := burner.SendCoinsFromAccountToModule(ctx, contractAddr, types.ModuleName, coins); err != nil { + return nil, nil, sdkerrors.Wrap(err, "transfer to module") + } + if err := burner.BurnCoins(ctx, types.ModuleName, coins); err != nil { + return nil, nil, sdkerrors.Wrap(err, "burn coins") + } + moduleLogger(ctx).Info("Burned", "amount", coins) + return nil, nil, nil + } + return nil, nil, types.ErrUnknownMsg + } +} diff --git a/x/wasm/keeper/handler_plugin_encoders.go b/x/wasm/keeper/handler_plugin_encoders.go new file mode 100644 index 00000000..f23b24bb --- /dev/null +++ b/x/wasm/keeper/handler_plugin_encoders.go @@ -0,0 +1,393 @@ +package keeper + +import ( + "encoding/json" + "fmt" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibcclienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +type ( + BankEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error) + CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) + DistributionEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) + StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) + StargateEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) + WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) + IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) +) + +type MessageEncoders struct { + Bank func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error) + Custom func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) + Distribution func(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) + IBC func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) + Staking func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) + Stargate func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) + Wasm func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) + Gov func(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) +} + +func DefaultEncoders(unpacker codectypes.AnyUnpacker, portSource types.ICS20TransferPortSource) MessageEncoders { + return MessageEncoders{ + Bank: EncodeBankMsg, + Custom: NoCustomMsg, + Distribution: EncodeDistributionMsg, + IBC: EncodeIBCMsg(portSource), + Staking: EncodeStakingMsg, + Stargate: EncodeStargateMsg(unpacker), + Wasm: EncodeWasmMsg, + Gov: EncodeGovMsg, + } +} + +func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders { + if o == nil { + return e + } + if o.Bank != nil { + e.Bank = o.Bank + } + if o.Custom != nil { + e.Custom = o.Custom + } + if o.Distribution != nil { + e.Distribution = o.Distribution + } + if o.IBC != nil { + e.IBC = o.IBC + } + if o.Staking != nil { + e.Staking = o.Staking + } + if o.Stargate != nil { + e.Stargate = o.Stargate + } + if o.Wasm != nil { + e.Wasm = o.Wasm + } + if o.Gov != nil { + e.Gov = o.Gov + } + return e +} + +func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) ([]sdk.Msg, error) { + switch { + case msg.Bank != nil: + return e.Bank(contractAddr, msg.Bank) + case msg.Custom != nil: + return e.Custom(contractAddr, msg.Custom) + case msg.Distribution != nil: + return e.Distribution(contractAddr, msg.Distribution) + case msg.IBC != nil: + return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC) + case msg.Staking != nil: + return e.Staking(contractAddr, msg.Staking) + case msg.Stargate != nil: + return e.Stargate(contractAddr, msg.Stargate) + case msg.Wasm != nil: + return e.Wasm(contractAddr, msg.Wasm) + case msg.Gov != nil: + return EncodeGovMsg(contractAddr, msg.Gov) + } + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Wasm") +} + +func EncodeBankMsg(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error) { + if msg.Send == nil { + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Bank") + } + if len(msg.Send.Amount) == 0 { + return nil, nil + } + toSend, err := ConvertWasmCoinsToSdkCoins(msg.Send.Amount) + if err != nil { + return nil, err + } + sdkMsg := banktypes.MsgSend{ + FromAddress: sender.String(), + ToAddress: msg.Send.ToAddress, + Amount: toSend, + } + return []sdk.Msg{&sdkMsg}, nil +} + +func NoCustomMsg(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "custom variant not supported") +} + +func EncodeDistributionMsg(sender sdk.AccAddress, msg *wasmvmtypes.DistributionMsg) ([]sdk.Msg, error) { + switch { + case msg.SetWithdrawAddress != nil: + setMsg := distributiontypes.MsgSetWithdrawAddress{ + DelegatorAddress: sender.String(), + WithdrawAddress: msg.SetWithdrawAddress.Address, + } + return []sdk.Msg{&setMsg}, nil + case msg.WithdrawDelegatorReward != nil: + withdrawMsg := distributiontypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: sender.String(), + ValidatorAddress: msg.WithdrawDelegatorReward.Validator, + } + return []sdk.Msg{&withdrawMsg}, nil + default: + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Distribution") + } +} + +func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error) { + switch { + case msg.Delegate != nil: + coin, err := ConvertWasmCoinToSdkCoin(msg.Delegate.Amount) + if err != nil { + return nil, err + } + sdkMsg := stakingtypes.MsgDelegate{ + DelegatorAddress: sender.String(), + ValidatorAddress: msg.Delegate.Validator, + Amount: coin, + } + return []sdk.Msg{&sdkMsg}, nil + + case msg.Redelegate != nil: + coin, err := ConvertWasmCoinToSdkCoin(msg.Redelegate.Amount) + if err != nil { + return nil, err + } + sdkMsg := stakingtypes.MsgBeginRedelegate{ + DelegatorAddress: sender.String(), + ValidatorSrcAddress: msg.Redelegate.SrcValidator, + ValidatorDstAddress: msg.Redelegate.DstValidator, + Amount: coin, + } + return []sdk.Msg{&sdkMsg}, nil + case msg.Undelegate != nil: + coin, err := ConvertWasmCoinToSdkCoin(msg.Undelegate.Amount) + if err != nil { + return nil, err + } + sdkMsg := stakingtypes.MsgUndelegate{ + DelegatorAddress: sender.String(), + ValidatorAddress: msg.Undelegate.Validator, + Amount: coin, + } + return []sdk.Msg{&sdkMsg}, nil + default: + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Staking") + } +} + +func EncodeStargateMsg(unpacker codectypes.AnyUnpacker) StargateEncoder { + return func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) { + any := codectypes.Any{ + TypeUrl: msg.TypeURL, + Value: msg.Value, + } + var sdkMsg sdk.Msg + if err := unpacker.UnpackAny(&any, &sdkMsg); err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("Cannot unpack proto message with type URL: %s", msg.TypeURL)) + } + if err := codectypes.UnpackInterfaces(sdkMsg, unpacker); err != nil { + return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("UnpackInterfaces inside msg: %s", err)) + } + return []sdk.Msg{sdkMsg}, nil + } +} + +func EncodeWasmMsg(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) { + switch { + case msg.Execute != nil: + coins, err := ConvertWasmCoinsToSdkCoins(msg.Execute.Funds) + if err != nil { + return nil, err + } + + sdkMsg := types.MsgExecuteContract{ + Sender: sender.String(), + Contract: msg.Execute.ContractAddr, + Msg: msg.Execute.Msg, + Funds: coins, + } + return []sdk.Msg{&sdkMsg}, nil + case msg.Instantiate != nil: + coins, err := ConvertWasmCoinsToSdkCoins(msg.Instantiate.Funds) + if err != nil { + return nil, err + } + + sdkMsg := types.MsgInstantiateContract{ + Sender: sender.String(), + CodeID: msg.Instantiate.CodeID, + Label: msg.Instantiate.Label, + Msg: msg.Instantiate.Msg, + Admin: msg.Instantiate.Admin, + Funds: coins, + } + return []sdk.Msg{&sdkMsg}, nil + case msg.Instantiate2 != nil: + coins, err := ConvertWasmCoinsToSdkCoins(msg.Instantiate2.Funds) + if err != nil { + return nil, err + } + + sdkMsg := types.MsgInstantiateContract2{ + Sender: sender.String(), + Admin: msg.Instantiate2.Admin, + CodeID: msg.Instantiate2.CodeID, + Label: msg.Instantiate2.Label, + Msg: msg.Instantiate2.Msg, + Funds: coins, + Salt: msg.Instantiate2.Salt, + // FixMsg is discouraged, see: https://medium.com/cosmwasm/dev-note-3-limitations-of-instantiate2-and-how-to-deal-with-them-a3f946874230 + FixMsg: false, + } + return []sdk.Msg{&sdkMsg}, nil + case msg.Migrate != nil: + sdkMsg := types.MsgMigrateContract{ + Sender: sender.String(), + Contract: msg.Migrate.ContractAddr, + CodeID: msg.Migrate.NewCodeID, + Msg: msg.Migrate.Msg, + } + return []sdk.Msg{&sdkMsg}, nil + case msg.ClearAdmin != nil: + sdkMsg := types.MsgClearAdmin{ + Sender: sender.String(), + Contract: msg.ClearAdmin.ContractAddr, + } + return []sdk.Msg{&sdkMsg}, nil + case msg.UpdateAdmin != nil: + sdkMsg := types.MsgUpdateAdmin{ + Sender: sender.String(), + Contract: msg.UpdateAdmin.ContractAddr, + NewAdmin: msg.UpdateAdmin.Admin, + } + return []sdk.Msg{&sdkMsg}, nil + default: + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of Wasm") + } +} + +func EncodeIBCMsg(portSource types.ICS20TransferPortSource) func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) { + return func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error) { + switch { + case msg.CloseChannel != nil: + return []sdk.Msg{&channeltypes.MsgChannelCloseInit{ + PortId: PortIDForContract(sender), + ChannelId: msg.CloseChannel.ChannelID, + Signer: sender.String(), + }}, nil + case msg.Transfer != nil: + amount, err := ConvertWasmCoinToSdkCoin(msg.Transfer.Amount) + if err != nil { + return nil, sdkerrors.Wrap(err, "amount") + } + msg := &ibctransfertypes.MsgTransfer{ + SourcePort: portSource.GetPort(ctx), + SourceChannel: msg.Transfer.ChannelID, + Token: amount, + Sender: sender.String(), + Receiver: msg.Transfer.ToAddress, + TimeoutHeight: ConvertWasmIBCTimeoutHeightToCosmosHeight(msg.Transfer.Timeout.Block), + TimeoutTimestamp: msg.Transfer.Timeout.Timestamp, + } + return []sdk.Msg{msg}, nil + default: + return nil, sdkerrors.Wrap(types.ErrUnknownMsg, "unknown variant of IBC") + } + } +} + +func EncodeGovMsg(sender sdk.AccAddress, msg *wasmvmtypes.GovMsg) ([]sdk.Msg, error) { + switch { + case msg.Vote != nil: + voteOption, err := convertVoteOption(msg.Vote.Vote) + if err != nil { + return nil, sdkerrors.Wrap(err, "vote option") + } + m := govtypes.NewMsgVote(sender, msg.Vote.ProposalId, voteOption) + return []sdk.Msg{m}, nil + case msg.VoteWeighted != nil: + opts := make([]govtypes.WeightedVoteOption, len(msg.VoteWeighted.Options)) + for i, v := range msg.VoteWeighted.Options { + weight, err := sdk.NewDecFromStr(v.Weight) + if err != nil { + return nil, sdkerrors.Wrapf(err, "weight for vote %d", i+1) + } + voteOption, err := convertVoteOption(v.Option) + if err != nil { + return nil, sdkerrors.Wrap(err, "vote option") + } + opts[i] = govtypes.WeightedVoteOption{Option: voteOption, Weight: weight} + } + m := govtypes.NewMsgVoteWeighted(sender, msg.VoteWeighted.ProposalId, opts) + return []sdk.Msg{m}, nil + + default: + return nil, types.ErrUnknownMsg.Wrap("unknown variant of gov") + } +} + +func convertVoteOption(s interface{}) (govtypes.VoteOption, error) { + var option govtypes.VoteOption + switch s { + case wasmvmtypes.Yes: + option = govtypes.OptionYes + case wasmvmtypes.No: + option = govtypes.OptionNo + case wasmvmtypes.NoWithVeto: + option = govtypes.OptionNoWithVeto + case wasmvmtypes.Abstain: + option = govtypes.OptionAbstain + default: + return govtypes.OptionEmpty, types.ErrInvalid + } + return option, nil +} + +// ConvertWasmIBCTimeoutHeightToCosmosHeight converts a wasmvm type ibc timeout height to ibc module type height +func ConvertWasmIBCTimeoutHeightToCosmosHeight(ibcTimeoutBlock *wasmvmtypes.IBCTimeoutBlock) ibcclienttypes.Height { + if ibcTimeoutBlock == nil { + return ibcclienttypes.NewHeight(0, 0) + } + return ibcclienttypes.NewHeight(ibcTimeoutBlock.Revision, ibcTimeoutBlock.Height) +} + +// ConvertWasmCoinsToSdkCoins converts the wasm vm type coins to sdk type coins +func ConvertWasmCoinsToSdkCoins(coins []wasmvmtypes.Coin) (sdk.Coins, error) { + var toSend sdk.Coins + for _, coin := range coins { + c, err := ConvertWasmCoinToSdkCoin(coin) + if err != nil { + return nil, err + } + toSend = toSend.Add(c) + } + return toSend.Sort(), nil +} + +// ConvertWasmCoinToSdkCoin converts a wasm vm type coin to sdk type coin +func ConvertWasmCoinToSdkCoin(coin wasmvmtypes.Coin) (sdk.Coin, error) { + amount, ok := sdk.NewIntFromString(coin.Amount) + if !ok { + return sdk.Coin{}, sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, coin.Amount+coin.Denom) + } + r := sdk.Coin{ + Denom: coin.Denom, + Amount: amount, + } + return r, r.Validate() +} diff --git a/x/wasm/keeper/handler_plugin_encoders_test.go b/x/wasm/keeper/handler_plugin_encoders_test.go new file mode 100644 index 00000000..eb33630c --- /dev/null +++ b/x/wasm/keeper/handler_plugin_encoders_test.go @@ -0,0 +1,932 @@ +package keeper + +import ( + "testing" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/assert" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestEncoding(t *testing.T) { + var ( + addr1 = RandomAccountAddress(t) + addr2 = RandomAccountAddress(t) + addr3 = RandomAccountAddress(t) + invalidAddr = "xrnd1d02kd90n38qvr3qb9qof83fn2d2" + ) + valAddr := make(sdk.ValAddress, types.SDKAddrLen) + valAddr[0] = 12 + valAddr2 := make(sdk.ValAddress, types.SDKAddrLen) + valAddr2[1] = 123 + + jsonMsg := types.RawContractMessage(`{"foo": 123}`) + + bankMsg := &banktypes.MsgSend{ + FromAddress: addr2.String(), + ToAddress: addr1.String(), + Amount: sdk.Coins{ + sdk.NewInt64Coin("uatom", 12345), + sdk.NewInt64Coin("utgd", 54321), + }, + } + bankMsgBin, err := proto.Marshal(bankMsg) + require.NoError(t, err) + + content, err := codectypes.NewAnyWithValue(types.StoreCodeProposalFixture()) + require.NoError(t, err) + + proposalMsg := &govtypes.MsgSubmitProposal{ + Proposer: addr1.String(), + InitialDeposit: sdk.NewCoins(sdk.NewInt64Coin("uatom", 12345)), + Content: content, + } + proposalMsgBin, err := proto.Marshal(proposalMsg) + require.NoError(t, err) + + cases := map[string]struct { + sender sdk.AccAddress + srcMsg wasmvmtypes.CosmosMsg + srcContractIBCPort string + transferPortSource types.ICS20TransferPortSource + // set if valid + output []sdk.Msg + // set if expect mapping fails + expError bool + // set if sdk validate basic should fail + expInvalid bool + }{ + "simple send": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: addr2.String(), + Amount: []wasmvmtypes.Coin{ + { + Denom: "uatom", + Amount: "12345", + }, + { + Denom: "usdt", + Amount: "54321", + }, + }, + }, + }, + }, + output: []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: addr1.String(), + ToAddress: addr2.String(), + Amount: sdk.Coins{ + sdk.NewInt64Coin("uatom", 12345), + sdk.NewInt64Coin("usdt", 54321), + }, + }, + }, + }, + "invalid send amount": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: addr2.String(), + Amount: []wasmvmtypes.Coin{ + { + Denom: "uatom", + Amount: "123.456", + }, + }, + }, + }, + }, + expError: true, + }, + "invalid address": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: invalidAddr, + Amount: []wasmvmtypes.Coin{ + { + Denom: "uatom", + Amount: "7890", + }, + }, + }, + }, + }, + expError: false, // addresses are checked in the handler + expInvalid: true, + output: []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: addr1.String(), + ToAddress: invalidAddr, + Amount: sdk.Coins{ + sdk.NewInt64Coin("uatom", 7890), + }, + }, + }, + }, + "wasm execute": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: addr2.String(), + Msg: jsonMsg, + Funds: []wasmvmtypes.Coin{ + wasmvmtypes.NewCoin(12, "eth"), + }, + }, + }, + }, + output: []sdk.Msg{ + &types.MsgExecuteContract{ + Sender: addr1.String(), + Contract: addr2.String(), + Msg: jsonMsg, + Funds: sdk.NewCoins(sdk.NewInt64Coin("eth", 12)), + }, + }, + }, + "wasm instantiate": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Instantiate: &wasmvmtypes.InstantiateMsg{ + CodeID: 7, + Msg: jsonMsg, + Funds: []wasmvmtypes.Coin{ + wasmvmtypes.NewCoin(123, "eth"), + }, + Label: "myLabel", + Admin: addr2.String(), + }, + }, + }, + output: []sdk.Msg{ + &types.MsgInstantiateContract{ + Sender: addr1.String(), + CodeID: 7, + Label: "myLabel", + Msg: jsonMsg, + Funds: sdk.NewCoins(sdk.NewInt64Coin("eth", 123)), + Admin: addr2.String(), + }, + }, + }, + "wasm instantiate2": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Instantiate2: &wasmvmtypes.Instantiate2Msg{ + CodeID: 7, + Msg: jsonMsg, + Funds: []wasmvmtypes.Coin{ + wasmvmtypes.NewCoin(123, "eth"), + }, + Label: "myLabel", + Admin: addr2.String(), + Salt: []byte("mySalt"), + }, + }, + }, + output: []sdk.Msg{ + &types.MsgInstantiateContract2{ + Sender: addr1.String(), + Admin: addr2.String(), + CodeID: 7, + Label: "myLabel", + Msg: jsonMsg, + Funds: sdk.NewCoins(sdk.NewInt64Coin("eth", 123)), + Salt: []byte("mySalt"), + FixMsg: false, + }, + }, + }, + "wasm migrate": { + sender: addr2, + srcMsg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Migrate: &wasmvmtypes.MigrateMsg{ + ContractAddr: addr1.String(), + NewCodeID: 12, + Msg: jsonMsg, + }, + }, + }, + output: []sdk.Msg{ + &types.MsgMigrateContract{ + Sender: addr2.String(), + Contract: addr1.String(), + CodeID: 12, + Msg: jsonMsg, + }, + }, + }, + "wasm update admin": { + sender: addr2, + srcMsg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + UpdateAdmin: &wasmvmtypes.UpdateAdminMsg{ + ContractAddr: addr1.String(), + Admin: addr3.String(), + }, + }, + }, + output: []sdk.Msg{ + &types.MsgUpdateAdmin{ + Sender: addr2.String(), + Contract: addr1.String(), + NewAdmin: addr3.String(), + }, + }, + }, + "wasm clear admin": { + sender: addr2, + srcMsg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + ClearAdmin: &wasmvmtypes.ClearAdminMsg{ + ContractAddr: addr1.String(), + }, + }, + }, + output: []sdk.Msg{ + &types.MsgClearAdmin{ + Sender: addr2.String(), + Contract: addr1.String(), + }, + }, + }, + "staking delegate": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Staking: &wasmvmtypes.StakingMsg{ + Delegate: &wasmvmtypes.DelegateMsg{ + Validator: valAddr.String(), + Amount: wasmvmtypes.NewCoin(777, "stake"), + }, + }, + }, + output: []sdk.Msg{ + &stakingtypes.MsgDelegate{ + DelegatorAddress: addr1.String(), + ValidatorAddress: valAddr.String(), + Amount: sdk.NewInt64Coin("stake", 777), + }, + }, + }, + "staking delegate to non-validator": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Staking: &wasmvmtypes.StakingMsg{ + Delegate: &wasmvmtypes.DelegateMsg{ + Validator: addr2.String(), + Amount: wasmvmtypes.NewCoin(777, "stake"), + }, + }, + }, + expError: false, // fails in the handler + output: []sdk.Msg{ + &stakingtypes.MsgDelegate{ + DelegatorAddress: addr1.String(), + ValidatorAddress: addr2.String(), + Amount: sdk.NewInt64Coin("stake", 777), + }, + }, + }, + "staking undelegate": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Staking: &wasmvmtypes.StakingMsg{ + Undelegate: &wasmvmtypes.UndelegateMsg{ + Validator: valAddr.String(), + Amount: wasmvmtypes.NewCoin(555, "stake"), + }, + }, + }, + output: []sdk.Msg{ + &stakingtypes.MsgUndelegate{ + DelegatorAddress: addr1.String(), + ValidatorAddress: valAddr.String(), + Amount: sdk.NewInt64Coin("stake", 555), + }, + }, + }, + "staking redelegate": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Staking: &wasmvmtypes.StakingMsg{ + Redelegate: &wasmvmtypes.RedelegateMsg{ + SrcValidator: valAddr.String(), + DstValidator: valAddr2.String(), + Amount: wasmvmtypes.NewCoin(222, "stake"), + }, + }, + }, + output: []sdk.Msg{ + &stakingtypes.MsgBeginRedelegate{ + DelegatorAddress: addr1.String(), + ValidatorSrcAddress: valAddr.String(), + ValidatorDstAddress: valAddr2.String(), + Amount: sdk.NewInt64Coin("stake", 222), + }, + }, + }, + "staking withdraw (explicit recipient)": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Distribution: &wasmvmtypes.DistributionMsg{ + WithdrawDelegatorReward: &wasmvmtypes.WithdrawDelegatorRewardMsg{ + Validator: valAddr2.String(), + }, + }, + }, + output: []sdk.Msg{ + &distributiontypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: addr1.String(), + ValidatorAddress: valAddr2.String(), + }, + }, + }, + "staking set withdraw address": { + sender: addr1, + srcMsg: wasmvmtypes.CosmosMsg{ + Distribution: &wasmvmtypes.DistributionMsg{ + SetWithdrawAddress: &wasmvmtypes.SetWithdrawAddressMsg{ + Address: addr2.String(), + }, + }, + }, + output: []sdk.Msg{ + &distributiontypes.MsgSetWithdrawAddress{ + DelegatorAddress: addr1.String(), + WithdrawAddress: addr2.String(), + }, + }, + }, + "stargate encoded bank msg": { + sender: addr2, + srcMsg: wasmvmtypes.CosmosMsg{ + Stargate: &wasmvmtypes.StargateMsg{ + TypeURL: "/cosmos.bank.v1beta1.MsgSend", + Value: bankMsgBin, + }, + }, + output: []sdk.Msg{bankMsg}, + }, + "stargate encoded msg with any type": { + sender: addr2, + srcMsg: wasmvmtypes.CosmosMsg{ + Stargate: &wasmvmtypes.StargateMsg{ + TypeURL: "/cosmos.gov.v1beta1.MsgSubmitProposal", + Value: proposalMsgBin, + }, + }, + output: []sdk.Msg{proposalMsg}, + }, + "stargate encoded invalid typeUrl": { + sender: addr2, + srcMsg: wasmvmtypes.CosmosMsg{ + Stargate: &wasmvmtypes.StargateMsg{ + TypeURL: "/cosmos.bank.v2.MsgSend", + Value: bankMsgBin, + }, + }, + expError: true, + }, + "IBC transfer with block timeout": { + sender: addr1, + srcContractIBCPort: "myIBCPort", + srcMsg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + Transfer: &wasmvmtypes.TransferMsg{ + ChannelID: "myChanID", + ToAddress: addr2.String(), + Amount: wasmvmtypes.Coin{ + Denom: "ALX", + Amount: "1", + }, + Timeout: wasmvmtypes.IBCTimeout{ + Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 2}, + }, + }, + }, + }, + transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "myTransferPort" + }}, + output: []sdk.Msg{ + &ibctransfertypes.MsgTransfer{ + SourcePort: "myTransferPort", + SourceChannel: "myChanID", + Token: sdk.Coin{ + Denom: "ALX", + Amount: sdk.NewInt(1), + }, + Sender: addr1.String(), + Receiver: addr2.String(), + TimeoutHeight: clienttypes.Height{RevisionNumber: 1, RevisionHeight: 2}, + }, + }, + }, + "IBC transfer with time timeout": { + sender: addr1, + srcContractIBCPort: "myIBCPort", + srcMsg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + Transfer: &wasmvmtypes.TransferMsg{ + ChannelID: "myChanID", + ToAddress: addr2.String(), + Amount: wasmvmtypes.Coin{ + Denom: "ALX", + Amount: "1", + }, + Timeout: wasmvmtypes.IBCTimeout{Timestamp: 100}, + }, + }, + }, + transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "transfer" + }}, + output: []sdk.Msg{ + &ibctransfertypes.MsgTransfer{ + SourcePort: "transfer", + SourceChannel: "myChanID", + Token: sdk.Coin{ + Denom: "ALX", + Amount: sdk.NewInt(1), + }, + Sender: addr1.String(), + Receiver: addr2.String(), + TimeoutTimestamp: 100, + }, + }, + }, + "IBC transfer with time and height timeout": { + sender: addr1, + srcContractIBCPort: "myIBCPort", + srcMsg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + Transfer: &wasmvmtypes.TransferMsg{ + ChannelID: "myChanID", + ToAddress: addr2.String(), + Amount: wasmvmtypes.Coin{ + Denom: "ALX", + Amount: "1", + }, + Timeout: wasmvmtypes.IBCTimeout{Timestamp: 100, Block: &wasmvmtypes.IBCTimeoutBlock{Height: 1, Revision: 2}}, + }, + }, + }, + transferPortSource: wasmtesting.MockIBCTransferKeeper{GetPortFn: func(ctx sdk.Context) string { + return "transfer" + }}, + output: []sdk.Msg{ + &ibctransfertypes.MsgTransfer{ + SourcePort: "transfer", + SourceChannel: "myChanID", + Token: sdk.Coin{ + Denom: "ALX", + Amount: sdk.NewInt(1), + }, + Sender: addr1.String(), + Receiver: addr2.String(), + TimeoutTimestamp: 100, + TimeoutHeight: clienttypes.NewHeight(2, 1), + }, + }, + }, + "IBC close channel": { + sender: addr1, + srcContractIBCPort: "myIBCPort", + srcMsg: wasmvmtypes.CosmosMsg{ + IBC: &wasmvmtypes.IBCMsg{ + CloseChannel: &wasmvmtypes.CloseChannelMsg{ + ChannelID: "channel-1", + }, + }, + }, + output: []sdk.Msg{ + &channeltypes.MsgChannelCloseInit{ + PortId: "wasm." + addr1.String(), + ChannelId: "channel-1", + Signer: addr1.String(), + }, + }, + }, + } + encodingConfig := MakeEncodingConfig(t) + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + var ctx sdk.Context + encoder := DefaultEncoders(encodingConfig.Marshaler, tc.transferPortSource) + res, err := encoder.Encode(ctx, tc.sender, tc.srcContractIBCPort, tc.srcMsg) + if tc.expError { + assert.Error(t, err) + return + } else { + require.NoError(t, err) + assert.Equal(t, tc.output, res) + } + // and valid sdk message + for _, v := range res { + gotErr := v.ValidateBasic() + if tc.expInvalid { + assert.Error(t, gotErr) + } else { + assert.NoError(t, gotErr) + } + } + }) + } +} + +func TestEncodeGovMsg(t *testing.T) { + myAddr := RandomAccountAddress(t) + + cases := map[string]struct { + sender sdk.AccAddress + srcMsg wasmvmtypes.CosmosMsg + transferPortSource types.ICS20TransferPortSource + // set if valid + output []sdk.Msg + // set if expect mapping fails + expError bool + // set if sdk validate basic should fail + expInvalid bool + }{ + "Gov vote: yes": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.Yes}, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVote{ + ProposalId: 1, + Voter: myAddr.String(), + Option: govtypes.OptionYes, + }, + }, + }, + "Gov vote: No": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.No}, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVote{ + ProposalId: 1, + Voter: myAddr.String(), + Option: govtypes.OptionNo, + }, + }, + }, + "Gov vote: Abstain": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + Vote: &wasmvmtypes.VoteMsg{ProposalId: 10, Vote: wasmvmtypes.Abstain}, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVote{ + ProposalId: 10, + Voter: myAddr.String(), + Option: govtypes.OptionAbstain, + }, + }, + }, + "Gov vote: No with veto": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1, Vote: wasmvmtypes.NoWithVeto}, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVote{ + ProposalId: 1, + Voter: myAddr.String(), + Option: govtypes.OptionNoWithVeto, + }, + }, + }, + "Gov vote: unset option": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + Vote: &wasmvmtypes.VoteMsg{ProposalId: 1}, + }, + }, + expError: true, + }, + "Gov weighted vote: single vote": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + VoteWeighted: &wasmvmtypes.VoteWeightedMsg{ + ProposalId: 1, + Options: []wasmvmtypes.WeightedVoteOption{ + {Option: wasmvmtypes.Yes, Weight: "1"}, + }, + }, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVoteWeighted{ + ProposalId: 1, + Voter: myAddr.String(), + Options: []govtypes.WeightedVoteOption{ + {Option: govtypes.OptionYes, Weight: sdk.NewDec(1)}, + }, + }, + }, + }, + "Gov weighted vote: splitted": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + VoteWeighted: &wasmvmtypes.VoteWeightedMsg{ + ProposalId: 1, + Options: []wasmvmtypes.WeightedVoteOption{ + {Option: wasmvmtypes.Yes, Weight: "0.23"}, + {Option: wasmvmtypes.No, Weight: "0.24"}, + {Option: wasmvmtypes.Abstain, Weight: "0.26"}, + {Option: wasmvmtypes.NoWithVeto, Weight: "0.27"}, + }, + }, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVoteWeighted{ + ProposalId: 1, + Voter: myAddr.String(), + Options: []govtypes.WeightedVoteOption{ + {Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(23, 2)}, + {Option: govtypes.OptionNo, Weight: sdk.NewDecWithPrec(24, 2)}, + {Option: govtypes.OptionAbstain, Weight: sdk.NewDecWithPrec(26, 2)}, + {Option: govtypes.OptionNoWithVeto, Weight: sdk.NewDecWithPrec(27, 2)}, + }, + }, + }, + }, + "Gov weighted vote: duplicate option": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + VoteWeighted: &wasmvmtypes.VoteWeightedMsg{ + ProposalId: 1, + Options: []wasmvmtypes.WeightedVoteOption{ + {Option: wasmvmtypes.Yes, Weight: "0.5"}, + {Option: wasmvmtypes.Yes, Weight: "0.5"}, + }, + }, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVoteWeighted{ + ProposalId: 1, + Voter: myAddr.String(), + Options: []govtypes.WeightedVoteOption{ + {Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(5, 1)}, + {Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(5, 1)}, + }, + }, + }, + expInvalid: true, + }, + "Gov weighted vote: weight sum exceeds 1": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + VoteWeighted: &wasmvmtypes.VoteWeightedMsg{ + ProposalId: 1, + Options: []wasmvmtypes.WeightedVoteOption{ + {Option: wasmvmtypes.Yes, Weight: "0.51"}, + {Option: wasmvmtypes.No, Weight: "0.5"}, + }, + }, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVoteWeighted{ + ProposalId: 1, + Voter: myAddr.String(), + Options: []govtypes.WeightedVoteOption{ + {Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(51, 2)}, + {Option: govtypes.OptionNo, Weight: sdk.NewDecWithPrec(5, 1)}, + }, + }, + }, + expInvalid: true, + }, + "Gov weighted vote: weight sum less than 1": { + sender: myAddr, + srcMsg: wasmvmtypes.CosmosMsg{ + Gov: &wasmvmtypes.GovMsg{ + VoteWeighted: &wasmvmtypes.VoteWeightedMsg{ + ProposalId: 1, + Options: []wasmvmtypes.WeightedVoteOption{ + {Option: wasmvmtypes.Yes, Weight: "0.49"}, + {Option: wasmvmtypes.No, Weight: "0.5"}, + }, + }, + }, + }, + output: []sdk.Msg{ + &govtypes.MsgVoteWeighted{ + ProposalId: 1, + Voter: myAddr.String(), + Options: []govtypes.WeightedVoteOption{ + {Option: govtypes.OptionYes, Weight: sdk.NewDecWithPrec(49, 2)}, + {Option: govtypes.OptionNo, Weight: sdk.NewDecWithPrec(5, 1)}, + }, + }, + }, + expInvalid: true, + }, + } + encodingConfig := MakeEncodingConfig(t) + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + var ctx sdk.Context + encoder := DefaultEncoders(encodingConfig.Marshaler, tc.transferPortSource) + res, gotEncErr := encoder.Encode(ctx, tc.sender, "myIBCPort", tc.srcMsg) + if tc.expError { + assert.Error(t, gotEncErr) + return + } else { + require.NoError(t, gotEncErr) + assert.Equal(t, tc.output, res) + } + // and valid sdk message + for _, v := range res { + gotErr := v.ValidateBasic() + if tc.expInvalid { + assert.Error(t, gotErr) + } else { + assert.NoError(t, gotErr) + } + } + }) + } +} + +func TestConvertWasmCoinToSdkCoin(t *testing.T) { + specs := map[string]struct { + src wasmvmtypes.Coin + expErr bool + expVal sdk.Coin + }{ + "all good": { + src: wasmvmtypes.Coin{ + Denom: "foo", + Amount: "1", + }, + expVal: sdk.NewCoin("foo", sdk.NewIntFromUint64(1)), + }, + "negative amount": { + src: wasmvmtypes.Coin{ + Denom: "foo", + Amount: "-1", + }, + expErr: true, + }, + "denom to short": { + src: wasmvmtypes.Coin{ + Denom: "f", + Amount: "1", + }, + expErr: true, + }, + "invalid demum char": { + src: wasmvmtypes.Coin{ + Denom: "&fff", + Amount: "1", + }, + expErr: true, + }, + "not a number amount": { + src: wasmvmtypes.Coin{ + Denom: "foo", + Amount: "bar", + }, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotVal, gotErr := ConvertWasmCoinToSdkCoin(spec.src) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expVal, gotVal) + }) + } +} + +func TestConvertWasmCoinsToSdkCoins(t *testing.T) { + specs := map[string]struct { + src []wasmvmtypes.Coin + exp sdk.Coins + expErr bool + }{ + "empty": { + src: []wasmvmtypes.Coin{}, + exp: nil, + }, + "single coin": { + src: []wasmvmtypes.Coin{{Denom: "foo", Amount: "1"}}, + exp: sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1))), + }, + "multiple coins": { + src: []wasmvmtypes.Coin{ + {Denom: "foo", Amount: "1"}, + {Denom: "bar", Amount: "2"}, + }, + exp: sdk.NewCoins( + sdk.NewCoin("bar", sdk.NewInt(2)), + sdk.NewCoin("foo", sdk.NewInt(1)), + ), + }, + "sorted": { + src: []wasmvmtypes.Coin{ + {Denom: "foo", Amount: "1"}, + {Denom: "other", Amount: "1"}, + {Denom: "bar", Amount: "1"}, + }, + exp: []sdk.Coin{ + sdk.NewCoin("bar", sdk.NewInt(1)), + sdk.NewCoin("foo", sdk.NewInt(1)), + sdk.NewCoin("other", sdk.NewInt(1)), + }, + }, + "zero amounts dropped": { + src: []wasmvmtypes.Coin{ + {Denom: "foo", Amount: "1"}, + {Denom: "bar", Amount: "0"}, + }, + exp: sdk.NewCoins( + sdk.NewCoin("foo", sdk.NewInt(1)), + ), + }, + "duplicate denoms merged": { + src: []wasmvmtypes.Coin{ + {Denom: "foo", Amount: "1"}, + {Denom: "foo", Amount: "1"}, + }, + exp: []sdk.Coin{sdk.NewCoin("foo", sdk.NewInt(2))}, + }, + "duplicate denoms with one 0 amount does not fail": { + src: []wasmvmtypes.Coin{ + {Denom: "foo", Amount: "0"}, + {Denom: "foo", Amount: "1"}, + }, + exp: []sdk.Coin{sdk.NewCoin("foo", sdk.NewInt(1))}, + }, + "empty denom rejected": { + src: []wasmvmtypes.Coin{{Denom: "", Amount: "1"}}, + expErr: true, + }, + "invalid denom rejected": { + src: []wasmvmtypes.Coin{{Denom: "!%&", Amount: "1"}}, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotCoins, gotErr := ConvertWasmCoinsToSdkCoins(spec.src) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.exp, gotCoins) + assert.NoError(t, gotCoins.Validate()) + }) + } +} diff --git a/x/wasm/keeper/handler_plugin_test.go b/x/wasm/keeper/handler_plugin_test.go new file mode 100644 index 00000000..b1a76d69 --- /dev/null +++ b/x/wasm/keeper/handler_plugin_test.go @@ -0,0 +1,410 @@ +package keeper + +import ( + "encoding/json" + "testing" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/baseapp" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + clienttypes "github.com/cosmos/ibc-go/v4/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + ibcexported "github.com/cosmos/ibc-go/v4/modules/core/exported" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestMessageHandlerChainDispatch(t *testing.T) { + capturingHandler, gotMsgs := wasmtesting.NewCapturingMessageHandler() + + alwaysUnknownMsgHandler := &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, types.ErrUnknownMsg + }, + } + + assertNotCalledHandler := &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + t.Fatal("not expected to be called") + return + }, + } + + myMsg := wasmvmtypes.CosmosMsg{Custom: []byte(`{}`)} + specs := map[string]struct { + handlers []Messenger + expErr *sdkerrors.Error + expEvents []sdk.Event + }{ + "single handler": { + handlers: []Messenger{capturingHandler}, + }, + "passed to next handler": { + handlers: []Messenger{alwaysUnknownMsgHandler, capturingHandler}, + }, + "stops iteration when handled": { + handlers: []Messenger{capturingHandler, assertNotCalledHandler}, + }, + "stops iteration on handler error": { + handlers: []Messenger{&wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, types.ErrInvalidMsg + }, + }, assertNotCalledHandler}, + expErr: types.ErrInvalidMsg, + }, + "return events when handle": { + handlers: []Messenger{ + &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + _, data, _ = capturingHandler.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg) + return []sdk.Event{sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar"))}, data, nil + }, + }, + }, + expEvents: []sdk.Event{sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar"))}, + }, + "return error when none can handle": { + handlers: []Messenger{alwaysUnknownMsgHandler}, + expErr: types.ErrUnknownMsg, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + *gotMsgs = make([]wasmvmtypes.CosmosMsg, 0) + + // when + h := MessageHandlerChain{spec.handlers} + gotEvents, gotData, gotErr := h.DispatchMsg(sdk.Context{}, RandomAccountAddress(t), "anyPort", myMsg) + + // then + require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) + if spec.expErr != nil { + return + } + assert.Equal(t, []wasmvmtypes.CosmosMsg{myMsg}, *gotMsgs) + assert.Equal(t, [][]byte{{1}}, gotData) // {1} is default in capturing handler + assert.Equal(t, spec.expEvents, gotEvents) + }) + } +} + +func TestSDKMessageHandlerDispatch(t *testing.T) { + myEvent := sdk.NewEvent("myEvent", sdk.NewAttribute("foo", "bar")) + const myData = "myData" + myRouterResult := sdk.Result{ + Data: []byte(myData), + Events: sdk.Events{myEvent}.ToABCIEvents(), + } + + var gotMsg []sdk.Msg + capturingMessageRouter := wasmtesting.MessageRouterFunc(func(msg sdk.Msg) baseapp.MsgServiceHandler { + return func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error) { + gotMsg = append(gotMsg, msg) + return &myRouterResult, nil + } + }) + noRouteMessageRouter := wasmtesting.MessageRouterFunc(func(msg sdk.Msg) baseapp.MsgServiceHandler { + return nil + }) + myContractAddr := RandomAccountAddress(t) + myContractMessage := wasmvmtypes.CosmosMsg{Custom: []byte("{}")} + + specs := map[string]struct { + srcRoute MessageRouter + srcEncoder CustomEncoder + expErr *sdkerrors.Error + expMsgDispatched int + }{ + "all good": { + srcRoute: capturingMessageRouter, + srcEncoder: func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + myMsg := types.MsgExecuteContract{ + Sender: myContractAddr.String(), + Contract: RandomBech32AccountAddress(t), + Msg: []byte("{}"), + } + return []sdk.Msg{&myMsg}, nil + }, + expMsgDispatched: 1, + }, + "multiple output msgs": { + srcRoute: capturingMessageRouter, + srcEncoder: func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + first := &types.MsgExecuteContract{ + Sender: myContractAddr.String(), + Contract: RandomBech32AccountAddress(t), + Msg: []byte("{}"), + } + second := &types.MsgExecuteContract{ + Sender: myContractAddr.String(), + Contract: RandomBech32AccountAddress(t), + Msg: []byte("{}"), + } + return []sdk.Msg{first, second}, nil + }, + expMsgDispatched: 2, + }, + "invalid sdk message rejected": { + srcRoute: capturingMessageRouter, + srcEncoder: func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + invalidMsg := types.MsgExecuteContract{ + Sender: myContractAddr.String(), + Contract: RandomBech32AccountAddress(t), + Msg: []byte("INVALID_JSON"), + } + return []sdk.Msg{&invalidMsg}, nil + }, + expErr: types.ErrInvalid, + }, + "invalid sender rejected": { + srcRoute: capturingMessageRouter, + srcEncoder: func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + invalidMsg := types.MsgExecuteContract{ + Sender: RandomBech32AccountAddress(t), + Contract: RandomBech32AccountAddress(t), + Msg: []byte("{}"), + } + return []sdk.Msg{&invalidMsg}, nil + }, + expErr: sdkerrors.ErrUnauthorized, + }, + "unroutable message rejected": { + srcRoute: noRouteMessageRouter, + srcEncoder: func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + myMsg := types.MsgExecuteContract{ + Sender: myContractAddr.String(), + Contract: RandomBech32AccountAddress(t), + Msg: []byte("{}"), + } + return []sdk.Msg{&myMsg}, nil + }, + expErr: sdkerrors.ErrUnknownRequest, + }, + "encoding error passed": { + srcRoute: capturingMessageRouter, + srcEncoder: func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + myErr := types.ErrUnpinContractFailed // any error that is not used + return nil, myErr + }, + expErr: types.ErrUnpinContractFailed, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotMsg = make([]sdk.Msg, 0) + + // when + ctx := sdk.Context{} + h := NewSDKMessageHandler(spec.srcRoute, MessageEncoders{Custom: spec.srcEncoder}) + gotEvents, gotData, gotErr := h.DispatchMsg(ctx, myContractAddr, "myPort", myContractMessage) + + // then + require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) + if spec.expErr != nil { + require.Len(t, gotMsg, 0) + return + } + assert.Len(t, gotMsg, spec.expMsgDispatched) + for i := 0; i < spec.expMsgDispatched; i++ { + assert.Equal(t, myEvent, gotEvents[i]) + assert.Equal(t, []byte(myData), gotData[i]) + } + }) + } +} + +func TestIBCRawPacketHandler(t *testing.T) { + ibcPort := "contractsIBCPort" + var ctx sdk.Context + + var capturedPacket ibcexported.PacketI + + chanKeeper := &wasmtesting.MockChannelKeeper{ + GetNextSequenceSendFn: func(ctx sdk.Context, portID, channelID string) (uint64, bool) { + return 1, true + }, + GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channeltypes.Channel, bool) { + return channeltypes.Channel{ + Counterparty: channeltypes.NewCounterparty( + "other-port", + "other-channel-1", + ), + }, true + }, + SendPacketFn: func(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error { + capturedPacket = packet + return nil + }, + } + capKeeper := &wasmtesting.MockCapabilityKeeper{ + GetCapabilityFn: func(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) { + return &capabilitytypes.Capability{}, true + }, + } + + specs := map[string]struct { + srcMsg wasmvmtypes.SendPacketMsg + chanKeeper types.ChannelKeeper + capKeeper types.CapabilityKeeper + expPacketSent channeltypes.Packet + expErr *sdkerrors.Error + }{ + "all good": { + srcMsg: wasmvmtypes.SendPacketMsg{ + ChannelID: "channel-1", + Data: []byte("myData"), + Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 2}}, + }, + chanKeeper: chanKeeper, + capKeeper: capKeeper, + expPacketSent: channeltypes.Packet{ + Sequence: 1, + SourcePort: ibcPort, + SourceChannel: "channel-1", + DestinationPort: "other-port", + DestinationChannel: "other-channel-1", + Data: []byte("myData"), + TimeoutHeight: clienttypes.Height{RevisionNumber: 1, RevisionHeight: 2}, + }, + }, + "sequence not found returns error": { + srcMsg: wasmvmtypes.SendPacketMsg{ + ChannelID: "channel-1", + Data: []byte("myData"), + Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 2}}, + }, + chanKeeper: &wasmtesting.MockChannelKeeper{ + GetNextSequenceSendFn: func(ctx sdk.Context, portID, channelID string) (uint64, bool) { + return 0, false + }, + }, + expErr: channeltypes.ErrSequenceSendNotFound, + }, + "capability not found returns error": { + srcMsg: wasmvmtypes.SendPacketMsg{ + ChannelID: "channel-1", + Data: []byte("myData"), + Timeout: wasmvmtypes.IBCTimeout{Block: &wasmvmtypes.IBCTimeoutBlock{Revision: 1, Height: 2}}, + }, + chanKeeper: chanKeeper, + capKeeper: wasmtesting.MockCapabilityKeeper{ + GetCapabilityFn: func(ctx sdk.Context, name string) (*capabilitytypes.Capability, bool) { + return nil, false + }, + }, + expErr: channeltypes.ErrChannelCapabilityNotFound, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + capturedPacket = nil + // when + h := NewIBCRawPacketHandler(spec.chanKeeper, spec.capKeeper) + data, evts, gotErr := h.DispatchMsg(ctx, RandomAccountAddress(t), ibcPort, wasmvmtypes.CosmosMsg{IBC: &wasmvmtypes.IBCMsg{SendPacket: &spec.srcMsg}}) + // then + require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) + if spec.expErr != nil { + return + } + assert.Nil(t, data) + assert.Nil(t, evts) + assert.Equal(t, spec.expPacketSent, capturedPacket) + }) + } +} + +func TestBurnCoinMessageHandlerIntegration(t *testing.T) { + // testing via full keeper setup so that we are confident the + // module permissions are set correct and no other handler + // picks the message in the default handler chain + ctx, keepers := CreateDefaultTestInput(t) + // set some supply + keepers.Faucet.NewFundedRandomAccount(ctx, sdk.NewCoin("denom", sdk.NewInt(10_000_000))) + k := keepers.WasmKeeper + + example := InstantiateHackatomExampleContract(t, ctx, keepers) // with deposit of 100 stake + + before, err := keepers.BankKeeper.TotalSupply(sdk.WrapSDKContext(ctx), &banktypes.QueryTotalSupplyRequest{}) + require.NoError(t, err) + + specs := map[string]struct { + msg wasmvmtypes.BurnMsg + expErr bool + }{ + "all good": { + msg: wasmvmtypes.BurnMsg{ + Amount: wasmvmtypes.Coins{{ + Denom: "denom", + Amount: "100", + }}, + }, + }, + "not enough funds in contract": { + msg: wasmvmtypes.BurnMsg{ + Amount: wasmvmtypes.Coins{{ + Denom: "denom", + Amount: "101", + }}, + }, + expErr: true, + }, + "zero amount rejected": { + msg: wasmvmtypes.BurnMsg{ + Amount: wasmvmtypes.Coins{{ + Denom: "denom", + Amount: "0", + }}, + }, + expErr: true, + }, + "unknown denom - insufficient funds": { + msg: wasmvmtypes.BurnMsg{ + Amount: wasmvmtypes.Coins{{ + Denom: "unknown", + Amount: "1", + }}, + }, + expErr: true, + }, + } + parentCtx := ctx + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ = parentCtx.CacheContext() + k.wasmVM = &wasmtesting.MockWasmer{ExecuteFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + {Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{Burn: &spec.msg}}, ReplyOn: wasmvmtypes.ReplyNever}, + }, + }, 0, nil + }} + + // when + _, err = k.execute(ctx, example.Contract, example.CreatorAddr, nil, nil) + + // then + if spec.expErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + // and total supply reduced by burned amount + after, err := keepers.BankKeeper.TotalSupply(sdk.WrapSDKContext(ctx), &banktypes.QueryTotalSupplyRequest{}) + require.NoError(t, err) + diff := before.Supply.Sub(after.Supply) + assert.Equal(t, sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(100))), diff) + }) + } + + // test cases: + // not enough money to burn +} diff --git a/x/wasm/keeper/ibc.go b/x/wasm/keeper/ibc.go new file mode 100644 index 00000000..62cbcc2e --- /dev/null +++ b/x/wasm/keeper/ibc.go @@ -0,0 +1,56 @@ +package keeper + +import ( + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + host "github.com/cosmos/ibc-go/v4/modules/core/24-host" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// bindIbcPort will reserve the port. +// returns a string name of the port or error if we cannot bind it. +// this will fail if call twice. +func (k Keeper) bindIbcPort(ctx sdk.Context, portID string) error { + cap := k.portKeeper.BindPort(ctx, portID) + return k.ClaimCapability(ctx, cap, host.PortPath(portID)) +} + +// ensureIbcPort is like registerIbcPort, but it checks if we already hold the port +// before calling register, so this is safe to call multiple times. +// Returns success if we already registered or just registered and error if we cannot +// (lack of permissions or someone else has it) +func (k Keeper) ensureIbcPort(ctx sdk.Context, contractAddr sdk.AccAddress) (string, error) { + portID := PortIDForContract(contractAddr) + if _, ok := k.capabilityKeeper.GetCapability(ctx, host.PortPath(portID)); ok { + return portID, nil + } + return portID, k.bindIbcPort(ctx, portID) +} + +const portIDPrefix = "wasm." + +func PortIDForContract(addr sdk.AccAddress) string { + return portIDPrefix + addr.String() +} + +func ContractFromPortID(portID string) (sdk.AccAddress, error) { + if !strings.HasPrefix(portID, portIDPrefix) { + return nil, sdkerrors.Wrapf(types.ErrInvalid, "without prefix") + } + return sdk.AccAddressFromBech32(portID[len(portIDPrefix):]) +} + +// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function +func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool { + return k.capabilityKeeper.AuthenticateCapability(ctx, cap, name) +} + +// ClaimCapability allows the transfer module to claim a capability +// that IBC module passes to it +func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error { + return k.capabilityKeeper.ClaimCapability(ctx, cap, name) +} diff --git a/x/wasm/keeper/ibc_test.go b/x/wasm/keeper/ibc_test.go new file mode 100644 index 00000000..063dfb7f --- /dev/null +++ b/x/wasm/keeper/ibc_test.go @@ -0,0 +1,82 @@ +package keeper + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" +) + +func TestDontBindPortNonIBCContract(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example := InstantiateHackatomExampleContract(t, ctx, keepers) // ensure we bound the port + _, _, err := keepers.IBCKeeper.PortKeeper.LookupModuleByPort(ctx, keepers.WasmKeeper.GetContractInfo(ctx, example.Contract).IBCPortID) + require.Error(t, err) +} + +func TestBindingPortForIBCContractOnInstantiate(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example := InstantiateIBCReflectContract(t, ctx, keepers) // ensure we bound the port + owner, _, err := keepers.IBCKeeper.PortKeeper.LookupModuleByPort(ctx, keepers.WasmKeeper.GetContractInfo(ctx, example.Contract).IBCPortID) + require.NoError(t, err) + require.Equal(t, "wasm", owner) + + initMsgBz := IBCReflectInitMsg{ + ReflectCodeID: example.ReflectCodeID, + }.GetBytes(t) + + // create a second contract should give yet another portID (and different address) + creator := RandomAccountAddress(t) + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, example.CodeID, creator, nil, initMsgBz, "ibc-reflect-2", nil) + require.NoError(t, err) + require.NotEqual(t, example.Contract, addr) + + portID2 := PortIDForContract(addr) + owner, _, err = keepers.IBCKeeper.PortKeeper.LookupModuleByPort(ctx, portID2) + require.NoError(t, err) + require.Equal(t, "wasm", owner) +} + +func TestContractFromPortID(t *testing.T) { + contractAddr := BuildContractAddressClassic(1, 100) + specs := map[string]struct { + srcPort string + expAddr sdk.AccAddress + expErr bool + }{ + "all good": { + srcPort: fmt.Sprintf("wasm.%s", contractAddr.String()), + expAddr: contractAddr, + }, + "without prefix": { + srcPort: contractAddr.String(), + expErr: true, + }, + "invalid prefix": { + srcPort: fmt.Sprintf("wasmx.%s", contractAddr.String()), + expErr: true, + }, + "without separator char": { + srcPort: fmt.Sprintf("wasm%s", contractAddr.String()), + expErr: true, + }, + "invalid account": { + srcPort: "wasm.foobar", + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + gotAddr, gotErr := ContractFromPortID(spec.srcPort) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expAddr, gotAddr) + }) + } +} diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go new file mode 100644 index 00000000..98b90dea --- /dev/null +++ b/x/wasm/keeper/keeper.go @@ -0,0 +1,1188 @@ +package keeper + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/hex" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "time" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingexported "github.com/cosmos/cosmos-sdk/x/auth/vesting/exported" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cerc-io/laconicd/x/wasm/ioutils" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// contractMemoryLimit is the memory limit of each contract execution (in MiB) +// constant value so all nodes run with the same limit. +const contractMemoryLimit = 32 + +type contextKey int + +const ( + // private type creates an interface key for Context that cannot be accessed by any other package + contextKeyQueryStackSize contextKey = iota +) + +// Option is an extension point to instantiate keeper with non default values +type Option interface { + apply(*Keeper) +} + +// WasmVMQueryHandler is an extension point for custom query handler implementations +type WasmVMQueryHandler interface { + // HandleQuery executes the requested query + HandleQuery(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) +} + +type CoinTransferrer interface { + // TransferCoins sends the coin amounts from the source to the destination with rules applied. + TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error +} + +// AccountPruner handles the balances and data cleanup for accounts that are pruned on contract instantiate. +// This is an extension point to attach custom logic +type AccountPruner interface { + // CleanupExistingAccount handles the cleanup process for balances and data of the given account. The persisted account + // type is already reset to base account at this stage. + // The method returns true when the account address can be reused. Unsupported account types are rejected by returning false + CleanupExistingAccount(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) +} + +// WasmVMResponseHandler is an extension point to handles the response data returned by a contract call. +type WasmVMResponseHandler interface { + // Handle processes the data returned by a contract invocation. + Handle( + ctx sdk.Context, + contractAddr sdk.AccAddress, + ibcPort string, + messages []wasmvmtypes.SubMsg, + origRspData []byte, + ) ([]byte, error) +} + +// list of account types that are accepted for wasm contracts. Chains importing wasmd +// can overwrite this list with the WithAcceptedAccountTypesOnContractInstantiation option. +var defaultAcceptedAccountTypes = map[reflect.Type]struct{}{ + reflect.TypeOf(&authtypes.BaseAccount{}): {}, +} + +// Keeper will have a reference to Wasmer with it's own data directory. +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.Codec + accountKeeper types.AccountKeeper + bank CoinTransferrer + portKeeper types.PortKeeper + capabilityKeeper types.CapabilityKeeper + wasmVM types.WasmerEngine + wasmVMQueryHandler WasmVMQueryHandler + wasmVMResponseHandler WasmVMResponseHandler + messenger Messenger + // queryGasLimit is the max wasmvm gas that can be spent on executing a query with a contract + queryGasLimit uint64 + paramSpace paramtypes.Subspace + gasRegister GasRegister + maxQueryStackSize uint32 + acceptedAccountTypes map[reflect.Type]struct{} + accountPruner AccountPruner +} + +func (k Keeper) getUploadAccessConfig(ctx sdk.Context) types.AccessConfig { + var a types.AccessConfig + k.paramSpace.Get(ctx, types.ParamStoreKeyUploadAccess, &a) + return a +} + +func (k Keeper) getInstantiateAccessConfig(ctx sdk.Context) types.AccessType { + var a types.AccessType + k.paramSpace.Get(ctx, types.ParamStoreKeyInstantiateAccess, &a) + return a +} + +// GetParams returns the total set of wasm parameters. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + var params types.Params + k.paramSpace.GetParamSet(ctx, ¶ms) + return params +} + +func (k Keeper) SetParams(ctx sdk.Context, ps types.Params) { + k.paramSpace.SetParamSet(ctx, &ps) +} + +func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, instantiateAccess *types.AccessConfig, authZ AuthorizationPolicy) (codeID uint64, checksum []byte, err error) { + if creator == nil { + return 0, checksum, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "cannot be nil") + } + + // figure out proper instantiate access + defaultAccessConfig := k.getInstantiateAccessConfig(ctx).With(creator) + if instantiateAccess == nil { + instantiateAccess = &defaultAccessConfig + } + chainConfigs := ChainAccessConfigs{ + Instantiate: defaultAccessConfig, + Upload: k.getUploadAccessConfig(ctx), + } + + if !authZ.CanCreateCode(chainConfigs, creator, *instantiateAccess) { + return 0, checksum, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not create code") + } + + if ioutils.IsGzip(wasmCode) { + ctx.GasMeter().ConsumeGas(k.gasRegister.UncompressCosts(len(wasmCode)), "Uncompress gzip bytecode") + wasmCode, err = ioutils.Uncompress(wasmCode, uint64(types.MaxWasmSize)) + if err != nil { + return 0, checksum, sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + } + + ctx.GasMeter().ConsumeGas(k.gasRegister.CompileCosts(len(wasmCode)), "Compiling wasm bytecode") + checksum, err = k.wasmVM.Create(wasmCode) + if err != nil { + return 0, checksum, sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + report, err := k.wasmVM.AnalyzeCode(checksum) + if err != nil { + return 0, checksum, sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + codeID = k.autoIncrementID(ctx, types.KeyLastCodeID) + k.Logger(ctx).Debug("storing new contract", "capabilities", report.RequiredCapabilities, "code_id", codeID) + codeInfo := types.NewCodeInfo(checksum, creator, *instantiateAccess) + k.storeCodeInfo(ctx, codeID, codeInfo) + + evt := sdk.NewEvent( + types.EventTypeStoreCode, + sdk.NewAttribute(types.AttributeKeyChecksum, hex.EncodeToString(checksum)), + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), // last element to be compatible with scripts + ) + for _, f := range strings.Split(report.RequiredCapabilities, ",") { + evt.AppendAttributes(sdk.NewAttribute(types.AttributeKeyRequiredCapability, strings.TrimSpace(f))) + } + ctx.EventManager().EmitEvent(evt) + + return codeID, checksum, nil +} + +func (k Keeper) storeCodeInfo(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo) { + store := ctx.KVStore(k.storeKey) + // 0x01 | codeID (uint64) -> ContractInfo + store.Set(types.GetCodeKey(codeID), k.cdc.MustMarshal(&codeInfo)) +} + +func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeInfo, wasmCode []byte) error { + if ioutils.IsGzip(wasmCode) { + var err error + wasmCode, err = ioutils.Uncompress(wasmCode, uint64(types.MaxWasmSize)) + if err != nil { + return sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + } + newCodeHash, err := k.wasmVM.Create(wasmCode) + if err != nil { + return sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + if !bytes.Equal(codeInfo.CodeHash, newCodeHash) { + return sdkerrors.Wrap(types.ErrInvalid, "code hashes not same") + } + + store := ctx.KVStore(k.storeKey) + key := types.GetCodeKey(codeID) + if store.Has(key) { + return sdkerrors.Wrapf(types.ErrDuplicate, "duplicate code: %d", codeID) + } + // 0x01 | codeID (uint64) -> ContractInfo + store.Set(key, k.cdc.MustMarshal(&codeInfo)) + return nil +} + +func (k Keeper) instantiate( + ctx sdk.Context, + codeID uint64, + creator, admin sdk.AccAddress, + initMsg []byte, + label string, + deposit sdk.Coins, + addressGenerator AddressGenerator, + authPolicy AuthorizationPolicy, +) (sdk.AccAddress, []byte, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "instantiate") + + if creator == nil { + return nil, nil, types.ErrEmpty.Wrap("creator") + } + instanceCosts := k.gasRegister.NewContractInstanceCosts(k.IsPinnedCode(ctx, codeID), len(initMsg)) + ctx.GasMeter().ConsumeGas(instanceCosts, "Loading CosmWasm module: instantiate") + + // get contact info + codeInfo := k.GetCodeInfo(ctx, codeID) + if codeInfo == nil { + return nil, nil, sdkerrors.Wrap(types.ErrNotFound, "code") + } + if !authPolicy.CanInstantiateContract(codeInfo.InstantiateConfig, creator) { + return nil, nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not instantiate") + } + + contractAddress := addressGenerator(ctx, codeID, codeInfo.CodeHash) + if k.HasContractInfo(ctx, contractAddress) { + return nil, nil, types.ErrDuplicate.Wrap("instance with this code id, sender and label exists: try a different label") + } + + // check account + // every cosmos module can define custom account types when needed. The cosmos-sdk comes with extension points + // to support this and a set of base and vesting account types that we integrated in our default lists. + // But not all account types of other modules are known or may make sense for contracts, therefore we kept this + // decision logic also very flexible and extendable. We provide new options to overwrite the default settings via WithAcceptedAccountTypesOnContractInstantiation and + // WithPruneAccountTypesOnContractInstantiation as constructor arguments + existingAcct := k.accountKeeper.GetAccount(ctx, contractAddress) + if existingAcct != nil { + if existingAcct.GetSequence() != 0 || existingAcct.GetPubKey() != nil { + return nil, nil, types.ErrAccountExists.Wrap("address is claimed by external account") + } + if _, accept := k.acceptedAccountTypes[reflect.TypeOf(existingAcct)]; accept { + // keep account and balance as it is + k.Logger(ctx).Info("instantiate contract with existing account", "address", contractAddress.String()) + } else { + // consider an account in the wasmd namespace spam and overwrite it. + k.Logger(ctx).Info("pruning existing account for contract instantiation", "address", contractAddress.String()) + contractAccount := k.accountKeeper.NewAccountWithAddress(ctx, contractAddress) + k.accountKeeper.SetAccount(ctx, contractAccount) + // also handle balance to not open cases where these accounts are abused and become liquid + switch handled, err := k.accountPruner.CleanupExistingAccount(ctx, existingAcct); { + case err != nil: + return nil, nil, sdkerrors.Wrap(err, "prune balance") + case !handled: + return nil, nil, types.ErrAccountExists.Wrap("address is claimed by external account") + } + } + } else { + // create an empty account (so we don't have issues later) + contractAccount := k.accountKeeper.NewAccountWithAddress(ctx, contractAddress) + k.accountKeeper.SetAccount(ctx, contractAccount) + } + // deposit initial contract funds + if !deposit.IsZero() { + if err := k.bank.TransferCoins(ctx, creator, contractAddress, deposit); err != nil { + return nil, nil, err + } + } + + // prepare params for contract instantiate call + env := types.NewEnv(ctx, contractAddress) + info := types.NewInfo(creator, deposit) + + // create prefixed data store + // 0x03 | BuildContractAddressClassic (sdk.AccAddress) + prefixStoreKey := types.GetContractStorePrefix(contractAddress) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) + + // prepare querier + querier := k.newQueryHandler(ctx, contractAddress) + + // instantiate wasm contract + gas := k.runtimeGasForContract(ctx) + res, gasUsed, err := k.wasmVM.Instantiate(codeInfo.CodeHash, env, info, initMsg, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if err != nil { + return nil, nil, sdkerrors.Wrap(types.ErrInstantiateFailed, err.Error()) + } + + // persist instance first + createdAt := types.NewAbsoluteTxPosition(ctx) + contractInfo := types.NewContractInfo(codeID, creator, admin, label, createdAt) + + // check for IBC flag + report, err := k.wasmVM.AnalyzeCode(codeInfo.CodeHash) + if err != nil { + return nil, nil, sdkerrors.Wrap(types.ErrInstantiateFailed, err.Error()) + } + if report.HasIBCEntryPoints { + // register IBC port + ibcPort, err := k.ensureIbcPort(ctx, contractAddress) + if err != nil { + return nil, nil, err + } + contractInfo.IBCPortID = ibcPort + } + + // store contract before dispatch so that contract could be called back + historyEntry := contractInfo.InitialHistory(initMsg) + k.addToContractCodeSecondaryIndex(ctx, contractAddress, historyEntry) + k.addToContractCreatorSecondaryIndex(ctx, creator, historyEntry.Updated, contractAddress) + k.appendToContractHistory(ctx, contractAddress, historyEntry) + k.storeContractInfo(ctx, contractAddress, &contractInfo) + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeInstantiate, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + if err != nil { + return nil, nil, sdkerrors.Wrap(err, "dispatch") + } + + return contractAddress, data, nil +} + +// Execute executes the contract instance +func (k Keeper) execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) ([]byte, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "execute") + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return nil, err + } + + executeCosts := k.gasRegister.InstantiateContractCosts(k.IsPinnedCode(ctx, contractInfo.CodeID), len(msg)) + ctx.GasMeter().ConsumeGas(executeCosts, "Loading CosmWasm module: execute") + + // add more funds + if !coins.IsZero() { + if err := k.bank.TransferCoins(ctx, caller, contractAddress, coins); err != nil { + return nil, err + } + } + + env := types.NewEnv(ctx, contractAddress) + info := types.NewInfo(caller, coins) + + // prepare querier + querier := k.newQueryHandler(ctx, contractAddress) + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.Execute(codeInfo.CodeHash, env, info, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeExecute, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + if err != nil { + return nil, sdkerrors.Wrap(err, "dispatch") + } + + return data, nil +} + +func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) ([]byte, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "migrate") + migrateSetupCosts := k.gasRegister.InstantiateContractCosts(k.IsPinnedCode(ctx, newCodeID), len(msg)) + ctx.GasMeter().ConsumeGas(migrateSetupCosts, "Loading CosmWasm module: migrate") + + contractInfo := k.GetContractInfo(ctx, contractAddress) + if contractInfo == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract") + } + if !authZ.CanModifyContract(contractInfo.AdminAddr(), caller) { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not migrate") + } + + newCodeInfo := k.GetCodeInfo(ctx, newCodeID) + if newCodeInfo == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown code") + } + + if !authZ.CanInstantiateContract(newCodeInfo.InstantiateConfig, caller) { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "to use new code") + } + + // check for IBC flag + switch report, err := k.wasmVM.AnalyzeCode(newCodeInfo.CodeHash); { + case err != nil: + return nil, sdkerrors.Wrap(types.ErrMigrationFailed, err.Error()) + case !report.HasIBCEntryPoints && contractInfo.IBCPortID != "": + // prevent update to non ibc contract + return nil, sdkerrors.Wrap(types.ErrMigrationFailed, "requires ibc callbacks") + case report.HasIBCEntryPoints && contractInfo.IBCPortID == "": + // add ibc port + ibcPort, err := k.ensureIbcPort(ctx, contractAddress) + if err != nil { + return nil, err + } + contractInfo.IBCPortID = ibcPort + } + + env := types.NewEnv(ctx, contractAddress) + + // prepare querier + querier := k.newQueryHandler(ctx, contractAddress) + + prefixStoreKey := types.GetContractStorePrefix(contractAddress) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) + gas := k.runtimeGasForContract(ctx) + res, gasUsed, err := k.wasmVM.Migrate(newCodeInfo.CodeHash, env, msg, &prefixStore, cosmwasmAPI, &querier, k.gasMeter(ctx), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if err != nil { + return nil, sdkerrors.Wrap(types.ErrMigrationFailed, err.Error()) + } + // delete old secondary index entry + k.removeFromContractCodeSecondaryIndex(ctx, contractAddress, k.getLastContractHistoryEntry(ctx, contractAddress)) + // persist migration updates + historyEntry := contractInfo.AddMigration(ctx, newCodeID, msg) + k.appendToContractHistory(ctx, contractAddress, historyEntry) + k.addToContractCodeSecondaryIndex(ctx, contractAddress, historyEntry) + k.storeContractInfo(ctx, contractAddress, contractInfo) + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeMigrate, + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(newCodeID, 10)), + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + if err != nil { + return nil, sdkerrors.Wrap(err, "dispatch") + } + + return data, nil +} + +// Sudo allows priviledged access to a contract. This can never be called by an external tx, but only by +// another native Go module directly, or on-chain governance (if sudo proposals are enabled). Thus, the keeper doesn't +// place any access controls on it, that is the responsibility or the app developer (who passes the wasm.Keeper in app.go) +func (k Keeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) ([]byte, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "sudo") + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return nil, err + } + + sudoSetupCosts := k.gasRegister.InstantiateContractCosts(k.IsPinnedCode(ctx, contractInfo.CodeID), len(msg)) + ctx.GasMeter().ConsumeGas(sudoSetupCosts, "Loading CosmWasm module: sudo") + + env := types.NewEnv(ctx, contractAddress) + + // prepare querier + querier := k.newQueryHandler(ctx, contractAddress) + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.Sudo(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeSudo, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + if err != nil { + return nil, sdkerrors.Wrap(err, "dispatch") + } + + return data, nil +} + +// reply is only called from keeper internal functions (dispatchSubmessages) after processing the submessage +func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) + if err != nil { + return nil, err + } + + // always consider this pinned + replyCosts := k.gasRegister.ReplyCosts(true, reply) + ctx.GasMeter().ConsumeGas(replyCosts, "Loading CosmWasm module: reply") + + env := types.NewEnv(ctx, contractAddress) + + // prepare querier + querier := k.newQueryHandler(ctx, contractAddress) + gas := k.runtimeGasForContract(ctx) + + res, gasUsed, execErr := k.wasmVM.Reply(codeInfo.CodeHash, env, reply, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeReply, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + )) + + data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events) + if err != nil { + return nil, sdkerrors.Wrap(err, "dispatch") + } + + return data, nil +} + +// addToContractCodeSecondaryIndex adds element to the index for contracts-by-codeid queries +func (k Keeper) addToContractCodeSecondaryIndex(ctx sdk.Context, contractAddress sdk.AccAddress, entry types.ContractCodeHistoryEntry) { + store := ctx.KVStore(k.storeKey) + store.Set(types.GetContractByCreatedSecondaryIndexKey(contractAddress, entry), []byte{}) +} + +// removeFromContractCodeSecondaryIndex removes element to the index for contracts-by-codeid queries +func (k Keeper) removeFromContractCodeSecondaryIndex(ctx sdk.Context, contractAddress sdk.AccAddress, entry types.ContractCodeHistoryEntry) { + ctx.KVStore(k.storeKey).Delete(types.GetContractByCreatedSecondaryIndexKey(contractAddress, entry)) +} + +// addToContractCreatorSecondaryIndex adds element to the index for contracts-by-creator queries +func (k Keeper) addToContractCreatorSecondaryIndex(ctx sdk.Context, creatorAddress sdk.AccAddress, position *types.AbsoluteTxPosition, contractAddress sdk.AccAddress) { + store := ctx.KVStore(k.storeKey) + store.Set(types.GetContractByCreatorSecondaryIndexKey(creatorAddress, position.Bytes(), contractAddress), []byte{}) +} + +// IterateContractsByCreator iterates over all contracts with given creator address in order of creation time asc. +func (k Keeper) IterateContractsByCreator(ctx sdk.Context, creator sdk.AccAddress, cb func(address sdk.AccAddress) bool) { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetContractsByCreatorPrefix(creator)) + for iter := prefixStore.Iterator(nil, nil); iter.Valid(); iter.Next() { + key := iter.Key() + if cb(key[types.AbsoluteTxPositionLen:]) { + return + } + } +} + +// IterateContractsByCode iterates over all contracts with given codeID ASC on code update time. +func (k Keeper) IterateContractsByCode(ctx sdk.Context, codeID uint64, cb func(address sdk.AccAddress) bool) { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetContractByCodeIDSecondaryIndexPrefix(codeID)) + iter := prefixStore.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + key := iter.Key() + if cb(key[types.AbsoluteTxPositionLen:]) { + return + } + } +} + +func (k Keeper) setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error { + contractInfo := k.GetContractInfo(ctx, contractAddress) + if contractInfo == nil { + return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract") + } + if !authZ.CanModifyContract(contractInfo.AdminAddr(), caller) { + return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not modify contract") + } + newAdminStr := newAdmin.String() + contractInfo.Admin = newAdminStr + k.storeContractInfo(ctx, contractAddress, contractInfo) + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeUpdateContractAdmin, + sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()), + sdk.NewAttribute(types.AttributeKeyNewAdmin, newAdminStr), + )) + + return nil +} + +func (k Keeper) appendToContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress, newEntries ...types.ContractCodeHistoryEntry) { + store := ctx.KVStore(k.storeKey) + // find last element position + var pos uint64 + prefixStore := prefix.NewStore(store, types.GetContractCodeHistoryElementPrefix(contractAddr)) + iter := prefixStore.ReverseIterator(nil, nil) + defer iter.Close() + + if iter.Valid() { + pos = sdk.BigEndianToUint64(iter.Key()) + } + // then store with incrementing position + for _, e := range newEntries { + pos++ + key := types.GetContractCodeHistoryElementKey(contractAddr, pos) + store.Set(key, k.cdc.MustMarshal(&e)) //nolint:gosec + } +} + +func (k Keeper) GetContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress) []types.ContractCodeHistoryEntry { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetContractCodeHistoryElementPrefix(contractAddr)) + r := make([]types.ContractCodeHistoryEntry, 0) + iter := prefixStore.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + var e types.ContractCodeHistoryEntry + k.cdc.MustUnmarshal(iter.Value(), &e) + r = append(r, e) + } + return r +} + +// getLastContractHistoryEntry returns the last element from history. To be used internally only as it panics when none exists +func (k Keeper) getLastContractHistoryEntry(ctx sdk.Context, contractAddr sdk.AccAddress) types.ContractCodeHistoryEntry { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.GetContractCodeHistoryElementPrefix(contractAddr)) + iter := prefixStore.ReverseIterator(nil, nil) + defer iter.Close() + + var r types.ContractCodeHistoryEntry + if !iter.Valid() { + // all contracts have a history + panic(fmt.Sprintf("no history for %s", contractAddr.String())) + } + k.cdc.MustUnmarshal(iter.Value(), &r) + return r +} + +// QuerySmart queries the smart contract itself. +func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "query-smart") + + // checks and increase query stack size + ctx, err := checkAndIncreaseQueryStackSize(ctx, k.maxQueryStackSize) + if err != nil { + return nil, err + } + + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return nil, err + } + + smartQuerySetupCosts := k.gasRegister.InstantiateContractCosts(k.IsPinnedCode(ctx, contractInfo.CodeID), len(req)) + ctx.GasMeter().ConsumeGas(smartQuerySetupCosts, "Loading CosmWasm module: query") + + // prepare querier + querier := k.newQueryHandler(ctx, contractAddr) + + env := types.NewEnv(ctx, contractAddr) + queryResult, gasUsed, qErr := k.wasmVM.Query(codeInfo.CodeHash, env, req, prefixStore, cosmwasmAPI, querier, k.gasMeter(ctx), k.runtimeGasForContract(ctx), costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if qErr != nil { + return nil, sdkerrors.Wrap(types.ErrQueryFailed, qErr.Error()) + } + return queryResult, nil +} + +func checkAndIncreaseQueryStackSize(ctx sdk.Context, maxQueryStackSize uint32) (sdk.Context, error) { + var queryStackSize uint32 + + // read current value + if size := ctx.Context().Value(contextKeyQueryStackSize); size != nil { + queryStackSize = size.(uint32) + } else { + queryStackSize = 0 + } + + // increase + queryStackSize++ + + // did we go too far? + if queryStackSize > maxQueryStackSize { + return ctx, types.ErrExceedMaxQueryStackSize + } + + // set updated stack size + ctx = ctx.WithContext(context.WithValue(ctx.Context(), contextKeyQueryStackSize, queryStackSize)) + + return ctx, nil +} + +// QueryRaw returns the contract's state for give key. Returns `nil` when key is `nil`. +func (k Keeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "query-raw") + if key == nil { + return nil + } + prefixStoreKey := types.GetContractStorePrefix(contractAddress) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) + return prefixStore.Get(key) +} + +func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress) (types.ContractInfo, types.CodeInfo, prefix.Store, error) { + store := ctx.KVStore(k.storeKey) + + contractBz := store.Get(types.GetContractAddressKey(contractAddress)) + if contractBz == nil { + return types.ContractInfo{}, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract") + } + var contractInfo types.ContractInfo + k.cdc.MustUnmarshal(contractBz, &contractInfo) + + codeInfoBz := store.Get(types.GetCodeKey(contractInfo.CodeID)) + if codeInfoBz == nil { + return contractInfo, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "code info") + } + var codeInfo types.CodeInfo + k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) + prefixStoreKey := types.GetContractStorePrefix(contractAddress) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) + return contractInfo, codeInfo, prefixStore, nil +} + +func (k Keeper) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + store := ctx.KVStore(k.storeKey) + var contract types.ContractInfo + contractBz := store.Get(types.GetContractAddressKey(contractAddress)) + if contractBz == nil { + return nil + } + k.cdc.MustUnmarshal(contractBz, &contract) + return &contract +} + +func (k Keeper) HasContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.GetContractAddressKey(contractAddress)) +} + +// storeContractInfo persists the ContractInfo. No secondary index updated here. +func (k Keeper) storeContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress, contract *types.ContractInfo) { + store := ctx.KVStore(k.storeKey) + store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshal(contract)) +} + +func (k Keeper) IterateContractInfo(ctx sdk.Context, cb func(sdk.AccAddress, types.ContractInfo) bool) { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.ContractKeyPrefix) + iter := prefixStore.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + var contract types.ContractInfo + k.cdc.MustUnmarshal(iter.Value(), &contract) + // cb returns true to stop early + if cb(iter.Key(), contract) { + break + } + } +} + +// IterateContractState iterates through all elements of the key value store for the given contract address and passes +// them to the provided callback function. The callback method can return true to abort early. +func (k Keeper) IterateContractState(ctx sdk.Context, contractAddress sdk.AccAddress, cb func(key, value []byte) bool) { + prefixStoreKey := types.GetContractStorePrefix(contractAddress) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) + iter := prefixStore.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + if cb(iter.Key(), iter.Value()) { + break + } + } +} + +func (k Keeper) importContractState(ctx sdk.Context, contractAddress sdk.AccAddress, models []types.Model) error { + prefixStoreKey := types.GetContractStorePrefix(contractAddress) + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) + for _, model := range models { + if model.Value == nil { + model.Value = []byte{} + } + if prefixStore.Has(model.Key) { + return sdkerrors.Wrapf(types.ErrDuplicate, "duplicate key: %x", model.Key) + } + prefixStore.Set(model.Key, model.Value) + } + return nil +} + +func (k Keeper) GetCodeInfo(ctx sdk.Context, codeID uint64) *types.CodeInfo { + store := ctx.KVStore(k.storeKey) + var codeInfo types.CodeInfo + codeInfoBz := store.Get(types.GetCodeKey(codeID)) + if codeInfoBz == nil { + return nil + } + k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) + return &codeInfo +} + +func (k Keeper) containsCodeInfo(ctx sdk.Context, codeID uint64) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.GetCodeKey(codeID)) +} + +func (k Keeper) IterateCodeInfos(ctx sdk.Context, cb func(uint64, types.CodeInfo) bool) { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.CodeKeyPrefix) + iter := prefixStore.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + var c types.CodeInfo + k.cdc.MustUnmarshal(iter.Value(), &c) + // cb returns true to stop early + if cb(binary.BigEndian.Uint64(iter.Key()), c) { + return + } + } +} + +func (k Keeper) GetByteCode(ctx sdk.Context, codeID uint64) ([]byte, error) { + store := ctx.KVStore(k.storeKey) + var codeInfo types.CodeInfo + codeInfoBz := store.Get(types.GetCodeKey(codeID)) + if codeInfoBz == nil { + return nil, nil + } + k.cdc.MustUnmarshal(codeInfoBz, &codeInfo) + return k.wasmVM.GetCode(codeInfo.CodeHash) +} + +// PinCode pins the wasm contract in wasmvm cache +func (k Keeper) pinCode(ctx sdk.Context, codeID uint64) error { + codeInfo := k.GetCodeInfo(ctx, codeID) + if codeInfo == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + + if err := k.wasmVM.Pin(codeInfo.CodeHash); err != nil { + return sdkerrors.Wrap(types.ErrPinContractFailed, err.Error()) + } + store := ctx.KVStore(k.storeKey) + // store 1 byte to not run into `nil` debugging issues + store.Set(types.GetPinnedCodeIndexPrefix(codeID), []byte{1}) + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypePinCode, + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), + )) + return nil +} + +// UnpinCode removes the wasm contract from wasmvm cache +func (k Keeper) unpinCode(ctx sdk.Context, codeID uint64) error { + codeInfo := k.GetCodeInfo(ctx, codeID) + if codeInfo == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + if err := k.wasmVM.Unpin(codeInfo.CodeHash); err != nil { + return sdkerrors.Wrap(types.ErrUnpinContractFailed, err.Error()) + } + + store := ctx.KVStore(k.storeKey) + store.Delete(types.GetPinnedCodeIndexPrefix(codeID)) + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeUnpinCode, + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), + )) + return nil +} + +// IsPinnedCode returns true when codeID is pinned in wasmvm cache +func (k Keeper) IsPinnedCode(ctx sdk.Context, codeID uint64) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.GetPinnedCodeIndexPrefix(codeID)) +} + +// InitializePinnedCodes updates wasmvm to pin to cache all contracts marked as pinned +func (k Keeper) InitializePinnedCodes(ctx sdk.Context) error { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PinnedCodeIndexPrefix) + iter := store.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + codeInfo := k.GetCodeInfo(ctx, types.ParsePinnedCodeIndex(iter.Key())) + if codeInfo == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + if err := k.wasmVM.Pin(codeInfo.CodeHash); err != nil { + return sdkerrors.Wrap(types.ErrPinContractFailed, err.Error()) + } + } + return nil +} + +// setContractInfoExtension updates the extension point data that is stored with the contract info +func (k Keeper) setContractInfoExtension(ctx sdk.Context, contractAddr sdk.AccAddress, ext types.ContractInfoExtension) error { + info := k.GetContractInfo(ctx, contractAddr) + if info == nil { + return sdkerrors.Wrap(types.ErrNotFound, "contract info") + } + if err := info.SetExtension(ext); err != nil { + return err + } + k.storeContractInfo(ctx, contractAddr, info) + return nil +} + +// setAccessConfig updates the access config of a code id. +func (k Keeper) setAccessConfig(ctx sdk.Context, codeID uint64, caller sdk.AccAddress, newConfig types.AccessConfig, authz AuthorizationPolicy) error { + info := k.GetCodeInfo(ctx, codeID) + if info == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + isSubset := newConfig.Permission.IsSubset(k.getInstantiateAccessConfig(ctx)) + if !authz.CanModifyCodeAccessConfig(sdk.MustAccAddressFromBech32(info.Creator), caller, isSubset) { + return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not modify code access config") + } + + info.InstantiateConfig = newConfig + k.storeCodeInfo(ctx, codeID, *info) + evt := sdk.NewEvent( + types.EventTypeUpdateCodeAccessConfig, + sdk.NewAttribute(types.AttributeKeyCodePermission, newConfig.Permission.String()), + sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)), + ) + if addrs := newConfig.AllAuthorizedAddresses(); len(addrs) != 0 { + attr := sdk.NewAttribute(types.AttributeKeyAuthorizedAddresses, strings.Join(addrs, ",")) + evt.Attributes = append(evt.Attributes, attr.ToKVPair()) + } + ctx.EventManager().EmitEvent(evt) + return nil +} + +// handleContractResponse processes the contract response data by emitting events and sending sub-/messages. +func (k *Keeper) handleContractResponse( + ctx sdk.Context, + contractAddr sdk.AccAddress, + ibcPort string, + msgs []wasmvmtypes.SubMsg, + attrs []wasmvmtypes.EventAttribute, + data []byte, + evts wasmvmtypes.Events, +) ([]byte, error) { + attributeGasCost := k.gasRegister.EventCosts(attrs, evts) + ctx.GasMeter().ConsumeGas(attributeGasCost, "Custom contract event attributes") + // emit all events from this contract itself + if len(attrs) != 0 { + wasmEvents, err := newWasmModuleEvent(attrs, contractAddr) + if err != nil { + return nil, err + } + ctx.EventManager().EmitEvents(wasmEvents) + } + if len(evts) > 0 { + customEvents, err := newCustomEvents(evts, contractAddr) + if err != nil { + return nil, err + } + ctx.EventManager().EmitEvents(customEvents) + } + return k.wasmVMResponseHandler.Handle(ctx, contractAddr, ibcPort, msgs, data) +} + +func (k Keeper) runtimeGasForContract(ctx sdk.Context) uint64 { + meter := ctx.GasMeter() + if meter.IsOutOfGas() { + return 0 + } + if meter.Limit() == 0 { // infinite gas meter with limit=0 and not out of gas + return math.MaxUint64 + } + return k.gasRegister.ToWasmVMGas(meter.Limit() - meter.GasConsumedToLimit()) +} + +func (k Keeper) consumeRuntimeGas(ctx sdk.Context, gas uint64) { + consumed := k.gasRegister.FromWasmVMGas(gas) + ctx.GasMeter().ConsumeGas(consumed, "wasm contract") + // throw OutOfGas error if we ran out (got exactly to zero due to better limit enforcing) + if ctx.GasMeter().IsOutOfGas() { + panic(sdk.ErrorOutOfGas{Descriptor: "Wasmer function execution"}) + } +} + +func (k Keeper) autoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64 { + store := ctx.KVStore(k.storeKey) + bz := store.Get(lastIDKey) + id := uint64(1) + if bz != nil { + id = binary.BigEndian.Uint64(bz) + } + bz = sdk.Uint64ToBigEndian(id + 1) + store.Set(lastIDKey, bz) + return id +} + +// PeekAutoIncrementID reads the current value without incrementing it. +func (k Keeper) PeekAutoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64 { + store := ctx.KVStore(k.storeKey) + bz := store.Get(lastIDKey) + id := uint64(1) + if bz != nil { + id = binary.BigEndian.Uint64(bz) + } + return id +} + +func (k Keeper) importAutoIncrementID(ctx sdk.Context, lastIDKey []byte, val uint64) error { + store := ctx.KVStore(k.storeKey) + if store.Has(lastIDKey) { + return sdkerrors.Wrapf(types.ErrDuplicate, "autoincrement id: %s", string(lastIDKey)) + } + bz := sdk.Uint64ToBigEndian(val) + store.Set(lastIDKey, bz) + return nil +} + +func (k Keeper) importContract(ctx sdk.Context, contractAddr sdk.AccAddress, c *types.ContractInfo, state []types.Model, entries []types.ContractCodeHistoryEntry) error { + if !k.containsCodeInfo(ctx, c.CodeID) { + return sdkerrors.Wrapf(types.ErrNotFound, "code id: %d", c.CodeID) + } + if k.HasContractInfo(ctx, contractAddr) { + return sdkerrors.Wrapf(types.ErrDuplicate, "contract: %s", contractAddr) + } + + creatorAddress, err := sdk.AccAddressFromBech32(c.Creator) + if err != nil { + return err + } + + k.appendToContractHistory(ctx, contractAddr, entries...) + k.storeContractInfo(ctx, contractAddr, c) + k.addToContractCodeSecondaryIndex(ctx, contractAddr, entries[len(entries)-1]) + k.addToContractCreatorSecondaryIndex(ctx, creatorAddress, entries[0].Updated, contractAddr) + return k.importContractState(ctx, contractAddr, state) +} + +func (k Keeper) newQueryHandler(ctx sdk.Context, contractAddress sdk.AccAddress) QueryHandler { + return NewQueryHandler(ctx, k.wasmVMQueryHandler, contractAddress, k.gasRegister) +} + +// MultipliedGasMeter wraps the GasMeter from context and multiplies all reads by out defined multiplier +type MultipliedGasMeter struct { + originalMeter sdk.GasMeter + GasRegister GasRegister +} + +func NewMultipliedGasMeter(originalMeter sdk.GasMeter, gr GasRegister) MultipliedGasMeter { + return MultipliedGasMeter{originalMeter: originalMeter, GasRegister: gr} +} + +var _ wasmvm.GasMeter = MultipliedGasMeter{} + +func (m MultipliedGasMeter) GasConsumed() sdk.Gas { + return m.GasRegister.ToWasmVMGas(m.originalMeter.GasConsumed()) +} + +func (k Keeper) gasMeter(ctx sdk.Context) MultipliedGasMeter { + return NewMultipliedGasMeter(ctx.GasMeter(), k.gasRegister) +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return moduleLogger(ctx) +} + +func moduleLogger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// Querier creates a new grpc querier instance +func Querier(k *Keeper) *grpcQuerier { //nolint:revive + return NewGrpcQuerier(k.cdc, k.storeKey, k, k.queryGasLimit) +} + +// QueryGasLimit returns the gas limit for smart queries. +func (k Keeper) QueryGasLimit() sdk.Gas { + return k.queryGasLimit +} + +// BankCoinTransferrer replicates the cosmos-sdk behaviour as in +// https://github.com/cosmos/cosmos-sdk/blob/v0.41.4/x/bank/keeper/msg_server.go#L26 +type BankCoinTransferrer struct { + keeper types.BankKeeper +} + +func NewBankCoinTransferrer(keeper types.BankKeeper) BankCoinTransferrer { + return BankCoinTransferrer{ + keeper: keeper, + } +} + +// TransferCoins transfers coins from source to destination account when coin send was enabled for them and the recipient +// is not in the blocked address list. +func (c BankCoinTransferrer) TransferCoins(parentCtx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error { + em := sdk.NewEventManager() + ctx := parentCtx.WithEventManager(em) + if err := c.keeper.IsSendEnabledCoins(ctx, amount...); err != nil { + return err + } + if c.keeper.BlockedAddr(toAddr) { + return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to receive funds", toAddr.String()) + } + + sdkerr := c.keeper.SendCoins(ctx, fromAddr, toAddr, amount) + if sdkerr != nil { + return sdkerr + } + for _, e := range em.Events() { + if e.Type == sdk.EventTypeMessage { // skip messages as we talk to the keeper directly + continue + } + parentCtx.EventManager().EmitEvent(e) + } + return nil +} + +var _ AccountPruner = VestingCoinBurner{} + +// VestingCoinBurner default implementation for AccountPruner to burn the coins +type VestingCoinBurner struct { + bank types.BankKeeper +} + +// NewVestingCoinBurner constructor +func NewVestingCoinBurner(bank types.BankKeeper) VestingCoinBurner { + if bank == nil { + panic("bank keeper must not be nil") + } + return VestingCoinBurner{bank: bank} +} + +// CleanupExistingAccount accepts only vesting account types to burns all their original vesting coin balances. +// Other account types will be rejected and returned as unhandled. +func (b VestingCoinBurner) CleanupExistingAccount(ctx sdk.Context, existingAcc authtypes.AccountI) (handled bool, err error) { + v, ok := existingAcc.(vestingexported.VestingAccount) + if !ok { + return false, nil + } + + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) + coinsToBurn := sdk.NewCoins() + for _, orig := range v.GetOriginalVesting() { // focus on the coin denoms that were setup originally; getAllBalances has some issues + coinsToBurn = append(coinsToBurn, b.bank.GetBalance(ctx, existingAcc.GetAddress(), orig.Denom)) + } + if err := b.bank.SendCoinsFromAccountToModule(ctx, existingAcc.GetAddress(), types.ModuleName, coinsToBurn); err != nil { + return false, sdkerrors.Wrap(err, "prune account balance") + } + if err := b.bank.BurnCoins(ctx, types.ModuleName, coinsToBurn); err != nil { + return false, sdkerrors.Wrap(err, "burn account balance") + } + return true, nil +} + +type msgDispatcher interface { + DispatchSubmessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) +} + +// DefaultWasmVMContractResponseHandler default implementation that first dispatches submessage then normal messages. +// The Submessage execution may include an success/failure response handling by the contract that can overwrite the +// original +type DefaultWasmVMContractResponseHandler struct { + md msgDispatcher +} + +func NewDefaultWasmVMContractResponseHandler(md msgDispatcher) *DefaultWasmVMContractResponseHandler { + return &DefaultWasmVMContractResponseHandler{md: md} +} + +// Handle processes the data returned by a contract invocation. +func (h DefaultWasmVMContractResponseHandler) Handle(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, messages []wasmvmtypes.SubMsg, origRspData []byte) ([]byte, error) { + result := origRspData + switch rsp, err := h.md.DispatchSubmessages(ctx, contractAddr, ibcPort, messages); { + case err != nil: + return nil, sdkerrors.Wrap(err, "submessages") + case rsp != nil: + result = rsp + } + return result, nil +} diff --git a/x/wasm/keeper/keeper_cgo.go b/x/wasm/keeper/keeper_cgo.go new file mode 100644 index 00000000..3eea2177 --- /dev/null +++ b/x/wasm/keeper/keeper_cgo.go @@ -0,0 +1,69 @@ +//go:build cgo + +package keeper + +import ( + "path/filepath" + + wasmvm "github.com/CosmWasm/wasmvm" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// NewKeeper creates a new contract Keeper instance +// If customEncoders is non-nil, we can use this to override some of the message handler, especially custom +func NewKeeper( + cdc codec.Codec, + storeKey sdk.StoreKey, + paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + stakingKeeper types.StakingKeeper, + distKeeper types.DistributionKeeper, + channelKeeper types.ChannelKeeper, + portKeeper types.PortKeeper, + capabilityKeeper types.CapabilityKeeper, + portSource types.ICS20TransferPortSource, + router MessageRouter, + queryRouter GRPCQueryRouter, + homeDir string, + wasmConfig types.WasmConfig, + availableCapabilities string, + opts ...Option, +) Keeper { + wasmer, err := wasmvm.NewVM(filepath.Join(homeDir, "wasm"), availableCapabilities, contractMemoryLimit, wasmConfig.ContractDebugMode, wasmConfig.MemoryCacheSize) + if err != nil { + panic(err) + } + // set KeyTable if it has not already been set + if !paramSpace.HasKeyTable() { + paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) + } + + keeper := &Keeper{ + storeKey: storeKey, + cdc: cdc, + wasmVM: wasmer, + accountKeeper: accountKeeper, + bank: NewBankCoinTransferrer(bankKeeper), + accountPruner: NewVestingCoinBurner(bankKeeper), + portKeeper: portKeeper, + capabilityKeeper: capabilityKeeper, + messenger: NewDefaultMessageHandler(router, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource), + queryGasLimit: wasmConfig.SmartQueryGasLimit, + paramSpace: paramSpace, + gasRegister: NewDefaultWasmGasRegister(), + maxQueryStackSize: types.DefaultMaxQueryStackSize, + acceptedAccountTypes: defaultAcceptedAccountTypes, + } + keeper.wasmVMQueryHandler = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, channelKeeper, keeper) + for _, o := range opts { + o.apply(keeper) + } + // not updateable, yet + keeper.wasmVMResponseHandler = NewDefaultWasmVMContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper)) + return *keeper +} diff --git a/x/wasm/keeper/keeper_no_cgo.go b/x/wasm/keeper/keeper_no_cgo.go new file mode 100644 index 00000000..f05ff0b7 --- /dev/null +++ b/x/wasm/keeper/keeper_no_cgo.go @@ -0,0 +1,35 @@ +//go:build !cgo + +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// NewKeeper creates a new contract Keeper instance +// If customEncoders is non-nil, we can use this to override some of the message handler, especially custom +func NewKeeper( + cdc codec.Codec, + storeKey sdk.StoreKey, + paramSpace paramtypes.Subspace, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, + stakingKeeper types.StakingKeeper, + distKeeper types.DistributionKeeper, + channelKeeper types.ChannelKeeper, + portKeeper types.PortKeeper, + capabilityKeeper types.CapabilityKeeper, + portSource types.ICS20TransferPortSource, + router MessageRouter, + queryRouter GRPCQueryRouter, + homeDir string, + wasmConfig types.WasmConfig, + availableCapabilities string, + opts ...Option, +) Keeper { + panic("not implemented, please build with cgo enabled") +} diff --git a/x/wasm/keeper/keeper_test.go b/x/wasm/keeper/keeper_test.go new file mode 100644 index 00000000..951a6a8c --- /dev/null +++ b/x/wasm/keeper/keeper_test.go @@ -0,0 +1,2410 @@ +package keeper + +import ( + "bytes" + _ "embed" + "encoding/json" + "errors" + "fmt" + "os" + "strings" + "testing" + "time" + + abci "github.com/tendermint/tendermint/abci/types" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + stypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + fuzz "github.com/google/gofuzz" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/rand" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +//go:embed testdata/hackatom.wasm +var hackatomWasm []byte + +const AvailableCapabilities = "iterator,staking,stargate,cosmwasm_1_1" + +func TestNewKeeper(t *testing.T) { + _, keepers := CreateTestInput(t, false, AvailableCapabilities) + require.NotNil(t, keepers.ContractKeeper) +} + +func TestCreateSuccess(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + em := sdk.NewEventManager() + contractID, _, err := keeper.Create(ctx.WithEventManager(em), creator, hackatomWasm, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), contractID) + // and verify content + storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID) + require.NoError(t, err) + require.Equal(t, hackatomWasm, storedCode) + // and events emitted + codeHash := strings.ToLower("beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b") + exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_checksum", codeHash), sdk.NewAttribute("code_id", "1"))} + assert.Equal(t, exp, em.Events()) +} + +func TestCreateNilCreatorAddress(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + _, _, err := keepers.ContractKeeper.Create(ctx, nil, hackatomWasm, nil) + require.Error(t, err, "nil creator is not allowed") +} + +func TestCreateNilWasmCode(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + _, _, err := keepers.ContractKeeper.Create(ctx, creator, nil, nil) + require.Error(t, err, "nil WASM code is not allowed") +} + +func TestCreateInvalidWasmCode(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + _, _, err := keepers.ContractKeeper.Create(ctx, creator, []byte("potatoes"), nil) + require.Error(t, err, "potatoes are not valid WASM code") +} + +func TestCreateStoresInstantiatePermission(t *testing.T) { + var ( + deposit = sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + myAddr sdk.AccAddress = bytes.Repeat([]byte{1}, types.SDKAddrLen) + ) + + specs := map[string]struct { + srcPermission types.AccessType + expInstConf types.AccessConfig + }{ + "default": { + srcPermission: types.DefaultParams().InstantiateDefaultPermission, + expInstConf: types.AllowEverybody, + }, + "everybody": { + srcPermission: types.AccessTypeEverybody, + expInstConf: types.AllowEverybody, + }, + "nobody": { + srcPermission: types.AccessTypeNobody, + expInstConf: types.AllowNobody, + }, + "onlyAddress with matching address": { + srcPermission: types.AccessTypeOnlyAddress, + expInstConf: types.AccessConfig{Permission: types.AccessTypeOnlyAddress, Address: myAddr.String()}, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper + keepers.WasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowEverybody, + InstantiateDefaultPermission: spec.srcPermission, + }) + fundAccounts(t, ctx, accKeeper, bankKeeper, myAddr, deposit) + + codeID, _, err := keeper.Create(ctx, myAddr, hackatomWasm, nil) + require.NoError(t, err) + + codeInfo := keepers.WasmKeeper.GetCodeInfo(ctx, codeID) + require.NotNil(t, codeInfo) + assert.True(t, spec.expInstConf.Equals(codeInfo.InstantiateConfig), "got %#v", codeInfo.InstantiateConfig) + }) + } +} + +func TestCreateWithParamPermissions(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + otherAddr := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + specs := map[string]struct { + policy AuthorizationPolicy + chainUpload types.AccessConfig + expError *sdkerrors.Error + }{ + "default": { + policy: DefaultAuthorizationPolicy{}, + chainUpload: types.DefaultUploadAccess, + }, + "everybody": { + policy: DefaultAuthorizationPolicy{}, + chainUpload: types.AllowEverybody, + }, + "nobody": { + policy: DefaultAuthorizationPolicy{}, + chainUpload: types.AllowNobody, + expError: sdkerrors.ErrUnauthorized, + }, + "onlyAddress with matching address": { + policy: DefaultAuthorizationPolicy{}, + chainUpload: types.AccessTypeOnlyAddress.With(creator), + }, + "onlyAddress with non matching address": { + policy: DefaultAuthorizationPolicy{}, + chainUpload: types.AccessTypeOnlyAddress.With(otherAddr), + expError: sdkerrors.ErrUnauthorized, + }, + "gov: always allowed": { + policy: GovAuthorizationPolicy{}, + chainUpload: types.AllowNobody, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + params := types.DefaultParams() + params.CodeUploadAccess = spec.chainUpload + keepers.WasmKeeper.SetParams(ctx, params) + keeper := NewPermissionedKeeper(keepers.WasmKeeper, spec.policy) + _, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.True(t, spec.expError.Is(err), err) + if spec.expError != nil { + return + } + }) + } +} + +// ensure that the user cannot set the code instantiate permission to something more permissive +// than the default +func TestEnforceValidPermissionsOnCreate(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + contractKeeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + other := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + onlyCreator := types.AccessTypeOnlyAddress.With(creator) + onlyOther := types.AccessTypeOnlyAddress.With(other) + + specs := map[string]struct { + defaultPermssion types.AccessType + requestedPermission *types.AccessConfig + // grantedPermission is set iff no error + grantedPermission types.AccessConfig + // expError is nil iff the request is allowed + expError *sdkerrors.Error + }{ + "override everybody": { + defaultPermssion: types.AccessTypeEverybody, + requestedPermission: &onlyCreator, + grantedPermission: onlyCreator, + }, + "default to everybody": { + defaultPermssion: types.AccessTypeEverybody, + requestedPermission: nil, + grantedPermission: types.AccessConfig{Permission: types.AccessTypeEverybody}, + }, + "explicitly set everybody": { + defaultPermssion: types.AccessTypeEverybody, + requestedPermission: &types.AccessConfig{Permission: types.AccessTypeEverybody}, + grantedPermission: types.AccessConfig{Permission: types.AccessTypeEverybody}, + }, + "cannot override nobody": { + defaultPermssion: types.AccessTypeNobody, + requestedPermission: &onlyCreator, + expError: sdkerrors.ErrUnauthorized, + }, + "default to nobody": { + defaultPermssion: types.AccessTypeNobody, + requestedPermission: nil, + grantedPermission: types.AccessConfig{Permission: types.AccessTypeNobody}, + }, + "only defaults to code creator": { + defaultPermssion: types.AccessTypeOnlyAddress, + requestedPermission: nil, + grantedPermission: onlyCreator, + }, + "can explicitly set to code creator": { + defaultPermssion: types.AccessTypeOnlyAddress, + requestedPermission: &onlyCreator, + grantedPermission: onlyCreator, + }, + "cannot override which address in only": { + defaultPermssion: types.AccessTypeOnlyAddress, + requestedPermission: &onlyOther, + expError: sdkerrors.ErrUnauthorized, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + params := types.DefaultParams() + params.InstantiateDefaultPermission = spec.defaultPermssion + keeper.SetParams(ctx, params) + codeID, _, err := contractKeeper.Create(ctx, creator, hackatomWasm, spec.requestedPermission) + require.True(t, spec.expError.Is(err), err) + if spec.expError == nil { + codeInfo := keeper.GetCodeInfo(ctx, codeID) + require.Equal(t, codeInfo.InstantiateConfig, spec.grantedPermission) + } + }) + } +} + +func TestCreateDuplicate(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // create one copy + contractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), contractID) + + // create second copy + duplicateID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + require.Equal(t, uint64(2), duplicateID) + + // and verify both content is proper + storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID) + require.NoError(t, err) + require.Equal(t, hackatomWasm, storedCode) + storedCode, err = keepers.WasmKeeper.GetByteCode(ctx, duplicateID) + require.NoError(t, err) + require.Equal(t, hackatomWasm, storedCode) +} + +func TestCreateWithSimulation(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + ctx = ctx.WithBlockHeader(tmproto.Header{Height: 1}). + WithGasMeter(stypes.NewInfiniteGasMeter()) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // create this once in simulation mode + contractID, _, err := keepers.ContractKeeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), contractID) + + // then try to create it in non-simulation mode (should not fail) + ctx, keepers = CreateTestInput(t, false, AvailableCapabilities) + ctx = ctx.WithGasMeter(sdk.NewGasMeter(10_000_000)) + creator = keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + contractID, _, err = keepers.ContractKeeper.Create(ctx, creator, hackatomWasm, nil) + + require.NoError(t, err) + require.Equal(t, uint64(1), contractID) + + // and verify content + code, err := keepers.WasmKeeper.GetByteCode(ctx, contractID) + require.NoError(t, err) + require.Equal(t, code, hackatomWasm) +} + +func TestIsSimulationMode(t *testing.T) { + specs := map[string]struct { + ctx sdk.Context + exp bool + }{ + "genesis block": { + ctx: sdk.Context{}.WithBlockHeader(tmproto.Header{}).WithGasMeter(stypes.NewInfiniteGasMeter()), + exp: false, + }, + "any regular block": { + ctx: sdk.Context{}.WithBlockHeader(tmproto.Header{Height: 1}).WithGasMeter(stypes.NewGasMeter(10000000)), + exp: false, + }, + "simulation": { + ctx: sdk.Context{}.WithBlockHeader(tmproto.Header{Height: 1}).WithGasMeter(stypes.NewInfiniteGasMeter()), + exp: true, + }, + } + for msg := range specs { + t.Run(msg, func(t *testing.T) { + // assert.Equal(t, spec.exp, isSimulationMode(spec.ctx)) + }) + } +} + +func TestCreateWithGzippedPayload(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm.gzip") + require.NoError(t, err, "reading gzipped WASM code") + + contractID, _, err := keeper.Create(ctx, creator, wasmCode, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), contractID) + // and verify content + storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID) + require.NoError(t, err) + require.Equal(t, hackatomWasm, storedCode) +} + +func TestCreateWithBrokenGzippedPayload(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + wasmCode, err := os.ReadFile("./testdata/broken_crc.gzip") + require.NoError(t, err, "reading gzipped WASM code") + + gm := sdk.NewInfiniteGasMeter() + codeID, checksum, err := keeper.Create(ctx.WithGasMeter(gm), creator, wasmCode, nil) + require.Error(t, err) + assert.Empty(t, codeID) + assert.Empty(t, checksum) + assert.GreaterOrEqual(t, gm.GasConsumed(), sdk.Gas(121384)) // 809232 * 0.15 (default uncompress costs) = 121384 +} + +func TestInstantiate(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) + keepers.Faucet.Fund(ctx, creator, deposit...) + example := StoreHackatomExampleContract(t, ctx, keepers) + + initMsg := HackatomExampleInitMsg{ + Verifier: RandomAccountAddress(t), + Beneficiary: RandomAccountAddress(t), + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + gasBefore := ctx.GasMeter().GasConsumed() + + em := sdk.NewEventManager() + // create with no balance is also legal + gotContractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) + require.NoError(t, err) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", gotContractAddr.String()) + + gasAfter := ctx.GasMeter().GasConsumed() + if types.EnableGasVerification { + require.Equal(t, uint64(0x1a7b6), gasAfter-gasBefore) + } + + // ensure it is stored properly + info := keepers.WasmKeeper.GetContractInfo(ctx, gotContractAddr) + require.NotNil(t, info) + assert.Equal(t, creator.String(), info.Creator) + assert.Equal(t, example.CodeID, info.CodeID) + assert.Equal(t, "demo contract 1", info.Label) + + exp := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: example.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: initMsgBz, + }} + assert.Equal(t, exp, keepers.WasmKeeper.GetContractHistory(ctx, gotContractAddr)) + + // and events emitted + expEvt := sdk.Events{ + sdk.NewEvent("instantiate", + sdk.NewAttribute("_contract_address", gotContractAddr.String()), sdk.NewAttribute("code_id", "1")), + sdk.NewEvent("wasm", + sdk.NewAttribute("_contract_address", gotContractAddr.String()), sdk.NewAttribute("Let the", "hacking begin")), + } + assert.Equal(t, expEvt, em.Events()) +} + +func TestInstantiateWithDeposit(t *testing.T) { + var ( + bob = bytes.Repeat([]byte{1}, types.SDKAddrLen) + fred = bytes.Repeat([]byte{2}, types.SDKAddrLen) + + deposit = sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) + initMsg = mustMarshal(t, HackatomExampleInitMsg{Verifier: fred, Beneficiary: bob}) + ) + + specs := map[string]struct { + srcActor sdk.AccAddress + expError bool + fundAddr bool + }{ + "address with funds": { + srcActor: bob, + fundAddr: true, + }, + "address without funds": { + srcActor: bob, + expError: true, + }, + "blocked address": { + srcActor: authtypes.NewModuleAddress(authtypes.FeeCollectorName), + fundAddr: true, + expError: false, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, bankKeeper, keeper := keepers.AccountKeeper, keepers.BankKeeper, keepers.ContractKeeper + + if spec.fundAddr { + fundAccounts(t, ctx, accKeeper, bankKeeper, spec.srcActor, sdk.NewCoins(sdk.NewInt64Coin("denom", 200))) + } + contractID, _, err := keeper.Create(ctx, spec.srcActor, hackatomWasm, nil) + require.NoError(t, err) + + // when + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, spec.srcActor, nil, initMsg, "my label", deposit) + // then + if spec.expError { + require.Error(t, err) + return + } + require.NoError(t, err) + balances := bankKeeper.GetAllBalances(ctx, addr) + assert.Equal(t, deposit, balances) + }) + } +} + +func TestInstantiateWithPermissions(t *testing.T) { + var ( + deposit = sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + myAddr = bytes.Repeat([]byte{1}, types.SDKAddrLen) + otherAddr = bytes.Repeat([]byte{2}, types.SDKAddrLen) + anyAddr = bytes.Repeat([]byte{3}, types.SDKAddrLen) + ) + + initMsg := HackatomExampleInitMsg{ + Verifier: anyAddr, + Beneficiary: anyAddr, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + specs := map[string]struct { + srcPermission types.AccessConfig + srcActor sdk.AccAddress + expError *sdkerrors.Error + }{ + "default": { + srcPermission: types.DefaultUploadAccess, + srcActor: anyAddr, + }, + "everybody": { + srcPermission: types.AllowEverybody, + srcActor: anyAddr, + }, + "nobody": { + srcPermission: types.AllowNobody, + srcActor: myAddr, + expError: sdkerrors.ErrUnauthorized, + }, + "onlyAddress with matching address": { + srcPermission: types.AccessTypeOnlyAddress.With(myAddr), + srcActor: myAddr, + }, + "onlyAddress with non matching address": { + srcActor: myAddr, + srcPermission: types.AccessTypeOnlyAddress.With(otherAddr), + expError: sdkerrors.ErrUnauthorized, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, bankKeeper, keeper := keepers.AccountKeeper, keepers.BankKeeper, keepers.ContractKeeper + fundAccounts(t, ctx, accKeeper, bankKeeper, spec.srcActor, deposit) + + contractID, _, err := keeper.Create(ctx, myAddr, hackatomWasm, &spec.srcPermission) + require.NoError(t, err) + + _, _, err = keepers.ContractKeeper.Instantiate(ctx, contractID, spec.srcActor, nil, initMsgBz, "demo contract 1", nil) + assert.True(t, spec.expError.Is(err), "got %+v", err) + }) + } +} + +func TestInstantiateWithAccounts(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example := StoreHackatomExampleContract(t, parentCtx, keepers) + require.Equal(t, uint64(1), example.CodeID) + initMsg := mustMarshal(t, HackatomExampleInitMsg{Verifier: RandomAccountAddress(t), Beneficiary: RandomAccountAddress(t)}) + + senderAddr := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(parentCtx, senderAddr, sdk.NewInt64Coin("denom", 100000000)) + const myLabel = "testing" + mySalt := []byte(`my salt`) + contractAddr := BuildContractAddressPredictable(example.Checksum, senderAddr, mySalt, []byte{}) + + lastAccountNumber := keepers.AccountKeeper.GetAccount(parentCtx, senderAddr).GetAccountNumber() + + specs := map[string]struct { + option Option + account authtypes.AccountI + initBalance sdk.Coin + deposit sdk.Coins + expErr error + expAccount authtypes.AccountI + expBalance sdk.Coins + }{ + "unused BaseAccount exists": { + account: authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + initBalance: sdk.NewInt64Coin("denom", 100000000), + expAccount: authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+1, 0), // +1 for next seq + expBalance: sdk.NewCoins(sdk.NewInt64Coin("denom", 100000000)), + }, + "BaseAccount with sequence exists": { + account: authtypes.NewBaseAccount(contractAddr, nil, 0, 1), + expErr: types.ErrAccountExists, + }, + "BaseAccount with pubkey exists": { + account: authtypes.NewBaseAccount(contractAddr, &ed25519.PubKey{}, 0, 0), + expErr: types.ErrAccountExists, + }, + "no account existed": { + expAccount: authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+1, 0), // +1 for next seq, + expBalance: sdk.NewCoins(), + }, + "no account existed before create with deposit": { + expAccount: authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+1, 0), // +1 for next seq + deposit: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), + expBalance: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), + }, + "prunable DelayedVestingAccount gets overwritten": { + account: vestingtypes.NewDelayedVestingAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), + initBalance: sdk.NewCoin("denom", sdk.NewInt(1_000)), + deposit: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1))), + expAccount: authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+2, 0), // +1 for next seq, +1 for spec.account created + expBalance: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1))), + }, + "prunable ContinuousVestingAccount gets overwritten": { + account: vestingtypes.NewContinuousVestingAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(time.Hour).Unix(), time.Now().Add(2*time.Hour).Unix()), + initBalance: sdk.NewCoin("denom", sdk.NewInt(1_000)), + deposit: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1))), + expAccount: authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+2, 0), // +1 for next seq, +1 for spec.account created + expBalance: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1))), + }, + "prunable account without balance gets overwritten": { + account: vestingtypes.NewContinuousVestingAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(0))), time.Now().Add(time.Hour).Unix(), time.Now().Add(2*time.Hour).Unix()), + expAccount: authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+2, 0), // +1 for next seq, +1 for spec.account created + expBalance: sdk.NewCoins(), + }, + "unknown account type is rejected with error": { + account: authtypes.NewModuleAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + "testing", + ), + initBalance: sdk.NewCoin("denom", sdk.NewInt(1_000)), + expErr: types.ErrAccountExists, + }, + "with option used to set non default type to accept list": { + option: WithAcceptedAccountTypesOnContractInstantiation(&vestingtypes.DelayedVestingAccount{}), + account: vestingtypes.NewDelayedVestingAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), + initBalance: sdk.NewCoin("denom", sdk.NewInt(1_000)), + deposit: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1))), + expAccount: vestingtypes.NewDelayedVestingAccount(authtypes.NewBaseAccount(contractAddr, nil, lastAccountNumber+1, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), + expBalance: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_001))), + }, + "pruning account fails": { + option: WithAccountPruner(wasmtesting.AccountPrunerMock{CleanupExistingAccountFn: func(ctx sdk.Context, existingAccount authtypes.AccountI) (handled bool, err error) { + return false, types.ErrUnsupportedForContract.Wrap("testing") + }}), + account: vestingtypes.NewDelayedVestingAccount( + authtypes.NewBaseAccount(contractAddr, nil, 0, 0), + sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))), time.Now().Add(30*time.Hour).Unix()), + expErr: types.ErrUnsupportedForContract, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + if spec.account != nil { + keepers.AccountKeeper.SetAccount(ctx, keepers.AccountKeeper.NewAccount(ctx, spec.account)) + } + if !spec.initBalance.IsNil() { + keepers.Faucet.Fund(ctx, spec.account.GetAddress(), spec.initBalance) + } + if spec.option != nil { + spec.option.apply(keepers.WasmKeeper) + } + defer func() { + if spec.option != nil { // reset + WithAcceptedAccountTypesOnContractInstantiation(&authtypes.BaseAccount{}).apply(keepers.WasmKeeper) + WithAccountPruner(NewVestingCoinBurner(keepers.BankKeeper)).apply(keepers.WasmKeeper) + } + }() + // when + gotAddr, _, gotErr := keepers.ContractKeeper.Instantiate2(ctx, 1, senderAddr, nil, initMsg, myLabel, spec.deposit, mySalt, false) + if spec.expErr != nil { + assert.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, contractAddr, gotAddr) + // and + gotAcc := keepers.AccountKeeper.GetAccount(ctx, contractAddr) + assert.Equal(t, spec.expAccount, gotAcc) + // and + gotBalance := keepers.BankKeeper.GetAllBalances(ctx, contractAddr) + assert.Equal(t, spec.expBalance, gotBalance) + }) + } +} + +func TestInstantiateWithNonExistingCodeID(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + initMsg := HackatomExampleInitMsg{} + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + const nonExistingCodeID = 9999 + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, nonExistingCodeID, creator, nil, initMsgBz, "demo contract 2", nil) + require.True(t, types.ErrNotFound.Is(err), err) + require.Nil(t, addr) +} + +func TestInstantiateWithContractDataResponse(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + wasmerMock := &wasmtesting.MockWasmer{ + InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return &wasmvmtypes.Response{Data: []byte("my-response-data")}, 0, nil + }, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + CreateFn: wasmtesting.NoOpCreateFn, + } + + example := StoreRandomContract(t, ctx, keepers, wasmerMock) + _, data, err := keepers.ContractKeeper.Instantiate(ctx, example.CodeID, example.CreatorAddr, nil, nil, "test", nil) + require.NoError(t, err) + assert.Equal(t, []byte("my-response-data"), data) +} + +func TestInstantiateWithContractFactoryChildQueriesParent(t *testing.T) { + // Scenario: + // given a factory contract stored + // when instantiated, the contract creates a new child contract instance + // and the child contracts queries the senders ContractInfo on instantiation + // then the factory contract's ContractInfo should be returned to the child contract + // + // see also: https://github.com/CosmWasm/wasmd/issues/896 + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + var instantiationCount int + callbacks := make([]func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error), 2) + wasmerMock := &wasmtesting.MockWasmer{ + // dispatch instantiation calls to callbacks + InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + require.Greater(t, len(callbacks), instantiationCount, "unexpected call to instantiation") + do := callbacks[instantiationCount] + instantiationCount++ + return do(codeID, env, info, initMsg, store, goapi, querier, gasMeter, gasLimit, deserCost) + }, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + CreateFn: wasmtesting.NoOpCreateFn, + } + + // overwrite wasmvm in router + router := baseapp.NewMsgServiceRouter() + router.SetInterfaceRegistry(keepers.EncodingConfig.InterfaceRegistry) + types.RegisterMsgServer(router, NewMsgServerImpl(NewDefaultPermissionKeeper(keeper))) + keeper.messenger = NewDefaultMessageHandler(router, nil, nil, nil, keepers.EncodingConfig.Marshaler, nil) + // overwrite wasmvm in response handler + keeper.wasmVMResponseHandler = NewDefaultWasmVMContractResponseHandler(NewMessageDispatcher(keeper.messenger, keeper)) + + example := StoreRandomContract(t, ctx, keepers, wasmerMock) + // factory contract + callbacks[0] = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + t.Log("called factory") + return &wasmvmtypes.Response{Data: []byte("parent"), Messages: []wasmvmtypes.SubMsg{ + { + ID: 1, ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Instantiate: &wasmvmtypes.InstantiateMsg{CodeID: example.CodeID, Msg: []byte(`{}`), Label: "child"}, + }, + }, + }, + }}, 0, nil + } + + // child contract + var capturedSenderAddr string + var capturedCodeInfo []byte + callbacks[1] = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + t.Log("called child") + capturedSenderAddr = info.Sender + var err error + capturedCodeInfo, err = querier.Query(wasmvmtypes.QueryRequest{ + Wasm: &wasmvmtypes.WasmQuery{ + ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: info.Sender}, + }, + }, gasLimit) + require.NoError(t, err) + return &wasmvmtypes.Response{Data: []byte("child")}, 0, nil + } + + // when + parentAddr, data, err := keepers.ContractKeeper.Instantiate(ctx, example.CodeID, example.CreatorAddr, nil, nil, "test", nil) + + // then + require.NoError(t, err) + assert.Equal(t, []byte("parent"), data) + require.Equal(t, parentAddr.String(), capturedSenderAddr) + expCodeInfo := fmt.Sprintf(`{"code_id":%d,"creator":%q,"pinned":false}`, example.CodeID, example.CreatorAddr.String()) + assert.JSONEq(t, expCodeInfo, string(capturedCodeInfo)) +} + +func TestExecute(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + bob := RandomAccountAddress(t) + + contractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit) + require.NoError(t, err) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String()) + + // ensure bob doesn't exist + bobAcct := accKeeper.GetAccount(ctx, bob) + require.Nil(t, bobAcct) + + // ensure funder has reduced balance + creatorAcct := accKeeper.GetAccount(ctx, creator) + require.NotNil(t, creatorAcct) + // we started at 2*deposit, should have spent one above + assert.Equal(t, deposit, bankKeeper.GetAllBalances(ctx, creatorAcct.GetAddress())) + + // ensure contract has updated balance + contractAcct := accKeeper.GetAccount(ctx, addr) + require.NotNil(t, contractAcct) + assert.Equal(t, deposit, bankKeeper.GetAllBalances(ctx, contractAcct.GetAddress())) + + // unauthorized - trialCtx so we don't change state + trialCtx := ctx.WithMultiStore(ctx.MultiStore().CacheWrap().(sdk.MultiStore)) + res, err := keepers.ContractKeeper.Execute(trialCtx, addr, creator, []byte(`{"release":{}}`), nil) + require.Error(t, err) + require.True(t, errors.Is(err, types.ErrExecuteFailed)) + require.Equal(t, "Unauthorized: execute wasm contract failed", err.Error()) + + // verifier can execute, and get proper gas amount + start := time.Now() + gasBefore := ctx.GasMeter().GasConsumed() + em := sdk.NewEventManager() + // when + res, err = keepers.ContractKeeper.Execute(ctx.WithEventManager(em), addr, fred, []byte(`{"release":{}}`), topUp) + diff := time.Now().Sub(start) + require.NoError(t, err) + require.NotNil(t, res) + + // make sure gas is properly deducted from ctx + gasAfter := ctx.GasMeter().GasConsumed() + if types.EnableGasVerification { + require.Equal(t, uint64(0x17d7f), gasAfter-gasBefore) + } + // ensure bob now exists and got both payments released + bobAcct = accKeeper.GetAccount(ctx, bob) + require.NotNil(t, bobAcct) + balance := bankKeeper.GetAllBalances(ctx, bobAcct.GetAddress()) + assert.Equal(t, deposit.Add(topUp...), balance) + + // ensure contract has updated balance + contractAcct = accKeeper.GetAccount(ctx, addr) + require.NotNil(t, contractAcct) + assert.Equal(t, sdk.Coins{}, bankKeeper.GetAllBalances(ctx, contractAcct.GetAddress())) + + // and events emitted + require.Len(t, em.Events(), 9) + expEvt := sdk.NewEvent("execute", + sdk.NewAttribute("_contract_address", addr.String())) + assert.Equal(t, expEvt, em.Events()[3], prettyEvents(t, em.Events())) + + t.Logf("Duration: %v (%d gas)\n", diff, gasAfter-gasBefore) +} + +func TestExecuteWithDeposit(t *testing.T) { + var ( + bob = bytes.Repeat([]byte{1}, types.SDKAddrLen) + fred = bytes.Repeat([]byte{2}, types.SDKAddrLen) + blockedAddr = authtypes.NewModuleAddress(distributiontypes.ModuleName) + deposit = sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) + ) + + specs := map[string]struct { + srcActor sdk.AccAddress + beneficiary sdk.AccAddress + newBankParams *banktypes.Params + expError bool + fundAddr bool + }{ + "actor with funds": { + srcActor: bob, + fundAddr: true, + beneficiary: fred, + }, + "actor without funds": { + srcActor: bob, + beneficiary: fred, + expError: true, + }, + "blocked address as actor": { + srcActor: blockedAddr, + fundAddr: true, + beneficiary: fred, + expError: false, + }, + "coin transfer with all transfers disabled": { + srcActor: bob, + fundAddr: true, + beneficiary: fred, + newBankParams: &banktypes.Params{DefaultSendEnabled: false}, + expError: true, + }, + "coin transfer with transfer denom disabled": { + srcActor: bob, + fundAddr: true, + beneficiary: fred, + newBankParams: &banktypes.Params{ + DefaultSendEnabled: true, + SendEnabled: []*banktypes.SendEnabled{{Denom: "denom", Enabled: false}}, + }, + expError: true, + }, + "blocked address as beneficiary": { + srcActor: bob, + fundAddr: true, + beneficiary: blockedAddr, + expError: true, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, bankKeeper, keeper := keepers.AccountKeeper, keepers.BankKeeper, keepers.ContractKeeper + if spec.newBankParams != nil { + bankKeeper.SetParams(ctx, *spec.newBankParams) + } + if spec.fundAddr { + fundAccounts(t, ctx, accKeeper, bankKeeper, spec.srcActor, sdk.NewCoins(sdk.NewInt64Coin("denom", 200))) + } + codeID, _, err := keeper.Create(ctx, spec.srcActor, hackatomWasm, nil) + require.NoError(t, err) + + initMsg := HackatomExampleInitMsg{Verifier: spec.srcActor, Beneficiary: spec.beneficiary} + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, spec.srcActor, nil, initMsgBz, "my label", nil) + require.NoError(t, err) + + // when + _, err = keepers.ContractKeeper.Execute(ctx, contractAddr, spec.srcActor, []byte(`{"release":{}}`), deposit) + + // then + if spec.expError { + require.Error(t, err) + return + } + require.NoError(t, err) + balances := bankKeeper.GetAllBalances(ctx, spec.beneficiary) + assert.Equal(t, deposit, balances) + }) + } +} + +func TestExecuteWithNonExistingAddress(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + + // unauthorized - trialCtx so we don't change state + nonExistingAddress := RandomAccountAddress(t) + _, err := keeper.Execute(ctx, nonExistingAddress, creator, []byte(`{}`), nil) + require.True(t, types.ErrNotFound.Is(err), err) +} + +func TestExecuteWithPanic(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + + contractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 4", deposit) + require.NoError(t, err) + + // let's make sure we get a reasonable error, no panic/crash + _, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"panic":{}}`), topUp) + require.Error(t, err) + require.True(t, errors.Is(err, types.ErrExecuteFailed)) + // test with contains as "Display" implementation of the Wasmer "RuntimeError" is different for Mac and Linux + assert.Contains(t, err.Error(), "Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: Aborted: panicked at 'This page intentionally faulted', src/contract.rs:169:5: execute wasm contract failed") +} + +func TestExecuteWithCpuLoop(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + + contractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 5", deposit) + require.NoError(t, err) + + // make sure we set a limit before calling + var gasLimit uint64 = 400_000 + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) + + // ensure we get an out of gas panic + defer func() { + r := recover() + require.NotNil(t, r) + _, ok := r.(sdk.ErrorOutOfGas) + require.True(t, ok, "%v", r) + }() + + // this should throw out of gas exception (panic) + _, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"cpu_loop":{}}`), nil) + require.True(t, false, "We must panic before this line") +} + +func TestExecuteWithStorageLoop(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + + contractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 6", deposit) + require.NoError(t, err) + + // make sure we set a limit before calling + var gasLimit uint64 = 400_002 + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) + + // ensure we get an out of gas panic + defer func() { + r := recover() + require.NotNil(t, r) + _, ok := r.(sdk.ErrorOutOfGas) + require.True(t, ok, "%v", r) + }() + + // this should throw out of gas exception (panic) + _, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"storage_loop":{}}`), nil) + require.True(t, false, "We must panic before this line") +} + +func TestMigrate(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(parentCtx, creator, deposit.Add(deposit...)...) + fred := DeterministicAccountAddress(t, 2) + keepers.Faucet.Fund(parentCtx, fred, topUp...) + + originalCodeID := StoreHackatomExampleContract(t, parentCtx, keepers).CodeID + newCodeID := StoreHackatomExampleContract(t, parentCtx, keepers).CodeID + ibcCodeID := StoreIBCReflectContract(t, parentCtx, keepers).CodeID + require.NotEqual(t, originalCodeID, newCodeID) + + restrictedCodeExample := StoreHackatomExampleContract(t, parentCtx, keepers) + require.NoError(t, keeper.SetAccessConfig(parentCtx, restrictedCodeExample.CodeID, restrictedCodeExample.CreatorAddr, types.AllowNobody)) + require.NotEqual(t, originalCodeID, restrictedCodeExample.CodeID) + + anyAddr := RandomAccountAddress(t) + newVerifierAddr := RandomAccountAddress(t) + initMsgBz := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: anyAddr, + }.GetBytes(t) + + migMsg := struct { + Verifier sdk.AccAddress `json:"verifier"` + }{Verifier: newVerifierAddr} + migMsgBz, err := json.Marshal(migMsg) + require.NoError(t, err) + + specs := map[string]struct { + admin sdk.AccAddress + overrideContractAddr sdk.AccAddress + caller sdk.AccAddress + fromCodeID uint64 + toCodeID uint64 + migrateMsg []byte + expErr *sdkerrors.Error + expVerifier sdk.AccAddress + expIBCPort bool + initMsg []byte + }{ + "all good with same code id": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: originalCodeID, + migrateMsg: migMsgBz, + expVerifier: newVerifierAddr, + }, + "all good with different code id": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: newCodeID, + migrateMsg: migMsgBz, + expVerifier: newVerifierAddr, + }, + "all good with admin set": { + admin: fred, + caller: fred, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: newCodeID, + migrateMsg: migMsgBz, + expVerifier: newVerifierAddr, + }, + "adds IBC port for IBC enabled contracts": { + admin: fred, + caller: fred, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: ibcCodeID, + migrateMsg: []byte(`{}`), + expIBCPort: true, + expVerifier: fred, // not updated + }, + "prevent migration when admin was not set on instantiate": { + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: originalCodeID, + expErr: sdkerrors.ErrUnauthorized, + }, + "prevent migration when not sent by admin": { + caller: creator, + admin: fred, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: originalCodeID, + expErr: sdkerrors.ErrUnauthorized, + }, + "prevent migration when new code is restricted": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: restrictedCodeExample.CodeID, + migrateMsg: migMsgBz, + expErr: sdkerrors.ErrUnauthorized, + }, + "fail with non existing code id": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: 99999, + expErr: sdkerrors.ErrInvalidRequest, + }, + "fail with non existing contract addr": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + overrideContractAddr: anyAddr, + fromCodeID: originalCodeID, + toCodeID: originalCodeID, + expErr: sdkerrors.ErrInvalidRequest, + }, + "fail in contract with invalid migrate msg": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: originalCodeID, + migrateMsg: bytes.Repeat([]byte{0x1}, 7), + expErr: types.ErrMigrationFailed, + }, + "fail in contract without migrate msg": { + admin: creator, + caller: creator, + initMsg: initMsgBz, + fromCodeID: originalCodeID, + toCodeID: originalCodeID, + expErr: types.ErrMigrationFailed, + }, + "fail when no IBC callbacks": { + admin: fred, + caller: fred, + initMsg: IBCReflectInitMsg{ReflectCodeID: StoreReflectContract(t, parentCtx, keepers).CodeID}.GetBytes(t), + fromCodeID: ibcCodeID, + toCodeID: newCodeID, + migrateMsg: migMsgBz, + expErr: types.ErrMigrationFailed, + }, + } + + blockHeight := parentCtx.BlockHeight() + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + // given a contract instance + ctx, _ := parentCtx.WithBlockHeight(blockHeight + 1).CacheContext() + blockHeight++ + + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, spec.fromCodeID, creator, spec.admin, spec.initMsg, "demo contract", nil) + require.NoError(t, err) + if spec.overrideContractAddr != nil { + contractAddr = spec.overrideContractAddr + } + // when + _, err = keeper.Migrate(ctx, contractAddr, spec.caller, spec.toCodeID, spec.migrateMsg) + + // then + require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err) + if spec.expErr != nil { + return + } + cInfo := keepers.WasmKeeper.GetContractInfo(ctx, contractAddr) + assert.Equal(t, spec.toCodeID, cInfo.CodeID) + assert.Equal(t, spec.expIBCPort, cInfo.IBCPortID != "", cInfo.IBCPortID) + + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: spec.fromCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: initMsgBz, + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: spec.toCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: spec.migrateMsg, + }} + assert.Equal(t, expHistory, keepers.WasmKeeper.GetContractHistory(ctx, contractAddr)) + + // and verify contract state + raw := keepers.WasmKeeper.QueryRaw(ctx, contractAddr, []byte("config")) + var stored map[string]string + require.NoError(t, json.Unmarshal(raw, &stored)) + require.Contains(t, stored, "verifier") + require.NoError(t, err) + assert.Equal(t, spec.expVerifier.String(), stored["verifier"]) + }) + } +} + +func TestMigrateReplacesTheSecondIndex(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example := InstantiateHackatomExampleContract(t, ctx, keepers) + + // then assert a second index exists + store := ctx.KVStore(keepers.WasmKeeper.storeKey) + oldContractInfo := keepers.WasmKeeper.GetContractInfo(ctx, example.Contract) + require.NotNil(t, oldContractInfo) + createHistoryEntry := types.ContractCodeHistoryEntry{ + CodeID: example.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + } + exists := store.Has(types.GetContractByCreatedSecondaryIndexKey(example.Contract, createHistoryEntry)) + require.True(t, exists) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // increment for different block + // when do migrate + newCodeExample := StoreBurnerExampleContract(t, ctx, keepers) + migMsgBz := BurnerExampleInitMsg{Payout: example.CreatorAddr}.GetBytes(t) + _, err := keepers.ContractKeeper.Migrate(ctx, example.Contract, example.CreatorAddr, newCodeExample.CodeID, migMsgBz) + require.NoError(t, err) + + // then the new index exists + migrateHistoryEntry := types.ContractCodeHistoryEntry{ + CodeID: newCodeExample.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + } + exists = store.Has(types.GetContractByCreatedSecondaryIndexKey(example.Contract, migrateHistoryEntry)) + require.True(t, exists) + // and the old index was removed + exists = store.Has(types.GetContractByCreatedSecondaryIndexKey(example.Contract, createHistoryEntry)) + require.False(t, exists) +} + +func TestMigrateWithDispatchedMessage(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(ctx, sdk.NewInt64Coin("denom", 5000)) + + burnerCode, err := os.ReadFile("./testdata/burner.wasm") + require.NoError(t, err) + + originalContractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + burnerContractID, _, err := keeper.Create(ctx, creator, burnerCode, nil) + require.NoError(t, err) + require.NotEqual(t, originalContractID, burnerContractID) + + _, _, myPayoutAddr := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: fred, + } + initMsgBz := initMsg.GetBytes(t) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, originalContractID, creator, fred, initMsgBz, "demo contract", deposit) + require.NoError(t, err) + + migMsgBz := BurnerExampleInitMsg{Payout: myPayoutAddr}.GetBytes(t) + ctx = ctx.WithEventManager(sdk.NewEventManager()).WithBlockHeight(ctx.BlockHeight() + 1) + data, err := keeper.Migrate(ctx, contractAddr, fred, burnerContractID, migMsgBz) + require.NoError(t, err) + assert.Equal(t, "burnt 1 keys", string(data)) + type dict map[string]interface{} + expEvents := []dict{ + { + "Type": "migrate", + "Attr": []dict{ + {"code_id": "2"}, + {"_contract_address": contractAddr}, + }, + }, + { + "Type": "wasm", + "Attr": []dict{ + {"_contract_address": contractAddr}, + {"action": "burn"}, + {"payout": myPayoutAddr}, + }, + }, + { + "Type": "coin_spent", + "Attr": []dict{ + {"spender": contractAddr}, + {"amount": "100000denom"}, + }, + }, + { + "Type": "coin_received", + "Attr": []dict{ + {"receiver": myPayoutAddr}, + {"amount": "100000denom"}, + }, + }, + { + "Type": "transfer", + "Attr": []dict{ + {"recipient": myPayoutAddr}, + {"sender": contractAddr}, + {"amount": "100000denom"}, + }, + }, + } + expJSONEvts := string(mustMarshal(t, expEvents)) + assert.JSONEq(t, expJSONEvts, prettyEvents(t, ctx.EventManager().Events()), prettyEvents(t, ctx.EventManager().Events())) + + // all persistent data cleared + m := keepers.WasmKeeper.QueryRaw(ctx, contractAddr, []byte("config")) + require.Len(t, m, 0) + + // and all deposit tokens sent to myPayoutAddr + balance := keepers.BankKeeper.GetAllBalances(ctx, myPayoutAddr) + assert.Equal(t, deposit, balance) +} + +func TestIterateContractsByCode(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k, c := keepers.WasmKeeper, keepers.ContractKeeper + example1 := InstantiateHackatomExampleContract(t, ctx, keepers) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + example2 := InstantiateIBCReflectContract(t, ctx, keepers) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + initMsg := HackatomExampleInitMsg{ + Verifier: RandomAccountAddress(t), + Beneficiary: RandomAccountAddress(t), + }.GetBytes(t) + contractAddr3, _, err := c.Instantiate(ctx, example1.CodeID, example1.CreatorAddr, nil, initMsg, "foo", nil) + require.NoError(t, err) + specs := map[string]struct { + codeID uint64 + exp []sdk.AccAddress + }{ + "multiple results": { + codeID: example1.CodeID, + exp: []sdk.AccAddress{example1.Contract, contractAddr3}, + }, + "single results": { + codeID: example2.CodeID, + exp: []sdk.AccAddress{example2.Contract}, + }, + "empty results": { + codeID: 99999, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + var gotAddr []sdk.AccAddress + k.IterateContractsByCode(ctx, spec.codeID, func(address sdk.AccAddress) bool { + gotAddr = append(gotAddr, address) + return false + }) + assert.Equal(t, spec.exp, gotAddr) + }) + } +} + +func TestIterateContractsByCodeWithMigration(t *testing.T) { + // mock migration so that it does not fail when migrate example1 to example2.codeID + mockWasmVM := wasmtesting.MockWasmer{MigrateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return &wasmvmtypes.Response{}, 1, nil + }} + wasmtesting.MakeInstantiable(&mockWasmVM) + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithWasmEngine(&mockWasmVM)) + k, c := keepers.WasmKeeper, keepers.ContractKeeper + example1 := InstantiateHackatomExampleContract(t, ctx, keepers) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + example2 := InstantiateIBCReflectContract(t, ctx, keepers) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + _, err := c.Migrate(ctx, example1.Contract, example1.CreatorAddr, example2.CodeID, []byte("{}")) + require.NoError(t, err) + + // when + var gotAddr []sdk.AccAddress + k.IterateContractsByCode(ctx, example2.CodeID, func(address sdk.AccAddress) bool { + gotAddr = append(gotAddr, address) + return false + }) + + // then + exp := []sdk.AccAddress{example2.Contract, example1.Contract} + assert.Equal(t, exp, gotAddr) +} + +type sudoMsg struct { + // This is a tongue-in-check demo command. This is not the intended purpose of Sudo. + // Here we show that some priviledged Go module can make a call that should never be exposed + // to end users (via Tx/Execute). + // + // The contract developer can choose to expose anything to sudo. This functionality is not a true + // backdoor (it can never be called by end users), but allows the developers of the native blockchain + // code to make special calls. This can also be used as an authentication mechanism, if you want to expose + // some callback that only can be triggered by some system module and not faked by external users. + StealFunds stealFundsMsg `json:"steal_funds"` +} + +type stealFundsMsg struct { + Recipient string `json:"recipient"` + Amount wasmvmtypes.Coins `json:"amount"` +} + +func TestSudo(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(ctx, creator, deposit.Add(deposit...)...) + + contractID, _, err := keeper.Create(ctx, creator, hackatomWasm, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + _, _, fred := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit) + require.NoError(t, err) + require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String()) + + // the community is broke + _, _, community := keyPubAddr() + comAcct := accKeeper.GetAccount(ctx, community) + require.Nil(t, comAcct) + + // now the community wants to get paid via sudo + msg := sudoMsg{ + // This is a tongue-in-check demo command. This is not the intended purpose of Sudo. + // Here we show that some priviledged Go module can make a call that should never be exposed + // to end users (via Tx/Execute). + StealFunds: stealFundsMsg{ + Recipient: community.String(), + Amount: wasmvmtypes.Coins{wasmvmtypes.NewCoin(76543, "denom")}, + }, + } + sudoMsg, err := json.Marshal(msg) + require.NoError(t, err) + + em := sdk.NewEventManager() + + // when + _, err = keepers.WasmKeeper.Sudo(ctx.WithEventManager(em), addr, sudoMsg) + require.NoError(t, err) + + // ensure community now exists and got paid + comAcct = accKeeper.GetAccount(ctx, community) + require.NotNil(t, comAcct) + balance := bankKeeper.GetBalance(ctx, comAcct.GetAddress(), "denom") + assert.Equal(t, sdk.NewInt64Coin("denom", 76543), balance) + // and events emitted + require.Len(t, em.Events(), 4, prettyEvents(t, em.Events())) + expEvt := sdk.NewEvent("sudo", + sdk.NewAttribute("_contract_address", addr.String())) + assert.Equal(t, expEvt, em.Events()[0]) +} + +func prettyEvents(t *testing.T, events sdk.Events) string { + t.Helper() + type prettyEvent struct { + Type string + Attr []map[string]string + } + + r := make([]prettyEvent, len(events)) + for i, e := range events { + attr := make([]map[string]string, len(e.Attributes)) + for j, a := range e.Attributes { + attr[j] = map[string]string{string(a.Key): string(a.Value)} + } + r[i] = prettyEvent{Type: e.Type, Attr: attr} + } + return string(mustMarshal(t, r)) +} + +func mustMarshal(t *testing.T, r interface{}) []byte { + t.Helper() + bz, err := json.Marshal(r) + require.NoError(t, err) + return bz +} + +func TestUpdateContractAdmin(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(parentCtx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(parentCtx, topUp...) + + originalContractID, _, err := keeper.Create(parentCtx, creator, hackatomWasm, nil) + require.NoError(t, err) + + _, _, anyAddr := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: anyAddr, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + specs := map[string]struct { + instAdmin sdk.AccAddress + newAdmin sdk.AccAddress + overrideContractAddr sdk.AccAddress + caller sdk.AccAddress + expErr *sdkerrors.Error + }{ + "all good with admin set": { + instAdmin: fred, + newAdmin: anyAddr, + caller: fred, + }, + "prevent update when admin was not set on instantiate": { + caller: creator, + newAdmin: fred, + expErr: sdkerrors.ErrUnauthorized, + }, + "prevent updates from non admin address": { + instAdmin: creator, + newAdmin: fred, + caller: fred, + expErr: sdkerrors.ErrUnauthorized, + }, + "fail with non existing contract addr": { + instAdmin: creator, + newAdmin: anyAddr, + caller: creator, + overrideContractAddr: anyAddr, + expErr: sdkerrors.ErrInvalidRequest, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, originalContractID, creator, spec.instAdmin, initMsgBz, "demo contract", nil) + require.NoError(t, err) + if spec.overrideContractAddr != nil { + addr = spec.overrideContractAddr + } + err = keeper.UpdateContractAdmin(ctx, addr, spec.caller, spec.newAdmin) + require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err) + if spec.expErr != nil { + return + } + cInfo := keepers.WasmKeeper.GetContractInfo(ctx, addr) + assert.Equal(t, spec.newAdmin.String(), cInfo.Admin) + }) + } +} + +func TestClearContractAdmin(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(parentCtx, creator, deposit.Add(deposit...)...) + fred := keepers.Faucet.NewFundedRandomAccount(parentCtx, topUp...) + + originalContractID, _, err := keeper.Create(parentCtx, creator, hackatomWasm, nil) + require.NoError(t, err) + + _, _, anyAddr := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: anyAddr, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + specs := map[string]struct { + instAdmin sdk.AccAddress + overrideContractAddr sdk.AccAddress + caller sdk.AccAddress + expErr *sdkerrors.Error + }{ + "all good when called by proper admin": { + instAdmin: fred, + caller: fred, + }, + "prevent update when admin was not set on instantiate": { + caller: creator, + expErr: sdkerrors.ErrUnauthorized, + }, + "prevent updates from non admin address": { + instAdmin: creator, + caller: fred, + expErr: sdkerrors.ErrUnauthorized, + }, + "fail with non existing contract addr": { + instAdmin: creator, + caller: creator, + overrideContractAddr: anyAddr, + expErr: sdkerrors.ErrInvalidRequest, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, originalContractID, creator, spec.instAdmin, initMsgBz, "demo contract", nil) + require.NoError(t, err) + if spec.overrideContractAddr != nil { + addr = spec.overrideContractAddr + } + err = keeper.ClearContractAdmin(ctx, addr, spec.caller) + require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err) + if spec.expErr != nil { + return + } + cInfo := keepers.WasmKeeper.GetContractInfo(ctx, addr) + assert.Empty(t, cInfo.Admin) + }) + } +} + +func TestPinCode(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + + var capturedChecksums []wasmvm.Checksum + mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error { + capturedChecksums = append(capturedChecksums, checksum) + return nil + }} + wasmtesting.MakeInstantiable(&mock) + myCodeID := StoreRandomContract(t, ctx, keepers, &mock).CodeID + require.Equal(t, uint64(1), myCodeID) + em := sdk.NewEventManager() + + // when + gotErr := k.pinCode(ctx.WithEventManager(em), myCodeID) + + // then + require.NoError(t, gotErr) + assert.NotEmpty(t, capturedChecksums) + assert.True(t, k.IsPinnedCode(ctx, myCodeID)) + + // and events + exp := sdk.Events{sdk.NewEvent("pin_code", sdk.NewAttribute("code_id", "1"))} + assert.Equal(t, exp, em.Events()) +} + +func TestUnpinCode(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + + var capturedChecksums []wasmvm.Checksum + mock := wasmtesting.MockWasmer{ + PinFn: func(checksum wasmvm.Checksum) error { + return nil + }, + UnpinFn: func(checksum wasmvm.Checksum) error { + capturedChecksums = append(capturedChecksums, checksum) + return nil + }, + } + wasmtesting.MakeInstantiable(&mock) + myCodeID := StoreRandomContract(t, ctx, keepers, &mock).CodeID + require.Equal(t, uint64(1), myCodeID) + err := k.pinCode(ctx, myCodeID) + require.NoError(t, err) + em := sdk.NewEventManager() + + // when + gotErr := k.unpinCode(ctx.WithEventManager(em), myCodeID) + + // then + require.NoError(t, gotErr) + assert.NotEmpty(t, capturedChecksums) + assert.False(t, k.IsPinnedCode(ctx, myCodeID)) + + // and events + exp := sdk.Events{sdk.NewEvent("unpin_code", sdk.NewAttribute("code_id", "1"))} + assert.Equal(t, exp, em.Events()) +} + +func TestInitializePinnedCodes(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + + var capturedChecksums []wasmvm.Checksum + mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error { + capturedChecksums = append(capturedChecksums, checksum) + return nil + }} + wasmtesting.MakeInstantiable(&mock) + + const testItems = 3 + myCodeIDs := make([]uint64, testItems) + for i := 0; i < testItems; i++ { + myCodeIDs[i] = StoreRandomContract(t, ctx, keepers, &mock).CodeID + require.NoError(t, k.pinCode(ctx, myCodeIDs[i])) + } + capturedChecksums = nil + + // when + gotErr := k.InitializePinnedCodes(ctx) + + // then + require.NoError(t, gotErr) + require.Len(t, capturedChecksums, testItems) + for i, c := range myCodeIDs { + var exp wasmvm.Checksum = k.GetCodeInfo(ctx, c).CodeHash + assert.Equal(t, exp, capturedChecksums[i]) + } +} + +func TestPinnedContractLoops(t *testing.T) { + var capturedChecksums []wasmvm.Checksum + mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error { + capturedChecksums = append(capturedChecksums, checksum) + return nil + }} + wasmtesting.MakeInstantiable(&mock) + + // a pinned contract that calls itself via submessages should terminate with an + // error at some point + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithWasmEngine(&mock)) + k := keepers.WasmKeeper + + example := SeedNewContractInstance(t, ctx, keepers, &mock) + require.NoError(t, k.pinCode(ctx, example.CodeID)) + var loops int + anyMsg := []byte(`{}`) + mock.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + loops++ + return &wasmvmtypes.Response{ + Messages: []wasmvmtypes.SubMsg{ + { + ID: 1, + ReplyOn: wasmvmtypes.ReplyNever, + Msg: wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: example.Contract.String(), + Msg: anyMsg, + }, + }, + }, + }, + }, + }, 0, nil + } + ctx = ctx.WithGasMeter(sdk.NewGasMeter(20000)) + require.PanicsWithValue(t, sdk.ErrorOutOfGas{Descriptor: "ReadFlat"}, func() { + _, err := k.execute(ctx, example.Contract, RandomAccountAddress(t), anyMsg, nil) + require.NoError(t, err) + }) + assert.True(t, ctx.GasMeter().IsOutOfGas()) + assert.Greater(t, loops, 2) +} + +func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) { + specs := map[string]struct { + srcData []byte + setup func(m *wasmtesting.MockMsgDispatcher) + expErr bool + expData []byte + expEvts sdk.Events + }{ + "submessage overwrites result when set": { + srcData: []byte("otherData"), + setup: func(m *wasmtesting.MockMsgDispatcher) { + m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) { + return []byte("mySubMsgData"), nil + } + }, + expErr: false, + expData: []byte("mySubMsgData"), + expEvts: sdk.Events{}, + }, + "submessage overwrites result when empty": { + srcData: []byte("otherData"), + setup: func(m *wasmtesting.MockMsgDispatcher) { + m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) { + return []byte(""), nil + } + }, + expErr: false, + expData: []byte(""), + expEvts: sdk.Events{}, + }, + "submessage do not overwrite result when nil": { + srcData: []byte("otherData"), + setup: func(m *wasmtesting.MockMsgDispatcher) { + m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) { + return nil, nil + } + }, + expErr: false, + expData: []byte("otherData"), + expEvts: sdk.Events{}, + }, + "submessage error aborts process": { + setup: func(m *wasmtesting.MockMsgDispatcher) { + m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) { + return nil, errors.New("test - ignore") + } + }, + expErr: true, + }, + "message emit non message events": { + setup: func(m *wasmtesting.MockMsgDispatcher) { + m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) { + ctx.EventManager().EmitEvent(sdk.NewEvent("myEvent")) + return nil, nil + } + }, + expEvts: sdk.Events{sdk.NewEvent("myEvent")}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + var msgs []wasmvmtypes.SubMsg + var mock wasmtesting.MockMsgDispatcher + spec.setup(&mock) + d := NewDefaultWasmVMContractResponseHandler(&mock) + em := sdk.NewEventManager() + + // when + gotData, gotErr := d.Handle(sdk.Context{}.WithEventManager(em), RandomAccountAddress(t), "ibc-port", msgs, spec.srcData) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expData, gotData) + assert.Equal(t, spec.expEvts, em.Events()) + }) + } +} + +func TestReply(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + var mock wasmtesting.MockWasmer + wasmtesting.MakeInstantiable(&mock) + example := SeedNewContractInstance(t, ctx, keepers, &mock) + + specs := map[string]struct { + replyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + expData []byte + expErr bool + expEvt sdk.Events + }{ + "all good": { + replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return &wasmvmtypes.Response{Data: []byte("foo")}, 1, nil + }, + expData: []byte("foo"), + expEvt: sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))}, + }, + "with query": { + replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + bzRsp, err := querier.Query(wasmvmtypes.QueryRequest{ + Bank: &wasmvmtypes.BankQuery{ + Balance: &wasmvmtypes.BalanceQuery{Address: env.Contract.Address, Denom: "stake"}, + }, + }, 10_000*DefaultGasMultiplier) + require.NoError(t, err) + var gotBankRsp wasmvmtypes.BalanceResponse + require.NoError(t, json.Unmarshal(bzRsp, &gotBankRsp)) + assert.Equal(t, wasmvmtypes.BalanceResponse{Amount: wasmvmtypes.NewCoin(0, "stake")}, gotBankRsp) + return &wasmvmtypes.Response{Data: []byte("foo")}, 1, nil + }, + expData: []byte("foo"), + expEvt: sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))}, + }, + "with query error handled": { + replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + bzRsp, err := querier.Query(wasmvmtypes.QueryRequest{}, 0) + require.Error(t, err) + assert.Nil(t, bzRsp) + return &wasmvmtypes.Response{Data: []byte("foo")}, 1, nil + }, + expData: []byte("foo"), + expEvt: sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))}, + }, + "error": { + replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return nil, 1, errors.New("testing") + }, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + mock.ReplyFn = spec.replyFn + em := sdk.NewEventManager() + gotData, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{}) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expData, gotData) + assert.Equal(t, spec.expEvt, em.Events()) + }) + } +} + +func TestQueryIsolation(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + var mock wasmtesting.MockWasmer + wasmtesting.MakeInstantiable(&mock) + example := SeedNewContractInstance(t, ctx, keepers, &mock) + WithQueryHandlerDecorator(func(other WasmVMQueryHandler) WasmVMQueryHandler { + return WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) { + if request.Custom == nil { + return other.HandleQuery(ctx, caller, request) + } + // here we write to DB which should not be persisted + ctx.KVStore(k.storeKey).Set([]byte(`set_in_query`), []byte(`this_is_allowed`)) + return nil, nil + }) + }).apply(k) + + // when + mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + _, err := querier.Query(wasmvmtypes.QueryRequest{ + Custom: []byte(`{}`), + }, 10000*DefaultGasMultiplier) + require.NoError(t, err) + return &wasmvmtypes.Response{}, 0, nil + } + em := sdk.NewEventManager() + _, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{}) + require.NoError(t, gotErr) + assert.Nil(t, ctx.KVStore(k.storeKey).Get([]byte(`set_in_query`))) +} + +func TestSetAccessConfig(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + creatorAddr := RandomAccountAddress(t) + nonCreatorAddr := RandomAccountAddress(t) + const codeID = 1 + + specs := map[string]struct { + authz AuthorizationPolicy + chainPermission types.AccessType + newConfig types.AccessConfig + caller sdk.AccAddress + expErr bool + expEvts map[string]string + }{ + "user with new permissions == chain permissions": { + authz: DefaultAuthorizationPolicy{}, + chainPermission: types.AccessTypeEverybody, + newConfig: types.AllowEverybody, + caller: creatorAddr, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "Everybody", + }, + }, + "user with new permissions < chain permissions": { + authz: DefaultAuthorizationPolicy{}, + chainPermission: types.AccessTypeEverybody, + newConfig: types.AllowNobody, + caller: creatorAddr, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "Nobody", + }, + }, + "user with new permissions > chain permissions": { + authz: DefaultAuthorizationPolicy{}, + chainPermission: types.AccessTypeNobody, + newConfig: types.AllowEverybody, + caller: creatorAddr, + expErr: true, + }, + "different actor": { + authz: DefaultAuthorizationPolicy{}, + chainPermission: types.AccessTypeEverybody, + newConfig: types.AllowEverybody, + caller: nonCreatorAddr, + expErr: true, + }, + "gov with new permissions == chain permissions": { + authz: GovAuthorizationPolicy{}, + chainPermission: types.AccessTypeEverybody, + newConfig: types.AllowEverybody, + caller: creatorAddr, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "Everybody", + }, + }, + "gov with new permissions < chain permissions": { + authz: GovAuthorizationPolicy{}, + chainPermission: types.AccessTypeEverybody, + newConfig: types.AllowNobody, + caller: creatorAddr, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "Nobody", + }, + }, + "gov with new permissions > chain permissions": { + authz: GovAuthorizationPolicy{}, + chainPermission: types.AccessTypeNobody, + newConfig: types.AccessTypeOnlyAddress.With(creatorAddr), + caller: creatorAddr, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "OnlyAddress", + "authorized_addresses": creatorAddr.String(), + }, + }, + "gov with new permissions > chain permissions - multiple addresses": { + authz: GovAuthorizationPolicy{}, + chainPermission: types.AccessTypeNobody, + newConfig: types.AccessTypeAnyOfAddresses.With(creatorAddr, nonCreatorAddr), + caller: creatorAddr, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "AnyOfAddresses", + "authorized_addresses": creatorAddr.String() + "," + nonCreatorAddr.String(), + }, + }, + "gov without actor": { + authz: GovAuthorizationPolicy{}, + chainPermission: types.AccessTypeEverybody, + newConfig: types.AllowEverybody, + expEvts: map[string]string{ + "code_id": "1", + "code_permission": "Everybody", + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + em := sdk.NewEventManager() + ctx = ctx.WithEventManager(em) + + newParams := types.DefaultParams() + newParams.InstantiateDefaultPermission = spec.chainPermission + k.SetParams(ctx, newParams) + + k.storeCodeInfo(ctx, codeID, types.NewCodeInfo(nil, creatorAddr, types.AllowNobody)) + // when + gotErr := k.setAccessConfig(ctx, codeID, spec.caller, spec.newConfig, spec.authz) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + // and event emitted + require.Len(t, em.Events(), 1) + assert.Equal(t, "update_code_access_config", em.Events()[0].Type) + assert.Equal(t, spec.expEvts, attrsToStringMap(em.Events()[0].Attributes)) + }) + } +} + +func TestAppendToContractHistory(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + var contractAddr sdk.AccAddress = rand.Bytes(types.ContractAddrLen) + var orderedEntries []types.ContractCodeHistoryEntry + + f := fuzz.New().Funcs(ModelFuzzers...) + for i := 0; i < 10; i++ { + var entry types.ContractCodeHistoryEntry + f.Fuzz(&entry) + keepers.WasmKeeper.appendToContractHistory(ctx, contractAddr, entry) + orderedEntries = append(orderedEntries, entry) + } + // when + gotHistory := keepers.WasmKeeper.GetContractHistory(ctx, contractAddr) + assert.Equal(t, orderedEntries, gotHistory) +} + +func TestCoinBurnerPruneBalances(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + amts := sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) + senderAddr := keepers.Faucet.NewFundedRandomAccount(parentCtx, amts...) + + // create vesting account + var vestingAddr sdk.AccAddress = rand.Bytes(types.ContractAddrLen) + msgCreateVestingAccount := vestingtypes.NewMsgCreateVestingAccount(senderAddr, vestingAddr, amts, time.Now().Add(time.Minute).Unix(), false) + _, err := vesting.NewMsgServerImpl(keepers.AccountKeeper, keepers.BankKeeper).CreateVestingAccount(sdk.WrapSDKContext(parentCtx), msgCreateVestingAccount) + require.NoError(t, err) + myVestingAccount := keepers.AccountKeeper.GetAccount(parentCtx, vestingAddr) + require.NotNil(t, myVestingAccount) + + specs := map[string]struct { + setupAcc func(t *testing.T, ctx sdk.Context) authtypes.AccountI + expBalances sdk.Coins + expHandled bool + expErr *sdkerrors.Error + }{ + "vesting account - all removed": { + setupAcc: func(t *testing.T, ctx sdk.Context) authtypes.AccountI { return myVestingAccount }, + expBalances: sdk.NewCoins(), + expHandled: true, + }, + "vesting account with other tokens - only original denoms removed": { + setupAcc: func(t *testing.T, ctx sdk.Context) authtypes.AccountI { + keepers.Faucet.Fund(ctx, vestingAddr, sdk.NewCoin("other", sdk.NewInt(2))) + return myVestingAccount + }, + expBalances: sdk.NewCoins(sdk.NewCoin("other", sdk.NewInt(2))), + expHandled: true, + }, + "non vesting account - not handled": { + setupAcc: func(t *testing.T, ctx sdk.Context) authtypes.AccountI { + return &authtypes.BaseAccount{Address: myVestingAccount.GetAddress().String()} + }, + expBalances: sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(100))), + expHandled: false, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + existingAccount := spec.setupAcc(t, ctx) + // overwrite account in store as in keeper before calling prune + keepers.AccountKeeper.SetAccount(ctx, keepers.AccountKeeper.NewAccountWithAddress(ctx, vestingAddr)) + + // when + noGasCtx := ctx.WithGasMeter(sdk.NewGasMeter(0)) // should not use callers gas + gotHandled, gotErr := NewVestingCoinBurner(keepers.BankKeeper).CleanupExistingAccount(noGasCtx, existingAccount) + // then + if spec.expErr != nil { + require.ErrorIs(t, gotErr, spec.expErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expBalances, keepers.BankKeeper.GetAllBalances(ctx, vestingAddr)) + assert.Equal(t, spec.expHandled, gotHandled) + // and no out of gas panic + }) + } +} + +func TestIteratorAllContract(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + example1 := InstantiateHackatomExampleContract(t, ctx, keepers) + example2 := InstantiateHackatomExampleContract(t, ctx, keepers) + example3 := InstantiateHackatomExampleContract(t, ctx, keepers) + example4 := InstantiateHackatomExampleContract(t, ctx, keepers) + + var allContract []string + keepers.WasmKeeper.IterateContractInfo(ctx, func(addr sdk.AccAddress, _ types.ContractInfo) bool { + allContract = append(allContract, addr.String()) + return false + }) + + // IterateContractInfo not ordering + expContracts := []string{example4.Contract.String(), example2.Contract.String(), example1.Contract.String(), example3.Contract.String()} + require.Equal(t, allContract, expContracts) +} + +func TestIteratorContractByCreator(t *testing.T) { + // setup test + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.ContractKeeper + + depositFund := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := DeterministicAccountAddress(t, 1) + keepers.Faucet.Fund(parentCtx, creator, depositFund.Add(depositFund...)...) + mockAddress1 := keepers.Faucet.NewFundedRandomAccount(parentCtx, topUp...) + mockAddress2 := keepers.Faucet.NewFundedRandomAccount(parentCtx, topUp...) + mockAddress3 := keepers.Faucet.NewFundedRandomAccount(parentCtx, topUp...) + + contract1ID, _, err := keeper.Create(parentCtx, creator, hackatomWasm, nil) + contract2ID, _, err := keeper.Create(parentCtx, creator, hackatomWasm, nil) + + require.NoError(t, err) + + initMsgBz := HackatomExampleInitMsg{ + Verifier: mockAddress1, + Beneficiary: mockAddress1, + }.GetBytes(t) + + depositContract := sdk.NewCoins(sdk.NewCoin("denom", sdk.NewInt(1_000))) + + gotAddr1, _, _ := keepers.ContractKeeper.Instantiate(parentCtx, contract1ID, mockAddress1, nil, initMsgBz, "label", depositContract) + ctx := parentCtx.WithBlockHeight(parentCtx.BlockHeight() + 1) + gotAddr2, _, _ := keepers.ContractKeeper.Instantiate(ctx, contract1ID, mockAddress2, nil, initMsgBz, "label", depositContract) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + gotAddr3, _, _ := keepers.ContractKeeper.Instantiate(ctx, contract1ID, gotAddr1, nil, initMsgBz, "label", depositContract) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + gotAddr4, _, _ := keepers.ContractKeeper.Instantiate(ctx, contract2ID, mockAddress2, nil, initMsgBz, "label", depositContract) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + gotAddr5, _, _ := keepers.ContractKeeper.Instantiate(ctx, contract2ID, mockAddress2, nil, initMsgBz, "label", depositContract) + + specs := map[string]struct { + creatorAddr sdk.AccAddress + contractsAddr []string + }{ + "single contract": { + creatorAddr: mockAddress1, + contractsAddr: []string{gotAddr1.String()}, + }, + "multiple contracts": { + creatorAddr: mockAddress2, + contractsAddr: []string{gotAddr2.String(), gotAddr4.String(), gotAddr5.String()}, + }, + "contractAdress": { + creatorAddr: gotAddr1, + contractsAddr: []string{gotAddr3.String()}, + }, + "no contracts- unknown": { + creatorAddr: mockAddress3, + contractsAddr: nil, + }, + } + + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + var allContract []string + keepers.WasmKeeper.IterateContractsByCreator(parentCtx, spec.creatorAddr, func(addr sdk.AccAddress) bool { + allContract = append(allContract, addr.String()) + return false + }) + require.Equal(t, + allContract, + spec.contractsAddr, + ) + }) + } +} + +func TestSetContractAdmin(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities) + k := keepers.WasmKeeper + myAddr := RandomAccountAddress(t) + example := InstantiateReflectExampleContract(t, parentCtx, keepers) + specs := map[string]struct { + newAdmin sdk.AccAddress + caller sdk.AccAddress + policy AuthorizationPolicy + expAdmin string + expErr bool + }{ + "update admin": { + newAdmin: myAddr, + caller: example.CreatorAddr, + policy: DefaultAuthorizationPolicy{}, + expAdmin: myAddr.String(), + }, + "update admin - unauthorized": { + newAdmin: myAddr, + caller: RandomAccountAddress(t), + policy: DefaultAuthorizationPolicy{}, + expErr: true, + }, + "clear admin - default policy": { + caller: example.CreatorAddr, + policy: DefaultAuthorizationPolicy{}, + expAdmin: "", + }, + "clear admin - unauthorized": { + expAdmin: "", + policy: DefaultAuthorizationPolicy{}, + caller: RandomAccountAddress(t), + expErr: true, + }, + "clear admin - gov policy": { + newAdmin: nil, + policy: GovAuthorizationPolicy{}, + caller: example.CreatorAddr, + expAdmin: "", + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + em := sdk.NewEventManager() + ctx = ctx.WithEventManager(em) + gotErr := k.setContractAdmin(ctx, example.Contract, spec.caller, spec.newAdmin, spec.policy) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expAdmin, k.GetContractInfo(ctx, example.Contract).Admin) + // and event emitted + require.Len(t, em.Events(), 1) + assert.Equal(t, "update_contract_admin", em.Events()[0].Type) + exp := map[string]string{ + "_contract_address": example.Contract.String(), + "new_admin_address": spec.expAdmin, + } + assert.Equal(t, exp, attrsToStringMap(em.Events()[0].Attributes)) + }) + } +} + +func attrsToStringMap(attrs []abci.EventAttribute) map[string]string { + r := make(map[string]string, len(attrs)) + for _, v := range attrs { + r[string(v.Key)] = string(v.Value) + } + return r +} diff --git a/x/wasm/keeper/legacy_querier.go b/x/wasm/keeper/legacy_querier.go new file mode 100644 index 00000000..3bd4e5fc --- /dev/null +++ b/x/wasm/keeper/legacy_querier.go @@ -0,0 +1,154 @@ +package keeper + +import ( + "encoding/json" + "reflect" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +const ( + QueryListContractByCode = "list-contracts-by-code" + QueryGetContract = "contract-info" + QueryGetContractState = "contract-state" + QueryGetCode = "code" + QueryListCode = "list-code" + QueryContractHistory = "contract-history" +) + +const ( + QueryMethodContractStateSmart = "smart" + QueryMethodContractStateAll = "all" + QueryMethodContractStateRaw = "raw" +) + +// NewLegacyQuerier creates a new querier +// Deprecated: the rest support will be removed. You can use the GRPC gateway instead +func NewLegacyQuerier(keeper types.ViewKeeper, gasLimit sdk.Gas) sdk.Querier { + return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { + var ( + rsp interface{} + err error + ) + switch path[0] { + case QueryGetContract: + addr, addrErr := sdk.AccAddressFromBech32(path[1]) + if addrErr != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, addrErr.Error()) + } + rsp, err = queryContractInfo(ctx, addr, keeper) + case QueryListContractByCode: + codeID, parseErr := strconv.ParseUint(path[1], 10, 64) + if parseErr != nil { + return nil, sdkerrors.Wrapf(types.ErrInvalid, "code id: %s", parseErr.Error()) + } + rsp = queryContractListByCode(ctx, codeID, keeper) + case QueryGetContractState: + if len(path) < 3 { + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint") + } + return queryContractState(ctx, path[1], path[2], req.Data, gasLimit, keeper) + case QueryGetCode: + codeID, parseErr := strconv.ParseUint(path[1], 10, 64) + if parseErr != nil { + return nil, sdkerrors.Wrapf(types.ErrInvalid, "code id: %s", parseErr.Error()) + } + rsp, err = queryCode(ctx, codeID, keeper) + case QueryListCode: + rsp, err = queryCodeList(ctx, keeper) + case QueryContractHistory: + contractAddr, addrErr := sdk.AccAddressFromBech32(path[1]) + if addrErr != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, addrErr.Error()) + } + rsp, err = queryContractHistory(ctx, contractAddr, keeper) + default: + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint") + } + if err != nil { + return nil, err + } + if rsp == nil || reflect.ValueOf(rsp).IsNil() { + return nil, nil + } + bz, err := json.MarshalIndent(rsp, "", " ") + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil + } +} + +func queryContractState(ctx sdk.Context, bech, queryMethod string, data []byte, gasLimit sdk.Gas, keeper types.ViewKeeper) (json.RawMessage, error) { + contractAddr, err := sdk.AccAddressFromBech32(bech) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, bech) + } + + switch queryMethod { + case QueryMethodContractStateAll: + resultData := make([]types.Model, 0) + // this returns a serialized json object (which internally encoded binary fields properly) + keeper.IterateContractState(ctx, contractAddr, func(key, value []byte) bool { + resultData = append(resultData, types.Model{Key: key, Value: value}) + return false + }) + bz, err := json.Marshal(resultData) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + return bz, nil + case QueryMethodContractStateRaw: + // this returns the raw data from the state, base64-encoded + return keeper.QueryRaw(ctx, contractAddr, data), nil + case QueryMethodContractStateSmart: + // we enforce a subjective gas limit on all queries to avoid infinite loops + ctx = ctx.WithGasMeter(sdk.NewGasMeter(gasLimit)) + msg := types.RawContractMessage(data) + if err := msg.ValidateBasic(); err != nil { + return nil, sdkerrors.Wrap(err, "json msg") + } + // this returns raw bytes (must be base64-encoded) + bz, err := keeper.QuerySmart(ctx, contractAddr, msg) + return bz, err + default: + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, queryMethod) + } +} + +func queryCodeList(ctx sdk.Context, keeper types.ViewKeeper) ([]types.CodeInfoResponse, error) { + var info []types.CodeInfoResponse + keeper.IterateCodeInfos(ctx, func(i uint64, res types.CodeInfo) bool { + info = append(info, types.CodeInfoResponse{ + CodeID: i, + Creator: res.Creator, + DataHash: res.CodeHash, + InstantiatePermission: res.InstantiateConfig, + }) + return false + }) + return info, nil +} + +func queryContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress, keeper types.ViewKeeper) ([]types.ContractCodeHistoryEntry, error) { + history := keeper.GetContractHistory(ctx, contractAddr) + // redact response + for i := range history { + history[i].Updated = nil + } + return history, nil +} + +func queryContractListByCode(ctx sdk.Context, codeID uint64, keeper types.ViewKeeper) []string { + var contracts []string + keeper.IterateContractsByCode(ctx, codeID, func(addr sdk.AccAddress) bool { + contracts = append(contracts, addr.String()) + return false + }) + return contracts +} diff --git a/x/wasm/keeper/legacy_querier_test.go b/x/wasm/keeper/legacy_querier_test.go new file mode 100644 index 00000000..96837001 --- /dev/null +++ b/x/wasm/keeper/legacy_querier_test.go @@ -0,0 +1,364 @@ +package keeper + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "os" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestLegacyQueryContractState(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit.Add(deposit...)...) + anyAddr := keepers.Faucet.NewFundedRandomAccount(ctx, sdk.NewInt64Coin("denom", 5000)) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + contractID, _, err := keepers.ContractKeeper.Create(ctx, creator, wasmCode, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: anyAddr, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract to query", deposit) + require.NoError(t, err) + + contractModel := []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + } + keeper.importContractState(ctx, addr, contractModel) + + // this gets us full error, not redacted sdk.Error + var defaultQueryGasLimit sdk.Gas = 3000000 + q := NewLegacyQuerier(keeper, defaultQueryGasLimit) + + specs := map[string]struct { + srcPath []string + srcReq abci.RequestQuery + // smart and raw queries (not all queries) return raw bytes from contract not []types.Model + // if this is set, then we just compare - (should be json encoded string) + expRes []byte + // if success and expSmartRes is not set, we parse into []types.Model and compare (all state) + expModelLen int + expModelContains []types.Model + expErr error + }{ + "query all": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateAll}, + expModelLen: 3, + expModelContains: []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + }, + }, + "query raw key": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw}, + srcReq: abci.RequestQuery{Data: []byte("foo")}, + expRes: []byte(`"bar"`), + }, + "query raw binary key": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw}, + srcReq: abci.RequestQuery{Data: []byte{0x0, 0x1}}, + expRes: []byte(`{"count":8}`), + }, + "query smart": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateSmart}, + srcReq: abci.RequestQuery{Data: []byte(`{"verifier":{}}`)}, + expRes: []byte(fmt.Sprintf(`{"verifier":"%s"}`, anyAddr.String())), + }, + "query smart invalid request": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateSmart}, + srcReq: abci.RequestQuery{Data: []byte(`{"raw":{"key":"config"}}`)}, + expErr: types.ErrQueryFailed, + }, + "query smart with invalid json": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateSmart}, + srcReq: abci.RequestQuery{Data: []byte(`not a json string`)}, + expErr: types.ErrInvalid, + }, + "query non-existent raw key": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw}, + srcReq: abci.RequestQuery{Data: []byte("i do not exist")}, + expRes: nil, + }, + "query empty raw key": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw}, + srcReq: abci.RequestQuery{Data: []byte("")}, + expRes: nil, + }, + "query nil raw key": { + srcPath: []string{QueryGetContractState, addr.String(), QueryMethodContractStateRaw}, + srcReq: abci.RequestQuery{Data: nil}, + expRes: nil, + }, + "query raw with unknown address": { + srcPath: []string{QueryGetContractState, anyAddr.String(), QueryMethodContractStateRaw}, + expRes: nil, + }, + "query all with unknown address": { + srcPath: []string{QueryGetContractState, anyAddr.String(), QueryMethodContractStateAll}, + expModelLen: 0, + }, + "query smart with unknown address": { + srcPath: []string{QueryGetContractState, anyAddr.String(), QueryMethodContractStateSmart}, + srcReq: abci.RequestQuery{Data: []byte(`{}`)}, + expModelLen: 0, + expErr: types.ErrNotFound, + }, + } + + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + binResult, err := q(ctx, spec.srcPath, spec.srcReq) + // require.True(t, spec.expErr.Is(err), "unexpected error") + require.True(t, errors.Is(err, spec.expErr), err) + + // if smart query, check custom response + if spec.srcPath[2] != QueryMethodContractStateAll { + require.Equal(t, spec.expRes, binResult) + return + } + + // otherwise, check returned models + var r []types.Model + if spec.expErr == nil { + require.NoError(t, json.Unmarshal(binResult, &r)) + require.NotNil(t, r) + } + require.Len(t, r, spec.expModelLen) + // and in result set + for _, v := range spec.expModelContains { + assert.Contains(t, r, v) + } + }) + } +} + +func TestLegacyQueryContractListByCodeOrdering(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 500)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit.Add(deposit...)...) + anyAddr := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, wasmCode, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: anyAddr, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + // manage some realistic block settings + var h int64 = 10 + setBlock := func(ctx sdk.Context, height int64) sdk.Context { + ctx = ctx.WithBlockHeight(height) + meter := sdk.NewGasMeter(1000000) + ctx = ctx.WithGasMeter(meter) + ctx = ctx.WithBlockGasMeter(meter) + return ctx + } + + // create 10 contracts with real block/gas setup + for i := range [10]int{} { + // 3 tx per block, so we ensure both comparisons work + if i%3 == 0 { + ctx = setBlock(ctx, h) + h++ + } + _, _, err = keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, fmt.Sprintf("contract %d", i), topUp) + require.NoError(t, err) + } + + // query and check the results are properly sorted + var defaultQueryGasLimit sdk.Gas = 3000000 + q := NewLegacyQuerier(keeper, defaultQueryGasLimit) + + query := []string{QueryListContractByCode, fmt.Sprintf("%d", codeID)} + data := abci.RequestQuery{} + res, err := q(ctx, query, data) + require.NoError(t, err) + + var contracts []string + err = json.Unmarshal(res, &contracts) + require.NoError(t, err) + + require.Equal(t, 10, len(contracts)) + + for _, contract := range contracts { + assert.NotEmpty(t, contract) + } +} + +func TestLegacyQueryContractHistory(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + var otherAddr sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen) + + specs := map[string]struct { + srcQueryAddr sdk.AccAddress + srcHistory []types.ContractCodeHistoryEntry + expContent []types.ContractCodeHistoryEntry + }{ + "response with internal fields cleared": { + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeGenesis, + CodeID: firstCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: []byte(`"init message"`), + }}, + expContent: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeGenesis, + CodeID: firstCodeID, + Msg: []byte(`"init message"`), + }}, + }, + "response with multiple entries": { + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: []byte(`"init message"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: []byte(`"migrate message 1"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 3, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: []byte(`"migrate message 2"`), + }}, + expContent: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Msg: []byte(`"init message"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Msg: []byte(`"migrate message 1"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 3, + Msg: []byte(`"migrate message 2"`), + }}, + }, + "unknown contract address": { + srcQueryAddr: otherAddr, + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeGenesis, + CodeID: firstCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: []byte(`"init message"`), + }}, + expContent: []types.ContractCodeHistoryEntry{}, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + _, _, myContractAddr := keyPubAddr() + keeper.appendToContractHistory(ctx, myContractAddr, spec.srcHistory...) + + var defaultQueryGasLimit sdk.Gas = 3000000 + q := NewLegacyQuerier(keeper, defaultQueryGasLimit) + queryContractAddr := spec.srcQueryAddr + if queryContractAddr == nil { + queryContractAddr = myContractAddr + } + + // when + query := []string{QueryContractHistory, queryContractAddr.String()} + data := abci.RequestQuery{} + resData, err := q(ctx, query, data) + + // then + require.NoError(t, err) + var got []types.ContractCodeHistoryEntry + err = json.Unmarshal(resData, &got) + require.NoError(t, err) + + assert.Equal(t, spec.expContent, got) + }) + } +} + +func TestLegacyQueryCodeList(t *testing.T) { + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + specs := map[string]struct { + codeIDs []uint64 + }{ + "none": {}, + "no gaps": { + codeIDs: []uint64{1, 2, 3}, + }, + "with gaps": { + codeIDs: []uint64{2, 4, 6}, + }, + } + + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + for _, codeID := range spec.codeIDs { + require.NoError(t, keeper.importCode(ctx, codeID, + types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)), + wasmCode), + ) + } + var defaultQueryGasLimit sdk.Gas = 3000000 + q := NewLegacyQuerier(keeper, defaultQueryGasLimit) + // when + query := []string{QueryListCode} + data := abci.RequestQuery{} + resData, err := q(ctx, query, data) + + // then + require.NoError(t, err) + if len(spec.codeIDs) == 0 { + require.Nil(t, resData) + return + } + + var got []map[string]interface{} + err = json.Unmarshal(resData, &got) + require.NoError(t, err) + require.Len(t, got, len(spec.codeIDs)) + for i, exp := range spec.codeIDs { + assert.EqualValues(t, exp, got[i]["id"]) + } + }) + } +} diff --git a/x/wasm/keeper/metrics.go b/x/wasm/keeper/metrics.go new file mode 100644 index 00000000..4c4b959f --- /dev/null +++ b/x/wasm/keeper/metrics.go @@ -0,0 +1,72 @@ +package keeper + +import ( + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/prometheus/client_golang/prometheus" +) + +const ( + labelPinned = "pinned" + labelMemory = "memory" + labelFs = "fs" +) + +// metricSource source of wasmvm metrics +type metricSource interface { + GetMetrics() (*wasmvmtypes.Metrics, error) +} + +var _ prometheus.Collector = (*WasmVMMetricsCollector)(nil) + +// WasmVMMetricsCollector custom metrics collector to be used with Prometheus +type WasmVMMetricsCollector struct { + source metricSource + CacheHitsDescr *prometheus.Desc + CacheMissesDescr *prometheus.Desc + CacheElementsDescr *prometheus.Desc + CacheSizeDescr *prometheus.Desc +} + +// NewWasmVMMetricsCollector constructor +func NewWasmVMMetricsCollector(s metricSource) *WasmVMMetricsCollector { + return &WasmVMMetricsCollector{ + source: s, + CacheHitsDescr: prometheus.NewDesc("wasmvm_cache_hits_total", "Total number of cache hits", []string{"type"}, nil), + CacheMissesDescr: prometheus.NewDesc("wasmvm_cache_misses_total", "Total number of cache misses", nil, nil), + CacheElementsDescr: prometheus.NewDesc("wasmvm_cache_elements_total", "Total number of elements in the cache", []string{"type"}, nil), + CacheSizeDescr: prometheus.NewDesc("wasmvm_cache_size_bytes", "Total number of elements in the cache", []string{"type"}, nil), + } +} + +// Register registers all metrics +func (p *WasmVMMetricsCollector) Register(r prometheus.Registerer) { + r.MustRegister(p) +} + +// Describe sends the super-set of all possible descriptors of metrics +func (p *WasmVMMetricsCollector) Describe(descs chan<- *prometheus.Desc) { + descs <- p.CacheHitsDescr + descs <- p.CacheMissesDescr + descs <- p.CacheElementsDescr + descs <- p.CacheSizeDescr +} + +// Collect is called by the Prometheus registry when collecting metrics. +func (p *WasmVMMetricsCollector) Collect(c chan<- prometheus.Metric) { + m, err := p.source.GetMetrics() + if err != nil { + return + } + c <- prometheus.MustNewConstMetric(p.CacheHitsDescr, prometheus.CounterValue, float64(m.HitsPinnedMemoryCache), labelPinned) + c <- prometheus.MustNewConstMetric(p.CacheHitsDescr, prometheus.CounterValue, float64(m.HitsMemoryCache), labelMemory) + c <- prometheus.MustNewConstMetric(p.CacheHitsDescr, prometheus.CounterValue, float64(m.HitsFsCache), labelFs) + c <- prometheus.MustNewConstMetric(p.CacheMissesDescr, prometheus.CounterValue, float64(m.Misses)) + c <- prometheus.MustNewConstMetric(p.CacheElementsDescr, prometheus.GaugeValue, float64(m.ElementsPinnedMemoryCache), labelPinned) + c <- prometheus.MustNewConstMetric(p.CacheElementsDescr, prometheus.GaugeValue, float64(m.ElementsMemoryCache), labelMemory) + c <- prometheus.MustNewConstMetric(p.CacheSizeDescr, prometheus.GaugeValue, float64(m.SizeMemoryCache), labelMemory) + c <- prometheus.MustNewConstMetric(p.CacheSizeDescr, prometheus.GaugeValue, float64(m.SizePinnedMemoryCache), labelPinned) + // Node about fs metrics: + // The number of elements and the size of elements in the file system cache cannot easily be obtained. + // We had to either scan the whole directory of potentially thousands of files or track the values when files are added or removed. + // Such a tracking would need to be on disk such that the values are not cleared when the node is restarted. +} diff --git a/x/wasm/keeper/migrate_test.go b/x/wasm/keeper/migrate_test.go new file mode 100644 index 00000000..fd7a437b --- /dev/null +++ b/x/wasm/keeper/migrate_test.go @@ -0,0 +1,61 @@ +package keeper + +import ( + "bytes" + "encoding/json" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestMigrate1To2(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + wasmKeeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := sdk.AccAddress(bytes.Repeat([]byte{1}, address.Len)) + keepers.Faucet.Fund(ctx, creator, deposit...) + example := StoreHackatomExampleContract(t, ctx, keepers) + + initMsg := HackatomExampleInitMsg{ + Verifier: RandomAccountAddress(t), + Beneficiary: RandomAccountAddress(t), + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + em := sdk.NewEventManager() + + // create with no balance is also legal + gotContractAddr1, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + gotContractAddr2, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + gotContractAddr3, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), example.CodeID, creator, nil, initMsgBz, "demo contract 1", nil) + + info1 := wasmKeeper.GetContractInfo(ctx, gotContractAddr1) + info2 := wasmKeeper.GetContractInfo(ctx, gotContractAddr2) + info3 := wasmKeeper.GetContractInfo(ctx, gotContractAddr3) + + // remove key + ctx.KVStore(wasmKeeper.storeKey).Delete(types.GetContractByCreatorSecondaryIndexKey(creator, info1.Created.Bytes(), gotContractAddr1)) + ctx.KVStore(wasmKeeper.storeKey).Delete(types.GetContractByCreatorSecondaryIndexKey(creator, info2.Created.Bytes(), gotContractAddr2)) + ctx.KVStore(wasmKeeper.storeKey).Delete(types.GetContractByCreatorSecondaryIndexKey(creator, info3.Created.Bytes(), gotContractAddr3)) + + // migrator + migrator := NewMigrator(*wasmKeeper) + migrator.Migrate1to2(ctx) + + // check new store + var allContract []string + wasmKeeper.IterateContractsByCreator(ctx, creator, func(addr sdk.AccAddress) bool { + allContract = append(allContract, addr.String()) + return false + }) + + require.Equal(t, []string{gotContractAddr1.String(), gotContractAddr2.String(), gotContractAddr3.String()}, allContract) +} diff --git a/x/wasm/keeper/migrations.go b/x/wasm/keeper/migrations.go new file mode 100644 index 00000000..f8d375d0 --- /dev/null +++ b/x/wasm/keeper/migrations.go @@ -0,0 +1,27 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{keeper: keeper} +} + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + m.keeper.IterateContractInfo(ctx, func(contractAddr sdk.AccAddress, contractInfo types.ContractInfo) bool { + creator := sdk.MustAccAddressFromBech32(contractInfo.Creator) + m.keeper.addToContractCreatorSecondaryIndex(ctx, creator, contractInfo.Created, contractAddr) + return false + }) + return nil +} diff --git a/x/wasm/keeper/msg_dispatcher.go b/x/wasm/keeper/msg_dispatcher.go new file mode 100644 index 00000000..07d3aab9 --- /dev/null +++ b/x/wasm/keeper/msg_dispatcher.go @@ -0,0 +1,222 @@ +package keeper + +import ( + "bytes" + "fmt" + "sort" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// Messenger is an extension point for custom wasmd message handling +type Messenger interface { + // DispatchMsg encodes the wasmVM message and dispatches it. + DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) +} + +// replyer is a subset of keeper that can handle replies to submessages +type replyer interface { + reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) +} + +// MessageDispatcher coordinates message sending and submessage reply/ state commits +type MessageDispatcher struct { + messenger Messenger + keeper replyer +} + +// NewMessageDispatcher constructor +func NewMessageDispatcher(messenger Messenger, keeper replyer) *MessageDispatcher { + return &MessageDispatcher{messenger: messenger, keeper: keeper} +} + +// DispatchMessages sends all messages. +func (d MessageDispatcher) DispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.CosmosMsg) error { + for _, msg := range msgs { + events, _, err := d.messenger.DispatchMsg(ctx, contractAddr, ibcPort, msg) + if err != nil { + return err + } + // redispatch all events, (type sdk.EventTypeMessage will be filtered out in the handler) + ctx.EventManager().EmitEvents(events) + } + return nil +} + +// dispatchMsgWithGasLimit sends a message with gas limit applied +func (d MessageDispatcher) dispatchMsgWithGasLimit(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msg wasmvmtypes.CosmosMsg, gasLimit uint64) (events []sdk.Event, data [][]byte, err error) { + limitedMeter := sdk.NewGasMeter(gasLimit) + subCtx := ctx.WithGasMeter(limitedMeter) + + // catch out of gas panic and just charge the entire gas limit + defer func() { + if r := recover(); r != nil { + // if it's not an OutOfGas error, raise it again + if _, ok := r.(sdk.ErrorOutOfGas); !ok { + // log it to get the original stack trace somewhere (as panic(r) keeps message but stacktrace to here + moduleLogger(ctx).Info("SubMsg rethrowing panic: %#v", r) + panic(r) + } + ctx.GasMeter().ConsumeGas(gasLimit, "Sub-Message OutOfGas panic") + err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "SubMsg hit gas limit") + } + }() + events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg) + + // make sure we charge the parent what was spent + spent := subCtx.GasMeter().GasConsumed() + ctx.GasMeter().ConsumeGas(spent, "From limited Sub-Message") + + return events, data, err +} + +// DispatchSubmessages builds a sandbox to execute these messages and returns the execution result to the contract +// that dispatched them, both on success as well as failure +func (d MessageDispatcher) DispatchSubmessages(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) { + var rsp []byte + for _, msg := range msgs { + switch msg.ReplyOn { + case wasmvmtypes.ReplySuccess, wasmvmtypes.ReplyError, wasmvmtypes.ReplyAlways, wasmvmtypes.ReplyNever: + default: + return nil, sdkerrors.Wrap(types.ErrInvalid, "replyOn value") + } + // first, we build a sub-context which we can use inside the submessages + subCtx, commit := ctx.CacheContext() + em := sdk.NewEventManager() + subCtx = subCtx.WithEventManager(em) + + // check how much gas left locally, optionally wrap the gas meter + gasRemaining := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumed() + limitGas := msg.GasLimit != nil && (*msg.GasLimit < gasRemaining) + + var err error + var events []sdk.Event + var data [][]byte + if limitGas { + events, data, err = d.dispatchMsgWithGasLimit(subCtx, contractAddr, ibcPort, msg.Msg, *msg.GasLimit) + } else { + events, data, err = d.messenger.DispatchMsg(subCtx, contractAddr, ibcPort, msg.Msg) + } + + // if it succeeds, commit state changes from submessage, and pass on events to Event Manager + var filteredEvents []sdk.Event + if err == nil { + commit() + filteredEvents = filterEvents(append(em.Events(), events...)) + ctx.EventManager().EmitEvents(filteredEvents) + if msg.Msg.Wasm == nil { + filteredEvents = []sdk.Event{} + } else { + for _, e := range filteredEvents { + attributes := e.Attributes + sort.SliceStable(attributes, func(i, j int) bool { + return bytes.Compare(attributes[i].Key, attributes[j].Key) < 0 + }) + } + } + } // on failure, revert state from sandbox, and ignore events (just skip doing the above) + + // we only callback if requested. Short-circuit here the cases we don't want to + if (msg.ReplyOn == wasmvmtypes.ReplySuccess || msg.ReplyOn == wasmvmtypes.ReplyNever) && err != nil { + return nil, err + } + if msg.ReplyOn == wasmvmtypes.ReplyNever || (msg.ReplyOn == wasmvmtypes.ReplyError && err == nil) { + continue + } + + // otherwise, we create a SubMsgResult and pass it into the calling contract + var result wasmvmtypes.SubMsgResult + if err == nil { + // just take the first one for now if there are multiple sub-sdk messages + // and safely return nothing if no data + var responseData []byte + if len(data) > 0 { + responseData = data[0] + } + result = wasmvmtypes.SubMsgResult{ + Ok: &wasmvmtypes.SubMsgResponse{ + Events: sdkEventsToWasmVMEvents(filteredEvents), + Data: responseData, + }, + } + } else { + // Issue #759 - we don't return error string for worries of non-determinism + moduleLogger(ctx).Info("Redacting submessage error", "cause", err) + result = wasmvmtypes.SubMsgResult{ + Err: redactError(err).Error(), + } + } + + // now handle the reply, we use the parent context, and abort on error + reply := wasmvmtypes.Reply{ + ID: msg.ID, + Result: result, + } + + // we can ignore any result returned as there is nothing to do with the data + // and the events are already in the ctx.EventManager() + rspData, err := d.keeper.reply(ctx, contractAddr, reply) + switch { + case err != nil: + return nil, sdkerrors.Wrap(err, "reply") + case rspData != nil: + rsp = rspData + } + } + return rsp, nil +} + +// Issue #759 - we don't return error string for worries of non-determinism +func redactError(err error) error { + // Do not redact system errors + // SystemErrors must be created in x/wasm and we can ensure determinism + if wasmvmtypes.ToSystemError(err) != nil { + return err + } + + // FIXME: do we want to hardcode some constant string mappings here as well? + // Or better document them? (SDK error string may change on a patch release to fix wording) + // sdk/11 is out of gas + // sdk/5 is insufficient funds (on bank send) + // (we can theoretically redact less in the future, but this is a first step to safety) + codespace, code, _ := sdkerrors.ABCIInfo(err, false) + return fmt.Errorf("codespace: %s, code: %d", codespace, code) +} + +func filterEvents(events []sdk.Event) []sdk.Event { + // pre-allocate space for efficiency + res := make([]sdk.Event, 0, len(events)) + for _, ev := range events { + if ev.Type != "message" { + res = append(res, ev) + } + } + return res +} + +func sdkEventsToWasmVMEvents(events []sdk.Event) []wasmvmtypes.Event { + res := make([]wasmvmtypes.Event, len(events)) + for i, ev := range events { + res[i] = wasmvmtypes.Event{ + Type: ev.Type, + Attributes: sdkAttributesToWasmVMAttributes(ev.Attributes), + } + } + return res +} + +func sdkAttributesToWasmVMAttributes(attrs []abci.EventAttribute) []wasmvmtypes.EventAttribute { + res := make([]wasmvmtypes.EventAttribute, len(attrs)) + for i, attr := range attrs { + res[i] = wasmvmtypes.EventAttribute{ + Key: string(attr.Key), + Value: string(attr.Value), + } + } + return res +} diff --git a/x/wasm/keeper/msg_dispatcher_test.go b/x/wasm/keeper/msg_dispatcher_test.go new file mode 100644 index 00000000..0e9db4e0 --- /dev/null +++ b/x/wasm/keeper/msg_dispatcher_test.go @@ -0,0 +1,426 @@ +package keeper + +import ( + "errors" + "fmt" + "testing" + + "github.com/tendermint/tendermint/libs/log" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" +) + +func TestDispatchSubmessages(t *testing.T) { + noReplyCalled := &mockReplyer{} + var anyGasLimit uint64 = 1 + specs := map[string]struct { + msgs []wasmvmtypes.SubMsg + replyer *mockReplyer + msgHandler *wasmtesting.MockMessageHandler + expErr bool + expData []byte + expCommits []bool + expEvents sdk.Events + }{ + "no reply on error without error": { + msgs: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyError}}, + replyer: noReplyCalled, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, [][]byte{[]byte("myData")}, nil + }, + }, + expCommits: []bool{true}, + }, + "no reply on success without success": { + msgs: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplySuccess}}, + replyer: noReplyCalled, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, errors.New("test, ignore") + }, + }, + expCommits: []bool{false}, + expErr: true, + }, + "reply on success - received": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplySuccess, + }}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + return []byte("myReplyData"), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, [][]byte{[]byte("myData")}, nil + }, + }, + expData: []byte("myReplyData"), + expCommits: []bool{true}, + }, + "reply on error - handled": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplyError, + }}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + return []byte("myReplyData"), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, errors.New("my error") + }, + }, + expData: []byte("myReplyData"), + expCommits: []bool{false}, + }, + "with reply events": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplySuccess, + }}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + ctx.EventManager().EmitEvent(sdk.NewEvent("wasm-reply")) + return []byte("myReplyData"), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: []byte("foo"), Value: []byte("bar")}}}} + return myEvents, [][]byte{[]byte("myData")}, nil + }, + }, + expData: []byte("myReplyData"), + expCommits: []bool{true}, + expEvents: []sdk.Event{ + { + Type: "myEvent", + Attributes: []abci.EventAttribute{{Key: []byte("foo"), Value: []byte("bar")}}, + }, + sdk.NewEvent("wasm-reply"), + }, + }, + "with context events - released on commit": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplyNever, + }}, + replyer: &mockReplyer{}, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: []byte("foo"), Value: []byte("bar")}}}} + ctx.EventManager().EmitEvents(myEvents) + return nil, nil, nil + }, + }, + expCommits: []bool{true}, + expEvents: []sdk.Event{{ + Type: "myEvent", + Attributes: []abci.EventAttribute{{Key: []byte("foo"), Value: []byte("bar")}}, + }}, + }, + "with context events - discarded on failure": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplyNever, + }}, + replyer: &mockReplyer{}, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + myEvents := []sdk.Event{{Type: "myEvent", Attributes: []abci.EventAttribute{{Key: []byte("foo"), Value: []byte("bar")}}}} + ctx.EventManager().EmitEvents(myEvents) + return nil, nil, errors.New("testing") + }, + }, + expCommits: []bool{false}, + expErr: true, + }, + "reply returns error": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplySuccess, + }}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + return nil, errors.New("reply failed") + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, nil + }, + }, + expCommits: []bool{false}, + expErr: true, + }, + "with gas limit - out of gas": { + msgs: []wasmvmtypes.SubMsg{{ + GasLimit: &anyGasLimit, + ReplyOn: wasmvmtypes.ReplyError, + }}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + return []byte("myReplyData"), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + ctx.GasMeter().ConsumeGas(sdk.Gas(101), "testing") + return nil, [][]byte{[]byte("someData")}, nil + }, + }, + expData: []byte("myReplyData"), + expCommits: []bool{false}, + }, + "with gas limit - within limit no error": { + msgs: []wasmvmtypes.SubMsg{{ + GasLimit: &anyGasLimit, + ReplyOn: wasmvmtypes.ReplyError, + }}, + replyer: &mockReplyer{}, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + ctx.GasMeter().ConsumeGas(sdk.Gas(1), "testing") + return nil, [][]byte{[]byte("someData")}, nil + }, + }, + expCommits: []bool{true}, + }, + "never reply - with nil response": { + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, + replyer: &mockReplyer{}, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, [][]byte{nil}, nil + }, + }, + expCommits: []bool{true, true}, + }, + "never reply - with any non nil response": { + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, + replyer: &mockReplyer{}, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, [][]byte{{}}, nil + }, + }, + expCommits: []bool{true, true}, + }, + "never reply - with error": { + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyNever}, {ID: 2, ReplyOn: wasmvmtypes.ReplyNever}}, + replyer: &mockReplyer{}, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, [][]byte{{}}, errors.New("testing") + }, + }, + expCommits: []bool{false, false}, + expErr: true, + }, + "multiple msg - last reply returned": { + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyError}, {ID: 2, ReplyOn: wasmvmtypes.ReplyError}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + return []byte(fmt.Sprintf("myReplyData:%d", reply.ID)), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, errors.New("my error") + }, + }, + expData: []byte("myReplyData:2"), + expCommits: []bool{false, false}, + }, + "multiple msg - last non nil reply returned": { + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyError}, {ID: 2, ReplyOn: wasmvmtypes.ReplyError}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if reply.ID == 2 { + return nil, nil + } + return []byte("myReplyData:1"), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, errors.New("my error") + }, + }, + expData: []byte("myReplyData:1"), + expCommits: []bool{false, false}, + }, + "multiple msg - empty reply can overwrite result": { + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyError}, {ID: 2, ReplyOn: wasmvmtypes.ReplyError}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if reply.ID == 2 { + return []byte{}, nil + } + return []byte("myReplyData:1"), nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + return nil, nil, errors.New("my error") + }, + }, + expData: []byte{}, + expCommits: []bool{false, false}, + }, + "message event filtered without reply": { + msgs: []wasmvmtypes.SubMsg{{ + ReplyOn: wasmvmtypes.ReplyNever, + }}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + return nil, errors.New("should never be called") + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + myEvents := []sdk.Event{ + sdk.NewEvent("message"), + sdk.NewEvent("execute", sdk.NewAttribute("foo", "bar")), + } + return myEvents, [][]byte{[]byte("myData")}, nil + }, + }, + expData: nil, + expCommits: []bool{true}, + expEvents: []sdk.Event{sdk.NewEvent("execute", sdk.NewAttribute("foo", "bar"))}, + }, + "wasm reply gets proper events": { + // put fake wasmmsg in here to show where it comes from + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Wasm: &wasmvmtypes.WasmMsg{}}}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if reply.Result.Err != "" { + return nil, errors.New(reply.Result.Err) + } + res := reply.Result.Ok + + // ensure the input events are what we expect + // I didn't use require.Equal() to act more like a contract... but maybe that would be better + if len(res.Events) != 2 { + return nil, fmt.Errorf("event count: %#v", res.Events) + } + if res.Events[0].Type != "execute" { + return nil, fmt.Errorf("event0: %#v", res.Events[0]) + } + if res.Events[1].Type != "wasm" { + return nil, fmt.Errorf("event1: %#v", res.Events[1]) + } + + // let's add a custom event here and see if it makes it out + ctx.EventManager().EmitEvent(sdk.NewEvent("wasm-reply")) + + // update data from what we got in + return res.Data, nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + events = []sdk.Event{ + sdk.NewEvent("message", sdk.NewAttribute("_contract_address", contractAddr.String())), + // we don't know what the contarctAddr will be so we can't use it in the final tests + sdk.NewEvent("execute", sdk.NewAttribute("_contract_address", "placeholder-random-addr")), + sdk.NewEvent("wasm", sdk.NewAttribute("random", "data")), + } + return events, [][]byte{[]byte("subData")}, nil + }, + }, + expData: []byte("subData"), + expCommits: []bool{true}, + expEvents: []sdk.Event{ + sdk.NewEvent("execute", sdk.NewAttribute("_contract_address", "placeholder-random-addr")), + sdk.NewEvent("wasm", sdk.NewAttribute("random", "data")), + sdk.NewEvent("wasm-reply"), + }, + }, + "non-wasm reply events get filtered": { + // show events from a stargate message gets filtered out + msgs: []wasmvmtypes.SubMsg{{ID: 1, ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Stargate: &wasmvmtypes.StargateMsg{}}}}, + replyer: &mockReplyer{ + replyFn: func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if reply.Result.Err != "" { + return nil, errors.New(reply.Result.Err) + } + res := reply.Result.Ok + + // ensure the input events are what we expect + // I didn't use require.Equal() to act more like a contract... but maybe that would be better + if len(res.Events) != 0 { + return nil, errors.New("events not filtered out") + } + + // let's add a custom event here and see if it makes it out + ctx.EventManager().EmitEvent(sdk.NewEvent("stargate-reply")) + + // update data from what we got in + return res.Data, nil + }, + }, + msgHandler: &wasmtesting.MockMessageHandler{ + DispatchMsgFn: func(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) { + events = []sdk.Event{ + // this is filtered out + sdk.NewEvent("message", sdk.NewAttribute("stargate", "something-something")), + // we still emit this to the client, but not the contract + sdk.NewEvent("non-determinstic"), + } + return events, [][]byte{[]byte("subData")}, nil + }, + }, + expData: []byte("subData"), + expCommits: []bool{true}, + expEvents: []sdk.Event{ + sdk.NewEvent("non-determinstic"), + // the event from reply is also exposed + sdk.NewEvent("stargate-reply"), + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + var mockStore wasmtesting.MockCommitMultiStore + em := sdk.NewEventManager() + ctx := sdk.Context{}.WithMultiStore(&mockStore). + WithGasMeter(sdk.NewGasMeter(100)). + WithEventManager(em).WithLogger(log.TestingLogger()) + d := NewMessageDispatcher(spec.msgHandler, spec.replyer) + gotData, gotErr := d.DispatchSubmessages(ctx, RandomAccountAddress(t), "any_port", spec.msgs) + if spec.expErr { + require.Error(t, gotErr) + assert.Empty(t, em.Events()) + return + } else { + require.NoError(t, gotErr) + assert.Equal(t, spec.expData, gotData) + } + assert.Equal(t, spec.expCommits, mockStore.Committed) + if len(spec.expEvents) == 0 { + assert.Empty(t, em.Events()) + } else { + assert.Equal(t, spec.expEvents, em.Events()) + } + }) + } +} + +type mockReplyer struct { + replyFn func(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) +} + +func (m mockReplyer) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply wasmvmtypes.Reply) ([]byte, error) { + if m.replyFn == nil { + panic("not expected to be called") + } + return m.replyFn(ctx, contractAddress, reply) +} diff --git a/x/wasm/keeper/msg_server.go b/x/wasm/keeper/msg_server.go new file mode 100644 index 00000000..3034b929 --- /dev/null +++ b/x/wasm/keeper/msg_server.go @@ -0,0 +1,256 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var _ types.MsgServer = msgServer{} + +type msgServer struct { + keeper types.ContractOpsKeeper +} + +func NewMsgServerImpl(k types.ContractOpsKeeper) types.MsgServer { + return &msgServer{keeper: k} +} + +func (m msgServer) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*types.MsgStoreCodeResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + ctx := sdk.UnwrapSDKContext(goCtx) + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + codeID, checksum, err := m.keeper.Create(ctx, senderAddr, msg.WASMByteCode, msg.InstantiatePermission) + if err != nil { + return nil, err + } + + return &types.MsgStoreCodeResponse{ + CodeID: codeID, + Checksum: checksum, + }, nil +} + +// InstantiateContract instantiate a new contract with classic sequence based address generation +func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInstantiateContract) (*types.MsgInstantiateContractResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + ctx := sdk.UnwrapSDKContext(goCtx) + + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + var adminAddr sdk.AccAddress + if msg.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(msg.Admin); err != nil { + return nil, sdkerrors.Wrap(err, "admin") + } + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + contractAddr, data, err := m.keeper.Instantiate(ctx, msg.CodeID, senderAddr, adminAddr, msg.Msg, msg.Label, msg.Funds) + if err != nil { + return nil, err + } + + return &types.MsgInstantiateContractResponse{ + Address: contractAddr.String(), + Data: data, + }, nil +} + +// InstantiateContract2 instantiate a new contract with predicatable address generated +func (m msgServer) InstantiateContract2(goCtx context.Context, msg *types.MsgInstantiateContract2) (*types.MsgInstantiateContract2Response, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + ctx := sdk.UnwrapSDKContext(goCtx) + + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + var adminAddr sdk.AccAddress + if msg.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(msg.Admin); err != nil { + return nil, sdkerrors.Wrap(err, "admin") + } + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + contractAddr, data, err := m.keeper.Instantiate2(ctx, msg.CodeID, senderAddr, adminAddr, msg.Msg, msg.Label, msg.Funds, msg.Salt, msg.FixMsg) + if err != nil { + return nil, err + } + + return &types.MsgInstantiateContract2Response{ + Address: contractAddr.String(), + Data: data, + }, nil +} + +func (m msgServer) ExecuteContract(goCtx context.Context, msg *types.MsgExecuteContract) (*types.MsgExecuteContractResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + contractAddr, err := sdk.AccAddressFromBech32(msg.Contract) + if err != nil { + return nil, sdkerrors.Wrap(err, "contract") + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + data, err := m.keeper.Execute(ctx, contractAddr, senderAddr, msg.Msg, msg.Funds) + if err != nil { + return nil, err + } + + return &types.MsgExecuteContractResponse{ + Data: data, + }, nil +} + +func (m msgServer) MigrateContract(goCtx context.Context, msg *types.MsgMigrateContract) (*types.MsgMigrateContractResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + contractAddr, err := sdk.AccAddressFromBech32(msg.Contract) + if err != nil { + return nil, sdkerrors.Wrap(err, "contract") + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + data, err := m.keeper.Migrate(ctx, contractAddr, senderAddr, msg.CodeID, msg.Msg) + if err != nil { + return nil, err + } + + return &types.MsgMigrateContractResponse{ + Data: data, + }, nil +} + +func (m msgServer) UpdateAdmin(goCtx context.Context, msg *types.MsgUpdateAdmin) (*types.MsgUpdateAdminResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + contractAddr, err := sdk.AccAddressFromBech32(msg.Contract) + if err != nil { + return nil, sdkerrors.Wrap(err, "contract") + } + newAdminAddr, err := sdk.AccAddressFromBech32(msg.NewAdmin) + if err != nil { + return nil, sdkerrors.Wrap(err, "new admin") + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + if err := m.keeper.UpdateContractAdmin(ctx, contractAddr, senderAddr, newAdminAddr); err != nil { + return nil, err + } + + return &types.MsgUpdateAdminResponse{}, nil +} + +func (m msgServer) ClearAdmin(goCtx context.Context, msg *types.MsgClearAdmin) (*types.MsgClearAdminResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + contractAddr, err := sdk.AccAddressFromBech32(msg.Contract) + if err != nil { + return nil, sdkerrors.Wrap(err, "contract") + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + if err := m.keeper.ClearContractAdmin(ctx, contractAddr, senderAddr); err != nil { + return nil, err + } + + return &types.MsgClearAdminResponse{}, nil +} + +func (m msgServer) UpdateInstantiateConfig(goCtx context.Context, msg *types.MsgUpdateInstantiateConfig) (*types.MsgUpdateInstantiateConfigResponse, error) { + if err := msg.ValidateBasic(); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := m.keeper.SetAccessConfig(ctx, msg.CodeID, sdk.AccAddress(msg.Sender), *msg.NewInstantiatePermission); err != nil { + return nil, err + } + ctx.EventManager().EmitEvent(sdk.NewEvent( + sdk.EventTypeMessage, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender), + )) + + return &types.MsgUpdateInstantiateConfigResponse{}, nil +} diff --git a/x/wasm/keeper/msg_server_integration_test.go b/x/wasm/keeper/msg_server_integration_test.go new file mode 100644 index 00000000..c5dd0b21 --- /dev/null +++ b/x/wasm/keeper/msg_server_integration_test.go @@ -0,0 +1,46 @@ +package keeper_test + +import ( + "crypto/sha256" + _ "embed" + "testing" + + "github.com/cosmos/cosmos-sdk/testutil/testdata" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cerc-io/laconicd/app" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +//go:embed testdata/reflect.wasm +var wasmContract []byte + +func TestStoreCode(t *testing.T) { + wasmApp := app.Setup(false) + ctx := wasmApp.BaseApp.NewContext(false, tmproto.Header{}) + _, _, sender := testdata.KeyTestPubAddr() + msg := types.MsgStoreCodeFixture(func(m *types.MsgStoreCode) { + m.WASMByteCode = wasmContract + m.Sender = sender.String() + }) + + // when + rsp, err := wasmApp.MsgServiceRouter().Handler(msg)(ctx, msg) + + // then + require.NoError(t, err) + var result types.MsgStoreCodeResponse + require.NoError(t, wasmApp.AppCodec().Unmarshal(rsp.Data, &result)) + assert.Equal(t, uint64(1), result.CodeID) + expHash := sha256.Sum256(wasmContract) + assert.Equal(t, expHash[:], result.Checksum) + // and + info := wasmApp.WasmKeeper.GetCodeInfo(ctx, 1) + assert.NotNil(t, info) + assert.Equal(t, expHash[:], info.CodeHash) + assert.Equal(t, sender.String(), info.Creator) + assert.Equal(t, types.DefaultParams().InstantiateDefaultPermission.With(sender), info.InstantiateConfig) +} diff --git a/x/wasm/keeper/options.go b/x/wasm/keeper/options.go new file mode 100644 index 00000000..3136fd00 --- /dev/null +++ b/x/wasm/keeper/options.go @@ -0,0 +1,170 @@ +package keeper + +import ( + "fmt" + "reflect" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/prometheus/client_golang/prometheus" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +type optsFn func(*Keeper) + +func (f optsFn) apply(keeper *Keeper) { + f(keeper) +} + +// WithWasmEngine is an optional constructor parameter to replace the default wasmVM engine with the +// given one. +func WithWasmEngine(x types.WasmerEngine) Option { + return optsFn(func(k *Keeper) { + k.wasmVM = x + }) +} + +// WithMessageHandler is an optional constructor parameter to set a custom handler for wasmVM messages. +// This option should not be combined with Option `WithMessageEncoders` or `WithMessageHandlerDecorator` +func WithMessageHandler(x Messenger) Option { + return optsFn(func(k *Keeper) { + k.messenger = x + }) +} + +// WithMessageHandlerDecorator is an optional constructor parameter to decorate the wasm handler for wasmVM messages. +// This option should not be combined with Option `WithMessageEncoders` or `WithMessageHandler` +func WithMessageHandlerDecorator(d func(old Messenger) Messenger) Option { + return optsFn(func(k *Keeper) { + k.messenger = d(k.messenger) + }) +} + +// WithQueryHandler is an optional constructor parameter to set custom query handler for wasmVM requests. +// This option should not be combined with Option `WithQueryPlugins` or `WithQueryHandlerDecorator` +func WithQueryHandler(x WasmVMQueryHandler) Option { + return optsFn(func(k *Keeper) { + k.wasmVMQueryHandler = x + }) +} + +// WithQueryHandlerDecorator is an optional constructor parameter to decorate the default wasm query handler for wasmVM requests. +// This option should not be combined with Option `WithQueryPlugins` or `WithQueryHandler` +func WithQueryHandlerDecorator(d func(old WasmVMQueryHandler) WasmVMQueryHandler) Option { + return optsFn(func(k *Keeper) { + k.wasmVMQueryHandler = d(k.wasmVMQueryHandler) + }) +} + +// WithQueryPlugins is an optional constructor parameter to pass custom query plugins for wasmVM requests. +// This option expects the default `QueryHandler` set and should not be combined with Option `WithQueryHandler` or `WithQueryHandlerDecorator`. +func WithQueryPlugins(x *QueryPlugins) Option { + return optsFn(func(k *Keeper) { + q, ok := k.wasmVMQueryHandler.(QueryPlugins) + if !ok { + panic(fmt.Sprintf("Unsupported query handler type: %T", k.wasmVMQueryHandler)) + } + k.wasmVMQueryHandler = q.Merge(x) + }) +} + +// WithMessageEncoders is an optional constructor parameter to pass custom message encoder to the default wasm message handler. +// This option expects the `DefaultMessageHandler` set and should not be combined with Option `WithMessageHandler` or `WithMessageHandlerDecorator`. +func WithMessageEncoders(x *MessageEncoders) Option { + return optsFn(func(k *Keeper) { + q, ok := k.messenger.(*MessageHandlerChain) + if !ok { + panic(fmt.Sprintf("Unsupported message handler type: %T", k.messenger)) + } + s, ok := q.handlers[0].(SDKMessageHandler) + if !ok { + panic(fmt.Sprintf("Unexpected message handler type: %T", q.handlers[0])) + } + e, ok := s.encoders.(MessageEncoders) + if !ok { + panic(fmt.Sprintf("Unsupported encoder type: %T", s.encoders)) + } + s.encoders = e.Merge(x) + q.handlers[0] = s + }) +} + +// WithCoinTransferrer is an optional constructor parameter to set a custom coin transferrer +func WithCoinTransferrer(x CoinTransferrer) Option { + if x == nil { + panic("must not be nil") + } + return optsFn(func(k *Keeper) { + k.bank = x + }) +} + +// WithAccountPruner is an optional constructor parameter to set a custom type that handles balances and data cleanup +// for accounts pruned on contract instantiate +func WithAccountPruner(x AccountPruner) Option { + if x == nil { + panic("must not be nil") + } + return optsFn(func(k *Keeper) { + k.accountPruner = x + }) +} + +func WithVMCacheMetrics(r prometheus.Registerer) Option { + return optsFn(func(k *Keeper) { + NewWasmVMMetricsCollector(k.wasmVM).Register(r) + }) +} + +// WithGasRegister set a new gas register to implement custom gas costs. +// When the "gas multiplier" for wasmvm gas conversion is modified inside the new register, +// make sure to also use `WithApiCosts` option for non default values +func WithGasRegister(x GasRegister) Option { + if x == nil { + panic("must not be nil") + } + return optsFn(func(k *Keeper) { + k.gasRegister = x + }) +} + +// WithAPICosts sets custom api costs. Amounts are in cosmwasm gas Not SDK gas. +func WithAPICosts(human, canonical uint64) Option { + return optsFn(func(_ *Keeper) { + costHumanize = human + costCanonical = canonical + }) +} + +// WithMaxQueryStackSize overwrites the default limit for maximum query stacks +func WithMaxQueryStackSize(m uint32) Option { + return optsFn(func(k *Keeper) { + k.maxQueryStackSize = m + }) +} + +// WithAcceptedAccountTypesOnContractInstantiation sets the accepted account types. Account types of this list won't be overwritten or cause a failure +// when they exist for an address on contract instantiation. +// +// Values should be references and contain the `*authtypes.BaseAccount` as default bank account type. +func WithAcceptedAccountTypesOnContractInstantiation(accts ...authtypes.AccountI) Option { + m := asTypeMap(accts) + return optsFn(func(k *Keeper) { + k.acceptedAccountTypes = m + }) +} + +func asTypeMap(accts []authtypes.AccountI) map[reflect.Type]struct{} { + m := make(map[reflect.Type]struct{}, len(accts)) + for _, a := range accts { + if a == nil { + panic(types.ErrEmpty.Wrap("address")) + } + at := reflect.TypeOf(a) + if _, exists := m[at]; exists { + panic(types.ErrDuplicate.Wrapf("%T", a)) + } + m[at] = struct{}{} + } + return m +} diff --git a/x/wasm/keeper/options_test.go b/x/wasm/keeper/options_test.go new file mode 100644 index 00000000..47e9e8c2 --- /dev/null +++ b/x/wasm/keeper/options_test.go @@ -0,0 +1,116 @@ +package keeper + +import ( + "reflect" + "testing" + + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestConstructorOptions(t *testing.T) { + specs := map[string]struct { + srcOpt Option + verify func(*testing.T, Keeper) + }{ + "wasm engine": { + srcOpt: WithWasmEngine(&wasmtesting.MockWasmer{}), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockWasmer{}, k.wasmVM) + }, + }, + "message handler": { + srcOpt: WithMessageHandler(&wasmtesting.MockMessageHandler{}), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockMessageHandler{}, k.messenger) + }, + }, + "query plugins": { + srcOpt: WithQueryHandler(&wasmtesting.MockQueryHandler{}), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockQueryHandler{}, k.wasmVMQueryHandler) + }, + }, + "message handler decorator": { + srcOpt: WithMessageHandlerDecorator(func(old Messenger) Messenger { + require.IsType(t, &MessageHandlerChain{}, old) + return &wasmtesting.MockMessageHandler{} + }), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockMessageHandler{}, k.messenger) + }, + }, + "query plugins decorator": { + srcOpt: WithQueryHandlerDecorator(func(old WasmVMQueryHandler) WasmVMQueryHandler { + require.IsType(t, QueryPlugins{}, old) + return &wasmtesting.MockQueryHandler{} + }), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockQueryHandler{}, k.wasmVMQueryHandler) + }, + }, + "coin transferrer": { + srcOpt: WithCoinTransferrer(&wasmtesting.MockCoinTransferrer{}), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockCoinTransferrer{}, k.bank) + }, + }, + "costs": { + srcOpt: WithGasRegister(&wasmtesting.MockGasRegister{}), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, &wasmtesting.MockGasRegister{}, k.gasRegister) + }, + }, + "api costs": { + srcOpt: WithAPICosts(1, 2), + verify: func(t *testing.T, k Keeper) { + t.Cleanup(setApiDefaults) + assert.Equal(t, uint64(1), costHumanize) + assert.Equal(t, uint64(2), costCanonical) + }, + }, + "max recursion query limit": { + srcOpt: WithMaxQueryStackSize(1), + verify: func(t *testing.T, k Keeper) { + assert.IsType(t, uint32(1), k.maxQueryStackSize) + }, + }, + "accepted account types": { + srcOpt: WithAcceptedAccountTypesOnContractInstantiation(&authtypes.BaseAccount{}, &vestingtypes.ContinuousVestingAccount{}), + verify: func(t *testing.T, k Keeper) { + exp := map[reflect.Type]struct{}{ + reflect.TypeOf(&authtypes.BaseAccount{}): {}, + reflect.TypeOf(&vestingtypes.ContinuousVestingAccount{}): {}, + } + assert.Equal(t, exp, k.acceptedAccountTypes) + }, + }, + "account pruner": { + srcOpt: WithAccountPruner(VestingCoinBurner{}), + verify: func(t *testing.T, k Keeper) { + assert.Equal(t, VestingCoinBurner{}, k.accountPruner) + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + k := NewKeeper(nil, nil, paramtypes.NewSubspace(nil, nil, nil, nil, ""), authkeeper.AccountKeeper{}, &bankkeeper.BaseKeeper{}, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, nil, nil, nil, nil, nil, "tempDir", types.DefaultWasmConfig(), AvailableCapabilities, spec.srcOpt) + spec.verify(t, k) + }) + } +} + +func setApiDefaults() { + costHumanize = DefaultGasCostHumanAddress * DefaultGasMultiplier + costCanonical = DefaultGasCostCanonicalAddress * DefaultGasMultiplier +} diff --git a/x/wasm/keeper/proposal_handler.go b/x/wasm/keeper/proposal_handler.go new file mode 100644 index 00000000..3f67a83a --- /dev/null +++ b/x/wasm/keeper/proposal_handler.go @@ -0,0 +1,326 @@ +package keeper + +import ( + "bytes" + "encoding/hex" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// NewWasmProposalHandler creates a new governance Handler for wasm proposals +func NewWasmProposalHandler(k decoratedKeeper, enabledProposalTypes []types.ProposalType) govtypes.Handler { + return NewWasmProposalHandlerX(NewGovPermissionKeeper(k), enabledProposalTypes) +} + +// NewWasmProposalHandlerX creates a new governance Handler for wasm proposals +func NewWasmProposalHandlerX(k types.ContractOpsKeeper, enabledProposalTypes []types.ProposalType) govtypes.Handler { + enabledTypes := make(map[string]struct{}, len(enabledProposalTypes)) + for i := range enabledProposalTypes { + enabledTypes[string(enabledProposalTypes[i])] = struct{}{} + } + return func(ctx sdk.Context, content govtypes.Content) error { + if content == nil { + return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "content must not be empty") + } + if _, ok := enabledTypes[content.ProposalType()]; !ok { + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unsupported wasm proposal content type: %q", content.ProposalType()) + } + switch c := content.(type) { + case *types.StoreCodeProposal: + return handleStoreCodeProposal(ctx, k, *c) + case *types.InstantiateContractProposal: + return handleInstantiateProposal(ctx, k, *c) + case *types.InstantiateContract2Proposal: + return handleInstantiate2Proposal(ctx, k, *c) + case *types.MigrateContractProposal: + return handleMigrateProposal(ctx, k, *c) + case *types.SudoContractProposal: + return handleSudoProposal(ctx, k, *c) + case *types.ExecuteContractProposal: + return handleExecuteProposal(ctx, k, *c) + case *types.UpdateAdminProposal: + return handleUpdateAdminProposal(ctx, k, *c) + case *types.ClearAdminProposal: + return handleClearAdminProposal(ctx, k, *c) + case *types.PinCodesProposal: + return handlePinCodesProposal(ctx, k, *c) + case *types.UnpinCodesProposal: + return handleUnpinCodesProposal(ctx, k, *c) + case *types.UpdateInstantiateConfigProposal: + return handleUpdateInstantiateConfigProposal(ctx, k, *c) + case *types.StoreAndInstantiateContractProposal: + return handleStoreAndInstantiateContractProposal(ctx, k, *c) + default: + return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized wasm proposal content type: %T", c) + } + } +} + +func handleStoreCodeProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.StoreCodeProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + + runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) + if err != nil { + return sdkerrors.Wrap(err, "run as address") + } + codeID, checksum, err := k.Create(ctx, runAsAddr, p.WASMByteCode, p.InstantiatePermission) + if err != nil { + return err + } + + if len(p.CodeHash) != 0 && !bytes.Equal(checksum, p.CodeHash) { + return fmt.Errorf("code-hash mismatch: %X, checksum: %X", p.CodeHash, checksum) + } + + // if code should not be pinned return earlier + if p.UnpinCode { + return nil + } + return k.PinCode(ctx, codeID) +} + +func handleInstantiateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.InstantiateContractProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) + if err != nil { + return sdkerrors.Wrap(err, "run as address") + } + var adminAddr sdk.AccAddress + if p.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(p.Admin); err != nil { + return sdkerrors.Wrap(err, "admin") + } + } + + _, data, err := k.Instantiate(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, p.Funds) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeGovContractResult, + sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), + )) + return nil +} + +func handleInstantiate2Proposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.InstantiateContract2Proposal) error { + // Validatebasic with proposal + if err := p.ValidateBasic(); err != nil { + return err + } + + // Get runAsAddr as AccAddress + runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) + if err != nil { + return sdkerrors.Wrap(err, "run as address") + } + + // Get admin address + var adminAddr sdk.AccAddress + if p.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(p.Admin); err != nil { + return sdkerrors.Wrap(err, "admin") + } + } + + _, data, err := k.Instantiate2(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, p.Funds, p.Salt, p.FixMsg) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeGovContractResult, + sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), + )) + return nil +} + +func handleStoreAndInstantiateContractProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.StoreAndInstantiateContractProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) + if err != nil { + return sdkerrors.Wrap(err, "run as address") + } + var adminAddr sdk.AccAddress + if p.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(p.Admin); err != nil { + return sdkerrors.Wrap(err, "admin") + } + } + + codeID, checksum, err := k.Create(ctx, runAsAddr, p.WASMByteCode, p.InstantiatePermission) + if err != nil { + return err + } + + if p.CodeHash != nil && !bytes.Equal(checksum, p.CodeHash) { + return sdkerrors.Wrap(fmt.Errorf("code-hash mismatch: %X, checksum: %X", p.CodeHash, checksum), "code-hash mismatch") + } + + if !p.UnpinCode { + if err := k.PinCode(ctx, codeID); err != nil { + return err + } + } + + _, data, err := k.Instantiate(ctx, codeID, runAsAddr, adminAddr, p.Msg, p.Label, p.Funds) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeGovContractResult, + sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), + )) + return nil +} + +func handleMigrateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.MigrateContractProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + + contractAddr, err := sdk.AccAddressFromBech32(p.Contract) + if err != nil { + return sdkerrors.Wrap(err, "contract") + } + + // runAs is not used if this is permissioned, so just put any valid address there (second contractAddr) + data, err := k.Migrate(ctx, contractAddr, contractAddr, p.CodeID, p.Msg) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeGovContractResult, + sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), + )) + return nil +} + +func handleSudoProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.SudoContractProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + + contractAddr, err := sdk.AccAddressFromBech32(p.Contract) + if err != nil { + return sdkerrors.Wrap(err, "contract") + } + data, err := k.Sudo(ctx, contractAddr, p.Msg) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeGovContractResult, + sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), + )) + return nil +} + +func handleExecuteProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ExecuteContractProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + + contractAddr, err := sdk.AccAddressFromBech32(p.Contract) + if err != nil { + return sdkerrors.Wrap(err, "contract") + } + runAsAddr, err := sdk.AccAddressFromBech32(p.RunAs) + if err != nil { + return sdkerrors.Wrap(err, "run as address") + } + data, err := k.Execute(ctx, contractAddr, runAsAddr, p.Msg, p.Funds) + if err != nil { + return err + } + + ctx.EventManager().EmitEvent(sdk.NewEvent( + types.EventTypeGovContractResult, + sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)), + )) + return nil +} + +func handleUpdateAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateAdminProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + contractAddr, err := sdk.AccAddressFromBech32(p.Contract) + if err != nil { + return sdkerrors.Wrap(err, "contract") + } + newAdminAddr, err := sdk.AccAddressFromBech32(p.NewAdmin) + if err != nil { + return sdkerrors.Wrap(err, "run as address") + } + + return k.UpdateContractAdmin(ctx, contractAddr, nil, newAdminAddr) +} + +func handleClearAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ClearAdminProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + + contractAddr, err := sdk.AccAddressFromBech32(p.Contract) + if err != nil { + return sdkerrors.Wrap(err, "contract") + } + if err := k.ClearContractAdmin(ctx, contractAddr, nil); err != nil { + return err + } + return nil +} + +func handlePinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.PinCodesProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + for _, v := range p.CodeIDs { + if err := k.PinCode(ctx, v); err != nil { + return sdkerrors.Wrapf(err, "code id: %d", v) + } + } + return nil +} + +func handleUnpinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UnpinCodesProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + for _, v := range p.CodeIDs { + if err := k.UnpinCode(ctx, v); err != nil { + return sdkerrors.Wrapf(err, "code id: %d", v) + } + } + return nil +} + +func handleUpdateInstantiateConfigProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateInstantiateConfigProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + + var emptyCaller sdk.AccAddress + for _, accessConfigUpdate := range p.AccessConfigUpdates { + if err := k.SetAccessConfig(ctx, accessConfigUpdate.CodeID, emptyCaller, accessConfigUpdate.InstantiatePermission); err != nil { + return sdkerrors.Wrapf(err, "code id: %d", accessConfigUpdate.CodeID) + } + } + return nil +} diff --git a/x/wasm/keeper/proposal_integration_test.go b/x/wasm/keeper/proposal_integration_test.go new file mode 100644 index 00000000..445d3a5d --- /dev/null +++ b/x/wasm/keeper/proposal_integration_test.go @@ -0,0 +1,1001 @@ +package keeper + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "errors" + "os" + "testing" + + wasmvm "github.com/CosmWasm/wasmvm" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/params/client/utils" + "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestStoreCodeProposal(t *testing.T) { + parentCtx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(parentCtx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + checksum, err := hex.DecodeString("beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b") + require.NoError(t, err) + + specs := map[string]struct { + codeID int64 + unpinCode bool + }{ + "upload with pinning (default)": { + unpinCode: false, + }, + "upload with code unpin": { + unpinCode: true, + }, + } + + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + myActorAddress := RandomBech32AccountAddress(t) + + src := types.StoreCodeProposalFixture(func(p *types.StoreCodeProposal) { + p.RunAs = myActorAddress + p.WASMByteCode = wasmCode + p.UnpinCode = spec.unpinCode + p.CodeHash = checksum + }) + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx, storedProposal.GetContent()) + require.NoError(t, err) + + // then + cInfo := wasmKeeper.GetCodeInfo(ctx, 1) + require.NotNil(t, cInfo) + assert.Equal(t, myActorAddress, cInfo.Creator) + assert.Equal(t, !spec.unpinCode, wasmKeeper.IsPinnedCode(ctx, 1)) + + storedCode, err := wasmKeeper.GetByteCode(ctx, 1) + require.NoError(t, err) + assert.Equal(t, wasmCode, storedCode) + }) + } +} + +func TestInstantiateProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + require.NoError(t, wasmKeeper.importCode(ctx, 1, + types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)), + wasmCode), + ) + + var ( + oneAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, types.ContractAddrLen) + otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen) + ) + src := types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) { + p.CodeID = firstCodeID + p.RunAs = oneAddress.String() + p.Admin = otherAddress.String() + p.Label = "testing" + }) + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // then + contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + require.NoError(t, err) + + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, cInfo) + assert.Equal(t, uint64(1), cInfo.CodeID) + assert.Equal(t, oneAddress.String(), cInfo.Creator) + assert.Equal(t, otherAddress.String(), cInfo.Admin) + assert.Equal(t, "testing", cInfo.Label) + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: src.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: src.Msg, + }} + assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) + // and event + require.Len(t, em.Events(), 3, "%#v", em.Events()) + require.Equal(t, types.EventTypeInstantiate, em.Events()[0].Type) + require.Equal(t, types.WasmModuleEventType, em.Events()[1].Type) + require.Equal(t, types.EventTypeGovContractResult, em.Events()[2].Type) + require.Len(t, em.Events()[2].Attributes, 1) + require.NotEmpty(t, em.Events()[2].Attributes[0]) +} + +func TestInstantiate2Proposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) + err = wasmKeeper.importCode(ctx, 1, codeInfo, wasmCode) + require.NoError(t, err) + + var ( + oneAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, types.ContractAddrLen) + otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen) + label string = "label" + salt []byte = []byte("mySalt") + ) + src := types.InstantiateContract2ProposalFixture(func(p *types.InstantiateContract2Proposal) { + p.CodeID = firstCodeID + p.RunAs = oneAddress.String() + p.Admin = otherAddress.String() + p.Label = label + p.Salt = salt + }) + contractAddress := BuildContractAddressPredictable(codeInfo.CodeHash, oneAddress, salt, []byte{}) + + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddress) + require.NotNil(t, cInfo) + + assert.Equal(t, uint64(1), cInfo.CodeID) + assert.Equal(t, oneAddress.String(), cInfo.Creator) + assert.Equal(t, otherAddress.String(), cInfo.Admin) + assert.Equal(t, "label", cInfo.Label) + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: src.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: src.Msg, + }} + assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddress)) + // and event + require.Len(t, em.Events(), 3, "%#v", em.Events()) + require.Equal(t, types.EventTypeInstantiate, em.Events()[0].Type) + require.Equal(t, types.WasmModuleEventType, em.Events()[1].Type) + require.Equal(t, types.EventTypeGovContractResult, em.Events()[2].Type) + require.Len(t, em.Events()[2].Attributes, 1) + require.NotEmpty(t, em.Events()[2].Attributes[0]) +} + +func TestInstantiateProposal_NoAdmin(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + require.NoError(t, wasmKeeper.importCode(ctx, 1, + types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)), + wasmCode), + ) + + var oneAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, types.ContractAddrLen) + + // test invalid admin address + src := types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) { + p.CodeID = firstCodeID + p.RunAs = oneAddress.String() + p.Admin = "invalid" + p.Label = "testing" + }) + _, err = govKeeper.SubmitProposal(ctx, src) + require.Error(t, err) + + // test with no admin + src = types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) { + p.CodeID = firstCodeID + p.RunAs = oneAddress.String() + p.Admin = "" + p.Label = "testing" + }) + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // then + contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + require.NoError(t, err) + + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, cInfo) + assert.Equal(t, uint64(1), cInfo.CodeID) + assert.Equal(t, oneAddress.String(), cInfo.Creator) + assert.Equal(t, "", cInfo.Admin) + assert.Equal(t, "testing", cInfo.Label) + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: src.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: src.Msg, + }} + assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) + // and event + require.Len(t, em.Events(), 3, "%#v", em.Events()) + require.Equal(t, types.EventTypeInstantiate, em.Events()[0].Type) + require.Equal(t, types.WasmModuleEventType, em.Events()[1].Type) + require.Equal(t, types.EventTypeGovContractResult, em.Events()[2].Type) + require.Len(t, em.Events()[2].Attributes, 1) + require.NotEmpty(t, em.Events()[2].Attributes[0]) +} + +func TestStoreAndInstantiateContractProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + checksum, err := hex.DecodeString("beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b") + require.NoError(t, err) + + var ( + oneAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, types.ContractAddrLen) + otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen) + ) + + src := types.StoreAndInstantiateContractProposalFixture(func(p *types.StoreAndInstantiateContractProposal) { + p.WASMByteCode = wasmCode + p.RunAs = oneAddress.String() + p.Admin = otherAddress.String() + p.Label = "testing" + p.CodeHash = checksum + }) + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // then + contractAddr, err := sdk.AccAddressFromBech32("cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr") + require.NoError(t, err) + + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, cInfo) + assert.Equal(t, oneAddress.String(), cInfo.Creator) + assert.Equal(t, otherAddress.String(), cInfo.Admin) + assert.Equal(t, "testing", cInfo.Label) + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: cInfo.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: src.Msg, + }} + assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) + // and event + require.Len(t, em.Events(), 5, "%#v", em.Events()) + require.Equal(t, types.EventTypeStoreCode, em.Events()[0].Type) + require.Equal(t, types.EventTypePinCode, em.Events()[1].Type) + require.Equal(t, types.EventTypeInstantiate, em.Events()[2].Type) + require.Equal(t, types.WasmModuleEventType, em.Events()[3].Type) + require.Equal(t, types.EventTypeGovContractResult, em.Events()[4].Type) + require.Len(t, em.Events()[4].Attributes, 1) + require.NotEmpty(t, em.Events()[4].Attributes[0]) +} + +func TestMigrateProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + codeInfoFixture := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) + require.NoError(t, wasmKeeper.importCode(ctx, 1, codeInfoFixture, wasmCode)) + require.NoError(t, wasmKeeper.importCode(ctx, 2, codeInfoFixture, wasmCode)) + + var ( + anyAddress = DeterministicAccountAddress(t, 1) + otherAddress = DeterministicAccountAddress(t, 2) + contractAddr = BuildContractAddressClassic(1, 1) + ) + + contractInfo := types.ContractInfoFixture(func(c *types.ContractInfo) { + c.Label = "testing" + c.Admin = anyAddress.String() + c.Created = types.NewAbsoluteTxPosition(ctx) + }) + entries := []types.ContractCodeHistoryEntry{ + {Operation: types.ContractCodeHistoryOperationTypeInit, CodeID: 1, Updated: contractInfo.Created}, + } + key, err := hex.DecodeString("636F6E666967") + require.NoError(t, err) + m := types.Model{Key: key, Value: []byte(`{"verifier":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","beneficiary":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","funder":"AQEBAQEBAQEBAQEBAQEBAQEBAQE="}`)} + require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &contractInfo, []types.Model{m}, entries)) + + migMsg := struct { + Verifier sdk.AccAddress `json:"verifier"` + }{Verifier: otherAddress} + migMsgBz, err := json.Marshal(migMsg) + require.NoError(t, err) + + src := types.MigrateContractProposal{ + Title: "Foo", + Description: "Bar", + CodeID: 2, + Contract: contractAddr.String(), + Msg: migMsgBz, + } + + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, &src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // then + require.NoError(t, err) + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, cInfo) + assert.Equal(t, uint64(2), cInfo.CodeID) + assert.Equal(t, anyAddress.String(), cInfo.Admin) + assert.Equal(t, "testing", cInfo.Label) + expHistory := []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: src.CodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: src.Msg, + }} + assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) + // and events emitted + require.Len(t, em.Events(), 2) + assert.Equal(t, types.EventTypeMigrate, em.Events()[0].Type) + require.Equal(t, types.EventTypeGovContractResult, em.Events()[1].Type) + require.Len(t, em.Events()[1].Attributes, 1) + assert.Equal(t, types.AttributeKeyResultDataHex, string(em.Events()[1].Attributes[0].Key)) +} + +func TestExecuteProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, bankKeeper := keepers.GovKeeper, keepers.BankKeeper + + exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + contractAddr := exampleContract.Contract + + // check balance + bal := bankKeeper.GetBalance(ctx, contractAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(100)) + + releaseMsg := struct { + Release struct{} `json:"release"` + }{} + releaseMsgBz, err := json.Marshal(releaseMsg) + require.NoError(t, err) + + // try with runAs that doesn't have pemission + badSrc := types.ExecuteContractProposal{ + Title: "First", + Description: "Beneficiary has no permission to run", + Contract: contractAddr.String(), + Msg: releaseMsgBz, + RunAs: exampleContract.BeneficiaryAddr.String(), + } + + em := sdk.NewEventManager() + + // fails on store - this doesn't have permission + storedProposal, err := govKeeper.SubmitProposal(ctx, &badSrc) + require.Error(t, err) + // balance should not change + bal = bankKeeper.GetBalance(ctx, contractAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(100)) + + // try again with the proper run-as + src := types.ExecuteContractProposal{ + Title: "Second", + Description: "Verifier can execute", + Contract: contractAddr.String(), + Msg: releaseMsgBz, + RunAs: exampleContract.VerifierAddr.String(), + } + + em = sdk.NewEventManager() + + // when stored + storedProposal, err = govKeeper.SubmitProposal(ctx, &src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // balance should be empty (proper release) + bal = bankKeeper.GetBalance(ctx, contractAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(0)) +} + +func TestSudoProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, bankKeeper := keepers.GovKeeper, keepers.BankKeeper + + exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + contractAddr := exampleContract.Contract + _, _, anyAddr := keyPubAddr() + + // check balance + bal := bankKeeper.GetBalance(ctx, contractAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(100)) + bal = bankKeeper.GetBalance(ctx, anyAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(0)) + + type StealMsg struct { + Recipient string `json:"recipient"` + Amount []sdk.Coin `json:"amount"` + } + stealMsg := struct { + Steal StealMsg `json:"steal_funds"` + }{Steal: StealMsg{ + Recipient: anyAddr.String(), + Amount: []sdk.Coin{sdk.NewInt64Coin("denom", 75)}, + }} + stealMsgBz, err := json.Marshal(stealMsg) + require.NoError(t, err) + + // sudo can do anything + src := types.SudoContractProposal{ + Title: "Sudo", + Description: "Steal funds for the verifier", + Contract: contractAddr.String(), + Msg: stealMsgBz, + } + + em := sdk.NewEventManager() + + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, &src) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx.WithEventManager(em), storedProposal.GetContent()) + require.NoError(t, err) + + // balance should be empty (and verifier richer) + bal = bankKeeper.GetBalance(ctx, contractAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(25)) + bal = bankKeeper.GetBalance(ctx, anyAddr, "denom") + require.Equal(t, bal.Amount, sdk.NewInt(75)) +} + +func TestAdminProposals(t *testing.T) { + var ( + otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, types.ContractAddrLen) + contractAddr = BuildContractAddressClassic(1, 1) + ) + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + specs := map[string]struct { + state types.ContractInfo + srcProposal govtypes.Content + expAdmin sdk.AccAddress + }{ + "update with different admin": { + state: types.ContractInfoFixture(), + srcProposal: &types.UpdateAdminProposal{ + Title: "Foo", + Description: "Bar", + Contract: contractAddr.String(), + NewAdmin: otherAddress.String(), + }, + expAdmin: otherAddress, + }, + "update with old admin empty": { + state: types.ContractInfoFixture(func(info *types.ContractInfo) { + info.Admin = "" + }), + srcProposal: &types.UpdateAdminProposal{ + Title: "Foo", + Description: "Bar", + Contract: contractAddr.String(), + NewAdmin: otherAddress.String(), + }, + expAdmin: otherAddress, + }, + "clear admin": { + state: types.ContractInfoFixture(), + srcProposal: &types.ClearAdminProposal{ + Title: "Foo", + Description: "Bar", + Contract: contractAddr.String(), + }, + expAdmin: nil, + }, + "clear with old admin empty": { + state: types.ContractInfoFixture(func(info *types.ContractInfo) { + info.Admin = "" + }), + srcProposal: &types.ClearAdminProposal{ + Title: "Foo", + Description: "Bar", + Contract: contractAddr.String(), + }, + expAdmin: nil, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + wasmKeeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) + require.NoError(t, wasmKeeper.importCode(ctx, 1, codeInfo, wasmCode)) + + entries := []types.ContractCodeHistoryEntry{ + { + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: 1, + Updated: spec.state.Created, + }, + } + + require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &spec.state, []types.Model{}, entries)) + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, spec.srcProposal) + require.NoError(t, err) + + // and execute proposal + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx, storedProposal.GetContent()) + require.NoError(t, err) + + // then + cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) + require.NotNil(t, cInfo) + assert.Equal(t, spec.expAdmin.String(), cInfo.Admin) + }) + } +} + +func TestUpdateParamsProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + + var ( + legacyAmino = keepers.EncodingConfig.Amino + myAddress sdk.AccAddress = make([]byte, types.ContractAddrLen) + oneAddressAccessConfig = types.AccessTypeOnlyAddress.With(myAddress) + ) + + specs := map[string]struct { + src proposal.ParamChange + expUploadConfig types.AccessConfig + expInstantiateType types.AccessType + }{ + "update upload permission param": { + src: proposal.ParamChange{ + Subspace: types.ModuleName, + Key: string(types.ParamStoreKeyUploadAccess), + Value: string(legacyAmino.MustMarshalJSON(&types.AllowNobody)), + }, + expUploadConfig: types.AllowNobody, + expInstantiateType: types.AccessTypeEverybody, + }, + "update upload permission with same as current value": { + src: proposal.ParamChange{ + Subspace: types.ModuleName, + Key: string(types.ParamStoreKeyUploadAccess), + Value: string(legacyAmino.MustMarshalJSON(&types.AllowEverybody)), + }, + expUploadConfig: types.AllowEverybody, + expInstantiateType: types.AccessTypeEverybody, + }, + "update upload permission param with address": { + src: proposal.ParamChange{ + Subspace: types.ModuleName, + Key: string(types.ParamStoreKeyUploadAccess), + Value: string(legacyAmino.MustMarshalJSON(&oneAddressAccessConfig)), + }, + expUploadConfig: oneAddressAccessConfig, + expInstantiateType: types.AccessTypeEverybody, + }, + "update instantiate param": { + src: proposal.ParamChange{ + Subspace: types.ModuleName, + Key: string(types.ParamStoreKeyInstantiateAccess), + Value: string(legacyAmino.MustMarshalJSON(types.AccessTypeNobody)), + }, + expUploadConfig: types.AllowEverybody, + expInstantiateType: types.AccessTypeNobody, + }, + "update instantiate param as default": { + src: proposal.ParamChange{ + Subspace: types.ModuleName, + Key: string(types.ParamStoreKeyInstantiateAccess), + Value: string(legacyAmino.MustMarshalJSON(types.AccessTypeEverybody)), + }, + expUploadConfig: types.AllowEverybody, + expInstantiateType: types.AccessTypeEverybody, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + wasmKeeper.SetParams(ctx, types.DefaultParams()) + + // encode + decode as CLI to play nice with amino + bz := legacyAmino.MustMarshalJSON(&utils.ParamChangeProposalJSON{ + Title: "Foo", + Description: "Bar", + Changes: []utils.ParamChangeJSON{{Subspace: spec.src.Subspace, Key: spec.src.Key, Value: json.RawMessage(spec.src.Value)}}, + }) + t.Log(string(bz)) + + var jsonProposal utils.ParamChangeProposalJSON + require.NoError(t, legacyAmino.UnmarshalJSON(bz, &jsonProposal)) + proposal := proposal.ParameterChangeProposal{ + Title: jsonProposal.Title, + Description: jsonProposal.Description, + Changes: jsonProposal.Changes.ToParamChanges(), + } + // when stored + storedProposal, err := govKeeper.SubmitProposal(ctx, &proposal) + require.NoError(t, err) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + err = handler(ctx, storedProposal.GetContent()) + require.NoError(t, err) + + // then + assert.True(t, spec.expUploadConfig.Equals(wasmKeeper.getUploadAccessConfig(ctx)), + "got %#v not %#v", wasmKeeper.getUploadAccessConfig(ctx), spec.expUploadConfig) + assert.Equal(t, spec.expInstantiateType, wasmKeeper.getInstantiateAccessConfig(ctx)) + }) + } +} + +func TestPinCodesProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + + mock := wasmtesting.MockWasmer{ + CreateFn: wasmtesting.NoOpCreateFn, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + } + var ( + hackatom = StoreHackatomExampleContract(t, ctx, keepers) + hackatomDuplicate = StoreHackatomExampleContract(t, ctx, keepers) + otherContract = StoreRandomContract(t, ctx, keepers, &mock) + gotPinnedChecksums []wasmvm.Checksum + ) + checksumCollector := func(checksum wasmvm.Checksum) error { + gotPinnedChecksums = append(gotPinnedChecksums, checksum) + return nil + } + specs := map[string]struct { + srcCodeIDs []uint64 + mockFn func(checksum wasmvm.Checksum) error + expPinned []wasmvm.Checksum + expErr bool + }{ + "pin one": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: checksumCollector, + }, + "pin multiple": { + srcCodeIDs: []uint64{hackatom.CodeID, otherContract.CodeID}, + mockFn: checksumCollector, + }, + "pin same code id": { + srcCodeIDs: []uint64{hackatom.CodeID, hackatomDuplicate.CodeID}, + mockFn: checksumCollector, + }, + "pin non existing code id": { + srcCodeIDs: []uint64{999}, + mockFn: checksumCollector, + expErr: true, + }, + "pin empty code id list": { + srcCodeIDs: []uint64{}, + mockFn: checksumCollector, + expErr: true, + }, + "wasmvm failed with error": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: func(_ wasmvm.Checksum) error { + return errors.New("test, ignore") + }, + expErr: true, + }, + } + parentCtx := ctx + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + gotPinnedChecksums = nil + ctx, _ := parentCtx.CacheContext() + mock.PinFn = spec.mockFn + proposal := types.PinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: spec.srcCodeIDs, + } + + // when stored + storedProposal, gotErr := govKeeper.SubmitProposal(ctx, &proposal) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + gotErr = handler(ctx, storedProposal.GetContent()) + require.NoError(t, gotErr) + + // then + for i := range spec.srcCodeIDs { + c := wasmKeeper.GetCodeInfo(ctx, spec.srcCodeIDs[i]) + require.Equal(t, wasmvm.Checksum(c.CodeHash), gotPinnedChecksums[i]) + } + }) + } +} + +func TestUnpinCodesProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + + mock := wasmtesting.MockWasmer{ + CreateFn: wasmtesting.NoOpCreateFn, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + } + var ( + hackatom = StoreHackatomExampleContract(t, ctx, keepers) + hackatomDuplicate = StoreHackatomExampleContract(t, ctx, keepers) + otherContract = StoreRandomContract(t, ctx, keepers, &mock) + gotUnpinnedChecksums []wasmvm.Checksum + ) + checksumCollector := func(checksum wasmvm.Checksum) error { + gotUnpinnedChecksums = append(gotUnpinnedChecksums, checksum) + return nil + } + specs := map[string]struct { + srcCodeIDs []uint64 + mockFn func(checksum wasmvm.Checksum) error + expUnpinned []wasmvm.Checksum + expErr bool + }{ + "unpin one": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: checksumCollector, + }, + "unpin multiple": { + srcCodeIDs: []uint64{hackatom.CodeID, otherContract.CodeID}, + mockFn: checksumCollector, + }, + "unpin same code id": { + srcCodeIDs: []uint64{hackatom.CodeID, hackatomDuplicate.CodeID}, + mockFn: checksumCollector, + }, + "unpin non existing code id": { + srcCodeIDs: []uint64{999}, + mockFn: checksumCollector, + expErr: true, + }, + "unpin empty code id list": { + srcCodeIDs: []uint64{}, + mockFn: checksumCollector, + expErr: true, + }, + "wasmvm failed with error": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: func(_ wasmvm.Checksum) error { + return errors.New("test, ignore") + }, + expErr: true, + }, + } + parentCtx := ctx + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + gotUnpinnedChecksums = nil + ctx, _ := parentCtx.CacheContext() + mock.UnpinFn = spec.mockFn + proposal := types.UnpinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: spec.srcCodeIDs, + } + + // when stored + storedProposal, gotErr := govKeeper.SubmitProposal(ctx, &proposal) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + gotErr = handler(ctx, storedProposal.GetContent()) + require.NoError(t, gotErr) + + // then + for i := range spec.srcCodeIDs { + c := wasmKeeper.GetCodeInfo(ctx, spec.srcCodeIDs[i]) + require.Equal(t, wasmvm.Checksum(c.CodeHash), gotUnpinnedChecksums[i]) + } + }) + } +} + +func TestUpdateInstantiateConfigProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking") + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + + mock := wasmtesting.MockWasmer{ + CreateFn: wasmtesting.NoOpCreateFn, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + } + anyAddress, err := sdk.AccAddressFromBech32("cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz") + require.NoError(t, err) + + withAddressAccessConfig := types.AccessTypeAnyOfAddresses.With(anyAddress) + var ( + nobody = StoreRandomContractWithAccessConfig(t, ctx, keepers, &mock, &types.AllowNobody) + everybody = StoreRandomContractWithAccessConfig(t, ctx, keepers, &mock, &types.AllowEverybody) + withAddress = StoreRandomContractWithAccessConfig(t, ctx, keepers, &mock, &withAddressAccessConfig) + ) + + specs := map[string]struct { + accessConfigUpdates []types.AccessConfigUpdate + expErr bool + }{ + "update one": { + accessConfigUpdates: []types.AccessConfigUpdate{ + {CodeID: nobody.CodeID, InstantiatePermission: types.AllowEverybody}, + }, + }, + "update multiple": { + accessConfigUpdates: []types.AccessConfigUpdate{ + {CodeID: everybody.CodeID, InstantiatePermission: types.AllowNobody}, + {CodeID: nobody.CodeID, InstantiatePermission: withAddressAccessConfig}, + {CodeID: withAddress.CodeID, InstantiatePermission: types.AllowEverybody}, + }, + }, + "update same code id": { + accessConfigUpdates: []types.AccessConfigUpdate{ + {CodeID: everybody.CodeID, InstantiatePermission: types.AllowNobody}, + {CodeID: everybody.CodeID, InstantiatePermission: types.AllowEverybody}, + }, + expErr: true, + }, + "update non existing code id": { + accessConfigUpdates: []types.AccessConfigUpdate{ + {CodeID: 100, InstantiatePermission: types.AllowNobody}, + {CodeID: everybody.CodeID, InstantiatePermission: types.AllowEverybody}, + }, + expErr: true, + }, + "update empty list": { + accessConfigUpdates: make([]types.AccessConfigUpdate, 0), + expErr: true, + }, + } + parentCtx := ctx + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + ctx, _ := parentCtx.CacheContext() + + updates := make([]types.AccessConfigUpdate, 0) + for _, cu := range spec.accessConfigUpdates { + updates = append(updates, types.AccessConfigUpdate{ + CodeID: cu.CodeID, + InstantiatePermission: cu.InstantiatePermission, + }) + } + + proposal := types.UpdateInstantiateConfigProposal{ + Title: "Foo", + Description: "Bar", + AccessConfigUpdates: updates, + } + + // when stored + storedProposal, gotErr := govKeeper.SubmitProposal(ctx, &proposal) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + gotErr = handler(ctx, storedProposal.GetContent()) + require.NoError(t, gotErr) + + // then + for i := range spec.accessConfigUpdates { + c := wasmKeeper.GetCodeInfo(ctx, spec.accessConfigUpdates[i].CodeID) + require.Equal(t, spec.accessConfigUpdates[i].InstantiatePermission, c.InstantiateConfig) + } + }) + } +} diff --git a/x/wasm/keeper/querier.go b/x/wasm/keeper/querier.go new file mode 100644 index 00000000..eebfb66a --- /dev/null +++ b/x/wasm/keeper/querier.go @@ -0,0 +1,346 @@ +package keeper + +import ( + "context" + "encoding/binary" + "runtime/debug" + + "github.com/cosmos/cosmos-sdk/codec" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var _ types.QueryServer = &grpcQuerier{} + +type grpcQuerier struct { + cdc codec.Codec + storeKey sdk.StoreKey + keeper types.ViewKeeper + queryGasLimit sdk.Gas +} + +// NewGrpcQuerier constructor +func NewGrpcQuerier(cdc codec.Codec, storeKey sdk.StoreKey, keeper types.ViewKeeper, queryGasLimit sdk.Gas) *grpcQuerier { //nolint:revive + return &grpcQuerier{cdc: cdc, storeKey: storeKey, keeper: keeper, queryGasLimit: queryGasLimit} +} + +func (q grpcQuerier) ContractInfo(c context.Context, req *types.QueryContractInfoRequest) (*types.QueryContractInfoResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + contractAddr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } + rsp, err := queryContractInfo(sdk.UnwrapSDKContext(c), contractAddr, q.keeper) + switch { + case err != nil: + return nil, err + case rsp == nil: + return nil, types.ErrNotFound + } + return rsp, nil +} + +func (q grpcQuerier) ContractHistory(c context.Context, req *types.QueryContractHistoryRequest) (*types.QueryContractHistoryResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + contractAddr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(c) + r := make([]types.ContractCodeHistoryEntry, 0) + + prefixStore := prefix.NewStore(ctx.KVStore(q.storeKey), types.GetContractCodeHistoryElementPrefix(contractAddr)) + pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { + if accumulate { + var e types.ContractCodeHistoryEntry + if err := q.cdc.Unmarshal(value, &e); err != nil { + return false, err + } + r = append(r, e) + } + return true, nil + }) + if err != nil { + return nil, err + } + return &types.QueryContractHistoryResponse{ + Entries: r, + Pagination: pageRes, + }, nil +} + +// ContractsByCode lists all smart contracts for a code id +func (q grpcQuerier) ContractsByCode(c context.Context, req *types.QueryContractsByCodeRequest) (*types.QueryContractsByCodeResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if req.CodeId == 0 { + return nil, sdkerrors.Wrap(types.ErrInvalid, "code id") + } + ctx := sdk.UnwrapSDKContext(c) + r := make([]string, 0) + + prefixStore := prefix.NewStore(ctx.KVStore(q.storeKey), types.GetContractByCodeIDSecondaryIndexPrefix(req.CodeId)) + pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { + if accumulate { + var contractAddr sdk.AccAddress = key[types.AbsoluteTxPositionLen:] + r = append(r, contractAddr.String()) + } + return true, nil + }) + if err != nil { + return nil, err + } + return &types.QueryContractsByCodeResponse{ + Contracts: r, + Pagination: pageRes, + }, nil +} + +func (q grpcQuerier) AllContractState(c context.Context, req *types.QueryAllContractStateRequest) (*types.QueryAllContractStateResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + contractAddr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } + ctx := sdk.UnwrapSDKContext(c) + if !q.keeper.HasContractInfo(ctx, contractAddr) { + return nil, types.ErrNotFound + } + + r := make([]types.Model, 0) + prefixStore := prefix.NewStore(ctx.KVStore(q.storeKey), types.GetContractStorePrefix(contractAddr)) + pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { + if accumulate { + r = append(r, types.Model{ + Key: key, + Value: value, + }) + } + return true, nil + }) + if err != nil { + return nil, err + } + return &types.QueryAllContractStateResponse{ + Models: r, + Pagination: pageRes, + }, nil +} + +func (q grpcQuerier) RawContractState(c context.Context, req *types.QueryRawContractStateRequest) (*types.QueryRawContractStateResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(c) + + contractAddr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } + + if !q.keeper.HasContractInfo(ctx, contractAddr) { + return nil, types.ErrNotFound + } + rsp := q.keeper.QueryRaw(ctx, contractAddr, req.QueryData) + return &types.QueryRawContractStateResponse{Data: rsp}, nil +} + +func (q grpcQuerier) SmartContractState(c context.Context, req *types.QuerySmartContractStateRequest) (rsp *types.QuerySmartContractStateResponse, err error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if err := req.QueryData.ValidateBasic(); err != nil { + return nil, status.Error(codes.InvalidArgument, "invalid query data") + } + contractAddr, err := sdk.AccAddressFromBech32(req.Address) + if err != nil { + return nil, err + } + ctx := sdk.UnwrapSDKContext(c).WithGasMeter(sdk.NewGasMeter(q.queryGasLimit)) + // recover from out-of-gas panic + defer func() { + if r := recover(); r != nil { + switch rType := r.(type) { + case sdk.ErrorOutOfGas: + err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, + "out of gas in location: %v; gasWanted: %d, gasUsed: %d", + rType.Descriptor, ctx.GasMeter().Limit(), ctx.GasMeter().GasConsumed(), + ) + default: + err = sdkerrors.ErrPanic + } + rsp = nil + moduleLogger(ctx). + Debug("smart query contract", + "error", "recovering panic", + "contract-address", req.Address, + "stacktrace", string(debug.Stack())) + } + }() + + bz, err := q.keeper.QuerySmart(ctx, contractAddr, req.QueryData) + switch { + case err != nil: + return nil, err + case bz == nil: + return nil, types.ErrNotFound + } + return &types.QuerySmartContractStateResponse{Data: bz}, nil +} + +func (q grpcQuerier) Code(c context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if req.CodeId == 0 { + return nil, sdkerrors.Wrap(types.ErrInvalid, "code id") + } + rsp, err := queryCode(sdk.UnwrapSDKContext(c), req.CodeId, q.keeper) + switch { + case err != nil: + return nil, err + case rsp == nil: + return nil, types.ErrNotFound + } + return &types.QueryCodeResponse{ + CodeInfoResponse: rsp.CodeInfoResponse, + Data: rsp.Data, + }, nil +} + +func (q grpcQuerier) Codes(c context.Context, req *types.QueryCodesRequest) (*types.QueryCodesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(c) + r := make([]types.CodeInfoResponse, 0) + prefixStore := prefix.NewStore(ctx.KVStore(q.storeKey), types.CodeKeyPrefix) + pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, value []byte, accumulate bool) (bool, error) { + if accumulate { + var c types.CodeInfo + if err := q.cdc.Unmarshal(value, &c); err != nil { + return false, err + } + r = append(r, types.CodeInfoResponse{ + CodeID: binary.BigEndian.Uint64(key), + Creator: c.Creator, + DataHash: c.CodeHash, + InstantiatePermission: c.InstantiateConfig, + }) + } + return true, nil + }) + if err != nil { + return nil, err + } + return &types.QueryCodesResponse{CodeInfos: r, Pagination: pageRes}, nil +} + +func queryContractInfo(ctx sdk.Context, addr sdk.AccAddress, keeper types.ViewKeeper) (*types.QueryContractInfoResponse, error) { + info := keeper.GetContractInfo(ctx, addr) + if info == nil { + return nil, types.ErrNotFound + } + return &types.QueryContractInfoResponse{ + Address: addr.String(), + ContractInfo: *info, + }, nil +} + +func queryCode(ctx sdk.Context, codeID uint64, keeper types.ViewKeeper) (*types.QueryCodeResponse, error) { + if codeID == 0 { + return nil, nil + } + res := keeper.GetCodeInfo(ctx, codeID) + if res == nil { + // nil, nil leads to 404 in rest handler + return nil, nil + } + info := types.CodeInfoResponse{ + CodeID: codeID, + Creator: res.Creator, + DataHash: res.CodeHash, + InstantiatePermission: res.InstantiateConfig, + } + + code, err := keeper.GetByteCode(ctx, codeID) + if err != nil { + return nil, sdkerrors.Wrap(err, "loading wasm code") + } + + return &types.QueryCodeResponse{CodeInfoResponse: &info, Data: code}, nil +} + +func (q grpcQuerier) PinnedCodes(c context.Context, req *types.QueryPinnedCodesRequest) (*types.QueryPinnedCodesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(c) + r := make([]uint64, 0) + + prefixStore := prefix.NewStore(ctx.KVStore(q.storeKey), types.PinnedCodeIndexPrefix) + pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, _ []byte, accumulate bool) (bool, error) { + if accumulate { + r = append(r, sdk.BigEndianToUint64(key)) + } + return true, nil + }) + if err != nil { + return nil, err + } + return &types.QueryPinnedCodesResponse{ + CodeIDs: r, + Pagination: pageRes, + }, nil +} + +// Params returns params of the module. +func (q grpcQuerier) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(c) + params := q.keeper.GetParams(ctx) + return &types.QueryParamsResponse{Params: params}, nil +} + +func (q grpcQuerier) ContractsByCreator(c context.Context, req *types.QueryContractsByCreatorRequest) (*types.QueryContractsByCreatorResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + ctx := sdk.UnwrapSDKContext(c) + contracts := make([]string, 0) + + creatorAddress, err := sdk.AccAddressFromBech32(req.CreatorAddress) + if err != nil { + return nil, err + } + prefixStore := prefix.NewStore(ctx.KVStore(q.storeKey), types.GetContractsByCreatorPrefix(creatorAddress)) + pageRes, err := query.FilteredPaginate(prefixStore, req.Pagination, func(key []byte, _ []byte, accumulate bool) (bool, error) { + if accumulate { + accAddres := sdk.AccAddress(key[types.AbsoluteTxPositionLen:]) + contracts = append(contracts, accAddres.String()) + } + return true, nil + }) + if err != nil { + return nil, err + } + + return &types.QueryContractsByCreatorResponse{ + ContractAddresses: contracts, + Pagination: pageRes, + }, nil +} diff --git a/x/wasm/keeper/querier_test.go b/x/wasm/keeper/querier_test.go new file mode 100644 index 00000000..da25b35f --- /dev/null +++ b/x/wasm/keeper/querier_test.go @@ -0,0 +1,917 @@ +package keeper + +import ( + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + "testing" + "time" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkErrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/query" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestQueryAllContractState(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + contractAddr := exampleContract.Contract + contractModel := []types.Model{ + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + } + require.NoError(t, keeper.importContractState(ctx, contractAddr, contractModel)) + + q := Querier(keeper) + specs := map[string]struct { + srcQuery *types.QueryAllContractStateRequest + expModelContains []types.Model + expModelContainsNot []types.Model + expErr *sdkErrors.Error + }{ + "query all": { + srcQuery: &types.QueryAllContractStateRequest{Address: contractAddr.String()}, + expModelContains: contractModel, + }, + "query all with unknown address": { + srcQuery: &types.QueryAllContractStateRequest{Address: RandomBech32AccountAddress(t)}, + expErr: types.ErrNotFound, + }, + "with pagination offset": { + srcQuery: &types.QueryAllContractStateRequest{ + Address: contractAddr.String(), + Pagination: &query.PageRequest{ + Offset: 1, + }, + }, + expModelContains: []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + }, + expModelContainsNot: []types.Model{ + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + }, + }, + "with pagination limit": { + srcQuery: &types.QueryAllContractStateRequest{ + Address: contractAddr.String(), + Pagination: &query.PageRequest{ + Limit: 1, + }, + }, + expModelContains: []types.Model{ + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + }, + expModelContainsNot: []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + }, + }, + "with pagination next key": { + srcQuery: &types.QueryAllContractStateRequest{ + Address: contractAddr.String(), + Pagination: &query.PageRequest{ + Key: fromBase64("Y29uZmln"), + }, + }, + expModelContains: []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + }, + expModelContainsNot: []types.Model{ + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + }, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + got, err := q.AllContractState(sdk.WrapSDKContext(ctx), spec.srcQuery) + require.True(t, spec.expErr.Is(err), err) + if spec.expErr != nil { + return + } + for _, exp := range spec.expModelContains { + assert.Contains(t, got.Models, exp) + } + for _, exp := range spec.expModelContainsNot { + assert.NotContains(t, got.Models, exp) + } + }) + } +} + +func TestQuerySmartContractState(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + contractAddr := exampleContract.Contract.String() + + q := Querier(keeper) + specs := map[string]struct { + srcAddr sdk.AccAddress + srcQuery *types.QuerySmartContractStateRequest + expResp string + expErr error + }{ + "query smart": { + srcQuery: &types.QuerySmartContractStateRequest{Address: contractAddr, QueryData: []byte(`{"verifier":{}}`)}, + expResp: fmt.Sprintf(`{"verifier":"%s"}`, exampleContract.VerifierAddr.String()), + }, + "query smart invalid request": { + srcQuery: &types.QuerySmartContractStateRequest{Address: contractAddr, QueryData: []byte(`{"raw":{"key":"config"}}`)}, + expErr: types.ErrQueryFailed, + }, + "query smart with invalid json": { + srcQuery: &types.QuerySmartContractStateRequest{Address: contractAddr, QueryData: []byte(`not a json string`)}, + expErr: status.Error(codes.InvalidArgument, "invalid query data"), + }, + "query smart with unknown address": { + srcQuery: &types.QuerySmartContractStateRequest{Address: RandomBech32AccountAddress(t), QueryData: []byte(`{"verifier":{}}`)}, + expErr: types.ErrNotFound, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + got, err := q.SmartContractState(sdk.WrapSDKContext(ctx), spec.srcQuery) + require.True(t, errors.Is(err, spec.expErr), "but got %+v", err) + if spec.expErr != nil { + return + } + assert.JSONEq(t, string(got.Data), spec.expResp) + }) + } +} + +func TestQuerySmartContractPanics(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + contractAddr := BuildContractAddressClassic(1, 1) + keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{}) + keepers.WasmKeeper.storeContractInfo(ctx, contractAddr, &types.ContractInfo{ + CodeID: 1, + Created: types.NewAbsoluteTxPosition(ctx), + }) + ctx = ctx.WithGasMeter(sdk.NewGasMeter(DefaultInstanceCost)).WithLogger(log.TestingLogger()) + + specs := map[string]struct { + doInContract func() + expErr *sdkErrors.Error + }{ + "out of gas": { + doInContract: func() { + ctx.GasMeter().ConsumeGas(ctx.GasMeter().Limit()+1, "test - consume more than limit") + }, + expErr: sdkErrors.ErrOutOfGas, + }, + "other panic": { + doInContract: func() { + panic("my panic") + }, + expErr: sdkErrors.ErrPanic, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + keepers.WasmKeeper.wasmVM = &wasmtesting.MockWasmer{QueryFn: func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + spec.doInContract() + return nil, 0, nil + }} + // when + q := Querier(keepers.WasmKeeper) + got, err := q.SmartContractState(sdk.WrapSDKContext(ctx), &types.QuerySmartContractStateRequest{ + Address: contractAddr.String(), + QueryData: types.RawContractMessage("{}"), + }) + require.True(t, spec.expErr.Is(err), "got error: %+v", err) + assert.Nil(t, got) + }) + } +} + +func TestQueryRawContractState(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + contractAddr := exampleContract.Contract.String() + contractModel := []types.Model{ + {Key: []byte("foo"), Value: []byte(`"bar"`)}, + {Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)}, + } + require.NoError(t, keeper.importContractState(ctx, exampleContract.Contract, contractModel)) + + q := Querier(keeper) + specs := map[string]struct { + srcQuery *types.QueryRawContractStateRequest + expData []byte + expErr *sdkErrors.Error + }{ + "query raw key": { + srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte("foo")}, + expData: []byte(`"bar"`), + }, + "query raw contract binary key": { + srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte{0x0, 0x1}}, + expData: []byte(`{"count":8}`), + }, + "query non-existent raw key": { + srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte("not existing key")}, + expData: nil, + }, + "query empty raw key": { + srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte("")}, + expData: nil, + }, + "query nil raw key": { + srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr}, + expData: nil, + }, + "query raw with unknown address": { + srcQuery: &types.QueryRawContractStateRequest{Address: RandomBech32AccountAddress(t), QueryData: []byte("foo")}, + expErr: types.ErrNotFound, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + got, err := q.RawContractState(sdk.WrapSDKContext(ctx), spec.srcQuery) + require.True(t, spec.expErr.Is(err), err) + if spec.expErr != nil { + return + } + assert.Equal(t, spec.expData, got.Data) + }) + } +} + +func TestQueryContractListByCodeOrdering(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 500)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + anyAddr := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, wasmCode, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: anyAddr, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + // manage some realistic block settings + var h int64 = 10 + setBlock := func(ctx sdk.Context, height int64) sdk.Context { + ctx = ctx.WithBlockHeight(height) + meter := sdk.NewGasMeter(1000000) + ctx = ctx.WithGasMeter(meter) + ctx = ctx.WithBlockGasMeter(meter) + return ctx + } + + // create 10 contracts with real block/gas setup + for i := 0; i < 10; i++ { + // 3 tx per block, so we ensure both comparisons work + if i%3 == 0 { + ctx = setBlock(ctx, h) + h++ + } + _, _, err = keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, fmt.Sprintf("contract %d", i), topUp) + require.NoError(t, err) + } + + // query and check the results are properly sorted + q := Querier(keeper) + res, err := q.ContractsByCode(sdk.WrapSDKContext(ctx), &types.QueryContractsByCodeRequest{CodeId: codeID}) + require.NoError(t, err) + + require.Equal(t, 10, len(res.Contracts)) + + for _, contractAddr := range res.Contracts { + assert.NotEmpty(t, contractAddr) + } +} + +func TestQueryContractHistory(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + var ( + myContractBech32Addr = RandomBech32AccountAddress(t) + otherBech32Addr = RandomBech32AccountAddress(t) + ) + + specs := map[string]struct { + srcHistory []types.ContractCodeHistoryEntry + req types.QueryContractHistoryRequest + expContent []types.ContractCodeHistoryEntry + }{ + "response with internal fields cleared": { + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeGenesis, + CodeID: firstCodeID, + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + Msg: []byte(`"init message"`), + }}, + req: types.QueryContractHistoryRequest{Address: myContractBech32Addr}, + expContent: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeGenesis, + CodeID: firstCodeID, + Msg: []byte(`"init message"`), + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + }}, + }, + "response with multiple entries": { + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + Msg: []byte(`"init message"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Updated: &types.AbsoluteTxPosition{BlockHeight: 3, TxIndex: 4}, + Msg: []byte(`"migrate message 1"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 3, + Updated: &types.AbsoluteTxPosition{BlockHeight: 5, TxIndex: 6}, + Msg: []byte(`"migrate message 2"`), + }}, + req: types.QueryContractHistoryRequest{Address: myContractBech32Addr}, + expContent: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Msg: []byte(`"init message"`), + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Msg: []byte(`"migrate message 1"`), + Updated: &types.AbsoluteTxPosition{BlockHeight: 3, TxIndex: 4}, + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 3, + Msg: []byte(`"migrate message 2"`), + Updated: &types.AbsoluteTxPosition{BlockHeight: 5, TxIndex: 6}, + }}, + }, + "with pagination offset": { + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + Msg: []byte(`"init message"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Updated: &types.AbsoluteTxPosition{BlockHeight: 3, TxIndex: 4}, + Msg: []byte(`"migrate message 1"`), + }}, + req: types.QueryContractHistoryRequest{ + Address: myContractBech32Addr, + Pagination: &query.PageRequest{ + Offset: 1, + }, + }, + expContent: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Msg: []byte(`"migrate message 1"`), + Updated: &types.AbsoluteTxPosition{BlockHeight: 3, TxIndex: 4}, + }}, + }, + "with pagination limit": { + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + Msg: []byte(`"init message"`), + }, { + Operation: types.ContractCodeHistoryOperationTypeMigrate, + CodeID: 2, + Updated: &types.AbsoluteTxPosition{BlockHeight: 3, TxIndex: 4}, + Msg: []byte(`"migrate message 1"`), + }}, + req: types.QueryContractHistoryRequest{ + Address: myContractBech32Addr, + Pagination: &query.PageRequest{ + Limit: 1, + }, + }, + expContent: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeInit, + CodeID: firstCodeID, + Msg: []byte(`"init message"`), + Updated: &types.AbsoluteTxPosition{BlockHeight: 1, TxIndex: 2}, + }}, + }, + "unknown contract address": { + req: types.QueryContractHistoryRequest{Address: otherBech32Addr}, + srcHistory: []types.ContractCodeHistoryEntry{{ + Operation: types.ContractCodeHistoryOperationTypeGenesis, + CodeID: firstCodeID, + Updated: types.NewAbsoluteTxPosition(ctx), + Msg: []byte(`"init message"`), + }}, + expContent: nil, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + xCtx, _ := ctx.CacheContext() + + cAddr, _ := sdk.AccAddressFromBech32(myContractBech32Addr) + keeper.appendToContractHistory(xCtx, cAddr, spec.srcHistory...) + + // when + q := Querier(keeper) + got, err := q.ContractHistory(sdk.WrapSDKContext(xCtx), &spec.req) + + // then + if spec.expContent == nil { + require.Error(t, types.ErrEmpty) + return + } + require.NoError(t, err) + assert.Equal(t, spec.expContent, got.Entries) + }) + } +} + +func TestQueryCodeList(t *testing.T) { + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + specs := map[string]struct { + storedCodeIDs []uint64 + req types.QueryCodesRequest + expCodeIDs []uint64 + }{ + "none": {}, + "no gaps": { + storedCodeIDs: []uint64{1, 2, 3}, + expCodeIDs: []uint64{1, 2, 3}, + }, + "with gaps": { + storedCodeIDs: []uint64{2, 4, 6}, + expCodeIDs: []uint64{2, 4, 6}, + }, + "with pagination offset": { + storedCodeIDs: []uint64{1, 2, 3}, + req: types.QueryCodesRequest{ + Pagination: &query.PageRequest{ + Offset: 1, + }, + }, + expCodeIDs: []uint64{2, 3}, + }, + "with pagination limit": { + storedCodeIDs: []uint64{1, 2, 3}, + req: types.QueryCodesRequest{ + Pagination: &query.PageRequest{ + Limit: 2, + }, + }, + expCodeIDs: []uint64{1, 2}, + }, + "with pagination next key": { + storedCodeIDs: []uint64{1, 2, 3}, + req: types.QueryCodesRequest{ + Pagination: &query.PageRequest{ + Key: fromBase64("AAAAAAAAAAI="), + }, + }, + expCodeIDs: []uint64{2, 3}, + }, + } + + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + xCtx, _ := ctx.CacheContext() + + for _, codeID := range spec.storedCodeIDs { + require.NoError(t, keeper.importCode(xCtx, codeID, + types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)), + wasmCode), + ) + } + // when + q := Querier(keeper) + got, err := q.Codes(sdk.WrapSDKContext(xCtx), &spec.req) + + // then + require.NoError(t, err) + require.NotNil(t, got.CodeInfos) + require.Len(t, got.CodeInfos, len(spec.expCodeIDs)) + for i, exp := range spec.expCodeIDs { + assert.EqualValues(t, exp, got.CodeInfos[i].CodeID) + } + }) + } +} + +func TestQueryContractInfo(t *testing.T) { + var ( + contractAddr = RandomAccountAddress(t) + anyDate = time.Now().UTC() + ) + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + // register an example extension. must be protobuf + keepers.EncodingConfig.InterfaceRegistry.RegisterImplementations( + (*types.ContractInfoExtension)(nil), + &govtypes.Proposal{}, + ) + govtypes.RegisterInterfaces(keepers.EncodingConfig.InterfaceRegistry) + + k := keepers.WasmKeeper + querier := NewGrpcQuerier(k.cdc, k.storeKey, k, k.queryGasLimit) + myExtension := func(info *types.ContractInfo) { + // abuse gov proposal as a random protobuf extension with an Any type + myExt, err := govtypes.NewProposal(&govtypes.TextProposal{Title: "foo", Description: "bar"}, 1, anyDate, anyDate) + require.NoError(t, err) + myExt.TotalDeposit = nil + info.SetExtension(&myExt) + } + specs := map[string]struct { + src *types.QueryContractInfoRequest + stored types.ContractInfo + expRsp *types.QueryContractInfoResponse + expErr bool + }{ + "found": { + src: &types.QueryContractInfoRequest{Address: contractAddr.String()}, + stored: types.ContractInfoFixture(), + expRsp: &types.QueryContractInfoResponse{ + Address: contractAddr.String(), + ContractInfo: types.ContractInfoFixture(), + }, + }, + "with extension": { + src: &types.QueryContractInfoRequest{Address: contractAddr.String()}, + stored: types.ContractInfoFixture(myExtension), + expRsp: &types.QueryContractInfoResponse{ + Address: contractAddr.String(), + ContractInfo: types.ContractInfoFixture(myExtension), + }, + }, + "not found": { + src: &types.QueryContractInfoRequest{Address: RandomBech32AccountAddress(t)}, + stored: types.ContractInfoFixture(), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + xCtx, _ := ctx.CacheContext() + k.storeContractInfo(xCtx, contractAddr, &spec.stored) + // when + gotRsp, gotErr := querier.ContractInfo(sdk.WrapSDKContext(xCtx), spec.src) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.Equal(t, spec.expRsp, gotRsp) + }) + } +} + +func TestQueryPinnedCodes(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + exampleContract1 := InstantiateHackatomExampleContract(t, ctx, keepers) + exampleContract2 := InstantiateIBCReflectContract(t, ctx, keepers) + require.NoError(t, keeper.pinCode(ctx, exampleContract1.CodeID)) + require.NoError(t, keeper.pinCode(ctx, exampleContract2.CodeID)) + + q := Querier(keeper) + specs := map[string]struct { + srcQuery *types.QueryPinnedCodesRequest + expCodeIDs []uint64 + expErr *sdkErrors.Error + }{ + "query all": { + srcQuery: &types.QueryPinnedCodesRequest{}, + expCodeIDs: []uint64{exampleContract1.CodeID, exampleContract2.CodeID}, + }, + "with pagination offset": { + srcQuery: &types.QueryPinnedCodesRequest{ + Pagination: &query.PageRequest{ + Offset: 1, + }, + }, + expCodeIDs: []uint64{exampleContract2.CodeID}, + }, + "with pagination limit": { + srcQuery: &types.QueryPinnedCodesRequest{ + Pagination: &query.PageRequest{ + Limit: 1, + }, + }, + expCodeIDs: []uint64{exampleContract1.CodeID}, + }, + "with pagination next key": { + srcQuery: &types.QueryPinnedCodesRequest{ + Pagination: &query.PageRequest{ + Key: fromBase64("AAAAAAAAAAM="), + }, + }, + expCodeIDs: []uint64{exampleContract2.CodeID}, + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + got, err := q.PinnedCodes(sdk.WrapSDKContext(ctx), spec.srcQuery) + require.True(t, spec.expErr.Is(err), err) + if spec.expErr != nil { + return + } + require.NotNil(t, got) + assert.Equal(t, spec.expCodeIDs, got.CodeIDs) + }) + } +} + +func TestQueryParams(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + q := Querier(keeper) + + paramsResponse, err := q.Params(sdk.WrapSDKContext(ctx), &types.QueryParamsRequest{}) + require.NoError(t, err) + require.NotNil(t, paramsResponse) + + defaultParams := types.DefaultParams() + + require.Equal(t, paramsResponse.Params.CodeUploadAccess, defaultParams.CodeUploadAccess) + require.Equal(t, paramsResponse.Params.InstantiateDefaultPermission, defaultParams.InstantiateDefaultPermission) + + keeper.SetParams(ctx, types.Params{ + CodeUploadAccess: types.AllowNobody, + InstantiateDefaultPermission: types.AccessTypeNobody, + }) + + paramsResponse, err = q.Params(sdk.WrapSDKContext(ctx), &types.QueryParamsRequest{}) + require.NoError(t, err) + require.NotNil(t, paramsResponse) + + require.Equal(t, paramsResponse.Params.CodeUploadAccess, types.AllowNobody) + require.Equal(t, paramsResponse.Params.InstantiateDefaultPermission, types.AccessTypeNobody) +} + +func TestQueryCodeInfo(t *testing.T) { + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + anyAddress, err := sdk.AccAddressFromBech32("cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz") + require.NoError(t, err) + specs := map[string]struct { + codeId uint64 + accessConfig types.AccessConfig + }{ + "everybody": { + codeId: 1, + accessConfig: types.AllowEverybody, + }, + "nobody": { + codeId: 10, + accessConfig: types.AllowNobody, + }, + "with_address": { + codeId: 20, + accessConfig: types.AccessTypeOnlyAddress.With(anyAddress), + }, + } + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) + codeInfo.InstantiateConfig = spec.accessConfig + require.NoError(t, keeper.importCode(ctx, spec.codeId, + codeInfo, + wasmCode), + ) + + q := Querier(keeper) + got, err := q.Code(sdk.WrapSDKContext(ctx), &types.QueryCodeRequest{ + CodeId: spec.codeId, + }) + require.NoError(t, err) + expectedResponse := &types.QueryCodeResponse{ + CodeInfoResponse: &types.CodeInfoResponse{ + CodeID: spec.codeId, + Creator: codeInfo.Creator, + DataHash: codeInfo.CodeHash, + InstantiatePermission: spec.accessConfig, + }, + Data: wasmCode, + } + require.NotNil(t, got.CodeInfoResponse) + require.EqualValues(t, expectedResponse, got) + }) + } +} + +func TestQueryCodeInfoList(t *testing.T) { + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + keeper := keepers.WasmKeeper + + anyAddress, err := sdk.AccAddressFromBech32("cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz") + require.NoError(t, err) + codeInfoWithConfig := func(accessConfig types.AccessConfig) types.CodeInfo { + codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) + codeInfo.InstantiateConfig = accessConfig + return codeInfo + } + + codes := []struct { + name string + codeId uint64 + codeInfo types.CodeInfo + }{ + { + name: "everybody", + codeId: 1, + codeInfo: codeInfoWithConfig(types.AllowEverybody), + }, + { + codeId: 10, + name: "nobody", + codeInfo: codeInfoWithConfig(types.AllowNobody), + }, + { + name: "with_address", + codeId: 20, + codeInfo: codeInfoWithConfig(types.AccessTypeOnlyAddress.With(anyAddress)), + }, + } + + allCodesResponse := make([]types.CodeInfoResponse, 0) + for _, code := range codes { + t.Run(fmt.Sprintf("import_%s", code.name), func(t *testing.T) { + require.NoError(t, keeper.importCode(ctx, code.codeId, + code.codeInfo, + wasmCode), + ) + }) + + allCodesResponse = append(allCodesResponse, types.CodeInfoResponse{ + CodeID: code.codeId, + Creator: code.codeInfo.Creator, + DataHash: code.codeInfo.CodeHash, + InstantiatePermission: code.codeInfo.InstantiateConfig, + }) + } + q := Querier(keeper) + got, err := q.Codes(sdk.WrapSDKContext(ctx), &types.QueryCodesRequest{ + Pagination: &query.PageRequest{ + Limit: 3, + }, + }) + require.NoError(t, err) + require.Len(t, got.CodeInfos, 3) + require.EqualValues(t, allCodesResponse, got.CodeInfos) +} + +func TestQueryContractsByCreatorList(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 500)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + anyAddr := keepers.Faucet.NewFundedRandomAccount(ctx, topUp...) + + wasmCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, wasmCode, nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: anyAddr, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + // manage some realistic block settings + var h int64 = 10 + setBlock := func(ctx sdk.Context, height int64) sdk.Context { + ctx = ctx.WithBlockHeight(height) + meter := sdk.NewGasMeter(1000000) + ctx = ctx.WithGasMeter(meter) + ctx = ctx.WithBlockGasMeter(meter) + return ctx + } + + var allExpecedContracts []string + // create 10 contracts with real block/gas setup + for i := 0; i < 10; i++ { + ctx = setBlock(ctx, h) + h++ + contract, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, fmt.Sprintf("contract %d", i), topUp) + allExpecedContracts = append(allExpecedContracts, contract.String()) + require.NoError(t, err) + } + + specs := map[string]struct { + srcQuery *types.QueryContractsByCreatorRequest + expContractAddr []string + expErr error + }{ + "query all": { + srcQuery: &types.QueryContractsByCreatorRequest{ + CreatorAddress: creator.String(), + }, + expContractAddr: allExpecedContracts, + expErr: nil, + }, + "with pagination offset": { + srcQuery: &types.QueryContractsByCreatorRequest{ + CreatorAddress: creator.String(), + Pagination: &query.PageRequest{ + Offset: 1, + }, + }, + expContractAddr: allExpecedContracts[1:], + expErr: nil, + }, + "with pagination limit": { + srcQuery: &types.QueryContractsByCreatorRequest{ + CreatorAddress: creator.String(), + Pagination: &query.PageRequest{ + Limit: 1, + }, + }, + expContractAddr: allExpecedContracts[0:1], + expErr: nil, + }, + "nil creator": { + srcQuery: &types.QueryContractsByCreatorRequest{ + Pagination: &query.PageRequest{}, + }, + expContractAddr: allExpecedContracts, + expErr: errors.New("empty address string is not allowed"), + }, + "nil req": { + srcQuery: nil, + expContractAddr: allExpecedContracts, + expErr: status.Error(codes.InvalidArgument, "empty request"), + }, + } + + q := Querier(keepers.WasmKeeper) + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + got, err := q.ContractsByCreator(sdk.WrapSDKContext(ctx), spec.srcQuery) + + if spec.expErr != nil { + require.Equal(t, spec.expErr, err) + return + } + require.NoError(t, err) + require.NotNil(t, got) + assert.Equal(t, spec.expContractAddr, got.ContractAddresses) + }) + } +} + +func fromBase64(s string) []byte { + r, err := base64.StdEncoding.DecodeString(s) + if err != nil { + panic(err) + } + return r +} diff --git a/x/wasm/keeper/query_plugins.go b/x/wasm/keeper/query_plugins.go new file mode 100644 index 00000000..0bcc4c1e --- /dev/null +++ b/x/wasm/keeper/query_plugins.go @@ -0,0 +1,614 @@ +package keeper + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + abci "github.com/tendermint/tendermint/abci/types" + + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + + "github.com/cerc-io/laconicd/x/wasm/types" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +type QueryHandler struct { + Ctx sdk.Context + Plugins WasmVMQueryHandler + Caller sdk.AccAddress + gasRegister GasRegister +} + +func NewQueryHandler(ctx sdk.Context, vmQueryHandler WasmVMQueryHandler, caller sdk.AccAddress, gasRegister GasRegister) QueryHandler { + return QueryHandler{ + Ctx: ctx, + Plugins: vmQueryHandler, + Caller: caller, + gasRegister: gasRegister, + } +} + +type GRPCQueryRouter interface { + Route(path string) baseapp.GRPCQueryHandler +} + +// -- end baseapp interfaces -- + +var _ wasmvmtypes.Querier = QueryHandler{} + +func (q QueryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) ([]byte, error) { + // set a limit for a subCtx + sdkGas := q.gasRegister.FromWasmVMGas(gasLimit) + // discard all changes/ events in subCtx by not committing the cached context + subCtx, _ := q.Ctx.WithGasMeter(sdk.NewGasMeter(sdkGas)).CacheContext() + + // make sure we charge the higher level context even on panic + defer func() { + q.Ctx.GasMeter().ConsumeGas(subCtx.GasMeter().GasConsumed(), "contract sub-query") + }() + + res, err := q.Plugins.HandleQuery(subCtx, q.Caller, request) + if err == nil { + // short-circuit, the rest is dealing with handling existing errors + return res, nil + } + + // special mappings to wasmvm system error (which are not redacted) + var wasmvmErr types.WasmVMErrorable + if ok := errors.As(err, &wasmvmErr); ok { + err = wasmvmErr.ToWasmVMError() + } + + // Issue #759 - we don't return error string for worries of non-determinism + return nil, redactError(err) +} + +func (q QueryHandler) GasConsumed() uint64 { + return q.Ctx.GasMeter().GasConsumed() +} + +type CustomQuerier func(ctx sdk.Context, request json.RawMessage) ([]byte, error) + +type QueryPlugins struct { + Bank func(ctx sdk.Context, request *wasmvmtypes.BankQuery) ([]byte, error) + Custom CustomQuerier + IBC func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) + Staking func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) + Stargate func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) + Wasm func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) +} + +type contractMetaDataSource interface { + GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo +} + +type wasmQueryKeeper interface { + contractMetaDataSource + GetCodeInfo(ctx sdk.Context, codeID uint64) *types.CodeInfo + QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte + QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) + IsPinnedCode(ctx sdk.Context, codeID uint64) bool +} + +func DefaultQueryPlugins( + bank types.BankViewKeeper, + staking types.StakingKeeper, + distKeeper types.DistributionKeeper, + channelKeeper types.ChannelKeeper, + wasm wasmQueryKeeper, +) QueryPlugins { + return QueryPlugins{ + Bank: BankQuerier(bank), + Custom: NoCustomQuerier, + IBC: IBCQuerier(wasm, channelKeeper), + Staking: StakingQuerier(staking, distKeeper), + Stargate: RejectStargateQuerier(), + Wasm: WasmQuerier(wasm), + } +} + +func (e QueryPlugins) Merge(o *QueryPlugins) QueryPlugins { + // only update if this is non-nil and then only set values + if o == nil { + return e + } + if o.Bank != nil { + e.Bank = o.Bank + } + if o.Custom != nil { + e.Custom = o.Custom + } + if o.IBC != nil { + e.IBC = o.IBC + } + if o.Staking != nil { + e.Staking = o.Staking + } + if o.Stargate != nil { + e.Stargate = o.Stargate + } + if o.Wasm != nil { + e.Wasm = o.Wasm + } + return e +} + +// HandleQuery executes the requested query +func (e QueryPlugins) HandleQuery(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) { + // do the query + if request.Bank != nil { + return e.Bank(ctx, request.Bank) + } + if request.Custom != nil { + return e.Custom(ctx, request.Custom) + } + if request.IBC != nil { + return e.IBC(ctx, caller, request.IBC) + } + if request.Staking != nil { + return e.Staking(ctx, request.Staking) + } + if request.Stargate != nil { + return e.Stargate(ctx, request.Stargate) + } + if request.Wasm != nil { + return e.Wasm(ctx, request.Wasm) + } + return nil, wasmvmtypes.Unknown{} +} + +func BankQuerier(bankKeeper types.BankViewKeeper) func(ctx sdk.Context, request *wasmvmtypes.BankQuery) ([]byte, error) { + return func(ctx sdk.Context, request *wasmvmtypes.BankQuery) ([]byte, error) { + if request.AllBalances != nil { + addr, err := sdk.AccAddressFromBech32(request.AllBalances.Address) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.AllBalances.Address) + } + coins := bankKeeper.GetAllBalances(ctx, addr) + res := wasmvmtypes.AllBalancesResponse{ + Amount: ConvertSdkCoinsToWasmCoins(coins), + } + return json.Marshal(res) + } + if request.Balance != nil { + addr, err := sdk.AccAddressFromBech32(request.Balance.Address) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Balance.Address) + } + coin := bankKeeper.GetBalance(ctx, addr, request.Balance.Denom) + res := wasmvmtypes.BalanceResponse{ + Amount: wasmvmtypes.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.String(), + }, + } + return json.Marshal(res) + } + if request.Supply != nil { + coin := bankKeeper.GetSupply(ctx, request.Supply.Denom) + res := wasmvmtypes.SupplyResponse{ + Amount: wasmvmtypes.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.String(), + }, + } + return json.Marshal(res) + } + return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown BankQuery variant"} + } +} + +func NoCustomQuerier(sdk.Context, json.RawMessage) ([]byte, error) { + return nil, wasmvmtypes.UnsupportedRequest{Kind: "custom"} +} + +func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper) func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) { + return func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) { + if request.PortID != nil { + contractInfo := wasm.GetContractInfo(ctx, caller) + res := wasmvmtypes.PortIDResponse{ + PortID: contractInfo.IBCPortID, + } + return json.Marshal(res) + } + if request.ListChannels != nil { + portID := request.ListChannels.PortID + channels := make(wasmvmtypes.IBCChannels, 0) + channelKeeper.IterateChannels(ctx, func(ch channeltypes.IdentifiedChannel) bool { + // it must match the port and be in open state + if (portID == "" || portID == ch.PortId) && ch.State == channeltypes.OPEN { + newChan := wasmvmtypes.IBCChannel{ + Endpoint: wasmvmtypes.IBCEndpoint{ + PortID: ch.PortId, + ChannelID: ch.ChannelId, + }, + CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{ + PortID: ch.Counterparty.PortId, + ChannelID: ch.Counterparty.ChannelId, + }, + Order: ch.Ordering.String(), + Version: ch.Version, + ConnectionID: ch.ConnectionHops[0], + } + channels = append(channels, newChan) + } + return false + }) + res := wasmvmtypes.ListChannelsResponse{ + Channels: channels, + } + return json.Marshal(res) + } + if request.Channel != nil { + channelID := request.Channel.ChannelID + portID := request.Channel.PortID + if portID == "" { + contractInfo := wasm.GetContractInfo(ctx, caller) + portID = contractInfo.IBCPortID + } + got, found := channelKeeper.GetChannel(ctx, portID, channelID) + var channel *wasmvmtypes.IBCChannel + // it must be in open state + if found && got.State == channeltypes.OPEN { + channel = &wasmvmtypes.IBCChannel{ + Endpoint: wasmvmtypes.IBCEndpoint{ + PortID: portID, + ChannelID: channelID, + }, + CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{ + PortID: got.Counterparty.PortId, + ChannelID: got.Counterparty.ChannelId, + }, + Order: got.Ordering.String(), + Version: got.Version, + ConnectionID: got.ConnectionHops[0], + } + } + res := wasmvmtypes.ChannelResponse{ + Channel: channel, + } + return json.Marshal(res) + } + return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown IBCQuery variant"} + } +} + +// RejectStargateQuerier rejects all stargate queries +func RejectStargateQuerier() func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { + return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { + return nil, wasmvmtypes.UnsupportedRequest{Kind: "Stargate queries are disabled"} + } +} + +// AcceptedStargateQueries define accepted Stargate queries as a map with path as key and response type as value. +// For example: +// acceptList["/cosmos.auth.v1beta1.Query/Account"]= &authtypes.QueryAccountResponse{} +type AcceptedStargateQueries map[string]codec.ProtoMarshaler + +// AcceptListStargateQuerier supports a preconfigured set of stargate queries only. +// All arguments must be non nil. +// +// Warning: Chains need to test and maintain their accept list carefully. +// There were critical consensus breaking issues in the past with non-deterministic behaviour in the SDK. +// +// This queries can be set via WithQueryPlugins option in the wasm keeper constructor: +// WithQueryPlugins(&QueryPlugins{Stargate: AcceptListStargateQuerier(acceptList, queryRouter, codec)}) +func AcceptListStargateQuerier(acceptList AcceptedStargateQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { + return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) { + protoResponse, accepted := acceptList[request.Path] + if !accepted { + return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("'%s' path is not allowed from the contract", request.Path)} + } + + route := queryRouter.Route(request.Path) + if route == nil { + return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", request.Path)} + } + + res, err := route(ctx, abci.RequestQuery{ + Data: request.Data, + Path: request.Path, + }) + if err != nil { + return nil, err + } + + return ConvertProtoToJSONMarshal(codec, protoResponse, res.Value) + } +} + +func StakingQuerier(keeper types.StakingKeeper, distKeeper types.DistributionKeeper) func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) { + return func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) { + if request.BondedDenom != nil { + denom := keeper.BondDenom(ctx) + res := wasmvmtypes.BondedDenomResponse{ + Denom: denom, + } + return json.Marshal(res) + } + if request.AllValidators != nil { + validators := keeper.GetBondedValidatorsByPower(ctx) + // validators := keeper.GetAllValidators(ctx) + wasmVals := make([]wasmvmtypes.Validator, len(validators)) + for i, v := range validators { + wasmVals[i] = wasmvmtypes.Validator{ + Address: v.OperatorAddress, + Commission: v.Commission.Rate.String(), + MaxCommission: v.Commission.MaxRate.String(), + MaxChangeRate: v.Commission.MaxChangeRate.String(), + } + } + res := wasmvmtypes.AllValidatorsResponse{ + Validators: wasmVals, + } + return json.Marshal(res) + } + if request.Validator != nil { + valAddr, err := sdk.ValAddressFromBech32(request.Validator.Address) + if err != nil { + return nil, err + } + v, found := keeper.GetValidator(ctx, valAddr) + res := wasmvmtypes.ValidatorResponse{} + if found { + res.Validator = &wasmvmtypes.Validator{ + Address: v.OperatorAddress, + Commission: v.Commission.Rate.String(), + MaxCommission: v.Commission.MaxRate.String(), + MaxChangeRate: v.Commission.MaxChangeRate.String(), + } + } + return json.Marshal(res) + } + if request.AllDelegations != nil { + delegator, err := sdk.AccAddressFromBech32(request.AllDelegations.Delegator) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.AllDelegations.Delegator) + } + sdkDels := keeper.GetAllDelegatorDelegations(ctx, delegator) + delegations, err := sdkToDelegations(ctx, keeper, sdkDels) + if err != nil { + return nil, err + } + res := wasmvmtypes.AllDelegationsResponse{ + Delegations: delegations, + } + return json.Marshal(res) + } + if request.Delegation != nil { + delegator, err := sdk.AccAddressFromBech32(request.Delegation.Delegator) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Delegation.Delegator) + } + validator, err := sdk.ValAddressFromBech32(request.Delegation.Validator) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Delegation.Validator) + } + + var res wasmvmtypes.DelegationResponse + d, found := keeper.GetDelegation(ctx, delegator, validator) + if found { + res.Delegation, err = sdkToFullDelegation(ctx, keeper, distKeeper, d) + if err != nil { + return nil, err + } + } + return json.Marshal(res) + } + return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown Staking variant"} + } +} + +func sdkToDelegations(ctx sdk.Context, keeper types.StakingKeeper, delegations []stakingtypes.Delegation) (wasmvmtypes.Delegations, error) { + result := make([]wasmvmtypes.Delegation, len(delegations)) + bondDenom := keeper.BondDenom(ctx) + + for i, d := range delegations { + delAddr, err := sdk.AccAddressFromBech32(d.DelegatorAddress) + if err != nil { + return nil, sdkerrors.Wrap(err, "delegator address") + } + valAddr, err := sdk.ValAddressFromBech32(d.ValidatorAddress) + if err != nil { + return nil, sdkerrors.Wrap(err, "validator address") + } + + // shares to amount logic comes from here: + // https://github.com/cosmos/cosmos-sdk/blob/v0.38.3/x/staking/keeper/querier.go#L404 + val, found := keeper.GetValidator(ctx, valAddr) + if !found { + return nil, sdkerrors.Wrap(stakingtypes.ErrNoValidatorFound, "can't load validator for delegation") + } + amount := sdk.NewCoin(bondDenom, val.TokensFromShares(d.Shares).TruncateInt()) + + result[i] = wasmvmtypes.Delegation{ + Delegator: delAddr.String(), + Validator: valAddr.String(), + Amount: ConvertSdkCoinToWasmCoin(amount), + } + } + return result, nil +} + +func sdkToFullDelegation(ctx sdk.Context, keeper types.StakingKeeper, distKeeper types.DistributionKeeper, delegation stakingtypes.Delegation) (*wasmvmtypes.FullDelegation, error) { + delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress) + if err != nil { + return nil, sdkerrors.Wrap(err, "delegator address") + } + valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress) + if err != nil { + return nil, sdkerrors.Wrap(err, "validator address") + } + val, found := keeper.GetValidator(ctx, valAddr) + if !found { + return nil, sdkerrors.Wrap(stakingtypes.ErrNoValidatorFound, "can't load validator for delegation") + } + bondDenom := keeper.BondDenom(ctx) + amount := sdk.NewCoin(bondDenom, val.TokensFromShares(delegation.Shares).TruncateInt()) + + delegationCoins := ConvertSdkCoinToWasmCoin(amount) + + // FIXME: this is very rough but better than nothing... + // https://github.com/CosmWasm/wasmd/issues/282 + // if this (val, delegate) pair is receiving a redelegation, it cannot redelegate more + // otherwise, it can redelegate the full amount + // (there are cases of partial funds redelegated, but this is a start) + redelegateCoins := wasmvmtypes.NewCoin(0, bondDenom) + if !keeper.HasReceivingRedelegation(ctx, delAddr, valAddr) { + redelegateCoins = delegationCoins + } + + // FIXME: make a cleaner way to do this (modify the sdk) + // we need the info from `distKeeper.calculateDelegationRewards()`, but it is not public + // neither is `queryDelegationRewards(ctx sdk.Context, _ []string, req abci.RequestQuery, k Keeper)` + // so we go through the front door of the querier.... + accRewards, err := getAccumulatedRewards(ctx, distKeeper, delegation) + if err != nil { + return nil, err + } + + return &wasmvmtypes.FullDelegation{ + Delegator: delAddr.String(), + Validator: valAddr.String(), + Amount: delegationCoins, + AccumulatedRewards: accRewards, + CanRedelegate: redelegateCoins, + }, nil +} + +// FIXME: simplify this enormously when +// https://github.com/cosmos/cosmos-sdk/issues/7466 is merged +func getAccumulatedRewards(ctx sdk.Context, distKeeper types.DistributionKeeper, delegation stakingtypes.Delegation) ([]wasmvmtypes.Coin, error) { + // Try to get *delegator* reward info! + params := distributiontypes.QueryDelegationRewardsRequest{ + DelegatorAddress: delegation.DelegatorAddress, + ValidatorAddress: delegation.ValidatorAddress, + } + cache, _ := ctx.CacheContext() + qres, err := distKeeper.DelegationRewards(sdk.WrapSDKContext(cache), ¶ms) + if err != nil { + return nil, err + } + + // now we have it, convert it into wasmvm types + rewards := make([]wasmvmtypes.Coin, len(qres.Rewards)) + for i, r := range qres.Rewards { + rewards[i] = wasmvmtypes.Coin{ + Denom: r.Denom, + Amount: r.Amount.TruncateInt().String(), + } + } + return rewards, nil +} + +func WasmQuerier(k wasmQueryKeeper) func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) { + return func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) { + switch { + case request.Smart != nil: + addr, err := sdk.AccAddressFromBech32(request.Smart.ContractAddr) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Smart.ContractAddr) + } + msg := types.RawContractMessage(request.Smart.Msg) + if err := msg.ValidateBasic(); err != nil { + return nil, sdkerrors.Wrap(err, "json msg") + } + return k.QuerySmart(ctx, addr, msg) + case request.Raw != nil: + addr, err := sdk.AccAddressFromBech32(request.Raw.ContractAddr) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Raw.ContractAddr) + } + return k.QueryRaw(ctx, addr, request.Raw.Key), nil + case request.ContractInfo != nil: + contractAddr := request.ContractInfo.ContractAddr + addr, err := sdk.AccAddressFromBech32(contractAddr) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, contractAddr) + } + info := k.GetContractInfo(ctx, addr) + if info == nil { + return nil, types.ErrNoSuchContractFn(contractAddr). + Wrapf("address %s", contractAddr) + } + res := wasmvmtypes.ContractInfoResponse{ + CodeID: info.CodeID, + Creator: info.Creator, + Admin: info.Admin, + Pinned: k.IsPinnedCode(ctx, info.CodeID), + IBCPort: info.IBCPortID, + } + return json.Marshal(res) + case request.CodeInfo != nil: + if request.CodeInfo.CodeID == 0 { + return nil, types.ErrEmpty.Wrap("code id") + } + info := k.GetCodeInfo(ctx, request.CodeInfo.CodeID) + if info == nil { + return nil, types.ErrNoSuchCodeFn(request.CodeInfo.CodeID). + Wrapf("code id %d", request.CodeInfo.CodeID) + } + + res := wasmvmtypes.CodeInfoResponse{ + CodeID: request.CodeInfo.CodeID, + Creator: info.Creator, + Checksum: info.CodeHash, + } + return json.Marshal(res) + } + return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown WasmQuery variant"} + } +} + +// ConvertSdkCoinsToWasmCoins covert sdk type to wasmvm coins type +func ConvertSdkCoinsToWasmCoins(coins []sdk.Coin) wasmvmtypes.Coins { + converted := make(wasmvmtypes.Coins, len(coins)) + for i, c := range coins { + converted[i] = ConvertSdkCoinToWasmCoin(c) + } + return converted +} + +// ConvertSdkCoinToWasmCoin covert sdk type to wasmvm coin type +func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin { + return wasmvmtypes.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.String(), + } +} + +// ConvertProtoToJSONMarshal unmarshals the given bytes into a proto message and then marshals it to json. +// This is done so that clients calling stargate queries do not need to define their own proto unmarshalers, +// being able to use response directly by json marshalling, which is supported in cosmwasm. +func ConvertProtoToJSONMarshal(cdc codec.Codec, protoResponse codec.ProtoMarshaler, bz []byte) ([]byte, error) { + // unmarshal binary into stargate response data structure + err := cdc.Unmarshal(bz, protoResponse) + if err != nil { + return nil, sdkerrors.Wrap(err, "to proto") + } + + bz, err = cdc.MarshalJSON(protoResponse) + if err != nil { + return nil, sdkerrors.Wrap(err, "to json") + } + + return bz, nil +} + +var _ WasmVMQueryHandler = WasmVMQueryHandlerFn(nil) + +// WasmVMQueryHandlerFn is a helper to construct a function based query handler. +type WasmVMQueryHandlerFn func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) + +// HandleQuery delegates call into wrapped WasmVMQueryHandlerFn +func (w WasmVMQueryHandlerFn) HandleQuery(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) { + return w(ctx, caller, request) +} diff --git a/x/wasm/keeper/query_plugins_test.go b/x/wasm/keeper/query_plugins_test.go new file mode 100644 index 00000000..da2d5f6b --- /dev/null +++ b/x/wasm/keeper/query_plugins_test.go @@ -0,0 +1,825 @@ +package keeper_test + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "testing" + "time" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/query" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + channeltypes "github.com/cosmos/ibc-go/v4/modules/core/04-channel/types" + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cerc-io/laconicd/app" + "github.com/cerc-io/laconicd/x/wasm/keeper" + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestIBCQuerier(t *testing.T) { + myExampleChannels := []channeltypes.IdentifiedChannel{ + // this is returned + { + State: channeltypes.OPEN, + Ordering: channeltypes.ORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "counterPartyPortID", + ChannelId: "counterPartyChannelID", + }, + ConnectionHops: []string{"one"}, + Version: "v1", + PortId: "myPortID", + ChannelId: "myChannelID", + }, + // this is filtered out + { + State: channeltypes.INIT, + Ordering: channeltypes.UNORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "foobar", + }, + ConnectionHops: []string{"one"}, + Version: "initversion", + PortId: "initPortID", + ChannelId: "initChannelID", + }, + // this is returned + { + State: channeltypes.OPEN, + Ordering: channeltypes.UNORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "otherCounterPartyPortID", + ChannelId: "otherCounterPartyChannelID", + }, + ConnectionHops: []string{"other", "second"}, + Version: "otherVersion", + PortId: "otherPortID", + ChannelId: "otherChannelID", + }, + // this is filtered out + { + State: channeltypes.CLOSED, + Ordering: channeltypes.ORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "super", + ChannelId: "duper", + }, + ConnectionHops: []string{"no-more"}, + Version: "closedVersion", + PortId: "closedPortID", + ChannelId: "closedChannelID", + }, + } + specs := map[string]struct { + srcQuery *wasmvmtypes.IBCQuery + wasmKeeper *mockWasmQueryKeeper + channelKeeper *wasmtesting.MockChannelKeeper + expJsonResult string + expErr *sdkerrors.Error + }{ + "query port id": { + srcQuery: &wasmvmtypes.IBCQuery{ + PortID: &wasmvmtypes.PortIDQuery{}, + }, + wasmKeeper: &mockWasmQueryKeeper{ + GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + return &types.ContractInfo{IBCPortID: "myIBCPortID"} + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{}, + expJsonResult: `{"port_id":"myIBCPortID"}`, + }, + "query list channels - all": { + srcQuery: &wasmvmtypes.IBCQuery{ + ListChannels: &wasmvmtypes.ListChannelsQuery{}, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels), + }, + expJsonResult: `{ + "channels": [ + { + "endpoint": { + "port_id": "myPortID", + "channel_id": "myChannelID" + }, + "counterparty_endpoint": { + "port_id": "counterPartyPortID", + "channel_id": "counterPartyChannelID" + }, + "order": "ORDER_ORDERED", + "version": "v1", + "connection_id": "one" + }, + { + "endpoint": { + "port_id": "otherPortID", + "channel_id": "otherChannelID" + }, + "counterparty_endpoint": { + "port_id": "otherCounterPartyPortID", + "channel_id": "otherCounterPartyChannelID" + }, + "order": "ORDER_UNORDERED", + "version": "otherVersion", + "connection_id": "other" + } + ] +}`, + }, + "query list channels - filtered": { + srcQuery: &wasmvmtypes.IBCQuery{ + ListChannels: &wasmvmtypes.ListChannelsQuery{ + PortID: "otherPortID", + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels), + }, + expJsonResult: `{ + "channels": [ + { + "endpoint": { + "port_id": "otherPortID", + "channel_id": "otherChannelID" + }, + "counterparty_endpoint": { + "port_id": "otherCounterPartyPortID", + "channel_id": "otherCounterPartyChannelID" + }, + "order": "ORDER_UNORDERED", + "version": "otherVersion", + "connection_id": "other" + } + ] +}`, + }, + "query list channels - filtered empty": { + srcQuery: &wasmvmtypes.IBCQuery{ + ListChannels: &wasmvmtypes.ListChannelsQuery{ + PortID: "none-existing", + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels), + }, + expJsonResult: `{"channels": []}`, + }, + "query channel": { + srcQuery: &wasmvmtypes.IBCQuery{ + Channel: &wasmvmtypes.ChannelQuery{ + PortID: "myQueryPortID", + ChannelID: "myQueryChannelID", + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { + return channeltypes.Channel{ + State: channeltypes.OPEN, + Ordering: channeltypes.UNORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "counterPartyPortID", + ChannelId: "otherCounterPartyChannelID", + }, + ConnectionHops: []string{"one"}, + Version: "version", + }, true + }, + }, + expJsonResult: `{ + "channel": { + "endpoint": { + "port_id": "myQueryPortID", + "channel_id": "myQueryChannelID" + }, + "counterparty_endpoint": { + "port_id": "counterPartyPortID", + "channel_id": "otherCounterPartyChannelID" + }, + "order": "ORDER_UNORDERED", + "version": "version", + "connection_id": "one" + } +}`, + }, + "query channel - without port set": { + srcQuery: &wasmvmtypes.IBCQuery{ + Channel: &wasmvmtypes.ChannelQuery{ + ChannelID: "myQueryChannelID", + }, + }, + wasmKeeper: &mockWasmQueryKeeper{ + GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + return &types.ContractInfo{IBCPortID: "myLoadedPortID"} + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { + return channeltypes.Channel{ + State: channeltypes.OPEN, + Ordering: channeltypes.UNORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "counterPartyPortID", + ChannelId: "otherCounterPartyChannelID", + }, + ConnectionHops: []string{"one"}, + Version: "version", + }, true + }, + }, + expJsonResult: `{ + "channel": { + "endpoint": { + "port_id": "myLoadedPortID", + "channel_id": "myQueryChannelID" + }, + "counterparty_endpoint": { + "port_id": "counterPartyPortID", + "channel_id": "otherCounterPartyChannelID" + }, + "order": "ORDER_UNORDERED", + "version": "version", + "connection_id": "one" + } +}`, + }, + "query channel in init state": { + srcQuery: &wasmvmtypes.IBCQuery{ + Channel: &wasmvmtypes.ChannelQuery{ + PortID: "myQueryPortID", + ChannelID: "myQueryChannelID", + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { + return channeltypes.Channel{ + State: channeltypes.INIT, + Ordering: channeltypes.UNORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "foobar", + }, + ConnectionHops: []string{"one"}, + Version: "initversion", + }, true + }, + }, + expJsonResult: "{}", + }, + "query channel in closed state": { + srcQuery: &wasmvmtypes.IBCQuery{ + Channel: &wasmvmtypes.ChannelQuery{ + PortID: "myQueryPortID", + ChannelID: "myQueryChannelID", + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { + return channeltypes.Channel{ + State: channeltypes.CLOSED, + Ordering: channeltypes.ORDERED, + Counterparty: channeltypes.Counterparty{ + PortId: "super", + ChannelId: "duper", + }, + ConnectionHops: []string{"no-more"}, + Version: "closedVersion", + }, true + }, + }, + expJsonResult: "{}", + }, + "query channel - empty result": { + srcQuery: &wasmvmtypes.IBCQuery{ + Channel: &wasmvmtypes.ChannelQuery{ + PortID: "myQueryPortID", + ChannelID: "myQueryChannelID", + }, + }, + channelKeeper: &wasmtesting.MockChannelKeeper{ + GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { + return channeltypes.Channel{}, false + }, + }, + expJsonResult: "{}", + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + h := keeper.IBCQuerier(spec.wasmKeeper, spec.channelKeeper) + gotResult, gotErr := h(sdk.Context{}, keeper.RandomAccountAddress(t), spec.srcQuery) + require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) + if spec.expErr != nil { + return + } + assert.JSONEq(t, spec.expJsonResult, string(gotResult), string(gotResult)) + }) + } +} + +func TestBankQuerierBalance(t *testing.T) { + mock := bankKeeperMock{GetBalanceFn: func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + return sdk.NewCoin(denom, sdk.NewInt(1)) + }} + + ctx := sdk.Context{} + q := keeper.BankQuerier(mock) + gotBz, gotErr := q(ctx, &wasmvmtypes.BankQuery{ + Balance: &wasmvmtypes.BalanceQuery{ + Address: keeper.RandomBech32AccountAddress(t), + Denom: "ALX", + }, + }) + require.NoError(t, gotErr) + var got wasmvmtypes.BalanceResponse + require.NoError(t, json.Unmarshal(gotBz, &got)) + exp := wasmvmtypes.BalanceResponse{ + Amount: wasmvmtypes.Coin{ + Denom: "ALX", + Amount: "1", + }, + } + assert.Equal(t, exp, got) +} + +func TestContractInfoWasmQuerier(t *testing.T) { + myValidContractAddr := keeper.RandomBech32AccountAddress(t) + myCreatorAddr := keeper.RandomBech32AccountAddress(t) + myAdminAddr := keeper.RandomBech32AccountAddress(t) + var ctx sdk.Context + + specs := map[string]struct { + req *wasmvmtypes.WasmQuery + mock mockWasmQueryKeeper + expRes wasmvmtypes.ContractInfoResponse + expErr bool + }{ + "all good": { + req: &wasmvmtypes.WasmQuery{ + ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, + }, + mock: mockWasmQueryKeeper{ + GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + val := types.ContractInfoFixture(func(i *types.ContractInfo) { + i.Admin, i.Creator, i.IBCPortID = myAdminAddr, myCreatorAddr, "myIBCPort" + }) + return &val + }, + IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return true }, + }, + expRes: wasmvmtypes.ContractInfoResponse{ + CodeID: 1, + Creator: myCreatorAddr, + Admin: myAdminAddr, + Pinned: true, + IBCPort: "myIBCPort", + }, + }, + "invalid addr": { + req: &wasmvmtypes.WasmQuery{ + ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: "not a valid addr"}, + }, + expErr: true, + }, + "unknown addr": { + req: &wasmvmtypes.WasmQuery{ + ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, + }, + mock: mockWasmQueryKeeper{GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + return nil + }}, + expErr: true, + }, + "not pinned": { + req: &wasmvmtypes.WasmQuery{ + ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, + }, + mock: mockWasmQueryKeeper{ + GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + val := types.ContractInfoFixture(func(i *types.ContractInfo) { + i.Admin, i.Creator = myAdminAddr, myCreatorAddr + }) + return &val + }, + IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return false }, + }, + expRes: wasmvmtypes.ContractInfoResponse{ + CodeID: 1, + Creator: myCreatorAddr, + Admin: myAdminAddr, + Pinned: false, + }, + }, + "without admin": { + req: &wasmvmtypes.WasmQuery{ + ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, + }, + mock: mockWasmQueryKeeper{ + GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + val := types.ContractInfoFixture(func(i *types.ContractInfo) { + i.Creator = myCreatorAddr + }) + return &val + }, + IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return true }, + }, + expRes: wasmvmtypes.ContractInfoResponse{ + CodeID: 1, + Creator: myCreatorAddr, + Pinned: true, + }, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + q := keeper.WasmQuerier(spec.mock) + gotBz, gotErr := q(ctx, spec.req) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + var gotRes wasmvmtypes.ContractInfoResponse + require.NoError(t, json.Unmarshal(gotBz, &gotRes)) + assert.Equal(t, spec.expRes, gotRes) + }) + } +} + +func TestCodeInfoWasmQuerier(t *testing.T) { + myCreatorAddr := keeper.RandomBech32AccountAddress(t) + var ctx sdk.Context + + myRawChecksum := []byte("myHash78901234567890123456789012") + specs := map[string]struct { + req *wasmvmtypes.WasmQuery + mock mockWasmQueryKeeper + expRes wasmvmtypes.CodeInfoResponse + expErr bool + }{ + "all good": { + req: &wasmvmtypes.WasmQuery{ + CodeInfo: &wasmvmtypes.CodeInfoQuery{CodeID: 1}, + }, + mock: mockWasmQueryKeeper{ + GetCodeInfoFn: func(ctx sdk.Context, codeID uint64) *types.CodeInfo { + return &types.CodeInfo{ + CodeHash: myRawChecksum, + Creator: myCreatorAddr, + InstantiateConfig: types.AccessConfig{ + Permission: types.AccessTypeNobody, + Addresses: []string{myCreatorAddr}, + }, + } + }, + }, + expRes: wasmvmtypes.CodeInfoResponse{ + CodeID: 1, + Creator: myCreatorAddr, + Checksum: myRawChecksum, + }, + }, + "empty code id": { + req: &wasmvmtypes.WasmQuery{ + CodeInfo: &wasmvmtypes.CodeInfoQuery{}, + }, + expErr: true, + }, + "unknown code id": { + req: &wasmvmtypes.WasmQuery{ + CodeInfo: &wasmvmtypes.CodeInfoQuery{CodeID: 1}, + }, + mock: mockWasmQueryKeeper{ + GetCodeInfoFn: func(ctx sdk.Context, codeID uint64) *types.CodeInfo { + return nil + }, + }, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + q := keeper.WasmQuerier(spec.mock) + gotBz, gotErr := q(ctx, spec.req) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + var gotRes wasmvmtypes.CodeInfoResponse + require.NoError(t, json.Unmarshal(gotBz, &gotRes), string(gotBz)) + assert.Equal(t, spec.expRes, gotRes) + }) + } +} + +func TestQueryErrors(t *testing.T) { + specs := map[string]struct { + src error + expErr error + }{ + "no error": {}, + "no such contract": { + src: types.ErrNoSuchContractFn("contract-addr"), + expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"}, + }, + "no such contract - wrapped": { + src: sdkerrors.Wrap(types.ErrNoSuchContractFn("contract-addr"), "my additional data"), + expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"}, + }, + "no such code": { + src: types.ErrNoSuchCodeFn(123), + expErr: wasmvmtypes.NoSuchCode{CodeID: 123}, + }, + "no such code - wrapped": { + src: sdkerrors.Wrap(types.ErrNoSuchCodeFn(123), "my additional data"), + expErr: wasmvmtypes.NoSuchCode{CodeID: 123}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + mock := keeper.WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) { + return nil, spec.src + }) + ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()).WithMultiStore(store.NewCommitMultiStore(dbm.NewMemDB())) + q := keeper.NewQueryHandler(ctx, mock, sdk.AccAddress{}, keeper.NewDefaultWasmGasRegister()) + _, gotErr := q.Query(wasmvmtypes.QueryRequest{}, 1) + assert.Equal(t, spec.expErr, gotErr) + }) + } +} + +func TestAcceptListStargateQuerier(t *testing.T) { + wasmApp := app.SetupWithEmptyStore(t) + ctx := wasmApp.NewUncachedContext(false, tmproto.Header{ChainID: "foo", Height: 1, Time: time.Now()}) + wasmApp.StakingKeeper.SetParams(ctx, stakingtypes.DefaultParams()) + + addrs := app.AddTestAddrs(wasmApp, ctx, 2, sdk.NewInt(1_000_000)) + accepted := keeper.AcceptedStargateQueries{ + "/cosmos.auth.v1beta1.Query/Account": &authtypes.QueryAccountResponse{}, + "/no/route/to/this": &authtypes.QueryAccountResponse{}, + } + + marshal := func(pb proto.Message) []byte { + b, err := proto.Marshal(pb) + require.NoError(t, err) + return b + } + + specs := map[string]struct { + req *wasmvmtypes.StargateQuery + expErr bool + expResp string + }{ + "in accept list - success result": { + req: &wasmvmtypes.StargateQuery{ + Path: "/cosmos.auth.v1beta1.Query/Account", + Data: marshal(&authtypes.QueryAccountRequest{Address: addrs[0].String()}), + }, + expResp: fmt.Sprintf(`{"account":{"@type":"/cosmos.auth.v1beta1.BaseAccount","address":%q,"pub_key":null,"account_number":"1","sequence":"0"}}`, addrs[0].String()), + }, + "in accept list - error result": { + req: &wasmvmtypes.StargateQuery{ + Path: "/cosmos.auth.v1beta1.Query/Account", + Data: marshal(&authtypes.QueryAccountRequest{Address: sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address()).String()}), + }, + expErr: true, + }, + "not in accept list": { + req: &wasmvmtypes.StargateQuery{ + Path: "/cosmos.bank.v1beta1.Query/AllBalances", + Data: marshal(&banktypes.QueryAllBalancesRequest{Address: addrs[0].String()}), + }, + expErr: true, + }, + "unknown route": { + req: &wasmvmtypes.StargateQuery{ + Path: "/no/route/to/this", + Data: marshal(&banktypes.QueryAllBalancesRequest{Address: addrs[0].String()}), + }, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + q := keeper.AcceptListStargateQuerier(accepted, wasmApp.GRPCQueryRouter(), wasmApp.AppCodec()) + gotBz, gotErr := q(ctx, spec.req) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.JSONEq(t, spec.expResp, string(gotBz), string(gotBz)) + }) + } +} + +type mockWasmQueryKeeper struct { + GetContractInfoFn func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo + QueryRawFn func(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte + QuerySmartFn func(ctx sdk.Context, contractAddr sdk.AccAddress, req types.RawContractMessage) ([]byte, error) + IsPinnedCodeFn func(ctx sdk.Context, codeID uint64) bool + GetCodeInfoFn func(ctx sdk.Context, codeID uint64) *types.CodeInfo +} + +func (m mockWasmQueryKeeper) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { + if m.GetContractInfoFn == nil { + panic("not expected to be called") + } + return m.GetContractInfoFn(ctx, contractAddress) +} + +func (m mockWasmQueryKeeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte { + if m.QueryRawFn == nil { + panic("not expected to be called") + } + return m.QueryRawFn(ctx, contractAddress, key) +} + +func (m mockWasmQueryKeeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) { + if m.QuerySmartFn == nil { + panic("not expected to be called") + } + return m.QuerySmartFn(ctx, contractAddr, req) +} + +func (m mockWasmQueryKeeper) IsPinnedCode(ctx sdk.Context, codeID uint64) bool { + if m.IsPinnedCodeFn == nil { + panic("not expected to be called") + } + return m.IsPinnedCodeFn(ctx, codeID) +} + +func (m mockWasmQueryKeeper) GetCodeInfo(ctx sdk.Context, codeID uint64) *types.CodeInfo { + if m.GetCodeInfoFn == nil { + panic("not expected to be called") + } + return m.GetCodeInfoFn(ctx, codeID) +} + +type bankKeeperMock struct { + GetSupplyFn func(ctx sdk.Context, denom string) sdk.Coin + GetBalanceFn func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + GetAllBalancesFn func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} + +func (m bankKeeperMock) GetSupply(ctx sdk.Context, denom string) sdk.Coin { + if m.GetSupplyFn == nil { + panic("not expected to be called") + } + return m.GetSupplyFn(ctx, denom) +} + +func (m bankKeeperMock) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { + if m.GetBalanceFn == nil { + panic("not expected to be called") + } + return m.GetBalanceFn(ctx, addr, denom) +} + +func (m bankKeeperMock) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { + if m.GetAllBalancesFn == nil { + panic("not expected to be called") + } + return m.GetAllBalancesFn(ctx, addr) +} + +func TestConvertProtoToJSONMarshal(t *testing.T) { + testCases := []struct { + name string + queryPath string + protoResponseStruct codec.ProtoMarshaler + originalResponse string + expectedProtoResponse codec.ProtoMarshaler + expectedError bool + }{ + { + name: "successful conversion from proto response to json marshalled response", + queryPath: "/cosmos.bank.v1beta1.Query/AllBalances", + originalResponse: "0a090a036261721202333012050a03666f6f", + protoResponseStruct: &banktypes.QueryAllBalancesResponse{}, + expectedProtoResponse: &banktypes.QueryAllBalancesResponse{ + Balances: sdk.NewCoins(sdk.NewCoin("bar", sdk.NewInt(30))), + Pagination: &query.PageResponse{ + NextKey: []byte("foo"), + }, + }, + }, + { + name: "invalid proto response struct", + queryPath: "/cosmos.bank.v1beta1.Query/AllBalances", + originalResponse: "0a090a036261721202333012050a03666f6f", + protoResponseStruct: &authtypes.QueryAccountResponse{}, + expectedError: true, + }, + } + + for _, tc := range testCases { + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + originalVersionBz, err := hex.DecodeString(tc.originalResponse) + require.NoError(t, err) + appCodec := app.MakeEncodingConfig().Marshaler + + jsonMarshalledResponse, err := keeper.ConvertProtoToJSONMarshal(appCodec, tc.protoResponseStruct, originalVersionBz) + if tc.expectedError { + require.Error(t, err) + return + } + require.NoError(t, err) + + // check response by json marshalling proto response into json response manually + jsonMarshalExpectedResponse, err := appCodec.MarshalJSON(tc.expectedProtoResponse) + require.NoError(t, err) + require.JSONEq(t, string(jsonMarshalledResponse), string(jsonMarshalExpectedResponse)) + }) + } +} + +// TestDeterministicJsonMarshal tests that we get deterministic JSON marshalled response upon +// proto struct update in the state machine. +func TestDeterministicJsonMarshal(t *testing.T) { + testCases := []struct { + name string + originalResponse string + updatedResponse string + queryPath string + responseProtoStruct codec.ProtoMarshaler + expectedProto func() codec.ProtoMarshaler + }{ + /** + * + * Origin Response + * 0a530a202f636f736d6f732e617574682e763162657461312e426173654163636f756e74122f0a2d636f736d6f7331346c3268686a6e676c3939367772703935673867646a6871653038326375367a7732706c686b + * + * Updated Response + * 0a530a202f636f736d6f732e617574682e763162657461312e426173654163636f756e74122f0a2d636f736d6f7331646a783375676866736d6b6135386676673076616a6e6533766c72776b7a6a346e6377747271122d636f736d6f7331646a783375676866736d6b6135386676673076616a6e6533766c72776b7a6a346e6377747271 + // Origin proto + message QueryAccountResponse { + // account defines the account of the corresponding address. + google.protobuf.Any account = 1 [(cosmos_proto.accepts_interface) = "AccountI"]; + } + // Updated proto + message QueryAccountResponse { + // account defines the account of the corresponding address. + google.protobuf.Any account = 1 [(cosmos_proto.accepts_interface) = "AccountI"]; + // address is the address to query for. + string address = 2; + } + */ + { + "Query Account", + "0a530a202f636f736d6f732e617574682e763162657461312e426173654163636f756e74122f0a2d636f736d6f733166387578756c746e3873717a687a6e72737a3371373778776171756867727367366a79766679", + "0a530a202f636f736d6f732e617574682e763162657461312e426173654163636f756e74122f0a2d636f736d6f733166387578756c746e3873717a687a6e72737a3371373778776171756867727367366a79766679122d636f736d6f733166387578756c746e3873717a687a6e72737a3371373778776171756867727367366a79766679", + "/cosmos.auth.v1beta1.Query/Account", + &authtypes.QueryAccountResponse{}, + func() codec.ProtoMarshaler { + account := authtypes.BaseAccount{ + Address: "cosmos1f8uxultn8sqzhznrsz3q77xwaquhgrsg6jyvfy", + } + accountResponse, err := codectypes.NewAnyWithValue(&account) + require.NoError(t, err) + return &authtypes.QueryAccountResponse{ + Account: accountResponse, + } + }, + }, + } + + for _, tc := range testCases { + t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) { + appCodec := app.MakeEncodingConfig().Marshaler + + originVersionBz, err := hex.DecodeString(tc.originalResponse) + require.NoError(t, err) + jsonMarshalledOriginalBz, err := keeper.ConvertProtoToJSONMarshal(appCodec, tc.responseProtoStruct, originVersionBz) + require.NoError(t, err) + + newVersionBz, err := hex.DecodeString(tc.updatedResponse) + require.NoError(t, err) + jsonMarshalledUpdatedBz, err := keeper.ConvertProtoToJSONMarshal(appCodec, tc.responseProtoStruct, newVersionBz) + require.NoError(t, err) + + // json marshalled bytes should be the same since we use the same proto struct for unmarshalling + require.Equal(t, jsonMarshalledOriginalBz, jsonMarshalledUpdatedBz) + + // raw build also make same result + jsonMarshalExpectedResponse, err := appCodec.MarshalJSON(tc.expectedProto()) + require.NoError(t, err) + require.Equal(t, jsonMarshalledUpdatedBz, jsonMarshalExpectedResponse) + }) + } +} diff --git a/x/wasm/keeper/recurse_test.go b/x/wasm/keeper/recurse_test.go new file mode 100644 index 00000000..26712bf6 --- /dev/null +++ b/x/wasm/keeper/recurse_test.go @@ -0,0 +1,306 @@ +package keeper + +import ( + "encoding/json" + "testing" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cerc-io/laconicd/x/wasm/types" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type Recurse struct { + Depth uint32 `json:"depth"` + Work uint32 `json:"work"` +} + +type recurseWrapper struct { + Recurse Recurse `json:"recurse"` +} + +func buildRecurseQuery(t *testing.T, msg Recurse) []byte { + wrapper := recurseWrapper{Recurse: msg} + bz, err := json.Marshal(wrapper) + require.NoError(t, err) + return bz +} + +type recurseResponse struct { + Hashed []byte `json:"hashed"` +} + +// number os wasm queries called from a contract +var totalWasmQueryCounter int + +func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.AccAddress, ctx sdk.Context, keeper *Keeper) { + countingQuerierDec := func(realWasmQuerier WasmVMQueryHandler) WasmVMQueryHandler { + return WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) { + totalWasmQueryCounter++ + return realWasmQuerier.HandleQuery(ctx, caller, request) + }) + } + ctx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithQueryHandlerDecorator(countingQuerierDec)) + keeper = keepers.WasmKeeper + exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers) + return exampleContract.Contract, exampleContract.CreatorAddr, ctx, keeper +} + +func TestGasCostOnQuery(t *testing.T) { + const ( + GasNoWork uint64 = 63_950 + // Note: about 100 SDK gas (10k wasmer gas) for each round of sha256 + GasWork50 uint64 = 64_218 // this is a little shy of 50k gas - to keep an eye on the limit + + GasReturnUnhashed uint64 = 32 + GasReturnHashed uint64 = 27 + ) + + cases := map[string]struct { + gasLimit uint64 + msg Recurse + expectedGas uint64 + }{ + "no recursion, no work": { + gasLimit: 400_000, + msg: Recurse{}, + expectedGas: GasNoWork, + }, + "no recursion, some work": { + gasLimit: 400_000, + msg: Recurse{ + Work: 50, // 50 rounds of sha256 inside the contract + }, + expectedGas: GasWork50, + }, + "recursion 1, no work": { + gasLimit: 400_000, + msg: Recurse{ + Depth: 1, + }, + expectedGas: 2*GasNoWork + GasReturnUnhashed, + }, + "recursion 1, some work": { + gasLimit: 400_000, + msg: Recurse{ + Depth: 1, + Work: 50, + }, + expectedGas: 2*GasWork50 + GasReturnHashed, + }, + "recursion 4, some work": { + gasLimit: 400_000, + msg: Recurse{ + Depth: 4, + Work: 50, + }, + expectedGas: 5*GasWork50 + 4*GasReturnHashed, + }, + } + + contractAddr, _, ctx, keeper := initRecurseContract(t) + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + // external limit has no effect (we get a panic if this is enforced) + keeper.queryGasLimit = 1000 + + // make sure we set a limit before calling + ctx = ctx.WithGasMeter(sdk.NewGasMeter(tc.gasLimit)) + require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) + + // do the query + recurse := tc.msg + msg := buildRecurseQuery(t, recurse) + data, err := keeper.QuerySmart(ctx, contractAddr, msg) + require.NoError(t, err) + + // check the gas is what we expected + if types.EnableGasVerification { + assert.Equal(t, tc.expectedGas, ctx.GasMeter().GasConsumed()) + } + // assert result is 32 byte sha256 hash (if hashed), or contractAddr if not + var resp recurseResponse + err = json.Unmarshal(data, &resp) + require.NoError(t, err) + if recurse.Work == 0 { + assert.Equal(t, len(contractAddr.String()), len(resp.Hashed)) + } else { + assert.Equal(t, 32, len(resp.Hashed)) + } + }) + } +} + +func TestGasOnExternalQuery(t *testing.T) { + const ( + GasWork50 uint64 = DefaultInstanceCost + 8_464 + ) + + cases := map[string]struct { + gasLimit uint64 + msg Recurse + expOutOfGas bool + }{ + "no recursion, plenty gas": { + gasLimit: 400_000, + msg: Recurse{ + Work: 50, // 50 rounds of sha256 inside the contract + }, + }, + "recursion 4, plenty gas": { + // this uses 244708 gas + gasLimit: 400_000, + msg: Recurse{ + Depth: 4, + Work: 50, + }, + }, + "no recursion, external gas limit": { + gasLimit: 5000, // this is not enough + msg: Recurse{ + Work: 50, + }, + expOutOfGas: true, + }, + "recursion 4, external gas limit": { + // this uses 244708 gas but give less + gasLimit: 4 * GasWork50, + msg: Recurse{ + Depth: 4, + Work: 50, + }, + expOutOfGas: true, + }, + } + + contractAddr, _, ctx, keeper := initRecurseContract(t) + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + recurse := tc.msg + msg := buildRecurseQuery(t, recurse) + + querier := NewGrpcQuerier(keeper.cdc, keeper.storeKey, keeper, tc.gasLimit) + req := &types.QuerySmartContractStateRequest{Address: contractAddr.String(), QueryData: msg} + _, gotErr := querier.SmartContractState(sdk.WrapSDKContext(ctx), req) + if tc.expOutOfGas { + require.Error(t, gotErr, sdkerrors.ErrOutOfGas) + return + } + require.NoError(t, gotErr) + }) + } +} + +func TestLimitRecursiveQueryGas(t *testing.T) { + // The point of this test from https://github.com/CosmWasm/cosmwasm/issues/456 + // Basically, if I burn 90% of gas in CPU loop, then query out (to my self) + // the sub-query will have all the original gas (minus the 40k instance charge) + // and can burn 90% and call a sub-contract again... + // This attack would allow us to use far more than the provided gas before + // eventually hitting an OutOfGas panic. + + const ( + // Note: about 100 SDK gas (10k wasmer gas) for each round of sha256 + GasWork2k uint64 = 77_206 // = NewContractInstanceCosts + x // we have 6x gas used in cpu than in the instance + // This is overhead for calling into a sub-contract + GasReturnHashed uint64 = 27 + ) + + cases := map[string]struct { + gasLimit uint64 + msg Recurse + expectQueriesFromContract int + expectedGas uint64 + expectOutOfGas bool + expectError string + }{ + "no recursion, lots of work": { + gasLimit: 4_000_000, + msg: Recurse{ + Depth: 0, + Work: 2000, + }, + expectQueriesFromContract: 0, + expectedGas: GasWork2k, + }, + "recursion 5, lots of work": { + gasLimit: 4_000_000, + msg: Recurse{ + Depth: 5, + Work: 2000, + }, + expectQueriesFromContract: 5, + // FIXME: why -1 ... confused a bit by calculations, seems like rounding issues + expectedGas: GasWork2k + 5*(GasWork2k+GasReturnHashed), + }, + // this is where we expect an error... + // it has enough gas to run 5 times and die on the 6th (5th time dispatching to sub-contract) + // however, if we don't charge the cpu gas before sub-dispatching, we can recurse over 20 times + "deep recursion, should die on 5th level": { + gasLimit: 400_000, + msg: Recurse{ + Depth: 50, + Work: 2000, + }, + expectQueriesFromContract: 5, + expectOutOfGas: true, + }, + "very deep recursion, hits recursion limit": { + gasLimit: 10_000_000, + msg: Recurse{ + Depth: 100, + Work: 2000, + }, + expectQueriesFromContract: 10, + expectOutOfGas: false, + expectError: "query wasm contract failed", // Error we get from the contract instance doing the failing query, not wasmd + expectedGas: 10*(GasWork2k+GasReturnHashed) - 247, + }, + } + + contractAddr, _, ctx, keeper := initRecurseContract(t) + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + // reset the counter before test + totalWasmQueryCounter = 0 + + // make sure we set a limit before calling + ctx = ctx.WithGasMeter(sdk.NewGasMeter(tc.gasLimit)) + require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed()) + + // prepare the query + recurse := tc.msg + msg := buildRecurseQuery(t, recurse) + + // if we expect out of gas, make sure this panics + if tc.expectOutOfGas { + require.Panics(t, func() { + _, err := keeper.QuerySmart(ctx, contractAddr, msg) + t.Logf("Got error not panic: %#v", err) + }) + assert.Equal(t, tc.expectQueriesFromContract, totalWasmQueryCounter) + return + } + + // otherwise, we expect a successful call + _, err := keeper.QuerySmart(ctx, contractAddr, msg) + if tc.expectError != "" { + require.ErrorContains(t, err, tc.expectError) + } else { + require.NoError(t, err) + } + if types.EnableGasVerification { + assert.Equal(t, tc.expectedGas, ctx.GasMeter().GasConsumed()) + } + assert.Equal(t, tc.expectQueriesFromContract, totalWasmQueryCounter) + }) + } +} diff --git a/x/wasm/keeper/reflect_test.go b/x/wasm/keeper/reflect_test.go new file mode 100644 index 00000000..fa5f3b12 --- /dev/null +++ b/x/wasm/keeper/reflect_test.go @@ -0,0 +1,665 @@ +package keeper + +import ( + "encoding/json" + "os" + "strings" + "testing" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/testdata" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// ReflectInitMsg is {} + +func buildReflectQuery(t *testing.T, query *testdata.ReflectQueryMsg) []byte { + bz, err := json.Marshal(query) + require.NoError(t, err) + return bz +} + +func mustParse(t *testing.T, data []byte, res interface{}) { + err := json.Unmarshal(data, res) + require.NoError(t, err) +} + +const ReflectFeatures = "staking,mask,stargate,cosmwasm_1_1" + +func TestReflectContractSend(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc))) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + _, _, bob := keyPubAddr() + + // upload reflect code + reflectID, _, err := keeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), reflectID) + + // upload hackatom escrow code + escrowCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + escrowID, _, err := keeper.Create(ctx, creator, escrowCode, nil) + require.NoError(t, err) + require.Equal(t, uint64(2), escrowID) + + // creator instantiates a contract and gives it tokens + reflectStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + reflectAddr, _, err := keeper.Instantiate(ctx, reflectID, creator, nil, []byte("{}"), "reflect contract 2", reflectStart) + require.NoError(t, err) + require.NotEmpty(t, reflectAddr) + + // now we set contract as verifier of an escrow + initMsg := HackatomExampleInitMsg{ + Verifier: reflectAddr, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + escrowStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 25000)) + escrowAddr, _, err := keeper.Instantiate(ctx, escrowID, creator, nil, initMsgBz, "escrow contract 2", escrowStart) + require.NoError(t, err) + require.NotEmpty(t, escrowAddr) + + // let's make sure all balances make sense + checkAccount(t, ctx, accKeeper, bankKeeper, creator, sdk.NewCoins(sdk.NewInt64Coin("denom", 35000))) // 100k - 40k - 25k + checkAccount(t, ctx, accKeeper, bankKeeper, reflectAddr, reflectStart) + checkAccount(t, ctx, accKeeper, bankKeeper, escrowAddr, escrowStart) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, nil) + + // now for the trick.... we reflect a message through the reflect to call the escrow + // we also send an additional 14k tokens there. + // this should reduce the reflect balance by 14k (to 26k) + // this 14k is added to the escrow, then the entire balance is sent to bob (total: 39k) + approveMsg := []byte(`{"release":{}}`) + msgs := []wasmvmtypes.CosmosMsg{{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: escrowAddr.String(), + Msg: approveMsg, + Funds: []wasmvmtypes.Coin{{ + Denom: "denom", + Amount: "14000", + }}, + }, + }, + }} + reflectSend := testdata.ReflectHandleMsg{ + Reflect: &testdata.ReflectPayload{ + Msgs: msgs, + }, + } + reflectSendBz, err := json.Marshal(reflectSend) + require.NoError(t, err) + _, err = keeper.Execute(ctx, reflectAddr, creator, reflectSendBz, nil) + require.NoError(t, err) + + // did this work??? + checkAccount(t, ctx, accKeeper, bankKeeper, creator, sdk.NewCoins(sdk.NewInt64Coin("denom", 35000))) // same as before + checkAccount(t, ctx, accKeeper, bankKeeper, reflectAddr, sdk.NewCoins(sdk.NewInt64Coin("denom", 26000))) // 40k - 14k (from send) + checkAccount(t, ctx, accKeeper, bankKeeper, escrowAddr, sdk.Coins{}) // emptied reserved + checkAccount(t, ctx, accKeeper, bankKeeper, bob, sdk.NewCoins(sdk.NewInt64Coin("denom", 39000))) // all escrow of 25k + 14k +} + +func TestReflectCustomMsg(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + bob := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + _, _, fred := keyPubAddr() + + // upload code + codeID, _, err := keeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract and gives it tokens + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + contractAddr, _, err := keeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // set owner to bob + transfer := testdata.ReflectHandleMsg{ + ChangeOwner: &testdata.OwnerPayload{ + Owner: bob, + }, + } + transferBz, err := json.Marshal(transfer) + require.NoError(t, err) + _, err = keeper.Execute(ctx, contractAddr, creator, transferBz, nil) + require.NoError(t, err) + + // check some account values + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, contractStart) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, deposit) + checkAccount(t, ctx, accKeeper, bankKeeper, fred, nil) + + // bob can send contract's tokens to fred (using SendMsg) + msgs := []wasmvmtypes.CosmosMsg{{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: fred.String(), + Amount: []wasmvmtypes.Coin{{ + Denom: "denom", + Amount: "15000", + }}, + }, + }, + }} + reflectSend := testdata.ReflectHandleMsg{ + Reflect: &testdata.ReflectPayload{ + Msgs: msgs, + }, + } + reflectSendBz, err := json.Marshal(reflectSend) + require.NoError(t, err) + _, err = keeper.Execute(ctx, contractAddr, bob, reflectSendBz, nil) + require.NoError(t, err) + + // fred got coins + checkAccount(t, ctx, accKeeper, bankKeeper, fred, sdk.NewCoins(sdk.NewInt64Coin("denom", 15000))) + // contract lost them + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.NewCoins(sdk.NewInt64Coin("denom", 25000))) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, deposit) + + // construct an opaque message + var sdkSendMsg sdk.Msg = &banktypes.MsgSend{ + FromAddress: contractAddr.String(), + ToAddress: fred.String(), + Amount: sdk.NewCoins(sdk.NewInt64Coin("denom", 23000)), + } + opaque, err := toReflectRawMsg(cdc, sdkSendMsg) + require.NoError(t, err) + reflectOpaque := testdata.ReflectHandleMsg{ + Reflect: &testdata.ReflectPayload{ + Msgs: []wasmvmtypes.CosmosMsg{opaque}, + }, + } + reflectOpaqueBz, err := json.Marshal(reflectOpaque) + require.NoError(t, err) + + _, err = keeper.Execute(ctx, contractAddr, bob, reflectOpaqueBz, nil) + require.NoError(t, err) + + // fred got more coins + checkAccount(t, ctx, accKeeper, bankKeeper, fred, sdk.NewCoins(sdk.NewInt64Coin("denom", 38000))) + // contract lost them + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.NewCoins(sdk.NewInt64Coin("denom", 2000))) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, deposit) +} + +func TestMaskReflectCustomQuery(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract and gives it tokens + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // let's perform a normal query of state + ownerQuery := testdata.ReflectQueryMsg{ + Owner: &struct{}{}, + } + ownerQueryBz, err := json.Marshal(ownerQuery) + require.NoError(t, err) + ownerRes, err := keeper.QuerySmart(ctx, contractAddr, ownerQueryBz) + require.NoError(t, err) + var res testdata.OwnerResponse + err = json.Unmarshal(ownerRes, &res) + require.NoError(t, err) + assert.Equal(t, res.Owner, creator.String()) + + // and now making use of the custom querier callbacks + customQuery := testdata.ReflectQueryMsg{ + Capitalized: &testdata.Text{ + Text: "all Caps noW", + }, + } + customQueryBz, err := json.Marshal(customQuery) + require.NoError(t, err) + custom, err := keeper.QuerySmart(ctx, contractAddr, customQueryBz) + require.NoError(t, err) + var resp capitalizedResponse + err = json.Unmarshal(custom, &resp) + require.NoError(t, err) + assert.Equal(t, resp.Text, "ALL CAPS NOW") +} + +func TestReflectStargateQuery(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + keeper := keepers.WasmKeeper + + funds := sdk.NewCoins(sdk.NewInt64Coin("denom", 320000)) + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + expectedBalance := funds.Sub(contractStart) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, funds...) + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract and gives it tokens + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // first, normal query for the bank balance (to make sure our query is proper) + bankQuery := wasmvmtypes.QueryRequest{ + Bank: &wasmvmtypes.BankQuery{ + AllBalances: &wasmvmtypes.AllBalancesQuery{ + Address: creator.String(), + }, + }, + } + simpleQueryBz, err := json.Marshal(testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{Request: &bankQuery}, + }) + require.NoError(t, err) + simpleRes, err := keeper.QuerySmart(ctx, contractAddr, simpleQueryBz) + require.NoError(t, err) + var simpleChain testdata.ChainResponse + mustParse(t, simpleRes, &simpleChain) + var simpleBalance wasmvmtypes.AllBalancesResponse + mustParse(t, simpleChain.Data, &simpleBalance) + require.Equal(t, len(expectedBalance), len(simpleBalance.Amount)) + assert.Equal(t, simpleBalance.Amount[0].Amount, expectedBalance[0].Amount.String()) + assert.Equal(t, simpleBalance.Amount[0].Denom, expectedBalance[0].Denom) +} + +func TestReflectTotalSupplyQuery(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + keeper := keepers.WasmKeeper + // upload code + codeID := StoreReflectContract(t, ctx, keepers).CodeID + // creator instantiates a contract and gives it tokens + creator := RandomAccountAddress(t) + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "testing", nil) + require.NoError(t, err) + + currentStakeSupply := keepers.BankKeeper.GetSupply(ctx, "stake") + require.NotEmpty(t, currentStakeSupply.Amount) // ensure we have real data + specs := map[string]struct { + denom string + expAmount wasmvmtypes.Coin + }{ + "known denom": { + denom: "stake", + expAmount: ConvertSdkCoinToWasmCoin(currentStakeSupply), + }, + "unknown denom": { + denom: "unknown", + expAmount: wasmvmtypes.Coin{Denom: "unknown", Amount: "0"}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // when + queryBz := mustMarshal(t, testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{ + Request: &wasmvmtypes.QueryRequest{ + Bank: &wasmvmtypes.BankQuery{ + Supply: &wasmvmtypes.SupplyQuery{spec.denom}, + }, + }, + }, + }) + simpleRes, err := keeper.QuerySmart(ctx, contractAddr, queryBz) + + // then + require.NoError(t, err) + var rsp testdata.ChainResponse + mustParse(t, simpleRes, &rsp) + var supplyRsp wasmvmtypes.SupplyResponse + mustParse(t, rsp.Data, &supplyRsp) + assert.Equal(t, spec.expAmount, supplyRsp.Amount, spec.expAmount) + }) + } +} + +func TestReflectInvalidStargateQuery(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + keeper := keepers.WasmKeeper + + funds := sdk.NewCoins(sdk.NewInt64Coin("denom", 320000)) + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, funds...) + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract and gives it tokens + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // now, try to build a protobuf query + protoQuery := banktypes.QueryAllBalancesRequest{ + Address: creator.String(), + } + protoQueryBin, err := proto.Marshal(&protoQuery) + protoRequest := wasmvmtypes.QueryRequest{ + Stargate: &wasmvmtypes.StargateQuery{ + Path: "/cosmos.bank.v1beta1.Query/AllBalances", + Data: protoQueryBin, + }, + } + protoQueryBz, err := json.Marshal(testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{Request: &protoRequest}, + }) + require.NoError(t, err) + + // make a query on the chain, should not be whitelisted + _, err = keeper.QuerySmart(ctx, contractAddr, protoQueryBz) + require.Error(t, err) + require.Contains(t, err.Error(), "Unsupported query") + + // now, try to build a protobuf query + protoRequest = wasmvmtypes.QueryRequest{ + Stargate: &wasmvmtypes.StargateQuery{ + Path: "/cosmos.tx.v1beta1.Service/GetTx", + Data: []byte{}, + }, + } + protoQueryBz, err = json.Marshal(testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{Request: &protoRequest}, + }) + require.NoError(t, err) + + // make a query on the chain, should be blacklisted + _, err = keeper.QuerySmart(ctx, contractAddr, protoQueryBz) + require.Error(t, err) + require.Contains(t, err.Error(), "Unsupported query") + + // and another one + protoRequest = wasmvmtypes.QueryRequest{ + Stargate: &wasmvmtypes.StargateQuery{ + Path: "/cosmos.base.tendermint.v1beta1.Service/GetNodeInfo", + Data: []byte{}, + }, + } + protoQueryBz, err = json.Marshal(testdata.ReflectQueryMsg{ + Chain: &testdata.ChainQuery{Request: &protoRequest}, + }) + require.NoError(t, err) + + // make a query on the chain, should be blacklisted + _, err = keeper.QuerySmart(ctx, contractAddr, protoQueryBz) + require.Error(t, err) + require.Contains(t, err.Error(), "Unsupported query") +} + +type reflectState struct { + Owner string `json:"owner"` +} + +func TestMaskReflectWasmQueries(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // upload reflect code + reflectID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), reflectID) + + // creator instantiates a contract and gives it tokens + reflectStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + reflectAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, reflectID, creator, nil, []byte("{}"), "reflect contract 2", reflectStart) + require.NoError(t, err) + require.NotEmpty(t, reflectAddr) + + // for control, let's make some queries directly on the reflect + ownerQuery := buildReflectQuery(t, &testdata.ReflectQueryMsg{Owner: &struct{}{}}) + res, err := keeper.QuerySmart(ctx, reflectAddr, ownerQuery) + require.NoError(t, err) + var ownerRes testdata.OwnerResponse + mustParse(t, res, &ownerRes) + require.Equal(t, ownerRes.Owner, creator.String()) + + // and a raw query: cosmwasm_storage::Singleton uses 2 byte big-endian length-prefixed to store data + configKey := append([]byte{0, 6}, []byte("config")...) + raw := keeper.QueryRaw(ctx, reflectAddr, configKey) + var stateRes reflectState + mustParse(t, raw, &stateRes) + require.Equal(t, stateRes.Owner, creator.String()) + + // now, let's reflect a smart query into the x/wasm handlers and see if we get the same result + reflectOwnerQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Wasm: &wasmvmtypes.WasmQuery{ + Smart: &wasmvmtypes.SmartQuery{ + ContractAddr: reflectAddr.String(), + Msg: ownerQuery, + }, + }}}} + reflectOwnerBin := buildReflectQuery(t, &reflectOwnerQuery) + res, err = keeper.QuerySmart(ctx, reflectAddr, reflectOwnerBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + var reflectRes testdata.ChainResponse + mustParse(t, res, &reflectRes) + var reflectOwnerRes testdata.OwnerResponse + mustParse(t, reflectRes.Data, &reflectOwnerRes) + require.Equal(t, reflectOwnerRes.Owner, creator.String()) + + // and with queryRaw + reflectStateQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Wasm: &wasmvmtypes.WasmQuery{ + Raw: &wasmvmtypes.RawQuery{ + ContractAddr: reflectAddr.String(), + Key: configKey, + }, + }}}} + reflectStateBin := buildReflectQuery(t, &reflectStateQuery) + res, err = keeper.QuerySmart(ctx, reflectAddr, reflectStateBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + var reflectRawRes testdata.ChainResponse + mustParse(t, res, &reflectRawRes) + // now, with the raw data, we can parse it into state + var reflectStateRes reflectState + mustParse(t, reflectRawRes.Data, &reflectStateRes) + require.Equal(t, reflectStateRes.Owner, creator.String()) +} + +func TestWasmRawQueryWithNil(t *testing.T) { + cdc := MakeEncodingConfig(t).Marshaler + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins())) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // upload reflect code + reflectID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), reflectID) + + // creator instantiates a contract and gives it tokens + reflectStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + reflectAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, reflectID, creator, nil, []byte("{}"), "reflect contract 2", reflectStart) + require.NoError(t, err) + require.NotEmpty(t, reflectAddr) + + // control: query directly + missingKey := []byte{0, 1, 2, 3, 4} + raw := keeper.QueryRaw(ctx, reflectAddr, missingKey) + require.Nil(t, raw) + + // and with queryRaw + reflectQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Wasm: &wasmvmtypes.WasmQuery{ + Raw: &wasmvmtypes.RawQuery{ + ContractAddr: reflectAddr.String(), + Key: missingKey, + }, + }}}} + reflectStateBin := buildReflectQuery(t, &reflectQuery) + res, err := keeper.QuerySmart(ctx, reflectAddr, reflectStateBin) + require.NoError(t, err) + + // first we pull out the data from chain response, before parsing the original response + var reflectRawRes testdata.ChainResponse + mustParse(t, res, &reflectRawRes) + // and make sure there is no data + require.Empty(t, reflectRawRes.Data) + // we get an empty byte slice not nil (if anyone care in go-land) + require.Equal(t, []byte{}, reflectRawRes.Data) +} + +func checkAccount(t *testing.T, ctx sdk.Context, accKeeper authkeeper.AccountKeeper, bankKeeper bankkeeper.Keeper, addr sdk.AccAddress, expected sdk.Coins) { + acct := accKeeper.GetAccount(ctx, addr) + if expected == nil { + assert.Nil(t, acct) + } else { + assert.NotNil(t, acct) + if expected.Empty() { + // there is confusion between nil and empty slice... let's just treat them the same + assert.True(t, bankKeeper.GetAllBalances(ctx, acct.GetAddress()).Empty()) + } else { + assert.Equal(t, bankKeeper.GetAllBalances(ctx, acct.GetAddress()), expected) + } + } +} + +/**** Code to support custom messages *****/ + +type reflectCustomMsg struct { + Debug string `json:"debug,omitempty"` + Raw []byte `json:"raw,omitempty"` +} + +// toReflectRawMsg encodes an sdk msg using any type with json encoding. +// Then wraps it as an opaque message +func toReflectRawMsg(cdc codec.Codec, msg sdk.Msg) (wasmvmtypes.CosmosMsg, error) { + any, err := codectypes.NewAnyWithValue(msg) + if err != nil { + return wasmvmtypes.CosmosMsg{}, err + } + rawBz, err := cdc.MarshalJSON(any) + if err != nil { + return wasmvmtypes.CosmosMsg{}, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error()) + } + customMsg, err := json.Marshal(reflectCustomMsg{ + Raw: rawBz, + }) + res := wasmvmtypes.CosmosMsg{ + Custom: customMsg, + } + return res, nil +} + +// reflectEncoders needs to be registered in test setup to handle custom message callbacks +func reflectEncoders(cdc codec.Codec) *MessageEncoders { + return &MessageEncoders{ + Custom: fromReflectRawMsg(cdc), + } +} + +// fromReflectRawMsg decodes msg.Data to an sdk.Msg using proto Any and json encoding. +// this needs to be registered on the Encoders +func fromReflectRawMsg(cdc codec.Codec) CustomEncoder { + return func(_sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error) { + var custom reflectCustomMsg + err := json.Unmarshal(msg, &custom) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + if custom.Raw != nil { + var any codectypes.Any + if err := cdc.UnmarshalJSON(custom.Raw, &any); err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + var msg sdk.Msg + if err := cdc.UnpackAny(&any, &msg); err != nil { + return nil, err + } + return []sdk.Msg{msg}, nil + } + if custom.Debug != "" { + return nil, sdkerrors.Wrapf(types.ErrInvalidMsg, "Custom Debug: %s", custom.Debug) + } + return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown Custom message variant") + } +} + +type reflectCustomQuery struct { + Ping *struct{} `json:"ping,omitempty"` + Capitalized *testdata.Text `json:"capitalized,omitempty"` +} + +// this is from the go code back to the contract (capitalized or ping) +type customQueryResponse struct { + Msg string `json:"msg"` +} + +// these are the return values from contract -> go depending on type of query +type ownerResponse struct { + Owner string `json:"owner"` +} + +type capitalizedResponse struct { + Text string `json:"text"` +} + +type chainResponse struct { + Data []byte `json:"data"` +} + +// reflectPlugins needs to be registered in test setup to handle custom query callbacks +func reflectPlugins() *QueryPlugins { + return &QueryPlugins{ + Custom: performCustomQuery, + } +} + +func performCustomQuery(_ sdk.Context, request json.RawMessage) ([]byte, error) { + var custom reflectCustomQuery + err := json.Unmarshal(request, &custom) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) + } + if custom.Capitalized != nil { + msg := strings.ToUpper(custom.Capitalized.Text) + return json.Marshal(customQueryResponse{Msg: msg}) + } + if custom.Ping != nil { + return json.Marshal(customQueryResponse{Msg: "pong"}) + } + return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown Custom query variant") +} diff --git a/x/wasm/keeper/relay.go b/x/wasm/keeper/relay.go new file mode 100644 index 00000000..16488346 --- /dev/null +++ b/x/wasm/keeper/relay.go @@ -0,0 +1,203 @@ +package keeper + +import ( + "time" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + "github.com/cosmos/cosmos-sdk/telemetry" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var _ types.IBCContractKeeper = (*Keeper)(nil) + +// OnOpenChannel calls the contract to participate in the IBC channel handshake step. +// In the IBC protocol this is either the `Channel Open Init` event on the initiating chain or +// `Channel Open Try` on the counterparty chain. +// Protocol version and channel ordering should be verified for example. +// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management +func (k Keeper) OnOpenChannel( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg wasmvmtypes.IBCChannelOpenMsg, +) (string, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-open-channel") + _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return "", err + } + + env := types.NewEnv(ctx, contractAddr) + querier := k.newQueryHandler(ctx, contractAddr) + + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.IBCChannelOpen(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return "", sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + if res != nil { + return res.Version, nil + } + return "", nil +} + +// OnConnectChannel calls the contract to let it know the IBC channel was established. +// In the IBC protocol this is either the `Channel Open Ack` event on the initiating chain or +// `Channel Open Confirm` on the counterparty chain. +// +// There is an open issue with the [cosmos-sdk](https://github.com/cosmos/cosmos-sdk/issues/8334) +// that the counterparty channelID is empty on the initiating chain +// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management +func (k Keeper) OnConnectChannel( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg wasmvmtypes.IBCChannelConnectMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-connect-channel") + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return err + } + + env := types.NewEnv(ctx, contractAddr) + querier := k.newQueryHandler(ctx, contractAddr) + + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.IBCChannelConnect(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) +} + +// OnCloseChannel calls the contract to let it know the IBC channel is closed. +// Calling modules MAY atomically execute appropriate application logic in conjunction with calling chanCloseConfirm. +// +// Once closed, channels cannot be reopened and identifiers cannot be reused. Identifier reuse is prevented because +// we want to prevent potential replay of previously sent packets +// See https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#channel-lifecycle-management +func (k Keeper) OnCloseChannel( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg wasmvmtypes.IBCChannelCloseMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-close-channel") + + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return err + } + + params := types.NewEnv(ctx, contractAddr) + querier := k.newQueryHandler(ctx, contractAddr) + + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.IBCChannelClose(codeInfo.CodeHash, params, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) +} + +// OnRecvPacket calls the contract to process the incoming IBC packet. The contract fully owns the data processing and +// returns the acknowledgement data for the chain level. This allows custom applications and protocols on top +// of IBC. Although it is recommended to use the standard acknowledgement envelope defined in +// https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope +// +// For more information see: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling +func (k Keeper) OnRecvPacket( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg wasmvmtypes.IBCPacketReceiveMsg, +) ([]byte, error) { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-recv-packet") + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return nil, err + } + + env := types.NewEnv(ctx, contractAddr) + querier := k.newQueryHandler(ctx, contractAddr) + + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.IBCPacketReceive(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + if res.Err != "" { // handle error case as before https://github.com/CosmWasm/wasmvm/commit/c300106fe5c9426a495f8e10821e00a9330c56c6 + return nil, sdkerrors.Wrap(types.ErrExecuteFailed, res.Err) + } + // note submessage reply results can overwrite the `Acknowledgement` data + return k.handleContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res.Ok.Messages, res.Ok.Attributes, res.Ok.Acknowledgement, res.Ok.Events) +} + +// OnAckPacket calls the contract to handle the "acknowledgement" data which can contain success or failure of a packet +// acknowledgement written on the receiving chain for example. This is application level data and fully owned by the +// contract. The use of the standard acknowledgement envelope is recommended: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope +// +// On application errors the contract can revert an operation like returning tokens as in ibc-transfer. +// +// For more information see: https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#packet-flow--handling +func (k Keeper) OnAckPacket( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg wasmvmtypes.IBCPacketAckMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-ack-packet") + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return err + } + + env := types.NewEnv(ctx, contractAddr) + querier := k.newQueryHandler(ctx, contractAddr) + + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.IBCPacketAck(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) +} + +// OnTimeoutPacket calls the contract to let it know the packet was never received on the destination chain within +// the timeout boundaries. +// The contract should handle this on the application level and undo the original operation +func (k Keeper) OnTimeoutPacket( + ctx sdk.Context, + contractAddr sdk.AccAddress, + msg wasmvmtypes.IBCPacketTimeoutMsg, +) error { + defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "ibc-timeout-packet") + + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + if err != nil { + return err + } + + env := types.NewEnv(ctx, contractAddr) + querier := k.newQueryHandler(ctx, contractAddr) + + gas := k.runtimeGasForContract(ctx) + res, gasUsed, execErr := k.wasmVM.IBCPacketTimeout(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas, costJSONDeserialization) + k.consumeRuntimeGas(ctx, gasUsed) + if execErr != nil { + return sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error()) + } + + return k.handleIBCBasicContractResponse(ctx, contractAddr, contractInfo.IBCPortID, res) +} + +func (k Keeper) handleIBCBasicContractResponse(ctx sdk.Context, addr sdk.AccAddress, id string, res *wasmvmtypes.IBCBasicResponse) error { + _, err := k.handleContractResponse(ctx, addr, id, res.Messages, res.Attributes, nil, res.Events) + return err +} diff --git a/x/wasm/keeper/relay_test.go b/x/wasm/keeper/relay_test.go new file mode 100644 index 00000000..6de4b745 --- /dev/null +++ b/x/wasm/keeper/relay_test.go @@ -0,0 +1,703 @@ +package keeper + +import ( + "encoding/json" + "errors" + "math" + "testing" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +func TestOnOpenChannel(t *testing.T) { + var m wasmtesting.MockWasmer + wasmtesting.MakeIBCInstantiable(&m) + messenger := &wasmtesting.MockMessageHandler{} + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithMessageHandler(messenger)) + example := SeedNewContractInstance(t, parentCtx, keepers, &m) + const myContractGas = 40 + + specs := map[string]struct { + contractAddr sdk.AccAddress + contractGas sdk.Gas + contractErr error + expGas uint64 + expErr bool + }{ + "consume contract gas": { + contractAddr: example.Contract, + contractGas: myContractGas, + expGas: myContractGas, + }, + "consume max gas": { + contractAddr: example.Contract, + contractGas: math.MaxUint64 / DefaultGasMultiplier, + expGas: math.MaxUint64 / DefaultGasMultiplier, + }, + "consume gas on error": { + contractAddr: example.Contract, + contractGas: myContractGas, + contractErr: errors.New("test, ignore"), + expErr: true, + }, + "unknown contract address": { + contractAddr: RandomAccountAddress(t), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} + myMsg := wasmvmtypes.IBCChannelOpenMsg{OpenTry: &wasmvmtypes.IBCOpenTry{Channel: myChannel, CounterpartyVersion: "foo"}} + m.IBCChannelOpenFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelOpenMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBC3ChannelOpenResponse, uint64, error) { + assert.Equal(t, myMsg, msg) + return &wasmvmtypes.IBC3ChannelOpenResponse{}, spec.contractGas * DefaultGasMultiplier, spec.contractErr + } + + ctx, _ := parentCtx.CacheContext() + before := ctx.GasMeter().GasConsumed() + + // when + msg := wasmvmtypes.IBCChannelOpenMsg{ + OpenTry: &wasmvmtypes.IBCOpenTry{ + Channel: myChannel, + CounterpartyVersion: "foo", + }, + } + _, err := keepers.WasmKeeper.OnOpenChannel(ctx, spec.contractAddr, msg) + + // then + if spec.expErr { + require.Error(t, err) + return + } + require.NoError(t, err) + // verify gas consumed + const storageCosts = sdk.Gas(2903) + assert.Equal(t, spec.expGas, ctx.GasMeter().GasConsumed()-before-storageCosts) + }) + } +} + +func TestOnConnectChannel(t *testing.T) { + var m wasmtesting.MockWasmer + wasmtesting.MakeIBCInstantiable(&m) + messenger := &wasmtesting.MockMessageHandler{} + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithMessageHandler(messenger)) + example := SeedNewContractInstance(t, parentCtx, keepers, &m) + const myContractGas = 40 + + specs := map[string]struct { + contractAddr sdk.AccAddress + contractResp *wasmvmtypes.IBCBasicResponse + contractErr error + overwriteMessenger *wasmtesting.MockMessageHandler + expContractGas sdk.Gas + expErr bool + expEventTypes []string + }{ + "consume contract gas": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{}, + }, + "consume gas on error, ignore events + messages": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + contractErr: errors.New("test, ignore"), + expErr: true, + }, + "dispatch contract messages on success": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + }, + }, + "emit contract events on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "messenger errors returned, events stored": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + overwriteMessenger: wasmtesting.NewErroringMessageHandler(), + expErr: true, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "unknown contract address": { + contractAddr: RandomAccountAddress(t), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} + myMsg := wasmvmtypes.IBCChannelConnectMsg{OpenConfirm: &wasmvmtypes.IBCOpenConfirm{Channel: myChannel}} + m.IBCChannelConnectFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelConnectMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + assert.Equal(t, msg, myMsg) + return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr + } + + ctx, _ := parentCtx.CacheContext() + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + before := ctx.GasMeter().GasConsumed() + msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler() + *messenger = *msger + if spec.overwriteMessenger != nil { + *messenger = *spec.overwriteMessenger + } + + // when + msg := wasmvmtypes.IBCChannelConnectMsg{ + OpenConfirm: &wasmvmtypes.IBCOpenConfirm{ + Channel: myChannel, + }, + } + err := keepers.WasmKeeper.OnConnectChannel(ctx, spec.contractAddr, msg) + + // then + if spec.expErr { + require.Error(t, err) + assert.Empty(t, capturedMsgs) // no messages captured on error + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + return + } + require.NoError(t, err) + // verify gas consumed + const storageCosts = sdk.Gas(2903) + assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) + // verify msgs dispatched + require.Len(t, *capturedMsgs, len(spec.contractResp.Messages)) + for i, m := range spec.contractResp.Messages { + assert.Equal(t, (*capturedMsgs)[i], m.Msg) + } + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + }) + } +} + +func TestOnCloseChannel(t *testing.T) { + var m wasmtesting.MockWasmer + wasmtesting.MakeIBCInstantiable(&m) + messenger := &wasmtesting.MockMessageHandler{} + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithMessageHandler(messenger)) + example := SeedNewContractInstance(t, parentCtx, keepers, &m) + const myContractGas = 40 + + specs := map[string]struct { + contractAddr sdk.AccAddress + contractResp *wasmvmtypes.IBCBasicResponse + contractErr error + overwriteMessenger *wasmtesting.MockMessageHandler + expContractGas sdk.Gas + expErr bool + expEventTypes []string + }{ + "consume contract gas": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{}, + }, + "consume gas on error, ignore events + messages": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + contractErr: errors.New("test, ignore"), + expErr: true, + }, + "dispatch contract messages on success": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + }, + }, + "emit contract events on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "messenger errors returned, events stored": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + overwriteMessenger: wasmtesting.NewErroringMessageHandler(), + expErr: true, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "unknown contract address": { + contractAddr: RandomAccountAddress(t), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myChannel := wasmvmtypes.IBCChannel{Version: "my test channel"} + myMsg := wasmvmtypes.IBCChannelCloseMsg{CloseInit: &wasmvmtypes.IBCCloseInit{Channel: myChannel}} + m.IBCChannelCloseFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCChannelCloseMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + assert.Equal(t, msg, myMsg) + return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr + } + + ctx, _ := parentCtx.CacheContext() + before := ctx.GasMeter().GasConsumed() + msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler() + *messenger = *msger + + if spec.overwriteMessenger != nil { + *messenger = *spec.overwriteMessenger + } + + // when + msg := wasmvmtypes.IBCChannelCloseMsg{ + CloseInit: &wasmvmtypes.IBCCloseInit{ + Channel: myChannel, + }, + } + err := keepers.WasmKeeper.OnCloseChannel(ctx, spec.contractAddr, msg) + + // then + if spec.expErr { + require.Error(t, err) + assert.Empty(t, capturedMsgs) // no messages captured on error + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + return + } + require.NoError(t, err) + // verify gas consumed + const storageCosts = sdk.Gas(2903) + assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) + // verify msgs dispatched + require.Len(t, *capturedMsgs, len(spec.contractResp.Messages)) + for i, m := range spec.contractResp.Messages { + assert.Equal(t, (*capturedMsgs)[i], m.Msg) + } + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + }) + } +} + +func TestOnRecvPacket(t *testing.T) { + var m wasmtesting.MockWasmer + wasmtesting.MakeIBCInstantiable(&m) + messenger := &wasmtesting.MockMessageHandler{} + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithMessageHandler(messenger)) + example := SeedNewContractInstance(t, parentCtx, keepers, &m) + const myContractGas = 40 + const storageCosts = sdk.Gas(2903) + + specs := map[string]struct { + contractAddr sdk.AccAddress + contractResp *wasmvmtypes.IBCReceiveResponse + contractErr error + overwriteMessenger *wasmtesting.MockMessageHandler + mockReplyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) + expContractGas sdk.Gas + expAck []byte + expErr bool + expEventTypes []string + }{ + "consume contract gas": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + }, + expAck: []byte("myAck"), + }, + "can return empty ack": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCReceiveResponse{}, + }, + "consume gas on error, ignore events + messages": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + contractErr: errors.New("test, ignore"), + expErr: true, + }, + "dispatch contract messages on success": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + }, + expAck: []byte("myAck"), + }, + "emit contract attributes on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + expEventTypes: []string{types.WasmModuleEventType}, + expAck: []byte("myAck"), + }, + "emit contract events on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 46, // charge or custom event as well + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + Events: []wasmvmtypes.Event{{ + Type: "custom", + Attributes: []wasmvmtypes.EventAttribute{{ + Key: "message", + Value: "to rudi", + }}, + }}, + }, + expEventTypes: []string{types.WasmModuleEventType, "wasm-custom"}, + expAck: []byte("myAck"), + }, + "messenger errors returned, events stored": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + overwriteMessenger: wasmtesting.NewErroringMessageHandler(), + expErr: true, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "submessage reply can overwrite ack data": { + contractAddr: example.Contract, + expContractGas: myContractGas + storageCosts, + contractResp: &wasmvmtypes.IBCReceiveResponse{ + Acknowledgement: []byte("myAck"), + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyAlways, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, + }, + mockReplyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + return &wasmvmtypes.Response{Data: []byte("myBetterAck")}, 0, nil + }, + expAck: []byte("myBetterAck"), + expEventTypes: []string{types.EventTypeReply}, + }, + "unknown contract address": { + contractAddr: RandomAccountAddress(t), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myPacket := wasmvmtypes.IBCPacket{Data: []byte("my data")} + + m.IBCPacketReceiveFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketReceiveMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCReceiveResult, uint64, error) { + assert.Equal(t, myPacket, msg.Packet) + return &wasmvmtypes.IBCReceiveResult{Ok: spec.contractResp}, myContractGas * DefaultGasMultiplier, spec.contractErr + } + if spec.mockReplyFn != nil { + m.ReplyFn = spec.mockReplyFn + h, ok := keepers.WasmKeeper.wasmVMResponseHandler.(*DefaultWasmVMContractResponseHandler) + require.True(t, ok) + h.md = NewMessageDispatcher(messenger, keepers.WasmKeeper) + } + + ctx, _ := parentCtx.CacheContext() + before := ctx.GasMeter().GasConsumed() + + msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler() + *messenger = *msger + + if spec.overwriteMessenger != nil { + *messenger = *spec.overwriteMessenger + } + + // when + msg := wasmvmtypes.IBCPacketReceiveMsg{Packet: myPacket} + gotAck, err := keepers.WasmKeeper.OnRecvPacket(ctx, spec.contractAddr, msg) + + // then + if spec.expErr { + require.Error(t, err) + assert.Empty(t, capturedMsgs) // no messages captured on error + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + return + } + require.NoError(t, err) + require.Equal(t, spec.expAck, gotAck) + + // verify gas consumed + const storageCosts = sdk.Gas(2903) + assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) + // verify msgs dispatched + require.Len(t, *capturedMsgs, len(spec.contractResp.Messages)) + for i, m := range spec.contractResp.Messages { + assert.Equal(t, (*capturedMsgs)[i], m.Msg) + } + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + }) + } +} + +func TestOnAckPacket(t *testing.T) { + var m wasmtesting.MockWasmer + wasmtesting.MakeIBCInstantiable(&m) + messenger := &wasmtesting.MockMessageHandler{} + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithMessageHandler(messenger)) + example := SeedNewContractInstance(t, parentCtx, keepers, &m) + const myContractGas = 40 + + specs := map[string]struct { + contractAddr sdk.AccAddress + contractResp *wasmvmtypes.IBCBasicResponse + contractErr error + overwriteMessenger *wasmtesting.MockMessageHandler + expContractGas sdk.Gas + expErr bool + expEventTypes []string + }{ + "consume contract gas": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{}, + }, + "consume gas on error, ignore events + messages": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + contractErr: errors.New("test, ignore"), + expErr: true, + }, + "dispatch contract messages on success": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + }, + }, + "emit contract events on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "messenger errors returned, events stored": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + overwriteMessenger: wasmtesting.NewErroringMessageHandler(), + expErr: true, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "unknown contract address": { + contractAddr: RandomAccountAddress(t), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myAck := wasmvmtypes.IBCPacketAckMsg{Acknowledgement: wasmvmtypes.IBCAcknowledgement{Data: []byte("myAck")}} + m.IBCPacketAckFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketAckMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + assert.Equal(t, myAck, msg) + return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr + } + + ctx, _ := parentCtx.CacheContext() + before := ctx.GasMeter().GasConsumed() + msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler() + *messenger = *msger + + if spec.overwriteMessenger != nil { + *messenger = *spec.overwriteMessenger + } + + // when + err := keepers.WasmKeeper.OnAckPacket(ctx, spec.contractAddr, myAck) + + // then + + if spec.expErr { + require.Error(t, err) + assert.Empty(t, capturedMsgs) // no messages captured on error + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + return + } + require.NoError(t, err) + // verify gas consumed + const storageCosts = sdk.Gas(2903) + assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) + // verify msgs dispatched + require.Len(t, *capturedMsgs, len(spec.contractResp.Messages)) + for i, m := range spec.contractResp.Messages { + assert.Equal(t, (*capturedMsgs)[i], m.Msg) + } + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + }) + } +} + +func TestOnTimeoutPacket(t *testing.T) { + var m wasmtesting.MockWasmer + wasmtesting.MakeIBCInstantiable(&m) + messenger := &wasmtesting.MockMessageHandler{} + parentCtx, keepers := CreateTestInput(t, false, AvailableCapabilities, WithMessageHandler(messenger)) + example := SeedNewContractInstance(t, parentCtx, keepers, &m) + const myContractGas = 40 + + specs := map[string]struct { + contractAddr sdk.AccAddress + contractResp *wasmvmtypes.IBCBasicResponse + contractErr error + overwriteMessenger *wasmtesting.MockMessageHandler + expContractGas sdk.Gas + expErr bool + expEventTypes []string + }{ + "consume contract gas": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{}, + }, + "consume gas on error, ignore events + messages": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + contractErr: errors.New("test, ignore"), + expErr: true, + }, + "dispatch contract messages on success": { + contractAddr: example.Contract, + expContractGas: myContractGas, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + }, + }, + "emit contract attributes on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "emit contract events on success": { + contractAddr: example.Contract, + expContractGas: myContractGas + 46, // cost for custom events + contractResp: &wasmvmtypes.IBCBasicResponse{ + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + Events: []wasmvmtypes.Event{{ + Type: "custom", + Attributes: []wasmvmtypes.EventAttribute{{ + Key: "message", + Value: "to rudi", + }}, + }}, + }, + expEventTypes: []string{types.WasmModuleEventType, "wasm-custom"}, + }, + "messenger errors returned, events stored before": { + contractAddr: example.Contract, + expContractGas: myContractGas + 10, + contractResp: &wasmvmtypes.IBCBasicResponse{ + Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}}, + Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}}, + }, + overwriteMessenger: wasmtesting.NewErroringMessageHandler(), + expErr: true, + expEventTypes: []string{types.WasmModuleEventType}, + }, + "unknown contract address": { + contractAddr: RandomAccountAddress(t), + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + myPacket := wasmvmtypes.IBCPacket{Data: []byte("my test packet")} + m.IBCPacketTimeoutFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, msg wasmvmtypes.IBCPacketTimeoutMsg, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.IBCBasicResponse, uint64, error) { + assert.Equal(t, myPacket, msg.Packet) + return spec.contractResp, myContractGas * DefaultGasMultiplier, spec.contractErr + } + + ctx, _ := parentCtx.CacheContext() + before := ctx.GasMeter().GasConsumed() + msger, capturedMsgs := wasmtesting.NewCapturingMessageHandler() + *messenger = *msger + + if spec.overwriteMessenger != nil { + *messenger = *spec.overwriteMessenger + } + + // when + msg := wasmvmtypes.IBCPacketTimeoutMsg{Packet: myPacket} + err := keepers.WasmKeeper.OnTimeoutPacket(ctx, spec.contractAddr, msg) + + // then + if spec.expErr { + require.Error(t, err) + assert.Empty(t, capturedMsgs) // no messages captured on error + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + return + } + require.NoError(t, err) + // verify gas consumed + const storageCosts = sdk.Gas(2903) + assert.Equal(t, spec.expContractGas, ctx.GasMeter().GasConsumed()-before-storageCosts) + // verify msgs dispatched + require.Len(t, *capturedMsgs, len(spec.contractResp.Messages)) + for i, m := range spec.contractResp.Messages { + assert.Equal(t, (*capturedMsgs)[i], m.Msg) + } + assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events())) + }) + } +} + +func stripTypes(events sdk.Events) []string { + var r []string + for _, e := range events { + r = append(r, e.Type) + } + return r +} diff --git a/x/wasm/keeper/snapshotter.go b/x/wasm/keeper/snapshotter.go new file mode 100644 index 00000000..d51b0570 --- /dev/null +++ b/x/wasm/keeper/snapshotter.go @@ -0,0 +1,156 @@ +package keeper + +import ( + "encoding/hex" + "io" + + snapshot "github.com/cosmos/cosmos-sdk/snapshots/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + protoio "github.com/gogo/protobuf/io" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cerc-io/laconicd/x/wasm/ioutils" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var _ snapshot.ExtensionSnapshotter = &WasmSnapshotter{} + +// SnapshotFormat format 1 is just gzipped wasm byte code for each item payload. No protobuf envelope, no metadata. +const SnapshotFormat = 1 + +type WasmSnapshotter struct { + wasm *Keeper + cms sdk.MultiStore +} + +func NewWasmSnapshotter(cms sdk.MultiStore, wasm *Keeper) *WasmSnapshotter { + return &WasmSnapshotter{ + wasm: wasm, + cms: cms, + } +} + +func (ws *WasmSnapshotter) SnapshotName() string { + return types.ModuleName +} + +func (ws *WasmSnapshotter) SnapshotFormat() uint32 { + return SnapshotFormat +} + +func (ws *WasmSnapshotter) SupportedFormats() []uint32 { + // If we support older formats, add them here and handle them in Restore + return []uint32{SnapshotFormat} +} + +func (ws *WasmSnapshotter) Snapshot(height uint64, protoWriter protoio.Writer) error { + cacheMS, err := ws.cms.CacheMultiStoreWithVersion(int64(height)) + if err != nil { + return err + } + + ctx := sdk.NewContext(cacheMS, tmproto.Header{}, false, log.NewNopLogger()) + seenBefore := make(map[string]bool) + var rerr error + + ws.wasm.IterateCodeInfos(ctx, func(id uint64, info types.CodeInfo) bool { + // Many code ids may point to the same code hash... only sync it once + hexHash := hex.EncodeToString(info.CodeHash) + // if seenBefore, just skip this one and move to the next + if seenBefore[hexHash] { + return false + } + seenBefore[hexHash] = true + + // load code and abort on error + wasmBytes, err := ws.wasm.GetByteCode(ctx, id) + if err != nil { + rerr = err + return true + } + + compressedWasm, err := ioutils.GzipIt(wasmBytes) + if err != nil { + rerr = err + return true + } + + err = snapshot.WriteExtensionItem(protoWriter, compressedWasm) + if err != nil { + rerr = err + return true + } + + return false + }) + + return rerr +} + +func (ws *WasmSnapshotter) Restore( + height uint64, format uint32, protoReader protoio.Reader, +) (snapshot.SnapshotItem, error) { + if format == SnapshotFormat { + return ws.processAllItems(height, protoReader, restoreV1, finalizeV1) + } + return snapshot.SnapshotItem{}, snapshot.ErrUnknownFormat +} + +func restoreV1(ctx sdk.Context, k *Keeper, compressedCode []byte) error { + if !ioutils.IsGzip(compressedCode) { + return types.ErrInvalid.Wrap("not a gzip") + } + wasmCode, err := ioutils.Uncompress(compressedCode, uint64(types.MaxWasmSize)) + if err != nil { + return sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + + // FIXME: check which codeIDs the checksum matches?? + _, err = k.wasmVM.Create(wasmCode) + if err != nil { + return sdkerrors.Wrap(types.ErrCreateFailed, err.Error()) + } + return nil +} + +func finalizeV1(ctx sdk.Context, k *Keeper) error { + // FIXME: ensure all codes have been uploaded? + return k.InitializePinnedCodes(ctx) +} + +func (ws *WasmSnapshotter) processAllItems( + height uint64, + protoReader protoio.Reader, + cb func(sdk.Context, *Keeper, []byte) error, + finalize func(sdk.Context, *Keeper) error, +) (snapshot.SnapshotItem, error) { + ctx := sdk.NewContext(ws.cms, tmproto.Header{Height: int64(height)}, false, log.NewNopLogger()) + + // keep the last item here... if we break, it will either be empty (if we hit io.EOF) + // or contain the last item (if we hit payload == nil) + var item snapshot.SnapshotItem + for { + item = snapshot.SnapshotItem{} + err := protoReader.ReadMsg(&item) + if err == io.EOF { + break + } else if err != nil { + return snapshot.SnapshotItem{}, sdkerrors.Wrap(err, "invalid protobuf message") + } + + // if it is not another ExtensionPayload message, then it is not for us. + // we should return it an let the manager handle this one + payload := item.GetExtensionPayload() + if payload == nil { + break + } + + if err := cb(ctx, ws.wasm, payload.Payload); err != nil { + return snapshot.SnapshotItem{}, sdkerrors.Wrap(err, "processing snapshot item") + } + } + + return item, finalize(ctx, ws.wasm) +} diff --git a/x/wasm/keeper/snapshotter_integration_test.go b/x/wasm/keeper/snapshotter_integration_test.go new file mode 100644 index 00000000..feb0b4ec --- /dev/null +++ b/x/wasm/keeper/snapshotter_integration_test.go @@ -0,0 +1,124 @@ +package keeper_test + +import ( + "crypto/sha256" + "os" + "testing" + "time" + + "github.com/cerc-io/laconicd/x/wasm/types" + + "github.com/stretchr/testify/assert" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + 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/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cerc-io/laconicd/app" + "github.com/cerc-io/laconicd/x/wasm/keeper" +) + +func TestSnapshotter(t *testing.T) { + specs := map[string]struct { + wasmFiles []string + }{ + "single contract": { + wasmFiles: []string{"./testdata/reflect.wasm"}, + }, + "multiple contract": { + wasmFiles: []string{"./testdata/reflect.wasm", "./testdata/burner.wasm", "./testdata/reflect.wasm"}, + }, + "duplicate contracts": { + wasmFiles: []string{"./testdata/reflect.wasm", "./testdata/reflect.wasm"}, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + // setup source app + srcWasmApp, genesisAddr := newWasmExampleApp(t) + + // store wasm codes on chain + ctx := srcWasmApp.NewUncachedContext(false, tmproto.Header{ + ChainID: "foo", + Height: srcWasmApp.LastBlockHeight() + 1, + Time: time.Now(), + }) + wasmKeeper := app.NewTestSupport(t, srcWasmApp).WasmKeeper() + contractKeeper := keeper.NewDefaultPermissionKeeper(&wasmKeeper) + + srcCodeIDToChecksum := make(map[uint64][]byte, len(spec.wasmFiles)) + for i, v := range spec.wasmFiles { + wasmCode, err := os.ReadFile(v) + require.NoError(t, err) + codeID, checksum, err := contractKeeper.Create(ctx, genesisAddr, wasmCode, nil) + require.NoError(t, err) + require.Equal(t, uint64(i+1), codeID) + srcCodeIDToChecksum[codeID] = checksum + } + // create snapshot + srcWasmApp.Commit() + snapshotHeight := uint64(srcWasmApp.LastBlockHeight()) + snapshot, err := srcWasmApp.SnapshotManager().Create(snapshotHeight) + require.NoError(t, err) + assert.NotNil(t, snapshot) + + // when snapshot imported into dest app instance + destWasmApp := app.SetupWithEmptyStore(t) + require.NoError(t, destWasmApp.SnapshotManager().Restore(*snapshot)) + for i := uint32(0); i < snapshot.Chunks; i++ { + chunkBz, err := srcWasmApp.SnapshotManager().LoadChunk(snapshot.Height, snapshot.Format, i) + require.NoError(t, err) + end, err := destWasmApp.SnapshotManager().RestoreChunk(chunkBz) + require.NoError(t, err) + if end { + break + } + } + + // then all wasm contracts are imported + wasmKeeper = app.NewTestSupport(t, destWasmApp).WasmKeeper() + ctx = destWasmApp.NewUncachedContext(false, tmproto.Header{ + ChainID: "foo", + Height: destWasmApp.LastBlockHeight() + 1, + Time: time.Now(), + }) + + destCodeIDToChecksum := make(map[uint64][]byte, len(spec.wasmFiles)) + wasmKeeper.IterateCodeInfos(ctx, func(id uint64, info types.CodeInfo) bool { + bz, err := wasmKeeper.GetByteCode(ctx, id) + require.NoError(t, err) + hash := sha256.Sum256(bz) + destCodeIDToChecksum[id] = hash[:] + assert.Equal(t, hash[:], info.CodeHash) + return false + }) + assert.Equal(t, srcCodeIDToChecksum, destCodeIDToChecksum) + }) + } +} + +func newWasmExampleApp(t *testing.T) (*app.WasmApp, sdk.AccAddress) { + senderPrivKey := ed25519.GenPrivKey() + pubKey, err := cryptocodec.ToTmPubKeyInterface(senderPrivKey.PubKey()) + require.NoError(t, err) + + senderAddr := senderPrivKey.PubKey().Address().Bytes() + acc := authtypes.NewBaseAccount(senderAddr, senderPrivKey.PubKey(), 0, 0) + amount, ok := sdk.NewIntFromString("10000000000000000000") + require.True(t, ok) + + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, amount)), + } + validator := tmtypes.NewValidator(pubKey, 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + wasmApp := app.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, "testing", nil, balance) + + return wasmApp, senderAddr +} diff --git a/x/wasm/keeper/staking_test.go b/x/wasm/keeper/staking_test.go new file mode 100644 index 00000000..679b8823 --- /dev/null +++ b/x/wasm/keeper/staking_test.go @@ -0,0 +1,748 @@ +package keeper + +import ( + "encoding/json" + "os" + "testing" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "github.com/cosmos/cosmos-sdk/x/staking/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/testdata" + wasmtypes "github.com/cerc-io/laconicd/x/wasm/types" +) + +type StakingInitMsg struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint8 `json:"decimals"` + Validator sdk.ValAddress `json:"validator"` + ExitTax sdk.Dec `json:"exit_tax"` + // MinWithdrawal is uint128 encoded as a string (use sdk.Int?) + MinWithdrawl string `json:"min_withdrawal"` +} + +// StakingHandleMsg is used to encode handle messages +type StakingHandleMsg struct { + Transfer *transferPayload `json:"transfer,omitempty"` + Bond *struct{} `json:"bond,omitempty"` + Unbond *unbondPayload `json:"unbond,omitempty"` + Claim *struct{} `json:"claim,omitempty"` + Reinvest *struct{} `json:"reinvest,omitempty"` + Change *testdata.OwnerPayload `json:"change_owner,omitempty"` +} + +type transferPayload struct { + Recipient sdk.Address `json:"recipient"` + // uint128 encoded as string + Amount string `json:"amount"` +} + +type unbondPayload struct { + // uint128 encoded as string + Amount string `json:"amount"` +} + +// StakingQueryMsg is used to encode query messages +type StakingQueryMsg struct { + Balance *addressQuery `json:"balance,omitempty"` + Claims *addressQuery `json:"claims,omitempty"` + TokenInfo *struct{} `json:"token_info,omitempty"` + Investment *struct{} `json:"investment,omitempty"` +} + +type addressQuery struct { + Address sdk.AccAddress `json:"address"` +} + +type BalanceResponse struct { + Balance string `json:"balance,omitempty"` +} + +type ClaimsResponse struct { + Claims string `json:"claims,omitempty"` +} + +type TokenInfoResponse struct { + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals uint8 `json:"decimals"` +} + +type InvestmentResponse struct { + TokenSupply string `json:"token_supply"` + StakedTokens sdk.Coin `json:"staked_tokens"` + NominalValue sdk.Dec `json:"nominal_value"` + Owner sdk.AccAddress `json:"owner"` + Validator sdk.ValAddress `json:"validator"` + ExitTax sdk.Dec `json:"exit_tax"` + // MinWithdrawl is uint128 encoded as a string (use sdk.Int?) + MinWithdrawl string `json:"min_withdrawal"` +} + +func TestInitializeStaking(t *testing.T) { + ctx, k := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, stakingKeeper, keeper, bankKeeper := k.AccountKeeper, k.StakingKeeper, k.ContractKeeper, k.BankKeeper + + valAddr := addValidator(t, ctx, stakingKeeper, k.Faucet, sdk.NewInt64Coin("stake", 1234567)) + ctx = nextBlock(ctx, stakingKeeper) + v, found := stakingKeeper.GetValidator(ctx, valAddr) + assert.True(t, found) + assert.Equal(t, v.GetDelegatorShares(), sdk.NewDec(1234567)) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000), sdk.NewInt64Coin("stake", 500000)) + creator := k.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // upload staking derivates code + stakingCode, err := os.ReadFile("./testdata/staking.wasm") + require.NoError(t, err) + stakingID, _, err := keeper.Create(ctx, creator, stakingCode, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), stakingID) + + // register to a valid address + initMsg := StakingInitMsg{ + Name: "Staking Derivatives", + Symbol: "DRV", + Decimals: 0, + Validator: valAddr, + ExitTax: sdk.MustNewDecFromStr("0.10"), + MinWithdrawl: "100", + } + initBz, err := json.Marshal(&initMsg) + require.NoError(t, err) + + stakingAddr, _, err := k.ContractKeeper.Instantiate(ctx, stakingID, creator, nil, initBz, "staking derivates - DRV", nil) + require.NoError(t, err) + require.NotEmpty(t, stakingAddr) + + // nothing spent here + checkAccount(t, ctx, accKeeper, bankKeeper, creator, deposit) + + // try to register with a validator not on the list and it fails + _, _, bob := keyPubAddr() + badInitMsg := StakingInitMsg{ + Name: "Missing Validator", + Symbol: "MISS", + Decimals: 0, + Validator: sdk.ValAddress(bob), + ExitTax: sdk.MustNewDecFromStr("0.10"), + MinWithdrawl: "100", + } + badBz, err := json.Marshal(&badInitMsg) + require.NoError(t, err) + + _, _, err = k.ContractKeeper.Instantiate(ctx, stakingID, creator, nil, badBz, "missing validator", nil) + require.Error(t, err) + + // no changes to bonding shares + val, _ := stakingKeeper.GetValidator(ctx, valAddr) + assert.Equal(t, val.GetDelegatorShares(), sdk.NewDec(1234567)) +} + +type initInfo struct { + valAddr sdk.ValAddress + creator sdk.AccAddress + contractAddr sdk.AccAddress + + ctx sdk.Context + accKeeper authkeeper.AccountKeeper + stakingKeeper stakingkeeper.Keeper + distKeeper distributionkeeper.Keeper + wasmKeeper Keeper + contractKeeper wasmtypes.ContractOpsKeeper + bankKeeper bankkeeper.Keeper + faucet *TestFaucet +} + +func initializeStaking(t *testing.T) initInfo { + ctx, k := CreateTestInput(t, false, AvailableCapabilities) + accKeeper, stakingKeeper, keeper, bankKeeper := k.AccountKeeper, k.StakingKeeper, k.WasmKeeper, k.BankKeeper + + valAddr := addValidator(t, ctx, stakingKeeper, k.Faucet, sdk.NewInt64Coin("stake", 1000000)) + ctx = nextBlock(ctx, stakingKeeper) + + // set some baseline - this seems to be needed + k.DistKeeper.SetValidatorHistoricalRewards(ctx, valAddr, 0, distributiontypes.ValidatorHistoricalRewards{ + CumulativeRewardRatio: sdk.DecCoins{}, + ReferenceCount: 1, + }) + + v, found := stakingKeeper.GetValidator(ctx, valAddr) + assert.True(t, found) + assert.Equal(t, v.GetDelegatorShares(), sdk.NewDec(1000000)) + assert.Equal(t, v.Status, stakingtypes.Bonded) + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000), sdk.NewInt64Coin("stake", 500000)) + creator := k.Faucet.NewFundedRandomAccount(ctx, deposit...) + + // upload staking derivates code + stakingCode, err := os.ReadFile("./testdata/staking.wasm") + require.NoError(t, err) + stakingID, _, err := k.ContractKeeper.Create(ctx, creator, stakingCode, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), stakingID) + + // register to a valid address + initMsg := StakingInitMsg{ + Name: "Staking Derivatives", + Symbol: "DRV", + Decimals: 0, + Validator: valAddr, + ExitTax: sdk.MustNewDecFromStr("0.10"), + MinWithdrawl: "100", + } + initBz, err := json.Marshal(&initMsg) + require.NoError(t, err) + + stakingAddr, _, err := k.ContractKeeper.Instantiate(ctx, stakingID, creator, nil, initBz, "staking derivates - DRV", nil) + require.NoError(t, err) + require.NotEmpty(t, stakingAddr) + + return initInfo{ + valAddr: valAddr, + creator: creator, + contractAddr: stakingAddr, + ctx: ctx, + accKeeper: accKeeper, + stakingKeeper: stakingKeeper, + wasmKeeper: *keeper, + distKeeper: k.DistKeeper, + bankKeeper: bankKeeper, + contractKeeper: k.ContractKeeper, + faucet: k.Faucet, + } +} + +func TestBonding(t *testing.T) { + initInfo := initializeStaking(t) + ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr + keeper, stakingKeeper, accKeeper, bankKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper, initInfo.bankKeeper + + // initial checks of bonding state + val, found := stakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + initPower := val.GetDelegatorShares() + + // bob has 160k, putting 80k into the contract + full := sdk.NewCoins(sdk.NewInt64Coin("stake", 160000)) + funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 80000)) + bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...) + + // check contract state before + assertBalance(t, ctx, keeper, contractAddr, bob, "0") + assertClaims(t, ctx, keeper, contractAddr, bob, "0") + assertSupply(t, ctx, keeper, contractAddr, "0", sdk.NewInt64Coin("stake", 0)) + + bond := StakingHandleMsg{ + Bond: &struct{}{}, + } + bondBz, err := json.Marshal(bond) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds) + require.NoError(t, err) + + // check some account values - the money is on neither account (cuz it is bonded) + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.Coins{}) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, funds) + + // make sure the proper number of tokens have been bonded + val, _ = stakingKeeper.GetValidator(ctx, valAddr) + finalPower := val.GetDelegatorShares() + assert.Equal(t, sdk.NewInt(80000), finalPower.Sub(initPower).TruncateInt()) + + // check the delegation itself + d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr) + require.True(t, found) + assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("80000")) + + // check we have the desired balance + assertBalance(t, ctx, keeper, contractAddr, bob, "80000") + assertClaims(t, ctx, keeper, contractAddr, bob, "0") + assertSupply(t, ctx, keeper, contractAddr, "80000", sdk.NewInt64Coin("stake", 80000)) +} + +func TestUnbonding(t *testing.T) { + initInfo := initializeStaking(t) + ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr + keeper, stakingKeeper, accKeeper, bankKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper, initInfo.bankKeeper + + // initial checks of bonding state + val, found := stakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + initPower := val.GetDelegatorShares() + + // bob has 160k, putting 80k into the contract + full := sdk.NewCoins(sdk.NewInt64Coin("stake", 160000)) + funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 80000)) + bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...) + + bond := StakingHandleMsg{ + Bond: &struct{}{}, + } + bondBz, err := json.Marshal(bond) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds) + require.NoError(t, err) + + // update height a bit + ctx = nextBlock(ctx, stakingKeeper) + + // now unbond 30k - note that 3k (10%) goes to the owner as a tax, 27k unbonded and available as claims + unbond := StakingHandleMsg{ + Unbond: &unbondPayload{ + Amount: "30000", + }, + } + unbondBz, err := json.Marshal(unbond) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, unbondBz, nil) + require.NoError(t, err) + + // check some account values - the money is on neither account (cuz it is bonded) + // Note: why is this immediate? just test setup? + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.Coins{}) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, funds) + + // make sure the proper number of tokens have been bonded (80k - 27k = 53k) + val, _ = stakingKeeper.GetValidator(ctx, valAddr) + finalPower := val.GetDelegatorShares() + assert.Equal(t, sdk.NewInt(53000), finalPower.Sub(initPower).TruncateInt(), finalPower.String()) + + // check the delegation itself + d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr) + require.True(t, found) + assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("53000")) + + // check there is unbonding in progress + un, found := stakingKeeper.GetUnbondingDelegation(ctx, contractAddr, valAddr) + require.True(t, found) + require.Equal(t, 1, len(un.Entries)) + assert.Equal(t, "27000", un.Entries[0].Balance.String()) + + // check we have the desired balance + assertBalance(t, ctx, keeper, contractAddr, bob, "50000") + assertBalance(t, ctx, keeper, contractAddr, initInfo.creator, "3000") + assertClaims(t, ctx, keeper, contractAddr, bob, "27000") + assertSupply(t, ctx, keeper, contractAddr, "53000", sdk.NewInt64Coin("stake", 53000)) +} + +func TestReinvest(t *testing.T) { + initInfo := initializeStaking(t) + ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr + keeper, stakingKeeper, accKeeper, bankKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper, initInfo.bankKeeper + distKeeper := initInfo.distKeeper + + // initial checks of bonding state + val, found := stakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + initPower := val.GetDelegatorShares() + assert.Equal(t, val.Tokens, sdk.NewInt(1000000), "%s", val.Tokens) + + // full is 2x funds, 1x goes to the contract, other stays on his wallet + full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000)) + funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000)) + bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...) + + // we will stake 200k to a validator with 1M self-bond + // this means we should get 1/6 of the rewards + bond := StakingHandleMsg{ + Bond: &struct{}{}, + } + bondBz, err := json.Marshal(bond) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds) + require.NoError(t, err) + + // update height a bit to solidify the delegation + ctx = nextBlock(ctx, stakingKeeper) + // we get 1/6, our share should be 40k minus 10% commission = 36k + setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000") + + // this should withdraw our outstanding 36k of rewards and reinvest them in the same delegation + reinvest := StakingHandleMsg{ + Reinvest: &struct{}{}, + } + reinvestBz, err := json.Marshal(reinvest) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, reinvestBz, nil) + require.NoError(t, err) + + // check some account values - the money is on neither account (cuz it is bonded) + // Note: why is this immediate? just test setup? + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.Coins{}) + checkAccount(t, ctx, accKeeper, bankKeeper, bob, funds) + + // check the delegation itself + d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr) + require.True(t, found) + // we started with 200k and added 36k + assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("236000")) + + // make sure the proper number of tokens have been bonded (80k + 40k = 120k) + val, _ = stakingKeeper.GetValidator(ctx, valAddr) + finalPower := val.GetDelegatorShares() + assert.Equal(t, sdk.NewInt(236000), finalPower.Sub(initPower).TruncateInt(), finalPower.String()) + + // check there is no unbonding in progress + un, found := stakingKeeper.GetUnbondingDelegation(ctx, contractAddr, valAddr) + assert.False(t, found, "%#v", un) + + // check we have the desired balance + assertBalance(t, ctx, keeper, contractAddr, bob, "200000") + assertBalance(t, ctx, keeper, contractAddr, initInfo.creator, "0") + assertClaims(t, ctx, keeper, contractAddr, bob, "0") + assertSupply(t, ctx, keeper, contractAddr, "200000", sdk.NewInt64Coin("stake", 236000)) +} + +func TestQueryStakingInfo(t *testing.T) { + // STEP 1: take a lot of setup from TestReinvest so we have non-zero info + initInfo := initializeStaking(t) + ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr + keeper, stakingKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper + distKeeper := initInfo.distKeeper + + // initial checks of bonding state + val, found := stakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + assert.Equal(t, sdk.NewInt(1000000), val.Tokens) + + // full is 2x funds, 1x goes to the contract, other stays on his wallet + full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000)) + funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000)) + bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...) + + // we will stake 200k to a validator with 1M self-bond + // this means we should get 1/6 of the rewards + bond := StakingHandleMsg{ + Bond: &struct{}{}, + } + bondBz, err := json.Marshal(bond) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds) + require.NoError(t, err) + + // update height a bit to solidify the delegation + ctx = nextBlock(ctx, stakingKeeper) + // we get 1/6, our share should be 40k minus 10% commission = 36k + setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000") + + // see what the current rewards are + origReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr) + + // STEP 2: Prepare the mask contract + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + creator := initInfo.faucet.NewFundedRandomAccount(ctx, deposit...) + + // upload mask code + maskID, _, err := initInfo.contractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(2), maskID) + + // creator instantiates a contract and gives it tokens + maskAddr, _, err := initInfo.contractKeeper.Instantiate(ctx, maskID, creator, nil, []byte("{}"), "mask contract 2", nil) + require.NoError(t, err) + require.NotEmpty(t, maskAddr) + + // STEP 3: now, let's reflect some queries. + // let's get the bonded denom + reflectBondedQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{ + BondedDenom: &struct{}{}, + }}}} + reflectBondedBin := buildReflectQuery(t, &reflectBondedQuery) + res, err := keeper.QuerySmart(ctx, maskAddr, reflectBondedBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + var reflectRes testdata.ChainResponse + mustParse(t, res, &reflectRes) + var bondedRes wasmvmtypes.BondedDenomResponse + mustParse(t, reflectRes.Data, &bondedRes) + assert.Equal(t, "stake", bondedRes.Denom) + + // now, let's reflect a smart query into the x/wasm handlers and see if we get the same result + reflectAllValidatorsQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{ + AllValidators: &wasmvmtypes.AllValidatorsQuery{}, + }}}} + reflectAllValidatorsBin := buildReflectQuery(t, &reflectAllValidatorsQuery) + res, err = keeper.QuerySmart(ctx, maskAddr, reflectAllValidatorsBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + mustParse(t, res, &reflectRes) + var allValidatorsRes wasmvmtypes.AllValidatorsResponse + mustParse(t, reflectRes.Data, &allValidatorsRes) + require.Len(t, allValidatorsRes.Validators, 1) + valInfo := allValidatorsRes.Validators[0] + // Note: this ValAddress not AccAddress, may change with #264 + require.Equal(t, valAddr.String(), valInfo.Address) + require.Contains(t, valInfo.Commission, "0.100") + require.Contains(t, valInfo.MaxCommission, "0.200") + require.Contains(t, valInfo.MaxChangeRate, "0.010") + + // find a validator + reflectValidatorQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{ + Validator: &wasmvmtypes.ValidatorQuery{ + Address: valAddr.String(), + }, + }}}} + reflectValidatorBin := buildReflectQuery(t, &reflectValidatorQuery) + res, err = keeper.QuerySmart(ctx, maskAddr, reflectValidatorBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + mustParse(t, res, &reflectRes) + var validatorRes wasmvmtypes.ValidatorResponse + mustParse(t, reflectRes.Data, &validatorRes) + require.NotNil(t, validatorRes.Validator) + valInfo = *validatorRes.Validator + // Note: this ValAddress not AccAddress, may change with #264 + require.Equal(t, valAddr.String(), valInfo.Address) + require.Contains(t, valInfo.Commission, "0.100") + require.Contains(t, valInfo.MaxCommission, "0.200") + require.Contains(t, valInfo.MaxChangeRate, "0.010") + + // missing validator + noVal := sdk.ValAddress(secp256k1.GenPrivKey().PubKey().Address()) + reflectNoValidatorQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{ + Validator: &wasmvmtypes.ValidatorQuery{ + Address: noVal.String(), + }, + }}}} + reflectNoValidatorBin := buildReflectQuery(t, &reflectNoValidatorQuery) + res, err = keeper.QuerySmart(ctx, maskAddr, reflectNoValidatorBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + mustParse(t, res, &reflectRes) + var noValidatorRes wasmvmtypes.ValidatorResponse + mustParse(t, reflectRes.Data, &noValidatorRes) + require.Nil(t, noValidatorRes.Validator) + + // test to get all my delegations + reflectAllDelegationsQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{ + AllDelegations: &wasmvmtypes.AllDelegationsQuery{ + Delegator: contractAddr.String(), + }, + }}}} + reflectAllDelegationsBin := buildReflectQuery(t, &reflectAllDelegationsQuery) + res, err = keeper.QuerySmart(ctx, maskAddr, reflectAllDelegationsBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + mustParse(t, res, &reflectRes) + var allDelegationsRes wasmvmtypes.AllDelegationsResponse + mustParse(t, reflectRes.Data, &allDelegationsRes) + require.Len(t, allDelegationsRes.Delegations, 1) + delInfo := allDelegationsRes.Delegations[0] + // Note: this ValAddress not AccAddress, may change with #264 + require.Equal(t, valAddr.String(), delInfo.Validator) + // note this is not bob (who staked to the contract), but the contract itself + require.Equal(t, contractAddr.String(), delInfo.Delegator) + // this is a different Coin type, with String not BigInt, compare field by field + require.Equal(t, funds[0].Denom, delInfo.Amount.Denom) + require.Equal(t, funds[0].Amount.String(), delInfo.Amount.Amount) + + // test to get one delegations + reflectDelegationQuery := testdata.ReflectQueryMsg{Chain: &testdata.ChainQuery{Request: &wasmvmtypes.QueryRequest{Staking: &wasmvmtypes.StakingQuery{ + Delegation: &wasmvmtypes.DelegationQuery{ + Validator: valAddr.String(), + Delegator: contractAddr.String(), + }, + }}}} + reflectDelegationBin := buildReflectQuery(t, &reflectDelegationQuery) + res, err = keeper.QuerySmart(ctx, maskAddr, reflectDelegationBin) + require.NoError(t, err) + // first we pull out the data from chain response, before parsing the original response + mustParse(t, res, &reflectRes) + var delegationRes wasmvmtypes.DelegationResponse + mustParse(t, reflectRes.Data, &delegationRes) + assert.NotEmpty(t, delegationRes.Delegation) + delInfo2 := delegationRes.Delegation + // Note: this ValAddress not AccAddress, may change with #264 + require.Equal(t, valAddr.String(), delInfo2.Validator) + // note this is not bob (who staked to the contract), but the contract itself + require.Equal(t, contractAddr.String(), delInfo2.Delegator) + // this is a different Coin type, with String not BigInt, compare field by field + require.Equal(t, funds[0].Denom, delInfo2.Amount.Denom) + require.Equal(t, funds[0].Amount.String(), delInfo2.Amount.Amount) + + require.Equal(t, wasmvmtypes.NewCoin(200000, "stake"), delInfo2.CanRedelegate) + require.Len(t, delInfo2.AccumulatedRewards, 1) + // see bonding above to see how we calculate 36000 (240000 / 6 - 10% commission) + require.Equal(t, wasmvmtypes.NewCoin(36000, "stake"), delInfo2.AccumulatedRewards[0]) + + // ensure rewards did not change when querying (neither amount nor period) + finalReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr) + require.Equal(t, origReward, finalReward) +} + +func TestQueryStakingPlugin(t *testing.T) { + // STEP 1: take a lot of setup from TestReinvest so we have non-zero info + initInfo := initializeStaking(t) + ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr + stakingKeeper := initInfo.stakingKeeper + distKeeper := initInfo.distKeeper + + // initial checks of bonding state + val, found := stakingKeeper.GetValidator(ctx, valAddr) + require.True(t, found) + assert.Equal(t, sdk.NewInt(1000000), val.Tokens) + + // full is 2x funds, 1x goes to the contract, other stays on his wallet + full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000)) + funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000)) + bob := initInfo.faucet.NewFundedRandomAccount(ctx, full...) + + // we will stake 200k to a validator with 1M self-bond + // this means we should get 1/6 of the rewards + bond := StakingHandleMsg{ + Bond: &struct{}{}, + } + bondBz, err := json.Marshal(bond) + require.NoError(t, err) + _, err = initInfo.contractKeeper.Execute(ctx, contractAddr, bob, bondBz, funds) + require.NoError(t, err) + + // update height a bit to solidify the delegation + ctx = nextBlock(ctx, stakingKeeper) + // we get 1/6, our share should be 40k minus 10% commission = 36k + setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000") + + // see what the current rewards are + origReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr) + + // Step 2: Try out the query plugins + query := wasmvmtypes.StakingQuery{ + Delegation: &wasmvmtypes.DelegationQuery{ + Delegator: contractAddr.String(), + Validator: valAddr.String(), + }, + } + raw, err := StakingQuerier(stakingKeeper, distKeeper)(ctx, &query) + require.NoError(t, err) + var res wasmvmtypes.DelegationResponse + mustParse(t, raw, &res) + assert.NotEmpty(t, res.Delegation) + delInfo := res.Delegation + // Note: this ValAddress not AccAddress, may change with #264 + require.Equal(t, valAddr.String(), delInfo.Validator) + // note this is not bob (who staked to the contract), but the contract itself + require.Equal(t, contractAddr.String(), delInfo.Delegator) + // this is a different Coin type, with String not BigInt, compare field by field + require.Equal(t, funds[0].Denom, delInfo.Amount.Denom) + require.Equal(t, funds[0].Amount.String(), delInfo.Amount.Amount) + + require.Equal(t, wasmvmtypes.NewCoin(200000, "stake"), delInfo.CanRedelegate) + require.Len(t, delInfo.AccumulatedRewards, 1) + // see bonding above to see how we calculate 36000 (240000 / 6 - 10% commission) + require.Equal(t, wasmvmtypes.NewCoin(36000, "stake"), delInfo.AccumulatedRewards[0]) + + // ensure rewards did not change when querying (neither amount nor period) + finalReward := distKeeper.GetValidatorCurrentRewards(ctx, valAddr) + require.Equal(t, origReward, finalReward) +} + +// adds a few validators and returns a list of validators that are registered +func addValidator(t *testing.T, ctx sdk.Context, stakingKeeper stakingkeeper.Keeper, faucet *TestFaucet, value sdk.Coin) sdk.ValAddress { + owner := faucet.NewFundedRandomAccount(ctx, value) + + privKey := secp256k1.GenPrivKey() + pubKey := privKey.PubKey() + addr := sdk.ValAddress(pubKey.Address()) + + pkAny, err := codectypes.NewAnyWithValue(pubKey) + require.NoError(t, err) + msg := stakingtypes.MsgCreateValidator{ + Description: types.Description{ + Moniker: "Validator power", + }, + Commission: types.CommissionRates{ + Rate: sdk.MustNewDecFromStr("0.1"), + MaxRate: sdk.MustNewDecFromStr("0.2"), + MaxChangeRate: sdk.MustNewDecFromStr("0.01"), + }, + MinSelfDelegation: sdk.OneInt(), + DelegatorAddress: owner.String(), + ValidatorAddress: addr.String(), + Pubkey: pkAny, + Value: value, + } + + h := staking.NewHandler(stakingKeeper) + _, err = h(ctx, &msg) + require.NoError(t, err) + return addr +} + +// this will commit the current set, update the block height and set historic info +// basically, letting two blocks pass +func nextBlock(ctx sdk.Context, stakingKeeper stakingkeeper.Keeper) sdk.Context { + staking.EndBlocker(ctx, stakingKeeper) + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) + staking.BeginBlocker(ctx, stakingKeeper) + return ctx +} + +func setValidatorRewards(ctx sdk.Context, stakingKeeper stakingkeeper.Keeper, distKeeper distributionkeeper.Keeper, valAddr sdk.ValAddress, reward string) { + // allocate some rewards + vali := stakingKeeper.Validator(ctx, valAddr) + amount, err := sdk.NewDecFromStr(reward) + if err != nil { + panic(err) + } + payout := sdk.DecCoins{{Denom: "stake", Amount: amount}} + distKeeper.AllocateTokensToValidator(ctx, vali, payout) +} + +func assertBalance(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, addr sdk.AccAddress, expected string) { + query := StakingQueryMsg{ + Balance: &addressQuery{ + Address: addr, + }, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + res, err := keeper.QuerySmart(ctx, contract, queryBz) + require.NoError(t, err) + var balance BalanceResponse + err = json.Unmarshal(res, &balance) + require.NoError(t, err) + assert.Equal(t, expected, balance.Balance) +} + +func assertClaims(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, addr sdk.AccAddress, expected string) { + query := StakingQueryMsg{ + Claims: &addressQuery{ + Address: addr, + }, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + res, err := keeper.QuerySmart(ctx, contract, queryBz) + require.NoError(t, err) + var claims ClaimsResponse + err = json.Unmarshal(res, &claims) + require.NoError(t, err) + assert.Equal(t, expected, claims.Claims) +} + +func assertSupply(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, expectedIssued string, expectedBonded sdk.Coin) { + query := StakingQueryMsg{Investment: &struct{}{}} + queryBz, err := json.Marshal(query) + require.NoError(t, err) + res, err := keeper.QuerySmart(ctx, contract, queryBz) + require.NoError(t, err) + var invest InvestmentResponse + err = json.Unmarshal(res, &invest) + require.NoError(t, err) + assert.Equal(t, expectedIssued, invest.TokenSupply) + assert.Equal(t, expectedBonded, invest.StakedTokens) +} diff --git a/x/wasm/keeper/submsg_test.go b/x/wasm/keeper/submsg_test.go new file mode 100644 index 00000000..fdb68820 --- /dev/null +++ b/x/wasm/keeper/submsg_test.go @@ -0,0 +1,552 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "os" + "strconv" + "testing" + + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cerc-io/laconicd/x/wasm/keeper/testdata" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +// test handing of submessages, very closely related to the reflect_test + +// Try a simple send, no gas limit to for a sanity check before trying table tests +func TestDispatchSubMsgSuccessCase(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, ReflectFeatures) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + creatorBalance := deposit.Sub(contractStart) + _, _, fred := keyPubAddr() + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + require.Equal(t, uint64(1), codeID) + + // creator instantiates a contract and gives it tokens + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // check some account values + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, contractStart) + checkAccount(t, ctx, accKeeper, bankKeeper, creator, creatorBalance) + checkAccount(t, ctx, accKeeper, bankKeeper, fred, nil) + + // creator can send contract's tokens to fred (using SendMsg) + msg := wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: fred.String(), + Amount: []wasmvmtypes.Coin{{ + Denom: "denom", + Amount: "15000", + }}, + }, + }, + } + reflectSend := testdata.ReflectHandleMsg{ + ReflectSubMsg: &testdata.ReflectSubPayload{ + Msgs: []wasmvmtypes.SubMsg{{ + ID: 7, + Msg: msg, + ReplyOn: wasmvmtypes.ReplyAlways, + }}, + }, + } + reflectSendBz, err := json.Marshal(reflectSend) + require.NoError(t, err) + _, err = keepers.ContractKeeper.Execute(ctx, contractAddr, creator, reflectSendBz, nil) + require.NoError(t, err) + + // fred got coins + checkAccount(t, ctx, accKeeper, bankKeeper, fred, sdk.NewCoins(sdk.NewInt64Coin("denom", 15000))) + // contract lost them + checkAccount(t, ctx, accKeeper, bankKeeper, contractAddr, sdk.NewCoins(sdk.NewInt64Coin("denom", 25000))) + checkAccount(t, ctx, accKeeper, bankKeeper, creator, creatorBalance) + + // query the reflect state to ensure the result was stored + query := testdata.ReflectQueryMsg{ + SubMsgResult: &testdata.SubCall{ID: 7}, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + queryRes, err := keeper.QuerySmart(ctx, contractAddr, queryBz) + require.NoError(t, err) + + var res wasmvmtypes.Reply + err = json.Unmarshal(queryRes, &res) + require.NoError(t, err) + assert.Equal(t, uint64(7), res.ID) + assert.Empty(t, res.Result.Err) + require.NotNil(t, res.Result.Ok) + sub := res.Result.Ok + assert.Empty(t, sub.Data) + // as of v0.28.0 we strip out all events that don't come from wasm contracts. can't trust the sdk. + require.Len(t, sub.Events, 0) +} + +func TestDispatchSubMsgErrorHandling(t *testing.T) { + fundedDenom := "funds" + fundedAmount := 1_000_000 + ctxGasLimit := uint64(1_000_000) + subGasLimit := uint64(300_000) + + // prep - create one chain and upload the code + ctx, keepers := CreateTestInput(t, false, ReflectFeatures) + ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter()) + ctx = ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) + keeper := keepers.WasmKeeper + contractStart := sdk.NewCoins(sdk.NewInt64Coin(fundedDenom, int64(fundedAmount))) + uploader := keepers.Faucet.NewFundedRandomAccount(ctx, contractStart.Add(contractStart...)...) + + // upload code + reflectID, _, err := keepers.ContractKeeper.Create(ctx, uploader, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + + // create hackatom contract for testing (for infinite loop) + hackatomCode, err := os.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + hackatomID, _, err := keepers.ContractKeeper.Create(ctx, uploader, hackatomCode, nil) + require.NoError(t, err) + _, _, bob := keyPubAddr() + _, _, fred := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + hackatomAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, hackatomID, uploader, nil, initMsgBz, "hackatom demo", contractStart) + require.NoError(t, err) + + validBankSend := func(contract, emptyAccount string) wasmvmtypes.CosmosMsg { + return wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: emptyAccount, + Amount: []wasmvmtypes.Coin{{ + Denom: fundedDenom, + Amount: strconv.Itoa(fundedAmount / 2), + }}, + }, + }, + } + } + + invalidBankSend := func(contract, emptyAccount string) wasmvmtypes.CosmosMsg { + return wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: emptyAccount, + Amount: []wasmvmtypes.Coin{{ + Denom: fundedDenom, + Amount: strconv.Itoa(fundedAmount * 2), + }}, + }, + }, + } + } + + infiniteLoop := func(contract, emptyAccount string) wasmvmtypes.CosmosMsg { + return wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Execute: &wasmvmtypes.ExecuteMsg{ + ContractAddr: hackatomAddr.String(), + Msg: []byte(`{"cpu_loop":{}}`), + }, + }, + } + } + + instantiateContract := func(contract, emptyAccount string) wasmvmtypes.CosmosMsg { + return wasmvmtypes.CosmosMsg{ + Wasm: &wasmvmtypes.WasmMsg{ + Instantiate: &wasmvmtypes.InstantiateMsg{ + CodeID: reflectID, + Msg: []byte("{}"), + Label: "subcall reflect", + }, + }, + } + } + + type assertion func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubMsgResult) + + assertReturnedEvents := func(expectedEvents int) assertion { + return func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubMsgResult) { + require.Len(t, response.Ok.Events, expectedEvents) + } + } + + assertGasUsed := func(minGas, maxGas uint64) assertion { + return func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubMsgResult) { + gasUsed := ctx.GasMeter().GasConsumed() + assert.True(t, gasUsed >= minGas, "Used %d gas (less than expected %d)", gasUsed, minGas) + assert.True(t, gasUsed <= maxGas, "Used %d gas (more than expected %d)", gasUsed, maxGas) + } + } + + assertErrorString := func(shouldContain string) assertion { + return func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubMsgResult) { + assert.Contains(t, response.Err, shouldContain) + } + } + + assertGotContractAddr := func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubMsgResult) { + // should get the events emitted on new contract + event := response.Ok.Events[0] + require.Equal(t, event.Type, "instantiate") + assert.Equal(t, event.Attributes[0].Key, "_contract_address") + eventAddr := event.Attributes[0].Value + assert.NotEqual(t, contract, eventAddr) + + var res types.MsgInstantiateContractResponse + keepers.EncodingConfig.Marshaler.MustUnmarshal(response.Ok.Data, &res) + assert.Equal(t, eventAddr, res.Address) + } + + cases := map[string]struct { + submsgID uint64 + // we will generate message from the + msg func(contract, emptyAccount string) wasmvmtypes.CosmosMsg + gasLimit *uint64 + + // true if we expect this to throw out of gas panic + isOutOfGasPanic bool + // true if we expect this execute to return an error (can be false when submessage errors) + executeError bool + // true if we expect submessage to return an error (but execute to return success) + subMsgError bool + // make assertions after dispatch + resultAssertions []assertion + }{ + "send tokens": { + submsgID: 5, + msg: validBankSend, + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(95000, 96000)}, + }, + "not enough tokens": { + submsgID: 6, + msg: invalidBankSend, + subMsgError: true, + // uses less gas than the send tokens (cost of bank transfer) + resultAssertions: []assertion{assertGasUsed(76000, 79000), assertErrorString("codespace: sdk, code: 5")}, + }, + "out of gas panic with no gas limit": { + submsgID: 7, + msg: infiniteLoop, + isOutOfGasPanic: true, + }, + + "send tokens with limit": { + submsgID: 15, + msg: validBankSend, + gasLimit: &subGasLimit, + // uses same gas as call without limit (note we do not charge the 40k on reply) + resultAssertions: []assertion{assertReturnedEvents(0), assertGasUsed(95000, 96000)}, + }, + "not enough tokens with limit": { + submsgID: 16, + msg: invalidBankSend, + subMsgError: true, + gasLimit: &subGasLimit, + // uses same gas as call without limit (note we do not charge the 40k on reply) + resultAssertions: []assertion{assertGasUsed(77800, 77900), assertErrorString("codespace: sdk, code: 5")}, + }, + "out of gas caught with gas limit": { + submsgID: 17, + msg: infiniteLoop, + subMsgError: true, + gasLimit: &subGasLimit, + // uses all the subGasLimit, plus the 52k or so for the main contract + resultAssertions: []assertion{assertGasUsed(subGasLimit+73000, subGasLimit+74000), assertErrorString("codespace: sdk, code: 11")}, + }, + "instantiate contract gets address in data and events": { + submsgID: 21, + msg: instantiateContract, + resultAssertions: []assertion{assertReturnedEvents(1), assertGotContractAddr}, + }, + } + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + creator := keepers.Faucet.NewFundedRandomAccount(ctx, contractStart...) + _, _, empty := keyPubAddr() + + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, reflectID, creator, nil, []byte("{}"), fmt.Sprintf("contract %s", name), contractStart) + require.NoError(t, err) + + msg := tc.msg(contractAddr.String(), empty.String()) + reflectSend := testdata.ReflectHandleMsg{ + ReflectSubMsg: &testdata.ReflectSubPayload{ + Msgs: []wasmvmtypes.SubMsg{{ + ID: tc.submsgID, + Msg: msg, + GasLimit: tc.gasLimit, + ReplyOn: wasmvmtypes.ReplyAlways, + }}, + }, + } + reflectSendBz, err := json.Marshal(reflectSend) + require.NoError(t, err) + + execCtx := ctx.WithGasMeter(sdk.NewGasMeter(ctxGasLimit)) + defer func() { + if tc.isOutOfGasPanic { + r := recover() + require.NotNil(t, r, "expected panic") + if _, ok := r.(sdk.ErrorOutOfGas); !ok { + t.Fatalf("Expected OutOfGas panic, got: %#v\n", r) + } + } + }() + _, err = keepers.ContractKeeper.Execute(execCtx, contractAddr, creator, reflectSendBz, nil) + + if tc.executeError { + require.Error(t, err) + } else { + require.NoError(t, err) + + // query the reply + query := testdata.ReflectQueryMsg{ + SubMsgResult: &testdata.SubCall{ID: tc.submsgID}, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + queryRes, err := keeper.QuerySmart(ctx, contractAddr, queryBz) + require.NoError(t, err) + var res wasmvmtypes.Reply + err = json.Unmarshal(queryRes, &res) + require.NoError(t, err) + assert.Equal(t, tc.submsgID, res.ID) + + if tc.subMsgError { + require.NotEmpty(t, res.Result.Err) + require.Nil(t, res.Result.Ok) + } else { + require.Empty(t, res.Result.Err) + require.NotNil(t, res.Result.Ok) + } + + for _, assertion := range tc.resultAssertions { + assertion(t, execCtx, contractAddr.String(), empty.String(), res.Result) + } + + } + }) + } +} + +// Test an error case, where the Encoded doesn't return any sdk.Msg and we trigger(ed) a null pointer exception. +// This occurs with the IBC encoder. Test this. +func TestDispatchSubMsgEncodeToNoSdkMsg(t *testing.T) { + // fake out the bank handle to return success with no data + nilEncoder := func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error) { + return nil, nil + } + customEncoders := &MessageEncoders{ + Bank: nilEncoder, + } + + ctx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageHandler(NewSDKMessageHandler(nil, customEncoders))) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + _, _, fred := keyPubAddr() + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + + // creator instantiates a contract and gives it tokens + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + require.NotEmpty(t, contractAddr) + + // creator can send contract's tokens to fred (using SendMsg) + msg := wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: fred.String(), + Amount: []wasmvmtypes.Coin{{ + Denom: "denom", + Amount: "15000", + }}, + }, + }, + } + reflectSend := testdata.ReflectHandleMsg{ + ReflectSubMsg: &testdata.ReflectSubPayload{ + Msgs: []wasmvmtypes.SubMsg{{ + ID: 7, + Msg: msg, + ReplyOn: wasmvmtypes.ReplyAlways, + }}, + }, + } + reflectSendBz, err := json.Marshal(reflectSend) + require.NoError(t, err) + _, err = keepers.ContractKeeper.Execute(ctx, contractAddr, creator, reflectSendBz, nil) + require.NoError(t, err) + + // query the reflect state to ensure the result was stored + query := testdata.ReflectQueryMsg{ + SubMsgResult: &testdata.SubCall{ID: 7}, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + queryRes, err := keeper.QuerySmart(ctx, contractAddr, queryBz) + require.NoError(t, err) + + var res wasmvmtypes.Reply + err = json.Unmarshal(queryRes, &res) + require.NoError(t, err) + assert.Equal(t, uint64(7), res.ID) + assert.Empty(t, res.Result.Err) + require.NotNil(t, res.Result.Ok) + sub := res.Result.Ok + assert.Empty(t, sub.Data) + require.Len(t, sub.Events, 0) +} + +// Try a simple send, no gas limit to for a sanity check before trying table tests +func TestDispatchSubMsgConditionalReplyOn(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, ReflectFeatures) + keeper := keepers.WasmKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + contractStart := sdk.NewCoins(sdk.NewInt64Coin("denom", 40000)) + + creator := keepers.Faucet.NewFundedRandomAccount(ctx, deposit...) + _, _, fred := keyPubAddr() + + // upload code + codeID, _, err := keepers.ContractKeeper.Create(ctx, creator, testdata.ReflectContractWasm(), nil) + require.NoError(t, err) + + // creator instantiates a contract and gives it tokens + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, []byte("{}"), "reflect contract 1", contractStart) + require.NoError(t, err) + + goodSend := wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: fred.String(), + Amount: []wasmvmtypes.Coin{{ + Denom: "denom", + Amount: "1000", + }}, + }, + }, + } + failSend := wasmvmtypes.CosmosMsg{ + Bank: &wasmvmtypes.BankMsg{ + Send: &wasmvmtypes.SendMsg{ + ToAddress: fred.String(), + Amount: []wasmvmtypes.Coin{{ + Denom: "no-such-token", + Amount: "777777", + }}, + }, + }, + } + + cases := map[string]struct { + // true for wasmvmtypes.ReplySuccess, false for wasmvmtypes.ReplyError + replyOnSuccess bool + msg wasmvmtypes.CosmosMsg + // true if the call should return an error (it wasn't handled) + expectError bool + // true if the reflect contract wrote the response (success or error) - it was captured + writeResult bool + }{ + "all good, reply success": { + replyOnSuccess: true, + msg: goodSend, + expectError: false, + writeResult: true, + }, + "all good, reply error": { + replyOnSuccess: false, + msg: goodSend, + expectError: false, + writeResult: false, + }, + "bad msg, reply success": { + replyOnSuccess: true, + msg: failSend, + expectError: true, + writeResult: false, + }, + "bad msg, reply error": { + replyOnSuccess: false, + msg: failSend, + expectError: false, + writeResult: true, + }, + } + + var id uint64 = 0 + for name, tc := range cases { + id++ + t.Run(name, func(t *testing.T) { + subMsg := wasmvmtypes.SubMsg{ + ID: id, + Msg: tc.msg, + ReplyOn: wasmvmtypes.ReplySuccess, + } + if !tc.replyOnSuccess { + subMsg.ReplyOn = wasmvmtypes.ReplyError + } + + reflectSend := testdata.ReflectHandleMsg{ + ReflectSubMsg: &testdata.ReflectSubPayload{ + Msgs: []wasmvmtypes.SubMsg{subMsg}, + }, + } + reflectSendBz, err := json.Marshal(reflectSend) + require.NoError(t, err) + _, err = keepers.ContractKeeper.Execute(ctx, contractAddr, creator, reflectSendBz, nil) + + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + // query the reflect state to check if the result was stored + query := testdata.ReflectQueryMsg{ + SubMsgResult: &testdata.SubCall{ID: id}, + } + queryBz, err := json.Marshal(query) + require.NoError(t, err) + queryRes, err := keeper.QuerySmart(ctx, contractAddr, queryBz) + if tc.writeResult { + // we got some data for this call + require.NoError(t, err) + var res wasmvmtypes.Reply + err = json.Unmarshal(queryRes, &res) + require.NoError(t, err) + require.Equal(t, id, res.ID) + } else { + // nothing should be there -> error + require.Error(t, err) + } + }) + } +} diff --git a/x/wasm/keeper/test_common.go b/x/wasm/keeper/test_common.go new file mode 100644 index 00000000..2e329d76 --- /dev/null +++ b/x/wasm/keeper/test_common.go @@ -0,0 +1,759 @@ +package keeper + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "os" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/std" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + "github.com/cosmos/cosmos-sdk/x/bank" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/capability" + capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + "github.com/cosmos/cosmos-sdk/x/crisis" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + "github.com/cosmos/cosmos-sdk/x/distribution" + distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client" + distributionkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/evidence" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + "github.com/cosmos/cosmos-sdk/x/feegrant" + "github.com/cosmos/cosmos-sdk/x/gov" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/mint" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/params" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + paramproposal "github.com/cosmos/cosmos-sdk/x/params/types/proposal" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/upgrade" + upgradeclient "github.com/cosmos/cosmos-sdk/x/upgrade/client" + upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + "github.com/cosmos/ibc-go/v4/modules/apps/transfer" + ibctransfertypes "github.com/cosmos/ibc-go/v4/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v4/modules/core" + ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host" + ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/libs/rand" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + dbm "github.com/tendermint/tm-db" + + wasmappparams "github.com/cerc-io/laconicd/app/params" + "github.com/cerc-io/laconicd/x/wasm/keeper/wasmtesting" + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var moduleBasics = module.NewBasicManager( + auth.AppModuleBasic{}, + bank.AppModuleBasic{}, + capability.AppModuleBasic{}, + staking.AppModuleBasic{}, + mint.AppModuleBasic{}, + distribution.AppModuleBasic{}, + gov.NewAppModuleBasic( + paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, + ), + params.AppModuleBasic{}, + crisis.AppModuleBasic{}, + slashing.AppModuleBasic{}, + ibc.AppModuleBasic{}, + upgrade.AppModuleBasic{}, + evidence.AppModuleBasic{}, + transfer.AppModuleBasic{}, + vesting.AppModuleBasic{}, +) + +func MakeTestCodec(t testing.TB) codec.Codec { + return MakeEncodingConfig(t).Marshaler +} + +func MakeEncodingConfig(_ testing.TB) wasmappparams.EncodingConfig { + encodingConfig := wasmappparams.MakeEncodingConfig() + amino := encodingConfig.Amino + interfaceRegistry := encodingConfig.InterfaceRegistry + + std.RegisterInterfaces(interfaceRegistry) + std.RegisterLegacyAminoCodec(amino) + + moduleBasics.RegisterLegacyAminoCodec(amino) + moduleBasics.RegisterInterfaces(interfaceRegistry) + // add wasmd types + types.RegisterInterfaces(interfaceRegistry) + types.RegisterLegacyAminoCodec(amino) + + return encodingConfig +} + +var TestingStakeParams = stakingtypes.Params{ + UnbondingTime: 100, + MaxValidators: 10, + MaxEntries: 10, + HistoricalEntries: 10, + BondDenom: "stake", +} + +type TestFaucet struct { + t testing.TB + bankKeeper bankkeeper.Keeper + sender sdk.AccAddress + balance sdk.Coins + minterModuleName string +} + +func NewTestFaucet(t testing.TB, ctx sdk.Context, bankKeeper bankkeeper.Keeper, minterModuleName string, initialAmount ...sdk.Coin) *TestFaucet { + require.NotEmpty(t, initialAmount) + r := &TestFaucet{t: t, bankKeeper: bankKeeper, minterModuleName: minterModuleName} + _, _, addr := keyPubAddr() + r.sender = addr + r.Mint(ctx, addr, initialAmount...) + r.balance = initialAmount + return r +} + +func (f *TestFaucet) Mint(parentCtx sdk.Context, addr sdk.AccAddress, amounts ...sdk.Coin) { + require.NotEmpty(f.t, amounts) + ctx := parentCtx.WithEventManager(sdk.NewEventManager()) // discard all faucet related events + err := f.bankKeeper.MintCoins(ctx, f.minterModuleName, amounts) + require.NoError(f.t, err) + err = f.bankKeeper.SendCoinsFromModuleToAccount(ctx, f.minterModuleName, addr, amounts) + require.NoError(f.t, err) + f.balance = f.balance.Add(amounts...) +} + +func (f *TestFaucet) Fund(parentCtx sdk.Context, receiver sdk.AccAddress, amounts ...sdk.Coin) { + require.NotEmpty(f.t, amounts) + // ensure faucet is always filled + if !f.balance.IsAllGTE(amounts) { + f.Mint(parentCtx, f.sender, amounts...) + } + ctx := parentCtx.WithEventManager(sdk.NewEventManager()) // discard all faucet related events + err := f.bankKeeper.SendCoins(ctx, f.sender, receiver, amounts) + require.NoError(f.t, err) + f.balance = f.balance.Sub(amounts) +} + +func (f *TestFaucet) NewFundedRandomAccount(ctx sdk.Context, amounts ...sdk.Coin) sdk.AccAddress { + _, _, addr := keyPubAddr() + f.Fund(ctx, addr, amounts...) + return addr +} + +type TestKeepers struct { + AccountKeeper authkeeper.AccountKeeper + StakingKeeper stakingkeeper.Keeper + DistKeeper distributionkeeper.Keeper + BankKeeper bankkeeper.Keeper + GovKeeper govkeeper.Keeper + ContractKeeper types.ContractOpsKeeper + WasmKeeper *Keeper + IBCKeeper *ibckeeper.Keeper + Router *baseapp.Router + EncodingConfig wasmappparams.EncodingConfig + Faucet *TestFaucet + MultiStore sdk.CommitMultiStore + ScopedWasmKeeper capabilitykeeper.ScopedKeeper +} + +// CreateDefaultTestInput common settings for CreateTestInput +func CreateDefaultTestInput(t testing.TB) (sdk.Context, TestKeepers) { + return CreateTestInput(t, false, "staking") +} + +// CreateTestInput encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default) +func CreateTestInput(t testing.TB, isCheckTx bool, availableCapabilities string, opts ...Option) (sdk.Context, TestKeepers) { + // Load default wasm config + return createTestInput(t, isCheckTx, availableCapabilities, types.DefaultWasmConfig(), dbm.NewMemDB(), opts...) +} + +// encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default) +func createTestInput( + t testing.TB, + isCheckTx bool, + availableCapabilities string, + wasmConfig types.WasmConfig, + db dbm.DB, + opts ...Option, +) (sdk.Context, TestKeepers) { + tempDir := t.TempDir() + + keys := sdk.NewKVStoreKeys( + authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, + minttypes.StoreKey, distributiontypes.StoreKey, slashingtypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, + evidencetypes.StoreKey, ibctransfertypes.StoreKey, + capabilitytypes.StoreKey, feegrant.StoreKey, authzkeeper.StoreKey, + types.StoreKey, + ) + ms := store.NewCommitMultiStore(db) + for _, v := range keys { + ms.MountStoreWithDB(v, sdk.StoreTypeIAVL, db) + } + tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) + for _, v := range tkeys { + ms.MountStoreWithDB(v, sdk.StoreTypeTransient, db) + } + + memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) + for _, v := range memKeys { + ms.MountStoreWithDB(v, sdk.StoreTypeMemory, db) + } + + require.NoError(t, ms.LoadLatestVersion()) + + ctx := sdk.NewContext(ms, tmproto.Header{ + Height: 1234567, + Time: time.Date(2020, time.April, 22, 12, 0, 0, 0, time.UTC), + }, isCheckTx, log.NewNopLogger()) + ctx = types.WithTXCounter(ctx, 0) + + encodingConfig := MakeEncodingConfig(t) + appCodec, legacyAmino := encodingConfig.Marshaler, encodingConfig.Amino + + paramsKeeper := paramskeeper.NewKeeper( + appCodec, + legacyAmino, + keys[paramstypes.StoreKey], + tkeys[paramstypes.TStoreKey], + ) + for _, m := range []string{ + authtypes.ModuleName, + banktypes.ModuleName, + stakingtypes.ModuleName, + minttypes.ModuleName, + distributiontypes.ModuleName, + slashingtypes.ModuleName, + crisistypes.ModuleName, + ibctransfertypes.ModuleName, + capabilitytypes.ModuleName, + ibchost.ModuleName, + govtypes.ModuleName, + types.ModuleName, + } { + paramsKeeper.Subspace(m) + } + subspace := func(m string) paramstypes.Subspace { + r, ok := paramsKeeper.GetSubspace(m) + require.True(t, ok) + return r + } + maccPerms := map[string][]string{ // module account permissions + authtypes.FeeCollectorName: nil, + distributiontypes.ModuleName: nil, + minttypes.ModuleName: {authtypes.Minter}, + stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking}, + stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking}, + govtypes.ModuleName: {authtypes.Burner}, + ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + types.ModuleName: {authtypes.Burner}, + } + accountKeeper := authkeeper.NewAccountKeeper( + appCodec, + keys[authtypes.StoreKey], // target store + subspace(authtypes.ModuleName), + authtypes.ProtoBaseAccount, // prototype + maccPerms, + ) + blockedAddrs := make(map[string]bool) + for acc := range maccPerms { + blockedAddrs[authtypes.NewModuleAddress(acc).String()] = true + } + + bankKeeper := bankkeeper.NewBaseKeeper( + appCodec, + keys[banktypes.StoreKey], + accountKeeper, + subspace(banktypes.ModuleName), + blockedAddrs, + ) + bankKeeper.SetParams(ctx, banktypes.DefaultParams()) + + stakingKeeper := stakingkeeper.NewKeeper( + appCodec, + keys[stakingtypes.StoreKey], + accountKeeper, + bankKeeper, + subspace(stakingtypes.ModuleName), + ) + stakingKeeper.SetParams(ctx, TestingStakeParams) + + distKeeper := distributionkeeper.NewKeeper( + appCodec, + keys[distributiontypes.StoreKey], + subspace(distributiontypes.ModuleName), + accountKeeper, + bankKeeper, + stakingKeeper, + authtypes.FeeCollectorName, + nil, + ) + distKeeper.SetParams(ctx, distributiontypes.DefaultParams()) + stakingKeeper.SetHooks(distKeeper.Hooks()) + + // set genesis items required for distribution + distKeeper.SetFeePool(ctx, distributiontypes.InitialFeePool()) + + upgradeKeeper := upgradekeeper.NewKeeper( + map[int64]bool{}, + keys[upgradetypes.StoreKey], + appCodec, + tempDir, + nil, + ) + + faucet := NewTestFaucet(t, ctx, bankKeeper, minttypes.ModuleName, sdk.NewCoin("stake", sdk.NewInt(100_000_000_000))) + + // set some funds ot pay out validatores, based on code from: + // https://github.com/cosmos/cosmos-sdk/blob/fea231556aee4d549d7551a6190389c4328194eb/x/distribution/keeper/keeper_test.go#L50-L57 + distrAcc := distKeeper.GetDistributionAccount(ctx) + faucet.Fund(ctx, distrAcc.GetAddress(), sdk.NewCoin("stake", sdk.NewInt(2000000))) + accountKeeper.SetModuleAccount(ctx, distrAcc) + + capabilityKeeper := capabilitykeeper.NewKeeper( + appCodec, + keys[capabilitytypes.StoreKey], + memKeys[capabilitytypes.MemStoreKey], + ) + scopedIBCKeeper := capabilityKeeper.ScopeToModule(ibchost.ModuleName) + scopedWasmKeeper := capabilityKeeper.ScopeToModule(types.ModuleName) + + ibcKeeper := ibckeeper.NewKeeper( + appCodec, + keys[ibchost.StoreKey], + subspace(ibchost.ModuleName), + stakingKeeper, + upgradeKeeper, + scopedIBCKeeper, + ) + + router := baseapp.NewRouter() + bh := bank.NewHandler(bankKeeper) + router.AddRoute(sdk.NewRoute(banktypes.RouterKey, bh)) + sh := staking.NewHandler(stakingKeeper) + router.AddRoute(sdk.NewRoute(stakingtypes.RouterKey, sh)) + dh := distribution.NewHandler(distKeeper) + router.AddRoute(sdk.NewRoute(distributiontypes.RouterKey, dh)) + + querier := baseapp.NewGRPCQueryRouter() + querier.SetInterfaceRegistry(encodingConfig.InterfaceRegistry) + msgRouter := baseapp.NewMsgServiceRouter() + msgRouter.SetInterfaceRegistry(encodingConfig.InterfaceRegistry) + + cfg := sdk.GetConfig() + cfg.SetAddressVerifier(types.VerifyAddressLen()) + + keeper := NewKeeper( + appCodec, + keys[types.StoreKey], + subspace(types.ModuleName), + accountKeeper, + bankKeeper, + stakingKeeper, + distKeeper, + ibcKeeper.ChannelKeeper, + &ibcKeeper.PortKeeper, + scopedWasmKeeper, + wasmtesting.MockIBCTransferKeeper{}, + msgRouter, + querier, + tempDir, + wasmConfig, + availableCapabilities, + opts..., + ) + keeper.SetParams(ctx, types.DefaultParams()) + // add wasm handler so we can loop-back (contracts calling contracts) + contractKeeper := NewDefaultPermissionKeeper(&keeper) + router.AddRoute(sdk.NewRoute(types.RouterKey, TestHandler(contractKeeper))) + + am := module.NewManager( // minimal module set that we use for message/ query tests + bank.NewAppModule(appCodec, bankKeeper, accountKeeper), + staking.NewAppModule(appCodec, stakingKeeper, accountKeeper, bankKeeper), + distribution.NewAppModule(appCodec, distKeeper, accountKeeper, bankKeeper, stakingKeeper), + ) + am.RegisterServices(module.NewConfigurator(appCodec, msgRouter, querier)) + types.RegisterMsgServer(msgRouter, NewMsgServerImpl(NewDefaultPermissionKeeper(keeper))) + types.RegisterQueryServer(querier, NewGrpcQuerier(appCodec, keys[types.ModuleName], keeper, keeper.queryGasLimit)) + + govRouter := govtypes.NewRouter(). + AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). + AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(paramsKeeper)). + AddRoute(distributiontypes.RouterKey, distribution.NewCommunityPoolSpendProposalHandler(distKeeper)). + AddRoute(types.RouterKey, NewWasmProposalHandler(&keeper, types.EnableAllProposals)) + + govKeeper := govkeeper.NewKeeper( + appCodec, + keys[govtypes.StoreKey], + subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()), + accountKeeper, + bankKeeper, + stakingKeeper, + govRouter, + ) + + govKeeper.SetProposalID(ctx, govtypes.DefaultStartingProposalID) + govKeeper.SetDepositParams(ctx, govtypes.DefaultDepositParams()) + govKeeper.SetVotingParams(ctx, govtypes.DefaultVotingParams()) + govKeeper.SetTallyParams(ctx, govtypes.DefaultTallyParams()) + + keepers := TestKeepers{ + AccountKeeper: accountKeeper, + StakingKeeper: stakingKeeper, + DistKeeper: distKeeper, + ContractKeeper: contractKeeper, + WasmKeeper: &keeper, + BankKeeper: bankKeeper, + GovKeeper: govKeeper, + IBCKeeper: ibcKeeper, + Router: router, + EncodingConfig: encodingConfig, + Faucet: faucet, + MultiStore: ms, + ScopedWasmKeeper: scopedWasmKeeper, + } + return ctx, keepers +} + +// TestHandler returns a wasm handler for tests (to avoid circular imports) +func TestHandler(k types.ContractOpsKeeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + switch msg := msg.(type) { + case *types.MsgStoreCode: + return handleStoreCode(ctx, k, msg) + case *types.MsgInstantiateContract: + return handleInstantiate(ctx, k, msg) + case *types.MsgExecuteContract: + return handleExecute(ctx, k, msg) + default: + errMsg := fmt.Sprintf("unrecognized wasm message type: %T", msg) + return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) + } + } +} + +func handleStoreCode(ctx sdk.Context, k types.ContractOpsKeeper, msg *types.MsgStoreCode) (*sdk.Result, error) { + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + codeID, _, err := k.Create(ctx, senderAddr, msg.WASMByteCode, msg.InstantiatePermission) + if err != nil { + return nil, err + } + + return &sdk.Result{ + Data: []byte(fmt.Sprintf("%d", codeID)), + Events: ctx.EventManager().ABCIEvents(), + }, nil +} + +func handleInstantiate(ctx sdk.Context, k types.ContractOpsKeeper, msg *types.MsgInstantiateContract) (*sdk.Result, error) { + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + var adminAddr sdk.AccAddress + if msg.Admin != "" { + if adminAddr, err = sdk.AccAddressFromBech32(msg.Admin); err != nil { + return nil, sdkerrors.Wrap(err, "admin") + } + } + + contractAddr, _, err := k.Instantiate(ctx, msg.CodeID, senderAddr, adminAddr, msg.Msg, msg.Label, msg.Funds) + if err != nil { + return nil, err + } + + return &sdk.Result{ + Data: contractAddr, + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +func handleExecute(ctx sdk.Context, k types.ContractOpsKeeper, msg *types.MsgExecuteContract) (*sdk.Result, error) { + senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) + if err != nil { + return nil, sdkerrors.Wrap(err, "sender") + } + contractAddr, err := sdk.AccAddressFromBech32(msg.Contract) + if err != nil { + return nil, sdkerrors.Wrap(err, "admin") + } + data, err := k.Execute(ctx, contractAddr, senderAddr, msg.Msg, msg.Funds) + if err != nil { + return nil, err + } + + return &sdk.Result{ + Data: data, + Events: ctx.EventManager().Events().ToABCIEvents(), + }, nil +} + +func RandomAccountAddress(_ testing.TB) sdk.AccAddress { + _, _, addr := keyPubAddr() + return addr +} + +// DeterministicAccountAddress creates a test address with v repeated to valid address size +func DeterministicAccountAddress(_ testing.TB, v byte) sdk.AccAddress { + return bytes.Repeat([]byte{v}, address.Len) +} + +func RandomBech32AccountAddress(t testing.TB) string { + return RandomAccountAddress(t).String() +} + +type ExampleContract struct { + InitialAmount sdk.Coins + Creator crypto.PrivKey + CreatorAddr sdk.AccAddress + CodeID uint64 + Checksum []byte +} + +func StoreHackatomExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleContract { + return StoreExampleContract(t, ctx, keepers, "./testdata/hackatom.wasm") +} + +func StoreBurnerExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleContract { + return StoreExampleContract(t, ctx, keepers, "./testdata/burner.wasm") +} + +func StoreIBCReflectContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleContract { + return StoreExampleContract(t, ctx, keepers, "./testdata/ibc_reflect.wasm") +} + +func StoreReflectContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleContract { + return StoreExampleContract(t, ctx, keepers, "./testdata/reflect.wasm") +} + +func StoreExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers, wasmFile string) ExampleContract { + anyAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)) + creator, _, creatorAddr := keyPubAddr() + fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, creatorAddr, anyAmount) + + wasmCode, err := os.ReadFile(wasmFile) + require.NoError(t, err) + + codeID, _, err := keepers.ContractKeeper.Create(ctx, creatorAddr, wasmCode, nil) + require.NoError(t, err) + hash := keepers.WasmKeeper.GetCodeInfo(ctx, codeID).CodeHash + return ExampleContract{anyAmount, creator, creatorAddr, codeID, hash} +} + +var wasmIdent = []byte("\x00\x61\x73\x6D") + +type ExampleContractInstance struct { + ExampleContract + Contract sdk.AccAddress +} + +// SeedNewContractInstance sets the mock wasmerEngine in keeper and calls store + instantiate to init the contract's metadata +func SeedNewContractInstance(t testing.TB, ctx sdk.Context, keepers TestKeepers, mock types.WasmerEngine) ExampleContractInstance { + t.Helper() + exampleContract := StoreRandomContract(t, ctx, keepers, mock) + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, exampleContract.CodeID, exampleContract.CreatorAddr, exampleContract.CreatorAddr, []byte(`{}`), "", nil) + require.NoError(t, err) + return ExampleContractInstance{ + ExampleContract: exampleContract, + Contract: contractAddr, + } +} + +// StoreRandomContract sets the mock wasmerEngine in keeper and calls store +func StoreRandomContract(t testing.TB, ctx sdk.Context, keepers TestKeepers, mock types.WasmerEngine) ExampleContract { + return StoreRandomContractWithAccessConfig(t, ctx, keepers, mock, nil) +} + +func StoreRandomContractWithAccessConfig( + t testing.TB, ctx sdk.Context, + keepers TestKeepers, + mock types.WasmerEngine, + cfg *types.AccessConfig, +) ExampleContract { + t.Helper() + anyAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)) + creator, _, creatorAddr := keyPubAddr() + fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, creatorAddr, anyAmount) + keepers.WasmKeeper.wasmVM = mock + wasmCode := append(wasmIdent, rand.Bytes(10)...) //nolint:gocritic + codeID, checksum, err := keepers.ContractKeeper.Create(ctx, creatorAddr, wasmCode, cfg) + require.NoError(t, err) + exampleContract := ExampleContract{InitialAmount: anyAmount, Creator: creator, CreatorAddr: creatorAddr, CodeID: codeID, Checksum: checksum} + return exampleContract +} + +type HackatomExampleInstance struct { + ExampleContract + Contract sdk.AccAddress + Verifier crypto.PrivKey + VerifierAddr sdk.AccAddress + Beneficiary crypto.PrivKey + BeneficiaryAddr sdk.AccAddress + Label string + Deposit sdk.Coins +} + +// InstantiateHackatomExampleContract load and instantiate the "./testdata/hackatom.wasm" contract +func InstantiateHackatomExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) HackatomExampleInstance { + contract := StoreHackatomExampleContract(t, ctx, keepers) + + verifier, _, verifierAddr := keyPubAddr() + fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, verifierAddr, contract.InitialAmount) + + beneficiary, _, beneficiaryAddr := keyPubAddr() + initMsgBz := HackatomExampleInitMsg{ + Verifier: verifierAddr, + Beneficiary: beneficiaryAddr, + }.GetBytes(t) + initialAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) + + adminAddr := contract.CreatorAddr + label := "demo contract to query" + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, contract.CodeID, contract.CreatorAddr, adminAddr, initMsgBz, label, initialAmount) + require.NoError(t, err) + return HackatomExampleInstance{ + ExampleContract: contract, + Contract: contractAddr, + Verifier: verifier, + VerifierAddr: verifierAddr, + Beneficiary: beneficiary, + BeneficiaryAddr: beneficiaryAddr, + Label: label, + Deposit: initialAmount, + } +} + +type ExampleInstance struct { + ExampleContract + Contract sdk.AccAddress + Label string + Deposit sdk.Coins +} + +// InstantiateReflectExampleContract load and instantiate the "./testdata/reflect.wasm" contract +func InstantiateReflectExampleContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) ExampleInstance { + example := StoreReflectContract(t, ctx, keepers) + initialAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 100)) + label := "demo contract to query" + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, example.CodeID, example.CreatorAddr, example.CreatorAddr, []byte("{}"), label, initialAmount) + + require.NoError(t, err) + return ExampleInstance{ + ExampleContract: example, + Contract: contractAddr, + Label: label, + Deposit: initialAmount, + } +} + +type HackatomExampleInitMsg struct { + Verifier sdk.AccAddress `json:"verifier"` + Beneficiary sdk.AccAddress `json:"beneficiary"` +} + +func (m HackatomExampleInitMsg) GetBytes(t testing.TB) []byte { + initMsgBz, err := json.Marshal(m) + require.NoError(t, err) + return initMsgBz +} + +type IBCReflectExampleInstance struct { + Contract sdk.AccAddress + Admin sdk.AccAddress + CodeID uint64 + ReflectCodeID uint64 +} + +// InstantiateIBCReflectContract load and instantiate the "./testdata/ibc_reflect.wasm" contract +func InstantiateIBCReflectContract(t testing.TB, ctx sdk.Context, keepers TestKeepers) IBCReflectExampleInstance { + reflectID := StoreReflectContract(t, ctx, keepers).CodeID + ibcReflectID := StoreIBCReflectContract(t, ctx, keepers).CodeID + + initMsgBz := IBCReflectInitMsg{ + ReflectCodeID: reflectID, + }.GetBytes(t) + adminAddr := RandomAccountAddress(t) + + contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, ibcReflectID, adminAddr, adminAddr, initMsgBz, "ibc-reflect-factory", nil) + require.NoError(t, err) + return IBCReflectExampleInstance{ + Admin: adminAddr, + Contract: contractAddr, + CodeID: ibcReflectID, + ReflectCodeID: reflectID, + } +} + +type IBCReflectInitMsg struct { + ReflectCodeID uint64 `json:"reflect_code_id"` +} + +func (m IBCReflectInitMsg) GetBytes(t testing.TB) []byte { + initMsgBz, err := json.Marshal(m) + require.NoError(t, err) + return initMsgBz +} + +type BurnerExampleInitMsg struct { + Payout sdk.AccAddress `json:"payout"` +} + +func (m BurnerExampleInitMsg) GetBytes(t testing.TB) []byte { + initMsgBz, err := json.Marshal(m) + require.NoError(t, err) + return initMsgBz +} + +func fundAccounts(t testing.TB, ctx sdk.Context, am authkeeper.AccountKeeper, bank bankkeeper.Keeper, addr sdk.AccAddress, coins sdk.Coins) { + acc := am.NewAccountWithAddress(ctx, addr) + am.SetAccount(ctx, acc) + NewTestFaucet(t, ctx, bank, minttypes.ModuleName, coins...).Fund(ctx, addr, coins...) +} + +var keyCounter uint64 + +// we need to make this deterministic (same every test run), as encoded address size and thus gas cost, +// depends on the actual bytes (due to ugly CanonicalAddress encoding) +func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) { + keyCounter++ + seed := make([]byte, 8) + binary.BigEndian.PutUint64(seed, keyCounter) + + key := ed25519.GenPrivKeyFromSecret(seed) + pub := key.PubKey() + addr := sdk.AccAddress(pub.Address()) + return key, pub, addr +} diff --git a/x/wasm/keeper/test_fuzz.go b/x/wasm/keeper/test_fuzz.go new file mode 100644 index 00000000..cca94eb7 --- /dev/null +++ b/x/wasm/keeper/test_fuzz.go @@ -0,0 +1,76 @@ +package keeper + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" + fuzz "github.com/google/gofuzz" + tmBytes "github.com/tendermint/tendermint/libs/bytes" + + "github.com/cerc-io/laconicd/x/wasm/types" +) + +var ModelFuzzers = []interface{}{FuzzAddr, FuzzAddrString, FuzzAbsoluteTxPosition, FuzzContractInfo, FuzzStateModel, FuzzAccessType, FuzzAccessConfig, FuzzContractCodeHistory} + +func FuzzAddr(m *sdk.AccAddress, c fuzz.Continue) { + *m = make([]byte, 20) + c.Read(*m) +} + +func FuzzAddrString(m *string, c fuzz.Continue) { + var x sdk.AccAddress + FuzzAddr(&x, c) + *m = x.String() +} + +func FuzzAbsoluteTxPosition(m *types.AbsoluteTxPosition, c fuzz.Continue) { + m.BlockHeight = c.RandUint64() + m.TxIndex = c.RandUint64() +} + +func FuzzContractInfo(m *types.ContractInfo, c fuzz.Continue) { + m.CodeID = c.RandUint64() + FuzzAddrString(&m.Creator, c) + FuzzAddrString(&m.Admin, c) + m.Label = c.RandString() + c.Fuzz(&m.Created) +} + +func FuzzContractCodeHistory(m *types.ContractCodeHistoryEntry, c fuzz.Continue) { + const maxMsgSize = 128 + m.CodeID = c.RandUint64() + msg := make([]byte, c.RandUint64()%maxMsgSize) + c.Read(msg) + var err error + if m.Msg, err = json.Marshal(msg); err != nil { + panic(err) + } + c.Fuzz(&m.Updated) + m.Operation = types.AllCodeHistoryTypes[c.Int()%len(types.AllCodeHistoryTypes)] +} + +func FuzzStateModel(m *types.Model, c fuzz.Continue) { + m.Key = tmBytes.HexBytes(c.RandString()) + if len(m.Key) == 0 { + m.Key = tmBytes.HexBytes("non empty key") + } + c.Fuzz(&m.Value) +} + +func FuzzAccessType(m *types.AccessType, c fuzz.Continue) { + pos := c.Int() % len(types.AllAccessTypes) + for _, v := range types.AllAccessTypes { + if pos == 0 { + *m = v + return + } + pos-- + } +} + +func FuzzAccessConfig(m *types.AccessConfig, c fuzz.Continue) { + FuzzAccessType(&m.Permission, c) + var add sdk.AccAddress + FuzzAddr(&add, c) + *m = m.Permission.With(add) +} diff --git a/x/wasm/keeper/testdata/broken_crc.gzip b/x/wasm/keeper/testdata/broken_crc.gzip new file mode 100644 index 0000000000000000000000000000000000000000..378713e2ff7a88e761305426258d73edfa5f9b4a GIT binary patch literal 809232 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

3m6q@~RYn(?_267q?0SfbxL*hGDn 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

i*cJgVZwQDe=E!#?c?_e>8xFw*1 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 z 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%0A!$FOEGbys&vO3)MGc{&XTA!bJ1lr24G>yP zmdP>nG5(bL+%ayt;u(*)nSscM)jK+wCMZcdpSx1MNn)-v|8Dj!?`0RSZq#3P0-q4) zVIfRz+SJ+%Gp2GMMFQN2;^G81hep|(S(M-}gU0pA;@dfYBRr3(`tD9O2Hm&L+qHVv z*~z5RRzvEBTU4+&J2V;Z^UysqKk`?5Tct!KLsHK2Pg1O-7-jBdd9w$9qAz^+ahDml zm1xnj9$Z;Z>*rG<$M>*NPH!{EXXmK*$9Vlx8y1%scL*O3((U7>Rm@H#W(q%ReO86Q z1ef)*j*Tv0W)C3Gd2%o#3aAfqfGb}YYz9qwsu}E5J-DK2^xQ}0qObNWR62PN^pEjX z$V(?>aj0>pveQl{^#f^L!?qoc)jg@lwyVzamZew=CA3hw6(ezVMifOWz1IH>XW!$M zqnpAjW=6**~L0mwNeG+_;s; z5}-ADP;*6DKyB+I9S!xBV5NY3#Klse+7n1-I7#tTdPBEC6f{Zs!u(~StM0=vqFe8+ z0s56~4yjSXP2rqf{!L)r18$^#NW-BQ&YfiStTdS$1IqlA=7=2HC$@E|`U$VtV-r?Y zHf7fJ&z*%2hW4;;#Y#k|B{w6a1BuCL&8!H65=kbWKnwswg7WX;{}5L|sY>C3!?Q8b>ej**-{k;IrID z4UcuV3C-5WI`d+EvTecSgDsmiuWCX~{94ptVa%tOJspT>~taO@9VB z#Dx^24#7m0m2c3iHXkMNQS`PD+eCMn*)*Zfq4catyG0QZ!^%>21kNmz`uHP@%R=lx z8oTkONQ__k;m9Kk$BKa>sgz-lE#jLo|DC_lJVQ*-0$mQv*`vBCZ#2uwe#e^c1z5mM&yd;Sv%|cc_#a_{! zwH7OZTOp_|$pN|7m6k0(ozU5l-ISp{PwduW$|_v|RiWits<|KB#*u{w5#*C- zz>nVvHyK%QOwWZ2{XDwEicbK=tX_sP;-!?o~~srh!1gM?I#D)V0%J&NRffpx5WaSojSf5DP?m{5=R$GW_|| zy)DtIQsp%tg?b@xp=E|4N(Sm$e!*O+f%^r@Onyi?Y@K zJb4Hea$QQX%55Zl3>R$ozu?_9Z)~8|D5dmL-J4d9LGKY_d$75pXAmSsj*{iIm|;|0 zlMX-)q8#K1zj;|A+p8HUbhnpdpAQXR8Z>X=%=)|G2ZW32#efVi0Sr9oH@ZTe1Rz=~Kig9rNz) zsDzBky)&|oo?6| z>}MvufXZkskqI$59%NDP+rR zV&2*mVo$<7LZ8#?llE3 z*l1nf9FluReT%6y{l62U<2p3DnFP;=59Cc1Qr8^>Y_lOn;)TLzqn z5Uy!A4B(M0kCG>8MEo#(J1jMTdEesJNX)dv!1gR{(N#I=VS!7ekw6E^$&Yq{3I?vM zx%10zA0fb_aUj~Ln_;%OSUq@HGQ0Zpsysr#ThRjl4-PWe7*EiItJZuWbp7}koM7!_ z5!?miM|H?h+LI<$1!Thg`t~U2`z1Y^Dv=A+Mma7J<$f63WA(mgaZl2DIt9TR1g%|+ z&{9a;9DS;Eo}?PmUUzGs7xD|a2h@zqK^-%mG-g6m3ENyVhi3Bd)Obz(PL8c~GA7?g z0Ckvyi1@49;$9_=|D0wVc^5@)hNG#2nRxz+FsdzrUY`Xib=)%{9V;y~X<>!!b6f52 zfb}zZAb{Z?e@QF{R1~(*Yr6?N`TgbVt=tWM!Mi^VJV4pdVPA&t-?|%1Fn?!)EStD1 z7UL$xE)%ysyckMpKXJOHkPAq9{J+x=V^hh#0#uL*^WcDY3x=v zlWUe`z;V>7Fo*27!S?s&lM-L?qpiV@@d|I|1h`5U86F5aul})0{p<~$#bP}GIF=kX zNX;xbm!7_#N>}Uz2TA+a);`6Cw%60>?WsZN8C5W3tBx{Ii6WJM=+RtV?m$b|p1NRN zT%9EjtS5KTG2Q``Fwi z_+wfNKD>VVS8Ea9w|y{ko+tV2yOAm*WzCD$k~utqPBo}`F?yO`+>%fL(u{1WPeypX z5>e2X3J|QYA^H%Auz2UHElapWZ)D#Vs%#^h7o14b^sXfKUJ*_lk}BGrIC~*=@Dx7aUus=BBgmK5=tUH@#nMOop2BgZoo?7BPAKb9pShLsX??qlf^Fw- z5y_-az7YJhx<$kpycJ=VQ+oj&{GzO3obHpRs$ExfHMIcN>R#OW4PBt00{Z)F0RRUv ze?W#qM6w|eFTxIN5tb``<8Ed9HDgwwO-q|ODuk$FBio?dfpORX5tog!3$$D=IDd;} zQ8gDRv%ibQ9~bGFp2b{H(pb2N?^X9vj2)Jx>vvvi0tx@^-NwvkjIkSTl4iysQ&M!% zJjOYpE6DwSkZ&NH^z0r5G+8D=Rq3;m*^zDXrd1#4YZFh}8w9IppN^ucnM;Wwf)O9| z=a49%eA2T;4?Rz}XBVgy*x4g6wwIwvRy-RSk*TlBG;WWHEMc+Ht{s-< z<8(4|GHLuOrq|YnJ2I@%fY0+-vEJ(w&B@EH1`r@7inlNIYk37TPpJFDS*hXl2=Nd2 z|IHUwl-E2c1M@&9$UvcB9|;L2hRYmfP!3C`43B9-Va##_i4|Z#Y_iAC6WV_Sw15TF z6&B>SD*g)Q5Ck=7(wnq}!eq7$G$H}^7(OQ-qj6~$3F1t#U6Lc;s$3uBUfiKpK_h9% z1<_kh>mWu%gWo4RN8uTd1I>KzyGzgm&rWgDLHUlXIlj2l%ds|WZK}HR%F!Cjx8gZ; zOUp+4BjJsYL&aoVd6)E`1kj{{3KWv5c*OohfN*W~2lJM>>&t2$4NAfvcIJP2ODZ}} zZS9@2Iox2j@C}UH>FRHl>;mWBo-9?hRu}TJUJ$veeKE;#>L&Ok_)nIbpOgE#SgC#9 zE#sam9GnpUG>_f-O>K*e(Q{@ECU5{pK)Ao#t2bpj9FFqgla<^LMEJlmf>No)CC)H9 z%lP`8qgPK^k2!BcB#qTW07*c$zcK5y)(Ugt!#M}{2ZX>bgV@W>2B%30lb9w&J45Wj zE+nZp4`7L}rqEyj+Ju~l0l5vsOJTjIrR`I^&)z5B1=?G$J_8l6_2o7PkE#Z);ex~? z@+o(ILXgKIYqrPRt)Wg_5K6%ruL8^@d-eW0;`q)Q3Vf%4F? z5Kmhv`0F#!eR>46WcQ4N!R$aBF^$xc;EbVtPpvTI@|DeN{obna8;Jn@I-mmFUsB+b z)9O&;jsu$Sin<3<7&s&^C;pc)5vtWS6wlAOWNK0QH?qm*O9;bZFc6ES3IrF_P;PZb zAiW?(_o1udd+|!<83A7Mr%BQzDRENgrYeG=CBNE!fp1qwQKJ=+fwnK<;4@4PTTT;ZgG-W4B~Eo1oa9I&#YU(g zccDHB#DPU^3uPG>mV)tr-#rT&0>Zy>o5NSqrsCef=IxP+_iB*`cyI|RUtV3~HpUI# z*stwiHEGL40>8KG8dRe?wo+CqfMYi`FOyrzy`S7+LfBt=0x}3N*dAlKQZj1OheK@4 zvqX9?FI?@CqzD$eUWi0#o%CqK!vnS8%RG!tE(dt}EDXiDpKl8(Zc?liixHP7xCQ^~ zR1l`-lr5L=NG5eTfVib6fHAkFe^*S%yVYn&ds1E%jr%C?MM2+@WBat^_qc3!XErCy z0KCGobtj318r4(9NWg~bbt}p(pDx{TnI|T)8p!~X(?lGT!3b4=rciwjr{TL(4k*oE z{!P$I;)Dkem_P0@BTUV1ul()?1IzS9;=C?lJr3wy2((&kUae7Z!&xEMq?JU#%aird7Fw){HlSj*b zVHvIOoR83y+l=NHO-Mqr>kzGlIU)@@zd=o)Ld8vHtHVB(iD~Q1{8m~j$H|a12jUJ0 z>VHxqO2>j{cY-NICiBF;!Uq$z(P)ut(B~|Tk`VM#1Zi^}lf!J>NX*_2VF~f>GSb;- z4LRnPZKz_bkC&H|-U*nbq;SywWbAGdZ4h#;;>t{J15pyIRR z26reD!vCguz%LZyGu(erqW9$3B{%*q@?$@FlH)<;c#m6)yZmZA7E!nPWo6;)ubZ-Y z>dQ~e-eS!zq-lR`S@N>tFKBZu)exoU^730P7UB~ZmxkE6H!X@m9m%`(j{PZJ#47ah8GguzFgVn`W|VUNRBwQ zikHE7&2$5tlG`Yw?ChUCAXCV^ylZ&J6(D4(4rzR0ko-|th~im%!B1{Liv8vT@nC9K zwRoo#{#CnR3GMvXBTbWHOlo~08TJQ({kL$N_aXwjqI$y}eq3hA79yObH&iQiO!+~Z zk+wIm`A8dLL8~$>Pc&HJ1xD6)ZZ1Lp(|npnskKAf`$I;E<1klfb-v)3LQ3MGWmNL$ z0$E`)U6aQih)cepxFWjzEcE?F!@?yU7MD8Lm$(KVsEB7j&HT{8-c}-^CJ2S85nbS2 zBz_afE)YN_=9Ifa3GrZSVxF6;*Kf-wVIjy~^V~o|01bbqR4Ap2SHyN9 zdz*igAL^h(1XP3#TxP{-Gz0AwY3nKm>@#kR9z}rD`?vT;!nU-YU)|UK@cHbKshW$R z0Hux(DW;t!u9^?LYOLic|0zsJ*_1BocZ?=*xQ*9MeB*aSei}fx9>Y|PN`3X6VFj{@ zz?l*DbQcjwH={}NnoPoS>|_E1C}qx2d&fu1Y%7Pc)Ag|2+ygDsT=MxO?g!Q3XiqEw zl-TAZr9kG+(C0>p{30yC>Yi~t@s*!lDpAHV0=Mw*q7v=1Bm7r+-I0KSvkI^}+jcMK z0IxdVqzp~ONlnL?uSNKH#{cD_b@|Rs~2OJ_&3v{R7 zy?n1LBoL`;G%-yM)@xDeLu8MU1av$4Q8PW$R z%*s99Lj&*u4kLqB1WFfP0X!UTcCyu58nS&@Aw`~V;*#^plsI&DbV09p7;>9mM(DM_ zV=^R7tmr;=Oib@FLA}r60=FhJ*p-(7==YCRMnnsum$`rqngP0*)ao0SNvf)IAEs>N2JmVy8?l-t1XZoj=ZQ^HdV@4!ay5Qf2<%vh7qH+!(i3XcCZ*3Kl ziC{323ckQ?#}JSGZoeM5U6(Fs3dS9K6FQL)jV}T`j;EX~01OE9l6l@JLtSv6{Vtsl zdwJbKf>y!%deCuiQXv2i?Ko5x#IDlC1q}5k{-)Tq`e|vhNYKwtJF8-N60{|d8S?QH z9Uz#8f}4wym~}kt=iCs!3k^}G!KyejwX$lzx-`7Ur%M}bnuVd|B@sz1rUo+M8Wfh& z4QTthwz)H&o*K|$o9PZ+SaaM`KlrsPpRtv`N`{~a%F5RSR-_*Mu8`Pem6&nLLCk8# z5)O6B^08v09fWpD``sfTAWzV**1Rje`R`{$k??!zork!`WWD#vB3!U9r(SoE8??tZ zV>Sx=;?p*=NB)KpUjS((gzSL(SY?`op4TZtNbQH7Z_VA;On!D^x5`iSDa3G+=a%u) zi!npLk|WM8btY2hX{u85&^bzbe4A5>)Q`ZpbM%P_KLu&sFeSCCETwOhs_E)EcueN3j7i_V>+Pd7{y*S7__KK?V2Xf_B7k>n%1%Ne3%oX**1^n(D7r+)CpqQ!G@?5PL&<0t-&_hyLie+^~0>DQW*(r zxOjtV)R#;*TpDpv#X4m7G8c99!Ru}d(mI;K^BoPwLh4Xop|@VFZ2%^ah!Wn(olLeZ za0R-y9v;Vug6q52?ZXhO;pTJfNWD(qWG=NNW}4^189X9d<}=gn8OjLW>N~N9jU0-n zj@$!0Kg6(JV0W$25_cW*6T!FfhRHurN{bjO3_TTe6W(9@&3vJ1u~C6rT|dGtQTl;J z1xl4399~X5p3oAv#;eYl*_Zc`!KzL*sAY6pt$HY|^3`kw*cf`~2(+L4lSBo$ebqfJ zZss%gY#XJkCHuW;d_eL3aIU`;o5Im$z76o|?IK)U!7Io>It=kzqJxf*M za(TxAAKePC*12G{;9*Xqc)U%&(XWL+tmU;|ww3^u*xIilMUJ|STVqnMm&5GLSh)Dl zQ=0TeO^T^BAu{PZ>&x;Q298cx6m5+NH}-@;kNir*RMU61eoF$ipSF%qZ|bfPgQApO zqEx}RLubwg#|nlcAQOEkl`gB z_2o~JO}1_JEhYd+75~DzHZYLBMn9#>cyNz0pe(q}%P^mWMnmS1f;)+pd?oFMyZ^da z=Wlb~ICCGhEEsd9L%I+`=h-;L^WcH@>O#h5$b~m2`Q%qF5rG##Bc_-)k^FOiP%ZhD z@V@M}(Mi_~lA%7D(>s0@5*t1!A#xjTmO@fVN0>p7iVXV;LuLDw_Spub5+XGS&j5YM zVPl#7CiSuqJDUdX%jZ7_s~ZOEn%ErT$*_U<(`aMbm#4Y z)Jx(O|5OjERjK+xqD9J8`W28~sRN>+P+HIS^`$>@z(~L56Y;AG<%t2XRj)cGP5p<* z|5;UB8a)b?)Z>!^Frc@WV8pihgEXjBNoklD{;qLz2l1`Eyw*KC$)77^w%4MkGL$|n zDa!DUzJo-v{uUQik46B2%8Qr)0{VNwxdTYbt96oI*7L!)Cf`EkqIl{lhk=yPzD_CS zB_2Z#w{4{PJ?~`VFAXIzWsLBZ;b3GwCeO~=|7;O_RCN+SUvKxmMr1LJu|$|D`5Mwb zU$#GLE3y2c>NGF5K9*Y=I!()g%`N{00 z?7|bVUs*9d+IDL-;#9|YFyYq-KH6TgBWt{I6L~O)=?B0q;0nHM=E+6}g(hR=amjF% z9sYbfp6Mws;|Hi~%tzrlRg8Yz5Uws|ZkYV-h8z<4WW#2kWv#sbz1fxPMZNuJ=JvswaRbfQj1*XR7aqY+p#Qw1^+|fXfiY066OF)4QQ}G z_Gmhx=+*cmdFJ~+Lh!hucqy%D?VN=3Y+jdY`H(?uT;T|aG6x~<7lPGho5?39M>MCj zV)rH@O}q!Pp8VeEqJna0nsSzB0X92J9|gz&{uYU7nxDdBdT?@x487+qrv5sd7}pQ+ zqfw9Np8dBq07>bnPJja@U$)>uMs=h% zwV(6j4dI(7J1ih^_2&j$u=KE#HlpJ6;XJIl6X!6-c?<-DfL~F-?Q&!ShS#A%%@u2w^*9TF* zo2U-x8iM<7!rA|WK1(qC%<9RBI9$6FM3Le4C`dU;*!6oRk6J-AnPl-rpnQrvKLc=C z)djLvoGTvw?;hEgYP1VPq$@x5nNE`gu#ln;Ol~M5fUu?scd>LWEv*B>Wu2^hu9pmt zG;kpnlXgR|`d7T)zjt!$9;{1W$9i+)qk4O^pYdcf9v&UYQZ$DA&jbrg_CG*>Wt}I`Wymq1LGV&?N~T@(pdf;eA8^2tdd2qz`IUvVp;o*RAvNPEUK@7=(i# z1J8&+qaYfT(aEk;%HvO6^w#6jPfdp>IfRn>j^mFTsVwA@;&{|g3v(g_M|=i6NKvV~ zhj&HR9Ia>$S!TI~2ou-6qn_8yhOERm(=1i4=jVun1bQpf0U@yp z%->aJgbY(cn?ZA0Z7nK6vmVj*m~Uw^`*vyJ!9R2nn=M?nJKK)Kb);xkxwVLJVrKu6 z6n^Uk?s)HuQ7(~` zP6cHHIqoGFs90)o7}eO z3-bKPaXCHr<^_9nS?D$U$JQkty*R|w>A6Gh|!0s_2ch>Io+_?36cV%h41^0Wy6=OP- z^jTNg^c};s_3zI_SoQ#qX;6H zFnHB)Z}cf4!7AqyG;5FCBtdh3>%EK35yF%5JC!rLA}fzHlA?k6<(DYO@UX zFd0pMlgBdb%2)v4J@9L_qJ1(nc42(55WzqPo8suXX%n)xxKQiBa3B%PpdV?hg-g-5 zB9v#omxhs%7#T%!!+&%FZPf}pT7|bPjy3(;^l4T{O(ldjr_4u?@sI$#`Na|T<o`I-gE(?F zw?sT5A~*Z$YL3+@RULw_5;*zO@ZlX#O8wDynu1LFj6EKzRu=Q6zgkasMT$?b1b z^RU-kJIa^+kvd7?GbUBIc4Vj?2z)Um338Rf$<{~AP$|2f*xbwgm&I^;(FXHbADBaR z*(D^CjcTQHf|k$vG6moUgjYa zeG$+3xD_``3;yLL(Zs3C2&{n;2D4NNU*HZr`6sbt>Oj z?ss{{1Ga5~fPdt~1xb$Gl~9g~$t-t6f)qM+_LG>8{VbiOaxVSE1mpVM7cZ-5I*+)nH~H*CGD(F@MD0Nc}{!Jhx*aGgFbzJg(#RDhn2;Wi~$ zw~sG6h_8bL{#CMiP>=f@Zp-c;6%aWcr0El62xt%ggH{J934eWBHEaIuZfVSZ#cx>27nTDa zB);>cxBKBhvh#c1YXicT)}UQgIDY%(Z3r-9gQLA1zx;rO1Jw~cP{WZLJeWHNyK;73 zJ;0}oFQ+c=`_B1dwxsyGR;r61-v#rdL^vjdk(Z#G z#9n{&pTsf;r>p*CL)6rvE6Va=X|~^p(pF3S?39`5GhD!iFD`$xue3}%h_8SKIH+qQ>~(J(v<^UAqXT|-NX!wvxUz2F4eZ$|$S?HTlk z9&m!tmn3|Z)>C-`6_j&n(6+MHFp}Q3Td=o+Ddoea-W%7%>fC??1?A8>#JQ~v)7!t| z@_`@q(24r@$+-R4ClRA&WQfxS9@FR%k?8Kvs!mf=h_`Y2bFrWi33#D7eu93Dwr#n6 zM7_FqZ4Z@7ER#Fk4bAtY=_KxdoY0#drPV^nzVyAY1JPkLV8RIa1|_M&I-drMcz&d(b#mHxgZ}^`4;M9`;6NVv7Rt<6EWOI-Hw2ERa$E8IbKyPZ zleTfWax%5@hoZEwq@=8ngbYnt6A5q^<{P>B_h^gC7#z#fRAW^YlSJgPIobCP8ycKZ$2Q_i*k{XtL?zCJa-;uAwTa>MT~TzA&=$*4*A+yW&VnC!}Z`LJx9gWiPq|pNL*rDbPI`<5Xz;K-%4F z8+~~>bN@u$y#w$f2jL?qGOt4-4z@9fBAE{A09Yw%9xZF%c~<#7J`v42Wi-Ynqrylo zhzAZ(wYkTc=tt>u@iZ1&6NcK{oO*K0Z1Yz;|3v7CCns z6yJ(#)9mkW(3CvJT~;Hk-v1}>CO8TxwfPwQEwSqI#dzM= zUVTeg2UGx~2QX}#pyn1^_6knYGqk|UruHlg8g#)~EBLD@z8ns(bGnob6p;0N`1dGG z!!QNOSGABRZ%ER^?8A79Rt+V%7jXh(_0fdNB5`sL@?aNyMzk}^r7PJY z3;JI~D{I3nonIary#6WFZRlo0lNsm`A-M|*zAwnF27BydB8P4Q5DQ@6SP%&_A|4xS z1e~Gb%;Nt2#@6ZdGb=RS-rQg#`ML(6pl1vRFm+=x$XgKfu;J!=0HF1Q#;`QAlCS8)7tNvp^D0 zantltCM3`0Jycemk|?FE6u;8c!v|>dwN}p*OMZ_+DWgt7-=toP*C>mQ1j5mp8FK0^ zLe615Z>Af8O$#~ly8Ei9L}nDBQzs-}3=p%>4L+MN>CukV)Hpo!m_VZHPn9Pkf|;u+ z=6wYZZ#MYuy;23_F3k`Bm>wI|JdC(dcb*kHx&4UZ%Oeub*-*S}6vR+{K??Tm5+eyq=X6 zkpQ&~Pmp}CJ`F3&di9AmLKEdnkFh?o02bzOZvFVo$?=>!71;O#37(eqEgiy^=W`HW z$4;KR9H^!~YO^3b6F^*!5$8d^o!hSzl3BDtyitv~80PIxWqSH>@Cp+8*tX%nBMh~k zUV5dT9WOu9&Jeq*(pQ*f{jX_lSE}7bD}1s9p*T&+dm)VPouM6kj4SuejBjB+HUJN# zhI5;${#-}O_GTdl!bc7>^h z7>{=s{#+14-SpWypTqJT@`EKk;;x6OG(ZX`+Q@9(733FJfl-+4K9@ZX&2^x!>=Xl2_mWSUtcW=YAqJ=u0n5cBCeZOJie6$4ImP*FBwz zUs{GoShweYmCj6OVbZ!$H^trJzVxLnw#LvnfE9i(`RNAY@p$NZz^2pRf$Or4+oJPJFRE<08#UTxU<}lDBCSanREt|H22jM2AeB;K# zNXB!=uWt(ZZClHm#N-3xn~Zg9R9f z<_H{MwnN0$Hn{|)G&LCot{{y^WYpBMx8-!OEqvy)}faVfQRPz&D1NSTY z9DjFYlo>ArDD@WvCtJobMPFBc`zm-lbo;Z>5$D1M+StrOPw4}rmeefu>x6OfmsN@S zEK_&G{>+k;?1${nYhTTjHbG?MZ^Yi9(0N527OZdvR&}FK z8;?c_61QoVUOi7O(6AWj9(uieF0${dp}GMDmH$o&6egEb)A^- z99OSEzLjD-}4c34zNS5z2;e70(B;D8OY4v<(0EPrB%~v9AM+b z0gNis=fsBxOK5Xh@(ElKCOEzv0Q(lQPzFp;MqMl_u)5q1tg&*pt7Hn#i&YGf@H^Bk`fwn~BnsYx6M^>dbms&XAqJ*mEgt{oV=P{$028 z$N`5R{&0t7kO$9>qLmU2DuG1s6~<^4Ox&S3<#a9)t(@l6EGM`FvuFsAq~Qa}EEy}x z@`HJUotEBPq-nkcBSGjso>t!a$fY_?9g@X96lIZNDKnrA{NjV#eZ}YSsYbl`StiU_ z(25b*GFXI_%gkf!vA=u`JCSq58?T3AIj~kJwWw=}!uCm{NWFB?m(u9CW2YN>5-ZMf z!ok1VvP%7h8Wi=sn)LZ@$;w|09f;L0UMPeNTCe$T30TBawl=AJu{?InpraL=F~ZfnO#kHr5 zyc!YU1hJeea(h9bO;ay$@Lt+R^g1!U!h{O&P@t2m&r3k6+$?h?L zK7*O*42AZ-v%?WysEe(LObJC#kjmR%Y_m<*lm-~3s4>xG#_6$JIxdVE*{v$ ze=R|JnV<3O`EXYJAuDN$z+%-3MLi8KFs=gn6B^3jaj8{!Xy}kYv=C_2;GmO>Pf(^= zmSUBMG9fMsjNoo0VQYV!SAvB*`5@L+po9v3a4ewdD(lB!BYYkZC-q}w%`LxvvK{}B z6i_wNA>sw|LBs;Al5asy+IEirv&MYmCh~)!^U(OYOr)PBkpB-QtdEf8D6CELJ0C*M z3@+H^O_zP^+kV8#mi2{-$zkJdSDH28s6Hsk)m2=Pwz(3h^%-eTsHaFTAfGI)@x2e= zxsbx@OpND!Q&tH37DG)`9<3-Lh2K|voJRDBzqgPfMPZXK9s%bDREX{u5+fJDrOqQJDp@NA&FFrL)4gQ|j}4be=G9WC2|c~n*g$U+l#TAE!dw~s zS*gh0k?hHdQlZE-_GhNNVjq*~8!zAx=>Rukw3Gw}1;@712v6gXC7?uAhR96ll+N$R zj)>`I_D;}ZjVDyg`HG7=YJ|61^Zy9zgtE8LKe(axH!T12a*l=jqK$icS4(vz&n3Q# zb1g}?m87G#XN2DX1z2F;r?w~qss0?r%{b3eIYuDWE6MTWb)22bTH!;|fOZHZ-6^hl zVlJRxB5Q=|v3Czmyf4i~rWcho7~q&t5n~g4eIto7!!?pFa^cKNZ!_tx)GltdXFG&2 zH(1v*^{oEgQfmC+5ERRMx?A&zvyJfZLvmcWqeYKPbmbBDMZ_llB@{}Myl$^Df5@sG zd`i(kIu}{q(L@`IbmB+0Ug!S*SpAm3|3w=P=g>06RBs^iv?#)j`cDYS%k|6+>r%=| z2HlEITb|sti!@8`7*=|zYiP~N(yxntZMSt1@h}7Bac00;F@?)@aZ84Vl^GlLu6Mno z;w$?6OqkOm>Hj$$@Z$M(|03$5$UZo9Yb)72Gk+JuN7?o-Pf^Xz)^kv;h3@~&SWs}Q z&2YBP4vfq9WhCupC)`XN_AlNdQdHatGc304j&4`T6y=P>FK1^gtOBEJzDb3Vg-Mu^ zvt)yye$C#U3ZqjlFY#d4l~|}YIU^)dp-;OQb)=TM4C4q2BC1T(wPf+t9zON+7wz8y zuHUqH{qDa)s0U84yCofUEYai1_RHLVLT|f0BF6mzppAFv2?iC^8`~rkt6;i*E5#&} ztEn3R;;bAdqzXlTWtM#S6&~^luzsFWW>)_orsWPbvkRjVx`LWi^7IIRQ@&p_79mE&Qqo)qfi zTmT*4UCO^?+8AyB!}Us7&}ETjgVK33jIN%4JST?_cn}Ty7)QRKl-PvViaJY=(M1pF zv$$ykZvQlJ*NlB1(*q>vL+L{l3k^>BGzJM`o2=M-X=uvbL{8=X{~m-E5I+%3)cE4= zi8-ST2XYCJymx+E#-eiQGcVK@*>|bT+K{@b09!uPJ??p15+|nVj@g5?W_GgXn*CT% zw$FV|oh4e>;d^m^F#Sne_)urevEguAt#jWqrAZ54$r2flds_9KgAR6G{Z*}VkjnVyk+sm8ZK!=%SsC85&q z^UAYeuVBh|31NK*orFYFd1Zh}=%CPAxqd00l`oFrR}+)izi=l=G+oJK9Ub~cIRUn+ ziE@4FjehF=S+(R-FQgJ10{G{|gkvZ*6CEB3@r^tI^2Nh_m{shyUtUPbeh7HE%umYe+jGQ%nPrp= z%EFrpX8v{R`Br-vaUDg4*_OQl5E|u&0njR^NzarAVGe@}>FfPCK>t3cgI%O%T~Kgpo)et3vn;5yrE_Ch3~~=_Bb^ zB(S@(w!d?@#M?Ds2_16q``N#$uF=E6?b3W5k7;B^U1a3ThBJoAJ%skXdo099|8g(X zlcb})nbbr)nTE4l?2#XX-yS_xaEQ5s+TvFp2kr*2{d*)q(}L_SDAQZfWL?JEZlt+$ zyC##}_>giprvF#p3pJ*d{;G{j8-~4N3m*m*VWaw`P3$4@q~5q|E6Lvq867>Gh9|=s zw2snYHN9>W8=+B}8&qJ|P7UFkI{-ont%f0i>RsZ8WR|C&UKDlFX5?jo8AeIl=6y1> zKv3uS?GCb@RB`qyi!FVK!{rs#=u!hbj&Wf1I)x3nskjzlrabRBu7UP6^e4pYQDECsAns$MkdRpSqLuZK1o)t^dP}6AStEKuZ-FeCQz#H0&ikIF}D?u zG_`W)&fF$*Q}mJZKE&LUDEolhrSbXR9CmdR`iRsp_ZK3@pF_;CnGuzaIV~h}U5&*} zlnhgi-{|5fRetheyvAyqzEl>=Kl0d*zMGsSzovF{>qvV{xPN!9N+H zz1jt)k611~es-3U^kg#ti8R3;3tiQSD9?e6?40{}{O8=2CyM4cLoQQT)t=I2Q$t#E zX@{ReR$ZiAoC5hA-gd0y0h?Ik4?(W$h7lBqYZJ`>B*FMvKL&~w-YB6%y^X-OTQ{rP zs_5-Yx73FA*AFr>`d{NukO&RQJWI08&#J|hj%GH)k{hre-1S%U+ccVw{!B*xNebsh ztolD}YC?FKSAt|<4PL;F>WN2snwMQPAU_PIK@Ib*cOp&d89d+r4r4Sz-jXe6v$jAK z8<1d5EOu)$3miAvr}~|pqYVvSjcq*rzJdXgRbJc4R%5f6hB%&tq@)Nul#2e1$l0nn z70`$_z#(ah2;WchVTsrce--1d?De#DlCuCm%9lP}z2G_u|BOip29&y4kI#y0%1*?X7nGB8o7|6myK<$zumEm@qT_>b2o8>Q|DI?Z ztdcwx;d6L(aZjc)uF8!IU@oCL=y%y2E4(hC^X~IT(!H93p+!B?f>`VUcHJa|P5ca0 z-Ec_f!to{d_C9XLv!^Ng`FCg+!=%j5$cD~nSZ-S*)e@nVjsvKhF-#C=5ks$1tB&pd zkR{z5`v*^r8LS<_s;xX&>`Mm})YNf4I>pSdR9SC6Op%K$*_|E+!B&`?=Lx)OZ<&Z% zzClrq?6;w2onH9W&L$!n>iDPILI8h4YGVaZNEEK8Y7`sm!U@}^vV%jdq;tW2#`I4l z8d#cX|9f*A)HyA`I~jjWU5|B04d*;}9G~I_SjZ_1#g%-Hr6npARWf^xug~ulJC3H1 zO)ZS;#cu!Z^_-yAXs@>Ewy>N>kH2Kl?S!0jz0^cy7AbaUR`i9oF@Sso@mH&ED3a2X zU7)8SfG~nEodYv0T%L|~%xHEG(*>wC7qbSL9y}(^0qx#rt&H_2Z>f9-3_}=M^~IwD zjeiL&?&F=J;O()`E6|k-HVzDDljU>|!*@1-G`nT+tyxGUsiN-?>cdp^O$9iSsUPW# zFZ*p37fX*5nq0OtY%w%A9>5nL&W1R>aMr@aSeR*jQbfvG;;gKJ;Z*th8$s`{%7{Gs zsIZq!$TVo1@YbK1OAuOQqaja2t1-9sjp4$yKI|=Zy0zHDoC}@@^CBFZb-vybaPf+| zwp|gW4WQ^T7+3H+mBZs(B0GS4aFM}dotjpHeciZw(li?A()-+?^weLvuI@J{pI9Eh z6a4u@%2UEmb=ZBUb9_2svP$s7sQ8D=o^JgAZOwjpNcMxed7M|Zn*4vWbQ`>- z^Xb2la+Pm5Y)|72S%M@eOjxhjbxQ&kxbTGQ%;y;_=*Wysf0k2yE(WW~MH?Ro_aD)Q zOY4Zwi8T+m_03>Y-Xm=m3@iK!!X*BQmO#Hsoe7(7|NPc^$4p13r5NKOd-5K%g@5Uy zgCxuD?LTk<%OVmJxpKB;BCzfoLuB02dMZ^@rV;teGC0gm(7_+Sw)Ria_7e?Z$1-N` zcSJH7yQZaT^ZF$IDS9_^yuQMvI66TZO~jP#cUu;j3(MF43xfoAXgv4<;hMr2yDd0bZ4X+N?==(0WacZ_ zu0#t>&C$axjdrox#MXQI{4A;RC(+i=m(Ll*b(ofLUo)jG%AnLFw-R2jxih|z+cfSE zIT7Q9R~8ujE#T#NAOZfKj`q}~{-Zu84dIs^%-JJhzbU^U?Fb1k(gJZs0*5)`L&iawlMF?i^)a`^Qb>WC zXB+@pTyr~JK>+5CeZ{<#!#b|OqBc+Q;D(z>(s}B1T&k|RJCSlKSK*j}gFlYK3U%!i zSxu1L&xXC5S!e>`keXK1Y?=GztDY#$bU|81wnh@DGUHpsB{0{Fw?(x%uvQ0&S3?_T zb_jBp%>#x0nFRtZWtr9)n5mO)Zz%2oMy)vF0T}R;MMsg5PPEh_Hc{}< zyY+9Sr7?BjgjSX4#mS6!(f*x40pEVsFLXR=Jj_G5Y{SAnko#2)V{)ITrjE&O|6$Ei zad9GfAW2LjiRuOmwR50!H`#OiwJ0vWBO;wGWz5YAOz8ftqHZlFQVT{&y({kn5aWcS zP6!phQ{+$Dnre00j3ngx3R@}i(F4&M!s%s^U{TPh$WZ|SO1q^4Cp87^!y#5UeR9cr zomG+mgq0TG{3&l9@e;E@%#?CBA^#MRLq1~iSM0K<+=sv}HsUGvghUZ`M2{RFcSK&8EKIqq7V zk@;3Otbd<{W=rN&O+j_-9Hb%}--L@!D^uPS`6x>XG_IP29H|9GISGNIsAV&gRvvUv z8-JE>C}r+9lBEb=OM&0ei%x>LR3F4(CB&ev%rSABqArTWsMMBfj*4xagV4wu!vPOn zcMli?M>oZDVS6$7I|}K)2j|>w2x{j9zfbsJ{jtHb4=$)_3k)WS4n&Gf7@++i#L-H? zV4!{~%SWaRDO*)r=?Zm~0{Txlo|%>f_L#CJ;SqZur`oe53A1Jvro`620p|rsbw-Vf zv8V5>5vK>o&1%*p7hw-I>@gl6`gJL|8+tBa9SOi)3sJ#v-z<#zg5Vh0inKDVHVTLb z4*YJ}KCipzQJUh{z6S0`OsA}Dz)#wpgu478uSbJ-Vjux#^tiyH9pnv89~Z!(7ZL|b zclz5)k#76%Lp{)#HaSj+;$9}uGv->B z@%-M;t=S7u{_z;^eI^w057r-&TRJcYJph0JImzvrwrmBhFyE9{pq1SF6%jz;7N;Z5W{Q2 z17$yjHt{*Z2#*jjvgd)-dilr~J%2ZvgQfZ6bL7>_51}lAY^v^$G^{o3-c@LwX#kBt}q#Bj0C)aKr(Q`Mw0ta(& zBMECyn^M9ee&(wl4tE>?!mbR=c|OJP`^Oa%(H^zH>mjNEqMQo#9`dZp&ZxX|t!Bf( z2i)Z{b|gkg6s%D-*!<~3C`D96IGwO}eO~?`%5MxVq-Mo#T=3nYtYN14aV#WFr2h~? zMkcUu*Ijpt9LcE^x|Hl|dz5IHtX_ltc7F={&?>gq!T+b+C&~fXKX*nzGI|J|tJH%+ z#n73BB#wuIjZ{ICr&G$iY5;x{;KeIZkUdYwqXnqLrljfQDh2&21auB{;>E1k{KgY| zCmx5^4vwe#mN+qulLU7btbDt$&$Wic3)3yMq5U*+jXqjQrn@KzuoUQJDnk@}+*Ds# zKF9%L<3x*?Xo%VudPFEtz9vWENK(RZg`;arGc;m1E8tC^brfKObGJdk`_hGJDt@nt zLvyh+Dk{c(GTFO@&hw?LNbt%vyVfc1=6$AfOXeO!oY!Sw1k5Xh>9g4BY!K$ksRGfC z;l}{-=p+s)?Y_G-LOjRplU%WM-r!$Py2@{Yp&{ST>^o%09{)Bw^j(~DpEh7*)aA-} zf%5@(@ZdNewSxQXY2M9cK3fitx4^B+wTGcn|GMTXK39Rx3HHPrf5k9T+MRY+zzjR);6#MxxB*8|i|XX~7)=*y_RQx+*88Lq?fO@h6{^af z0dpnC?nfU%^i|8&{on0Qb@^>D_vNmZsEy#GAL7LS*t9Bpz159aRA5ZIxflymy-h{@ zzvT;S$g4Gu+uS4EjA9_MFal%y**(5hQ|=N}=oA$%GR`}JYq3gSgMF#Ah1tiL#lv2#?OkrUyJ(a!+nK~_R+U=A zH5S{fW*>&145s}A@~wATM*m2Bq|pxBbHyM`h2|1UPN6zJ(Bd|I4}^lNJ0`_Lv33% zbzLn;hdeC8fA=oXoZpAK=e;D;3k=m3SxzoX*_s+j7I;VQ^&YKw%V&2RH9S5UIf0+% zIJ{PKTo1MYYYndRTKhi-OnijS4j`ct4K*klo)HmlegAQO18g*w8_BfKd%dL}IW_oQ zn-=oOyzle@=68AgJtef2G{le*kU_B%IPB}Hs)4Q+7`t1Mr7!zU!BAE_ODj#k)ZSXR zQDiq_iTr`uKx`wosGsdcFHe(BFb~2HEM~G7C8HCy2K_T;ssMnZ8Yj?DV^^yi47{Fs=c&OlsGbff-I?_!>V8z& zim!PY4b-=e)7wbu+Aw{O=5P*hWQxYWblN1YNH>SM#tLu&N|_1&$f*O9=})jj9Fw9( zbJDZyU7)01My-6B+}F*VYAMGv?nh%K?+N5^MAON6vYf&ftxltewm8(U;8DmRwtk5K zNkF#05!cqy&O%CX_G$HT}Yb~USG&`KJ$OHFldO<<=HWCe0{FSOmzEODD@jAFx1HjxciXYnD*(w(; z?8Xs$B!*(-8^*|5gd{Qx2H}LlTs^3qUQ^lgGX2a6+J_tK!EHZC2v}u41{fCBZ#;9M0e(Usqea@vbX!_tjP}&2NAS`Y6U|Sb-_6+A~33 zi|L8K2m-t7SL3ZMHolSH#(Dd&pt>UxQAp}w)^}Fpv#O-q7rK^F4>7M2V2h13yzh_* z=MmlQ;Zj-1Mu_j_7CfiuxYQBiy>IoDvq89o(xcL~kwvt!vZt=2&KsN2_!5J9+AU2K zq6&H@oCy|D^(u+q>LE1&d0FRNMBV1HuH>niHzKY*skmSP7Ci~UV((pr&Yta>>sJKD;<_LWqA^zw(zd5ymvlq*Vt2Y++KpJ_JF{__MPqmnKgDlAVD~xbtgNcaESaK&zf8 zsCHTXL>TiQDJ}AtUPX1lW5a0cKX)T-2vY^pxUw(>)}9uhT9MK4bEUM<<2n%Oz1DP( zyWOu!EXUOXgu|shA8IdVWsGVq(1@3ll;wfHi@)MABqac70CrVZY=SqZc_x{OcS9#L zQ0K|Yh@AvzW9EDj_JEFl!9{)%pYqi$0M-LtcKR5aNK1=Q?0@nk7pCLt9K$|ha6%r9 zAeDsk1x9!4O6k0lUTzO4`}pMhhj;OFS%x_?3(`HGwlxoS%p9hn7Psz}2h-G8oAR-z zW!WfdBf}P?anAQ!qMH^*L4Y2gEYM0CBS!kE+`K)QOSL=oh&pr7R9Xi#SN$%WRQDxt z&AT{?fkYfMM`5j-^A|v4o#?GdmDKdsjPZ2U&W2E7nAHm#<@BMf(VE-|I1nzH`!{hE zj}fQ=GNXeM?zJ#A@Qu64>d>qh(#)H?yS>oW$TD!Z)9TUcO)Scc-GEAO^J+NywuwgY zc-s1-!iW)_%%l>$les42&E;7Ap?pQxPbsAnZ0%Q89Q;W$=OwZ7>yrCHc7h$=Sj1r$8ftC*C>+T{0}|UV7}ER)dl=dCsNx1W)llRTiZ8+HMyVyd2jM|UGWnX zK;c?vacazKEePTwbMB_<%h%hpil&54k(0t6yrL4~)R1t6XRW#jo2Xcvvh>)BI2;1% zfAqDp5nrmMEy8{i^-HS-b{@oiA3wpu%RAE*HA>)&6{P|E@^qoIpYo#_fVo&>n4)}p zCq<1mf*VVM1WtoZKs;;B7~XKsuW}rIDZ(j7g#HqsLu^t2zx$S4B@E6dhY3B*O-3f; z?mBs5q|>?cgWH3Paw@8XHoCr{c-Bo~pKqk!qP0zX7An1Qjddna3R z39BxTE1dLapK_RZ7h<6rzYv0OSis@2Ua3S45}C0%512{i$~ia}J1wUb)~N;w6K(zU zMWem^h?GPSWiTa#j6r`nB@P27X@m2PXJEX}xa*7J3WQONd4aJjsqptBszLr=*_fY` zXpV$aEobEc-^G=ixzEC+00KeWD(hlmhQ?kW;4cNW(^H$B3Rk+6W)r(hwhD%*R9$)s&`Tmnn4|BdM`wK3s)*g z(=ZlV@-2cOO&5cG!*0lI09oOq)LG=CNEywLK}y|Zt=n5or+`iO5cwDZ$Cclg7LH}O zTG@p%t?f4TWe`l8@tn_O(~lO|T(n`Ji2J%~oe53U^?uoup1WvEO*|+&pp}m8sjoon zw^(I_)3>5=?sgoQZ%|GL%`Lc_0`F3DgoS35 z=3Z*f>hhT2(K}f^QUoGrC zG8NxbV)RiUp~kbb-%4LWHQ#J8oaNIA?g_Y0cfFM5Uu#O<D$3>)MZ&*kVpc=S=@uuGxzFcNcV%B5>xDe>|=e2 z1d=AZLt-io(hDQ@-ott8mhN*Rca0J#*(DsxG^LFfF!%Rl^#_yJ&Y-hcO_uzaLyqwP zjX#L7tY&P6cdTRQFBJ0S$Z<|4A%X;iWW8)~dioS+u$gmh(9m%S=bHsreRZxj$q!Wq z^dwo@Yvl#KlUl1S4(HJl-tJv}t-Y+R+M%AQqS9OBNIT;Ol*(;j{+F*)7rO4cTv>R2 zcJcQTh%@I=jYLJ&*YqOAl8}=830^J69r1&kxu!RN3U}R_CdngM1DTDlL$j zOH+@3HJMuIaOKNB9l`9V+*qe2ye*g3w8%|MIC<>oWD^8ABbIXZs>|CA&#ImA6dz%j ze6hqntMy*72l0ecmL%Tl=XHj}U4u)I=WGmhTcR-?yl$gKdP8)GO)AwU+#2PCLH8qxy!Sv~@UZkDBV?`hxwQnXxl8zf?i_0R1)bsab&)wzH z$;u7zWw-mTqqFHlJ|RxR{sy;z5d@}w%JGTCiZi~e65!STo?bdbK$iE&nZpd90jeZ7 z+R|z_YZU@5C5|;y>wMo6K4d3B-QQF0Dy|&GMx`MvtLO|N`}Eg_$g0MW*L7S+X=t7|ilr9g5$MVg7YdwsSMnBYAa=8emLWaz5o-BLcUler6+vH6I%{l|%Zh zi*#|xotEUtOZET{GNJfDua+m~A5>l?2QVx{Gq^4 zxUd#1sVBKU#%-|WRgUhb`Xs!V6@v}1br#sbPN%9s`iNATO!KUE>d0^c)&3yJJQN=r zIebi}%%A&7#;AyLx6Mn)Ms6K_`MhUIzpSW`yaXswF29o+i&RYM_ID5CzAtwT3=w1OZwUlb|5xL_gA*8Pq)nwQkS=$eaoH@9 z)>d-s{~>z3kmuZrO)Q8IubEHC;7c9M%DC8)X5NM=Bty@%E9iUoi_Hjc#l~m#p;VJi z;Cx6$+T`3DhRbYSy_?#UZ#+jL49SwZX`7v3Z(zltzD}E_Q*#V;gpM8!S)EAFCk_Hb zMq&E0c0wb;?xXJJX#Iq2Xq9shA;l+SFhLPM-$CY;f=Vvuy$T}pCIp|_ZCH0j6t@`p zhH}@=2n$T_wmW&@0GqQniB5kGK1p_L3>5WUOZ34DaxZ#hRr?;TUU03P2SPB1>a{GT! zmiTo%(p}UhQ?P(=%CJ#++tVy)kpF3UmWVpd=ciXpMlOr4#H)_KJ2Xain}9tA8Pf@y z=1m}_#=Bh}V{Q0vnsrNJk4sACKb_3>HwsId_Va29KrcEzQ9bX!9V*B1+3mishpjJy z$Fno2c&ce>4dY>YF$@xb8cSYn_o=xAk4T^1cxy{WQN~|8lhYGn#olt^&RFFRY7Y~j z=I2$Q)3G%AOygrx`9L-#Tt)Xi6@~EVj041J>9(YVN7>HS*|bL{@#&R$oU`DlqL=lp z7*Gy>PBusPYX*;vmE1!n#iMJ{&!iKgt4UPytFwupaL~w=0~Fq*ZvuxSk47AKcS%P=Zpg7 zFT0$Hf?_S5X=mvXT@$IryK@QD7mS%^rI5wW4=NFpC0W9P#Y}iln(k!78BSJlA6U7f zOcB#-Sd8xl`340|3T$-`e!$$x$fmxKSo>3pUluFOsoN6wGJB)5p*1vxc{(xWB1hHe zIhbJ7F@WEi`i^I1)m~L)&&fS^jLc|quw)4XI?BnlLaty z?%N$TcT_h`ql7o*Zq6WdQpL`%0mStAv7(ZE{-ig$&!k2xfh|Q$4*G8J!OG!-R+4$q zQB0D}o)Ah1s`l`O_I3fIVHz)_L99N6jtdJI zfYFm;*X*~rK(-UpP_c`5f(&jZgf`NQil72aL%zEpaRZ2W#fPE#?Ghk3U`bMRmqA zmX>mMwH|e#fKNH>znCT3diE|dzC{PYlCT>|x+l8jZ6nC9|H6l!$g!afk~-BLCUHe0 z1w|YERnBVRb1o@3j3_QWv*kDwPH+y8qhA`e#9F}J!$0UScxz%PSwojZ)|fqS19x&U z!_d6P1s+QZma##d1t;D7DF=v`OkWdhl}P*aGF?O7s(i%O=_o+zTK14z_*=i^vA}U1 ztV=D7wjsK1V+F-G0A*+1mtr>uicAtOP%mbs@~w=R5I9p2#rHSxpHMh1ienCWWoc37&bhZH8du9*Cabs=TIFM_}#>PI1fpeTe0w32^KC z)zB@)!XD}F{Fmy4^leY)`?f{_LiTA0q^1H_e2#=q+;~1cMF!`k4H!Mu>Q&JzrSeM&^?o#Og`#tC`%E|bku#W@utmy}7Yl~}BT7+c*(kE<$k zKH$qSdk@5_LS)uO)^xx-ILIj5y8rYR=FN^NM%H6E_wGS*yN2AXAn||BKY3B$VcDj< z8%XE(#O=J(J^BS?D8(Z&O)N>F;K>qgR~dyTIdpV*U+=uSZWjadvLYa_t$VOQC;0a*{W?()ew3TEDQX0)rMUSW-Xm{25d@c|2r09W@d;x6o^Egok`3Vu5Ll zq~ZzOZvdi>@4knyuzw>pQs~dr;Q^47|G^5PRtQoe<*|{@)lz zd_FP@M>b#k!K4xy`ZM8}tcR zK^kGP+Mei``Nc5F3Dc&$AhcZV@gH&J>f-cj?eT^&6;p@vEkTXQ*)#zY_QomzUW}6f zdR`hI&Qp58fWEe4?CNIrARmV9_>~fec+AQ_wNSfk7ic;O{%XzSk2j;Q%dp`v=avcP zDDSgdgd`upv?A38?#=DF*aM3qj4co52pi|&PEg69`7(E|eF4z@gk10(+M7nU@qnrP@e4zf94!yqf*@8yHV@(FuEmp+K$^teF;bY*4;6Q{$t8$_4U?_n5o(tb>{|E0qD=UYp`HE^C^BGBvMog)ltNqe z;|@$jK%d!Yp|O%}%J*AkxT*Hf6V@hu>6o$_#B-=*eo?Yiy0q?}T}NZL&aIoqYi$$= zIYZLnr68-wOvSw%Ks^yd7p-mfIHNz6OiD%OIYg z13=P-H;Vtc<-S&=mV@p|+_0?O+v-Xz#=v!BZN{xj2Mmm{8%Y*$z{YlHzPqO4zdMjI z;Nb%8YhO6u4SG{0`5=8Xz#tI#O5*(17(2BvR6J%c8~>Ff)r3Q)5vF;fUT{72;maX@ zA-QnYbOA*JP2bhW-sRgo&oy(Ql|MHn4tM5(C(v3C#u5Fj_RUE)OflUGA*F9q|3v}Y z5Uo~}wUfagaxY=Tr??iyUyF$l_g?VIill2@&zc=FKpuMm#e+m2SW*p~!qxREfSZz% zu8dMR(C(<}s2zKJf2!sJ9dD)g^kHkJd|aq}jx{a2oOY?LyvJe|Uo!mE^(Oq$F&2Fs zR>D;nSdQY$ZbZe+ViswM`**FmNC^Kp01fxE_C%R~@KqJR7KSsJUNa;Uo~0t!TYp4v zu@0>t)30!%SAu$BWP~896aL2K+QuiE??@aX`nfi4p`PVyK*nUC+tIG^T1~SJqL3#U z5N)w3EU#)w=R8qG%^%0JJ0JJOctbjq6mkzp!=7S{l#n5@gzKT?3`~X=p z#SmD0tk=s(Wdn$yqNmCuj{Ur_#CA{k0;Wh9(;L&r+#gMN zHI7X}Jn+GtbP@Ueo{$93XK55PPnOvjB+OqLE@D9Lkf*gO{51ip11u_ zVoVzL(t316ipEUZvl}EX1RruliM1)&>IUP}Gyt70J%y ziVKNi$ybyyXY=TYBTv$i+?i}`NQ3;mJ|X(G(W8Vlrxq=mB=RqWA}|Em!9g!bJB>iX z6jtCqy}V-v21P{lhJo#~rTwNu0%HMQFtrXguBH8`D)gMU3napX3U|2-1?HTq8d$aN zfMBJ6R;yeME33g%2bBv0QvD#VQzR{O++sFnF>?t*#QyQ?P8x?MR@Wg`i|;eBCs&Lq zS7d|VpKs3?$}6ACpTY zzO679ZV{%uck5qe8MO~1r9mpf%S64hR6Z^z7^l+rEs!IwsK!@G>f3%Nkm>vLjAEU* z&SKOwjqb}*IC^4lr0HDFiN{c}Yp5|Qf`3XbFgHB$fE)z0`sh5;RB)81&4;r)#cv_@EiVI$h-yLbIOvy*^(mq zW+WvOHd-6DLKVi~>Aa!71Y`Uie5-gnyQ3WTh7cjhH2-K^(6i(oLHS@e)Vwxx+ z*5_M3Ol?H9+CHZo2}wWSfU!$5w=P~GIh5vyGVW@Kn5gJ-d#b`kp~67V^*s$e69w#G zY_>pK;t0geYX$%XCcmQK^06|$bnG!4k{Gs?F{D!53u+3wZVA`L@q&V5Xe)83-4%$_ z&m4J?=t0Lu$Crr<=!41wIR9T1*&Q{~E9VE*^x!ejHCL{g*FRnjC~HFYT>YaFs!q>>p`oViBo&*oRd{`1 zCzkaK!h3y~ZDn3p`1Qe8OI68J$@=nDzXnBs#w!X@v)$`#g%g4E^F}3|WGOMc31TK{`Wr z(U+UJ+5?R`ZRKldI5hw2p zz$swo$I&TdbR*k@LD(;C@8e%hOHwlR6nxk?thZWZbw&VR$rQ3A8Kb$fvI33pcj#xj zXti!di)8uRc!PY)_%7+8XL3`qQ|Wv~)zQ~ei5MY;kEAblJeEnKz=*+v!J;>@lHZ1I zAs7JB5q7L_8TpZvoaX2% z#JraJk4-n-`->xwc><<2^o)ZVkY>B5_#a^`WhCDIg|<%OoJzG zKtOm=+d^fg^J*g6J9Sutfc{n{-p=g!v$^S(vm*>Ooyi|~T8VG6 z0l6au4DAQCb@xDBX;Zd1k73mc+LP2#3M-L34dzh7RJ4;#>1fphAx!S^xpWfOcfk!K03=mVUr1WHBe4JqT>*SQP&7fzblr0Z zyO3;Hmt^ztz6Vd}rpoD%-XFa{Fee|1@Xk#Fz}qC}1P5b!m50;yxE}%i4~y<8aG5ZE zw`fC!!eba?WH)v=4_u1OWyD8DHeQ49T3+Z8B~@;UrJ}77QTHPu@S5NR1b4>2WGHpo z;|?aL${Dk~p0P8i^2h<9^f(W~Akdu`t`Cdf^rRFc z;u@a$taZ|b1O+U{SCrCtyFlj*o01B8zrJn8|1Ag#tO&pu6~XE+H2~}Vz#GsFygz&1cx(0gRbMFQdiRv18Rd-DWtb@q(i2;O)VsCx!8`KKq%F%7V z6Unvc4eRiEaW*OijFBu*3`qD41=@@9iaU@;I;a4JHlM8XG7~1C6%fyDThNxMrYT#Q zI^*E}i;3yx2D}to=oOq@g!Qh+f;_;xO}zD)h3*-|9a6UiA&h%6);KXsTIKj3Hu&n+ zj}dS2iBLGd6}2}d$}P&&Os|Kck0IhGCicIoAOuy`mpy>- z3I`^)Q+j7s$P4M&74%5QA=;ruG7_sz-|`*6y4j85fE5_n zFzKhAFPqBGjox>N2?dWU1?h~cRAnHlszf|z22Fqtx?rK6;ATEtwL+o(6IQ^;zrQHu zM<;_Xh0xKi6f!ZrJ-`L~;Wjv$#*dn{M0O>=Kg><4*Y|!f8Y+?8x$e}YxCL8&H;h6YEk9SD^E@!T^U2|zM3gu`;xCuceP^M}|;tbDj9&C3yxM$N`T%lDEa>D#QHwdUZ zY_rB9gDh{anmP-_rzJ#WlUwk4sA?-KD3>#3J!}z*X?z4%=(<2aIDJ-FL&FZSU58o% z>2Ul`tU8O!*rwVNG^eJxbZ-`uiFQ`Omw(!@fwYFMog%Z9>SvgLp5OiDSWYLC`NT7; zTr0mSfbb<22;;G5=_>~-|ED&HN%afqq{swN2X@C?IV;wbMt`LT#<$SdbebH!1IlOYg$g@0e|%GY2SC2e+6H2tRMg zB12rfGRQI4LE*7ByiK}N?RH1ZI6+i!ekDiRMJhlH1nHu}&nb z8J(FMNILQRRK*e4SJ4HF3_Pf$c&hPc|9E^^eB?Y zsV=+uH+e!+hS6wMFPL@rn?tu9+KVF}M$FjkmT3gXlh7LBV@fG%Hz0z;xuy6E_Vo6k zgfg-GgR=@|Zh6=_mmX--R{M9qoeollP!GzsibtIqNX-B)uiy*p5I)GKWxT6RM3 zCA`2+_dGlRxwmu$4DBhzm~Gfd`NWjkHieZ`<{E)#b+C2<9CBm~v)m@>Q!f{rpGaA@^h0DIORZ_m~(N~Jbee#l2LuvCXoDBF#VG_Ty2ZF8E? z^52dPeb~XSgs|Sr4Z!^rbZ{M|w$YAW@f$_52t-aE`h^RlQ-0$6do>uCtHV6}#iT$3 zrTyuL{l0H;@c=njvvqpcQX09H^0kB->*NHR%wd(n%jLKV@Up}ESoD%9C9|C@m5UIM zG}mHIF}@B`hBElO)aIqnU#=6~IMX7C%ZqL%x!FrxB8HJaPVD1fYi~)G^54tJDOZU9 zni(Ri`yrv~JR~iMo{zi-VjQ6Y-;UNES$M&GSpoKtF8X~S=6_+R!iY{hipGXtgX||e zU}{#jwA=V>mXan*u)Tyfnn2t3kQ5(m)l|3#7wTJ4&ZtAQwaG=?r#@NX9K1W>55X(K z&>u#${Yk4Aph{z36=Na0Wo(wuG)JS8bPkK9m_ZHX=Z`ozgZk_dc4)qmlnPfL5YfLL z$1zWOY{@QX;=1nS1iQJz51-;UBa(66t94(Lh*?di`QH&iZO2uVmB)E^4~s#dX?CI* z{|)E%dX~IwbUiM+#qUsXBOBU8v6;WJAIK!21SzCwj8yVwhXDtd8ihluPoYDX++Y6*-xN^#(YrcLC_xMvm_)Jx_7yZ70GbntQSeq zH$eknUxbtaW1v5b>BbS&l0&xPyzree^?g^Tp6`>Kxrg98AEsc%*g?1CuPV^;IU;N?;R*y*>yG+TJ2g2Tw-#y*-Ge9 z@|bW@5?YXIK;A{y=F2UR!!K8TTb_mD%DiNr#${r5R*AMLvR zeXMc0b(6rm07aMZk)f;~VQWU$x+VRCKR3P>OqeO~wNI-l625+u9!sbeuX%DX+MKg5 z$Jssr&uf9jZD7PSuYf@c7!vvRH0jO7XFGj&AKK-GT6!l2cS1}y+oBpNWoVn}tl>Ee z1GPMBD;+TYpyh~Y4T-9x9%p|i3Zygpm~;F2I92u3GCHC#2!3aV?_kH=vpKMyzFGwJ zcJ7VLM3)|N0P2%vE8>Kw{yh)f{>O08@dG*QX(j(9guO!X+x<&6mDs*K|3bA~qA794 zx{oq!E{EDZM;ZqWX8p7?ad)tg^1hmbqdyLD8DLE6aty71ad{S=1^1(h2`K^5>6R5( z=8}hDtiTH&iAg*+z6r>pY(#EEzIS)Y+LzE-KV8W7@p+a(9waM4tVCmlG*G+CVhpE8 z2qQ2ana#Y-EaS>A%*~0EW4}&=Fz0r@Yp`1JJ-+@@yNS9+0Uq&>Mlr% z0qeLPnIVeys@l`Q1F7IFkpTYyfJxr8%c=TDwL{T>?gs-n%z6%s_&Q)ZeV(Gi{8kSz z2pnUDaun4>sLZ>8cSy_BtcH#W4eGD({RV{*(SprjtdR8J0yfD5(OO)pHMmQz@pRi368%NTLtn)0y*m5%NAZjsi(j^X7<02lnPM{ zNfH6`ew7>EFzxKk0AK5sS^1KC@)94)Ok)1;J{2Cg09qJkzI2%>c30@RgwhyH;wf3_ z)VkIn_vB>_QEN|%kfS_ zwT>*g9L)JXE(}>QKNnS4;s6bE2PrZ1q>_HlQjgkwO0jK~7M!Pl0KnIx6?rW8PPrvD zL%i$)qsMOI!rQTdGBKi83u6*kxqF8d(kkn|Y-8}wm%u>LU-T$@f6)~l7~`}Cz$`r7 zD%}vlOcUu1(!V=K4*s$a4uL7CgH);Jvg7O8DTNZj=bIm}j!2B%M&@Cd`CPSfr$}rznB-e}yz1hNGHy8e0;+W#*C4YqlsCZ*;u)%%@?8LK&PnHHSylT(S zi;S;y@IXv)Ptz+^YSXAOf#4rYmjb<@8i+Vp5ird}tmbu)XPd8e7sAIe0hAOXXjQSd zex!Ol8|73wb3d%<2#I-E-j_z-U2n}qJ=&YVk0D4r+GLiDD&4PfYbc^GnkH0rWyOo! zjG<#*XT7H|1^6KCk2b?6eWRP>nzb#{9Tm>Tpd~&=wY^$f>MiJJPqb;Xlk!;gVNyl` zu!O@t*;mF-cnrXQ)3N8Z`gcX0313W7^e zh*5m*ss-UhGHvg3S7O}yVf~`ex8nR)!J@VOgNPnY_fWdq8|&chTMlDB=s1l{{5~s6 zU+ydT(v^W>iWwNQfmVyB%ALeM2DJ94IVWbRegkC+$}DOK!Y@A4{~4~IheH{IF$?VO zZE;7zm-swQJJ}M=77pp{;fV`TUHj#h1<&0FbZk-DTc&5K+F1~v447rciK$tY(J1h~ zUwTY*`E}x7^G2{@y7r>W!Us80tDG>tmG-hI@uHL_nI*~?LWr7rYO|s!1C6uoO_>Eh z?S!XeituijNM><#W`V?-0|wmcsCp*4rP0iArYS){yXmD=`bou5_n#k)lN*#Z)G@BG zt;2VQ4$T&O=P@(cB0Drr4W;epWYMcqeQ>|qrga#k(YzyN>ME6|4~4INyZ*i+N0^OG z?s82UTDJ4>NsL|9D!XCB0u)%}q2e-wg`5L@8D?oNj1vJZn7<$XE}!6R@$}s)*PsG= zJ7)1Ps84Ad^lTL-vcr@~$C+)gG=sit8QfMvvwS^a8$n_XO32S))`p-JJ#eMb!1-Up zLuhoAnFh>D#jsD)$L2C}w7PP3QSA_R?FI{91P}W(KmpkTpzOy_S70EY+Q;D=E6n-# zc&th_b6yE$A$XC&Gi*uS=Pa60$=w~Q?$YR+Lw8OB`E&W(fi#r%U@qyOOfb*>c=A|c zy`t}71*T7QFLGlEv z9nt|+tRts65WH8~UZKzDof7c##JdS0j;Sox_B6wJ1MPQ_f4y>jvAAd? zPIUarx$|Lw**tgW+bV8r(HX4f?B>PiBLefsX5deZqae!^Mij>JuBq~Y_3o;$5a?hBWuRhneVq|aY3q4 zl#mNby_=SzTh1ta$h@@Ol?~vqiDlzGY(2@YH@4*>Vha*E3xxEx5ThV>_AM+S5aI|Z zRjUs)nUCUqq4-JdlbRNmaI#ysX-ri5XGYJvRp0uQ#?o`W4-8$|$fk+_a@tmQKYi(}=lM!E@vJ3|tCW7d2ew?966%V*~1; zC7D<%okI0&Ux3F?h#+o_piFC;f@MxV2LP*r=}VPp&fN-v6vgSX6i8Y`lh zjk)4W94qGNy8p+kn|r+D=;yg`Dd(ZkQ0BTVH%=F<<%smIiT}V}o7?NioJulJ(Ygu zlTrtCgpWtPQ+aw+JtYikFl%V)Nb56R8lbBFxTn-x5C4Gn57iTqLmH4a)dJ;C>CMWd zkVPxik@``WN6;RmT4R!|{=DK=wlH2qcOghE+rYKw;evd{A8eXOcF%?|@yd~1H@*pW zrAG2e0i8NM@QrDs!>y6ydDx@Vj34V&5WN4A{*ub9Q!O&c9s*6x*4WCq?PUf~gZkLDKt^94Od8?q(Q!y8cEo|F8D8N6&lP+q16YN~M*C zt#@M4Wh!i6u>1hL8;-udcS^E@v#b_81m(NS`EO*cRWOw81L$xf4{tfKayhh#zM#F1 zNrfm}|Mh<&DP>Dhf*#7uU}A>aY4DvnQ;fCthpvA&5gX8PBrbtY9CMkx+ZwuL7=Y+n z(j-li%G1y>=4HRZdF#Ga$}T_e!L}~6A5s5Jhlg3Qk|wWbyRfBs`^?=S9un5g?75tOfSWHxJ63+3j)3L`S<8w! z6aWkTH>Z$kY5d=lILbIw;vh7@KRB8uzf>QYcMeCGS(5+a)ojbHe@n@co;WZ<3+sbt zA`-OzS;Sqn$Kc}WU-K2@B*kDio^5xzVA!Hyzd{X?GhyjS{FWcBS_QE znPbn6>i@SPo;E6~2^Ee)ub*1Zf_8G-dk(Y96jzaxCIz0q$E)w+ z9?BPL!URF9-A0&B(Cdtj#y#q46yu`SKB*9_`*Z9@Bx~wBrqFVB zpu6{RfBLXz$gE;fyqx#lEzGR-QJQPkwyqAFtd79 z$dIRaeMGJ^|BH6#G5d`PCYt?T*_toWFoul4CUzbA0U>q}bJ<=wC?A9|@obIcwPkl@ z58U2Ucx=5KmGjze0hsh=cXbW`85%1Ph7KkHmO7Prf;;_US`n5yJA0!@_wI@Em#WDhzxMBaFO#qif%);!TMRT}Bfo>c?3Z=)s=;%AvNg z0ZU;Yx1QdaJ&v+s2k@yfgn)0}n~Dodxk7}ydDi<|qmPt$nigS;UkQ9=P2 ze%n&pQIeTFf6WB{iFy1L|L&k}7gdHegzp^%4A`^tW6V%?6ub-_ouRXw?0pl$*2~j} zSJ`99Lym^YxxnH&g`nbza z8n|TQwtNSH(ha~%`%Ht{?zd65T@1ls`t?+aiGej*M_8!n+chcy%@L(R(WIV>CaL+U z&a-YytQL||`M2s_@a>895G`8dg$_s>A2m9D1WRU71aHBTkYO$>bWJbQJl5jbSTud( zULx(=!weFg>T`a*Cz{FwbP0H8l!henT7%0w^!rM{_#e0X-7)pj09K~M_bd7{5XS0y z=DPyZwbMoZPaYt|cdTLcR-teA-HMvI}zqmVfixEe5j7U>@KtYI`+1ex)-V04;7Wyx;kl^_HR$UI=WGvu&azW zBHs@(&!SqRX31%`lVQup9I#y0%7g~|!QY1vU=T8{aAhe(;WRmSrm$A8@=2DR`es-J zE>(GPjO3s(i21X6`JmFJPBT(0ocD2DDrrLfYhz@e9;Tx3Rd+91G5n$dpPoXqUibub ziv3nN;NlO#Z2M#0m~ifJOuD~`pM=w^zhBIroN+){ql-l)@^ePdhf)^hrHt zgF5wFluRv$0KaH=fKR+~Q^0X(@utxUKQC^QINVZP2@kMQibMoEkjko+^8h6|LF1^w z-UKpfb5(w`9m#8ibZyNiP<>42%-+A|3pCIMJJ&k1VI0urNsk{}CYIsoU??uC?6^h5 zo+WGOuKXiFy6kjrHWcVb(Vp-q)!bf-ZtkyNouv;#u53F2pw8x!;!|)m9(u)%n$OOnlt>ppxZgGVi0&}*j@f@gK^yo~BSX}x9u?tTLh|6# z3>B!<$As47Ljs$tW9Hw3~?<-rj&kl+Wb}-RvS_(7EkK*uedg9&%Dz`JfS7FW{%78IWq;=wF zXc^Hs9kR4yQvHia;}owA?mPY^m4hi$g1ArzvWVhmG(kG&Ca3%^>=(Zns#9LuSRP4p zQcgmBLA^)2eQQ-R!bUBDns9xdwhw-cH_Y22mzsM)dyd12v**tXo<>hnmQ9IvC-~*G z&bJmdfG-`am7~oDOZtiS6ezGba8HT&mdDP%*q&(CdSnY&g&Zxm=)>BV_Hl;DhCocs z)GFute9&X*mp;uRm4_P^8Y)wfzaN!f!>SxUh@0deGbyVfAvwpCl=G7Ym3w{>@ zwzNxcbIalqQeUu=Y+AJmf>nr7p0 zhG-vOXR(3g4uUB4eh{cw*9bb|54{tVzQJ1p`50h!%9GS^1u)c= zMvsssTNSa7n=7l7R#dxd#hd+Gza1;Vp;K|p&9oBPYY#a|HPP&2d?7UrYK+Y@e7&Qt zGJg|~Q4@Akvt=ybEzw^kEwrW$7}Up!a2=X2-vzqcx~;aRxh%xO)5r0*#`6?y7J!=E z(m3c(3;7Rs{AZ-L=RI}YQn-Wk#97|J!uU{AQ!796`Mc0KOIcA#G6;+DB=_|M7Qw#ZC`XHUYq7zh%C&!z%H zHJr*A0u;Lmx2mn*uV33YEfk(ESQ4R#;-qi((jK=4mPzxCL92vfyeI1<8t zvE!w(*PWwDzm@OiXlnuG=vSE=&90&QeM*c7pEMxjB#I811!_=P0F}%~oC$T8Tfvb+ zBAP8T`&d7kgmwJs!ninIr3cnOIb~7JdenDoH{(8}$94b;+~5_#-oTE`bsnDxS;1xZ zj~w^eKx|BMDNT}h0gvql4F$gJ&8*h+|A_^Jdg<9=x{Y_6Vg-s{`56DfyGM`}!V26O z@)DPXC#&tT)k2tSx63G;*z#SdGr<6hbQgr(<|0FQeku5;icx2dz?O#c3Un9;P4`sU{}A0`%bZDw!^ip>M{RN&c?(M`ZFvPK6_o@w9`zJMZNhy+hr z>$$DfP?bia`9%gjHjaCUvGWOO?*{^@X$*=v5QISge@; zJaquO$)!uL;=<3u8>NT8_6^N6N=R^Y1pJK`ctRRh*V0!grYxOFAT92AR_~=hXJ7V# zP%>*kRe9y7)fXZD#-DG~FQEw~H|mJ!cAtuG-A)j47b;0nIhVvmJ01Ad&!-hjLJpx# zxm0rrlwndvN#hO4+ilcTrZ@lyZzfszNHylBe^WJH>%xZ^-NKRn@cBR$MQ$wPt0MgD z_fW}8=vB#x&NHM$0p?5>DU)s`STab(c%+qkFSs1l)jqQ$%iO#jYt)J>L~0cA^=Pej#RiS zD}%8)lp0)bZ67v7wM11YFM%I>0+YWZD$U8IR6(*J_U|K3hz|GE=y}J-N8fQ zTd9vEa_D8%IYVybOKPM<7X{iLjFB3Re!7scHZa!Ct1#ek-^{E|Dp0l+DHmw7sL9Yw z&)vPw)|ZVJ%s)PrP9{VBDVMmByzlc4#G|0q9`Cv@hb!?>^JVjQl8jtdhp2aww|~tUT}B z*1Ume)VvHH6NwZwg||(sJ9~ZW*xUlU$mu2zmN_R|4mMgFsKE>cu)ssfmj(hfC_0J7dH28;T7e7i0Mt2o&RbB&Hk?8%jL9(t)4ROy&|t; z3qW1S_Fg@e2&#M&7fULl2K!}#E-w$(o^sK2{!iXMh`D+XZ~KDm)kf3*{#q_qsSI&# zzYXYsyk_kuF&I{%y$&~E+=YYP&fkH6v99Ek6OQ6tys$_#KnK-fIa-{xz zi;oUg@1U_mp?NY|qnJSu)H=h9-@?_@_lQ+J2%hg(p%{lRyrRV_rBNkY6oauf>~F-f zoy25JN5lQ*@Zoe*kR=Z<>7S0%pt`Z$IZwFup+b9`wUj*(W9-AM#u7Me-?@R~M-vNn zGYbl;JUmZ-ccj^(HK%Z@BHLRJws@s7@GqoxGlDlByH0bAtbaYh4rkzVgED309r0`P znoJ*p15F<(_y|xB7sp?Z_L~0FIL3See)=m_dBZw}6CvAOoz-6`eb0miWGr0uq+p=; z4Ei%!Dtu-tS(2!`d=Jnj>nmJ&zTIt&LK2dJ0R*qFtGv?<8Jo#iehVYC)bA3R``Z00 zmyihC7Vda7;>}vRKa379I{C22@%y~1gfM9O;IuNlqca#?FV!(+pY^g=WT@8?x0R%t zCLo4|{><*dG*@fSvo!;c(*&zE^*qoKX|8q|jWBA_fb|_=uBe=M94XwDr?Nk<{PoP# zl@4_pKQ$Xj3gABY?iCE#z3kp`BovE)lC=}U&4}>ivg@=vhc#LsF>%T_vW#XltJSMs zez^2+h;ClC0e_oWRu`JqoDKg*hz#VcpE))T(*WD^!(ODJX&{I((VLZsU$s#1az&N# zaAHzIVMX5nG{eo~vuc~TceH=rczbgYf3Vh_U$+6{u>L3AyLy0%qr$excHHR&{K2dh zw+&o~Olaeok1XHwP*+9N5a|{-0n`DrC>NjkO}^N(;#jK&NU(P5mZnm;)=(LHp4M6v z$(;8npG}AxP$0AtY4KGevSp3ZwX%pw8&ROP)@vUOn+|jEqlaHEMKlDOla`5@qT7J^ zK2*D;1=Q+a%%^)B0NtPb5C7 zUxgQex~Qef{iL2r#9B1HA}p$)V2~7gC3I0%hx5-m=g1B+@*q|aP%nJ$MV}Y}7Oar! z{~V_N%#c3bD_!S@U%{X_^5-Sm)xV`i!LrySBHstwN*3ARW@~tHoLWhV+-S7be=7Hf zNwdVtT;MT8|2V_1_yu$D2sNh?cS~FKWMkd_m8>61l8!1zS0WHU=)ns%?3923kQ%xQ zRwuh_6d|c9a&OAuJi-45(AUV~hY?jTb9|?AMHP=Sds!nx$3B@qqa12X?Y%e1PLL~` z^BU+HGtvv?w(19UUlhtu=)H89{lt{#S`Her1{eVetb4?m1T9?C*!m}&p-CknDfWqy z=F=a~&(7pxFWNe&(7Xg$5h>VCy<&r3wB${K!1n=GYZvtw9R0;Qj169OxJ`$BW0!=? z0BHSbr{S(5b01|*4UkR^$Gy$nx80uXt4iuA=IZFmry}zHx>w62DZSnN$>m7Djpl;| zFIf@lLHS?M_CS{UHk6TDH|e;q98D!?D|tT!@s(^HXxQ5$GyT&&b;qv2$95zZX z4d=d?7MG^siXz;^Dtk;av05o;r#z%*L!@TcR*wMB6PI{zvATul2|=L^IM+N_K(A%~ zPW9A@;Pi+4w(wgC%T1@fcXpms#OF!m2QneyoRWxzU3PN?dNLRy6$jBVEzV0jjKktx z+Q4`b*Iy@m#t^>E`FQkR3K^^#Ae8cG=S~-x26knl@7UlqT;r121XXp}yQ6Kh$~84h zl{5@y>R&gopdQ~gR4!a76`wTEPL8p!Ul;RkxTrn{SQ)b>V)`3Vt z=2clfJe6Z(V=jCq9|g&IsaIN___k<%X<_LSr=Xn*ia`bp`X$cfuqRTti5tD>8W_Ch z+ikS(z;A6_j2yX!H0MMeMAPLW@%d@w`O8Tr8PHoXHT=i_Z0Kvi`avh2(ITc|n8C5s z_eU-HsQP^U&(2rvm}7RW0OV=#385tw-On zLx}Ubh4IpoL6{aW6JJOpCgKv)*J2@8IiH~)Q*E2$vL_t2|(egVA*Asz_x3@oVo3~RYp)Q!bZRWJ@i!A zHm;v{q9jjx7%dptZ+)%xf;BGMhlCG5n15b9R$YUQ8#L&D1U(VM%-otq*koNdG-h?G zu1^OW|HY})bjFb~+w4ii<0=fP_DoCK~(f&j9`kHi8o9Yh1ChNqg#X6pFU{slQ=n(1rum zmQJ$fgMqFO8P!S&n{u&IgYy9q{xIl`X&!=b;!~bcqU7J!Bb<}rHpw~lmd=P$1DlC@ zwkt|!bkWw$?k5c|Z@RVsW1}JK)U!E2 zENNt%<#DU&8&WdSh88zfe}}rOYZ!`();W%BKwB)vtMy9#9&s5^&h+b-nqS=MnVCzn zrEYf@H^k1ZFW7}Sliat7CBrkA@FkZ$-nMU=!rN!o00zaa>@QW0TtEi$nM&!wzR+^i zRsJ#q<|txpXl6Yu`p)9^M4@SPZ~Cs$OQt_ZtoARKYW`=4#|(z^lYQT`sfwdBwkX{9 zHM+!7HpKJEIU9gqP+9fdbmHPWW<5zBS(^YpoNdEj^Lpw9SYM?0`D1%tJVIfgACKZ4 ziVCg!T>cvnQgV_=*_!XZ-^wZQ;_&DJkT~_kC2=BLYm(Ls9jAsDjj4FyZ+ILl503wc zl6PkPq_DkkxLd`&vp%3Cne?mD)^%wwCLVD_qR29GZ{rw+LaqTfVjSS`kdim%f|E}U zX1@;}{s4WgheZ(C$yig?&k0b4iEA=KNA&pTj_~bXS(8$!OXOGqSUAD1a zbRvXht)+k8byl21DT%A8S876zPa@9$R;mB030hgPl2iQJ&QCSkQ!o<&4 zd|Y9G+?G&IB#WXtlRgDEWvTK?PV(+KJFs_n1JTROXQWdHPBJ_hmt$o@FiLCr45v+d z3J#Pqav}$QV%Ww&yaI~9Zhk2*M_#}KVo1IVJ#7V#%8^I;;D>c&s16|XmRU9MP63vH zjGj3E>t>~=4+8eReOQE^CpR?kA8;Z~Q@76~X1+oqOT>Dr3XCK z0hm&R$2nC+?=S)#`1(LR34%fd901S%5iUz1Mibn^q26^Rg2=4gr^;d>q_@I_V}h9g z%|vm!F}A*6^LNMM@wsDa_9=%=fdnNavdJ6M!Je%(P03#}R0tvJGo9B0VtOO;DZG~m zUTxQLj4z=fHtNT?vPK!Ds2YONkNDitK=ZS~2wOpyQa*59&Bj)1TS$a@VC~E^bm&M6 zuU?pnp(LYl8HO;!aD1vX`G_hpr*zwNPKivdN=x@#`mKfYHv`AED&i+3bJ%HAoQZr1 zn#{mXRlo&T^>W2kND0<02BcxIc47)Y(zL2wST2^hlby34|$+FhTW;oU!Dvze0Jl_ z!u(0nb@?!?U}h02w5Su&W8@3>)wI)P#EgAgI}>zip(KlYZ(a5whK1QltvbVOz&b9a&w$BT-HtO{YwXtD-NLrajd z8=~_tiJeQ20r-AbfH34gv$|6TlWUaiebPgNUNJ`-0>DJhr3d^AZgBmE ze!b7hmukpHP3aX2k}f2NYO?_!+iD*`gOFc`%RbLoO*Bzq*J{?WJNslem$1divy<~M5ZYij?27e8Yzx7 zyaLPjD~8+%N*5D#JJfyIu~QFz9)(M;eW~<$6|R!Ft3c#v*;E!|4bq_qm>RwAC&>%> z&#VmbT1|pi(;Rl;MA-9gQ<|T{5BYf4?NkSl21s+g>QKb-!IFSSPu$Epml6BPctNj7 z{@(^fuvet9Wdroh_-~*6Q=ng(=P-Uv&GAz^Q$^o*jkIHqMeBCanxf;NA$Q)-|3d!2JzphS$dO z+P?J*#FKLaj9z`EDNPV}{oq;`Waivf*v79_3-+$wQgdqjZ-L~JaF1uJEk6LpsBWPK zSi791*yO;Lg31P%DVpZ0U6enrD#{A^++?2gV=h{-0rCjHlH0kjajb|)N?+_s{Lo^(TJIpPS4HK&LDCxxl6WZoOt5?VTdZ|YaeCNk36gy(`$$?!Z;V=sS4m@u1&Ea z^ATdsLM=hX%ZN+akw5A%({UFFrtzUxtW>L3xaYcDm*gkw2};N8Y=+Ou>g|`$Z~mXO z)2!A(pD-eOd|_YX@n`0kR3Mx|&`+)n`-CR$SKA=AkgF*vUbuF_+944hgOM#4vRxlJ zsPqbO0dasfNJ)mlUmjfNKMW_o;kXlGofK$G=)gdS5fi#RJ?(y?YkQt&8{?}Ih9!;F zmUq#{kLLgRHG;MnHI*|fe`luuo^J2ET1>7xceET4w`}oFrVxsK7khTuJL4Z^8 zQvR9RfB{K6du<%)r-5kzVxMwdA^?d^K%WT<*5CkrTwXWG{J&2l(cJ7h+Wdp;x2tak>ZtP{s1|N2G z0yon|3nIkah%ReC^J;lXD6g7=^_Mp=`tk3WAWh(zIf=DL^L~qPLZM3=ZtE_ADrkPcGx&I?f zuG^W|<|OJT-?Dhxnk+@P4g3So>te33c5bWR9QWJ2^H*nPH$^wJV%zCKQ%V=NHfsw3 zlNEy@Ep$ za%*$2V=d^!0^=R)4dTMt31z082Fe_Wm9td`D{^gwMiG>@d=zGEd-z~~ME)rLW=Rky zP}N(4-sxq#ETKF+$U#tokKGnN-X^!CLRRevSW|Qv%B7$*$2HTSjTgNjVUH}&!6&d2 zt|Y%Rw|yzRUQJAH$U;x;~ha&?y(`0*WL!+h_9$*|;R zR{!DWE7@%FUNFqL%jhR~+}sP|{paHL0F?~O%ZNK#VY$vSj(AP-@^sKxvuCP~5~WlD zV@}a|3NqlbsTADI_+38{r{0Ce)x#aweKSLeD}jypp|_4bl%y`Duz=2)}+g+w+dz z$1OyrJncU{-IkZ~QviFCa*<%}c?az8rTodoL8~qDx<=#nio8$I6Duu$CM*eUjek2R z7lM(gt7o5`?}`+MmepTiR1O_^tXE&8s@bB8d^F8z_w+*K2_GvkDZ);`PK@;V=jS_6 z$#u+^N1pR%U)k6wZ-u$BeUpn3G;Lp~9%LHhaW+5Qm5u4b(7pi^3D{G*P+;}S1+s9< zy4u1;qR+G*6Jo@v6D|ohlnv8Xhc`~HwC=FNC%Fb;BhU(%Ew>FcRWPREp3bfAKVSzw zY|#X%kFSSQJJL9YyXwN)=h(|_WILhf(l3K&c?Xb{yD%DQ04=^>5azWEleB&+@b6=% z$gVBIW=BwQCs)wFPdoOiVrtlY_+S2rHHmwxMU#()l>?g4e1X3#GP+JS)0*+O9vb2* z>5?T$>f{O7)Eab?ETZNoi-2A<9eWvnOFnx25Q7j6%QlQ^7||FlC#i^O^5eOFsq{nTxMs z{Vm(D=kzNP3hZz=eMah;tdf+nXdZ*!VIp@!_{1NTW@E#!Ku|9 z7v7D-Lx+7^ENBNwbjzh_Jy!ycSkCh+zN*#$pNcc_JEja2VIZH$-fM^p(h*Tcfu5sW zRu@|n2DEZWS2623nokh7x&#Cn@rfh_nUButt?RIPmPg<#L^sRow>wq}X&z7GEQmzjn8@Cy@{vNTjGP9pJPirNLJ zSt_h*p45QxI{)4b?aRfn9J1_I!$g}|zA$#cZ9YZf{C0vwH;_J7lIS)b;s$Mc-A*^S z>yLyF!m^{7p=x7@?Gu=QsL$jm!!Ivw)hIaCYH8Y9k1?PB%P(i@L;C(-3RB)pmHzo& z9O0j9qtLhcpb;MKKRr=@zd}C6LgpOz0JVgU?TLjb8_5sdAumDh)tD2KSlj=9eNE;{ z0Cb-+RWFGOXK~n5xlPzMx|C2zzuj++k?IcPaG~6HfSG^F&-x0m$qn|F;{(>P3PWWm zIt6Rs`%AfRoPsndceBk>d>+LerX9VVKN`NUF{&0(7bQ>7P^!%g7jRe=Wye4V$ox|DT&Ugj6I1Hya^JEwdgwSA;ER)(2r%KQ4U6H`~#9 z?ZYhT`+T)~ZEcxr+xoJ`^Vzamv+81?hY&WoKQr8DhsErxJaZoRv9-orY z#O_p=V)@ZJITMl41b*1+@n%IWc2F|A(|vDpDl~hE&+44`rmN!1cvZ1uH|vyecAn39V$gO#P#MmJ z^sCAS6)Q0`Tb61Y{-5RGC&#ped8=jpI>T*^!f5kB{N>Wu$3p}0^o4VzqwjGdxFu*^ zgJLgVf4r2bKfV@LNDcWy*gU;D_CfKEJOf}*`tLV5nPzaPZ>RRsfC{8edJ;+w=r2p; zwRHTpa9-ZiS=9|@hhW(#C()n|7B zZE2PMPIRP>>~e&3q1}1!mK~Yl_5neUhD`1;xcu*V1eZr%^ylJJ7bmhK#o;F~Jpr7~ z1pTzxs_BR1ipCLDih-&s%9fcSVLhM-$V2GYY9n~i~Bpr93o3Fv6Sic0TJ;_92nI43N=OEacv6qD5tdK z59O&On09C)2$1%#V(k{ug67U1CUFf4#IX{#iip@ubxHSpioLzM{osc7I$|?u=cA~$ z+v6gKR$L{j)h6ir0aCa+>d~KV)jq_9k|xr9)qQwgMjHTXj9*R)zUPp!O!lzO^erGW zd*4|>v9)uEcd7^5v+1rlZL19L_PcWm@Ka&`JJvddgU2SP>=gaLP@03Z1mpEeu60~{ z{?Qr0vuCs@c_AN!k3$(YYS6-0ov3Dnl}sRji`}pYW^GetD3PzwrI=2 z4uaPqwsmlJ8^5&Zq*}s!?OoM}qeIO`XZs{eTugn5vMZ|9uBd17YX4+dP%mm5=3^AO ziDP`XCPY}!6>nd^1BJwY7A{x|&Vw*n9nM@WG>w8B#JuqVFg{ZgbNekgj&NWd-09?n zJs8cJmgFDsCL9%ezPi%UwtPvt_LlS=4Vg5jrk*pGJmupFdl<{+;uy1ycGDDA`;jdt zBZO8_QZQh^CRVWc8SCq)?Nh5iGIkXO8Pl)^b>L~%8*u{o9ORID0$;9Noqv+RP`1@k z{m)fmul@s(_oN2BFAjTAj77a$HK=8oCxr+V4$>{5`?z0^o0Qm~To!O5pa8`>ApzJv zr9X;w)~VVKe3ZlfB26)nN24NO2A+F5oy>|A#3$}PHo*HXVzZbVdrY?+dp5xa>quWv zpvb=d*6G6H^e+uI=9HOf`qO$^`-kGlLtl=k6^VxsNmQw?d4A3IQ6pL6>eUqOiY2Vf zMGb~|d;0o{AgYbn!!Cuu{^Eum)1zsYhhu{w;u_hKTP3eRyS6}Brq=Fplxxu@HVv-Y zkvPaK&JZXr5m=Z4)Eznv|-eCM*wt`Z$-eO0NJOYMjmCJZCv?02A-WFlm5rF5>VMfO> zKUMxU81$g0U{0i;cB3a@&%I!{RGlRn#pjoCq#S;Y`sR#QhT*i| zi&%fErG6%d)QVFMbe}x6m+#|rUaDf+M+No-f)+FJlxKPe~-{YHuK%^z#Eu0o`>t{AOScI!Zi%UfjhqyLWrm;?=uQx}Zc4 z2&2?mKoi=#V5Dsmu43NK4xxPCzg8L(_=xi^Tk_x`P3}6Xy9#q7T3mjjjNExaRKLuM zz_-HJ7)*ulK{%o{7 zw0-}))#g&IiQhzxyirA5WOqVGOoF!^pC4((fwv7BT$7#{#arxrGI{^q2&Ru$^WU4t z*sv!)Ep{)WS+*ta%H9_^VY(Y#(j_B&FQh1z;7l9O(AI z`ayO^|JX7GB$euhEXI}zcy=ajL>e*F8@B(2RBMvQf3L&~F%uB7VN(bQHBdjQE72Ye zD`+@HRA%NGkKpE``b?HJIQ{d3yRFOru~DghO&HHTiY_b5Js+QbRWTiDt98Sf7+KQL z9cfVNp4c)5A1}6ceMQD!fF8Al%x+G^j;VECWj2M%&~3&dJ@sv>r*e6&yU@PKK;JzY z3VBn2Z|;bhEOv_IISspUO_0>5E$B}wsZsCS;%tleB>p!--&g8UnjrbjZ~k?mfM-Do zB32Hk30aP1D3GfSebw=_WbOyIZ`tr%s0`E1?;-gfZ~!bU=B>mhU=;Qvo+r6!$yoaO zw&xq^o5i4)wzfE86cD_&s8Wo)QrJ%<4{)3w!SE%5cO0PVOT3o3bmx)l>jEKJKR0TCRlb4uoOZp}aPuucz4t-&=7Z4uZZXP(ncVx^ns1FCiVQ zr~MBTlu&WWM7pLmci-aWWRLa|KVRO)FO&ju1-s9ZJ(aCi6HAtZ-;1+(G$YqAv=+LP zdd_{RzI~CuTz=>msseHOx)%njE*_GGL%Mr6kdP6o0T*_V?>W%)k+f9B?}y#lNOlsX zyAz}FMu}bCS_CKkSp?(C_4%f>uYa+MN*oeP=qYMk=K2lo8qr>Z5#A`+rYy?|W*(fwh_e6fro9ER3HF`DG^ ziZ}TyERgLn!dtv;3ua^ty<|!vEqHe4+kyaCq&d!Aao1oJ7!0~`9zw$agF^^Y+B z;-+hhNM*Go<&dbtuO9H>s8(UPmzVSK>BkMq_#d@A8q`5eazu2v|)fzhQ1#$q=LwsCQ(-$}!or-1=_8Ov)`3A!v7< zkSi)Bq5@LOeeB zwPQTqS~2IOsl^`@?^MBWY?!UwA9=}VT}JhpP*r)}Ktbnsroesd-F$Zpyr)ml z7~F$aw0{&(VOk)=x%Ow!p19W*qyx4OK^Rf*2BLwwPgO?j>89ga47(ZD;CghEa&Y~7 z2`xJ(0lBuM@4V>sol%gn$ewcbcgFRo=5BBbg6Z|5jy-kNrBDXX+KTDrE6Y)hM$Fu z^vOFvcu4A>biL5N?z}X}EB-tZ;Cl8VSCy2@*Ls&dI7Fi9pat$V+GFeme#P32W*Etz zL=o_}1!YYRjg%1B_`Zg(BaRV4kBH`Ox{M~J0K4YGs{bjrWEZMPKwgkq==Sif7g*(G ziVmTGn^VwHDHkK&f7)J+c2n$1a->(CX@(&)^3O3~Mc!DI*JG3Zdyd2UBjDVJCq}6z zwH2Xtt*!U*@DSCW7n3@UkMC`S%9F53r{}wpId%OZ06U#mURKg}N4oRBC4mpd;RPc; zon-RBJVjFLD+^29KtwP)6tDVrkw8N4)6%ab*dNKuiPE9kCisU1A{_G#>MY!0lCQ3b zrCNA7rAo}PXtA2}%|jjj6tybC>=h?s(E!1qYfIthkG#{Uj~Abwlb+4?7VqaHz71Y| zyO1h(+JhMrZ3<*|l`}8H*cl1Nme@6XLQDOna$pqVyftody>gKE{h%lxg=xTY6DX{f z_FXsn&$dwrN2MqlR11Rx+=!Z}rlS?1McCFt^gzlT|YR|d0 zasF15WM-EKvFajts)>|s1408^F7_^^p><_f*8~;)9j7DO;WL}PGsF;LzPM2zD#_ot zRqU|~HbWPwi&)kgxA6anG*jzth>&KkP<^a6-om{=5t^;2vVsqfh*FKc{|io<68+~= z9-TKbQ$9d9N??M(ArhLL6i=rpHzP^M#m8Rp`Y*Xu#$6_VtEqAr($6&JT6>>}=15zA z+#*0zzEypyp4-U&jLaKgUAoK>x@8ACqziOB07b_ln4JKJe@&dFld+Rt;RcohwT8-2 zP(3IIMP)6)=~P2&0}1HGm=}KsAY5HPS zbVkP+8`%kPHd3zHF$H0~WXhb?TJf`*Wnl~L)nC<~z zkG{`~L zn@E`9H*UtT0Q;*0Rj#VWaYR&qh+EQgmuW0prz$O%98kn4Ld-F9U`|+GI8yR0tC@5TPH1;Uo^ZzPg{o!)EEkB>zfDlrC)FaU*y3 z5tGyAbX7wg|GiSz7GP-del#fTsE!F6SIx)8Fg53(zU{p-2COH)_k-(eba_$P|GrEK zNV!yvRUyAZG1QsFWtA7;qw(s3hJ8c`dEf~Rjcp@yRH&^2vRUaf@Mal`si**qQ!{T^ z_r*gEci9VzYQinN&M}Q^L`=P)jQ@m@tlS821%KM*N{STriXMEv=GIAU%R2? z=m{1>ah)*i3Klxkn_OUpXi9KKv@mxdx!=+a0D-!o$j-rVlf3N_a@;ffx#0y*>ZYq@ zl_FR$FmjKb5A!g5@7ZZ^ZDx4vtVhKu7O0W@b~&yym~v*!=%j3!@e!&Lh`IMX%Tm*R zt+z(d*V*d zf?VMqGh<8jdGf6N5L-EM0O#|J^`3RC%qtNhlB(9tnc_C>p0rbc6#Qr_unAn@nywM| zazIn38liogY6cbG(pQHNfCz^n`D>WTbRdBZS+oJSh=lL0jZ4+*$|a;LWF4!6VtZ}m z0Z|WfS2aH7dk6BXmw)d3-=XxmFsGx@0*ci)nzCjky9rm``ST~g@q~_#6}aZ8vn6bo zqo@Jeu6g)L`VL|Ofal?By(9Z8IPQ9K4OXIP$p-1&x7GR$L_*l6Q9ll#@?3_7h|OCL z*quq}os0=3K>coj5%?YxYeWc-lsRlo=nfoGEFkWT#8o}Pk6JbJYLDQ)tF4uJ0M7Al zu~_X>CgfNymaUVfMdHNZYf>tdG3*@^U9S(#B;B)9a#SkkLFsg{#2^MiJkOIOQe^oPR9vp#3c~*Pi z+;wMPutkx$!!-D0zdQ51R-T5Q_{P+54*wmy6gtutY>`8I$wHCuohZw}=`pEVjoNRU==)i$U!Uky7RAnTCdXyYC_N`xSp|stA3?Z@-z|V2I z>%=iDB`x!s4^BKb`$eE2 z&LQNoIL6YRi7r_NP148GsZGV2U^ZgCYRpm@H>Vqh1B}n7rZTj%cd@yKGq+;seG}dU zxPuIETE}LezW8D*aW$k;q*Lk@7vAR~h!~Vn1EhkS=V&1Ks&!4C-s)grxeF}p!j*iy zh3MV15=*WWV>%XY_^tmLQ5L|%@7!?9S)Kwto}KF z(h(XjML9u>@U%c&opp1BuPX(!bAoFx7;fL!=ZL zb;XICu?#cMp_GTdQnnKzWx#vNF|?9B)jEsZXjwd_&r6#vW&;KcS543uFOQ?O2o&3b z{@3}H-Tve2-QbLq_sIB-@@QdOie2}9x%v1}Ew$sRwFx88CUTG_#mtea4sDo!&3&-m zhS~k%a9F@YF}Z}Md^pc|iChtp)&Mm?%D*n1(_l9MTGTgo+$Qc&H9Q}gl&Z|@HLPkL ztnR&PLlZ^<`nyPJA|j*eA9pxGbxy){64~B`Z7ly*j?-G#pzpk4HOFMuC~E?bV)}Qy z6r&sdCJ{^Xf$?BLgs5=eX3+C>4k0~9(-PsMGD?aq6D{QZRt9fa`Xm({ zWxLE4FqFAEiAJ92TuBY;*Qo5|g;BxQkclJ$w?0~~pSI8{s97+>Gsrb4 zfZr<_2`oRTq`y5kS`75zzg^fp(XCA%d4Q%ewToeqlw#RCHdY(k0p?+B-hvKQs{ULJ zC<9n%iTK%Sp~PK%mq0wrP^q-Eks3@_l`}Vnl7i+`IaW{=H~Ho0uk#%P{_lf)v+dOYzv)om1B z!JdJs(kLN!`u~!k!5FaKxRF*Hv&3}}9DsxM!chf%v&s_*)=4m4z?xm})BKWG22XD5 zk_E#?*|lm!8#Le+j(+ASVPcH0>}bo1u&Su{VT6;0O~V?)>IeQ))8NudpR&wZ^E|(> z6nE+!w;2={f@U26Nz&R61l)SZcza#yo2O4CWhzSa4*g6y$fGnQxv6{@z1agw#w%MQ zywTDx^A7ilMz~pQN`5@+Pg}ao856n!H87+Y?TmnQs2Tf|WG)THEAGakXAYN$nde(& z7?HJdPzzi*Dm2d!n?>W~Q$!4~4S1v+ZR9%^s{ehy3;%D8A1!*3^~w3%=}b)(Tys{G z>%e(XreOC9%!)ORC5@6H-b-{^<(SFb&nL|@J&r&<@0BjtFp9@2a zn=Tqo4|_bHHYT;KP0kZsH3d`e$KCpFmv^4~p9Y7^d{yc&5xv6jc>Ei?jTn?-HvAnFMqgJl=;tO|>Br{a5j7V4lMB7LjIAG&HX)rQrBlp?5!cLoS{;wO*D2%WAw^Kw1q4CNyooX_xab878`lac(lRMI+={b@y+wokkQ zC6I5(B~8y|2sG8dh6rC|{SV@9R998?x9SRqSePZH_2c<2z@FoAFCVYuB zCQr)>U%GXT7-q^^9YYWjYsW@kuiuIgq{3|U~6tQXuus;*c*UKT#ACXxY3s1m*o zKC9;8hK!A~=qy&|?GbUIV1u1;ENpz!=Xc8qKL81LW`dD(+LtM{T%8ixds@OJ-a<9#G zd=Yw2h^voAEX#aOesd*t+c6H$mirp73hI4ve|$3G?kep_*_^SBak9;^TE%D^#Kmxd zW?20Z*`vuR$Z$u~T6fKIm>e)RO*=yhD8kCL-Ym2gp0sJ;vryo$9kiLzr~!Y8sU-S} z=3dZE5eEVvEeppuwpgUWeR0;idT(28B@ zj$=z{FNa%ty*Zz2=U_UA3|otF)()NVSC}zbUza7EtrriT@iQ)Khqw;*T&`Rb9(iRc zFeN@i;ik0atQfkHUUIrIgRCr1bCgBZX=+bz6S@_a8{HV=Fd~qVG=l&%MFZMZ zU9m9HE>zlNN*zEXsZ3G~M5+ZkYxA1v4T@zJq*TZTJnmG4@^P<2EJ!00e_w7N6HMK$ zE=ik}en*z|n()amkxez$#$-YOZ6xJa&o8&6%d6_BsMnrHR)pBqwz}{1J#$3`1(1-6 z0x*MAVsH47@nR-)UP{T14~0>%#NcE`^M!&ZgSZcdWxXS{&HGbfQ23<#k@eH;{Cd1) zS~U{*hn$SNoOkq8M%m6Umtwl ze$#9Us~gOHSCdl^ozsVp#fk)r+N$=I4K#r69eViVSN@mK$NQq>AY@)a%@7q0(@>o} z+%& zfk+{J4xo5i8U&?=qHn@5k9qJ%exjEYm{Q_v)zNY|%lgsxh^2?G5<0OTol~apYE~;> z6TfHouz2`b!AA*dA<2{pNxFPR(?G9e)AaDmVZqGI+9;`_8ui12Lo=IjTu$S8fje#n zj0I-twD%qXo^)Nx{xu4ZyG6FNUl3LL2U50l&=x5qrD--AF763Ex-bPZO1T{m2U(%> zuv)c$x3h=k5eY&QG2Ph1d>S zYb_U+w@;7K0(V!1|*p=rpwa+w)qku$ht_Bzx zYBlX_S&6);p%tW;<3urBQOQDFmk}u&Fhku(f z#A6i3UnW&r&1EjGGjV+n4xc*Y-%<*0{m-VJ_6{=YT_q`x=P9Yku*P;SuwJ5gy9?!uh5OzPw2-(jpcnPU+)G-=)Lhld6c#eQ9V*|k&s^()?hl8^E zHFr{&M&|>cm32{N6P|OSe4{KVzx=S5X`Tl&1SK&ls5hj-nqt}DX^FaJF{=Db()lTl zSBswpq>Q3n`3_+~1*EXt9N#gwjRQQx;U=&P9HCh*3g6Gz9WWioESEwMiI zT!gMl|9HL+!7Y$!kt`vW@S?Ag2jl)BZ6&1M3W+rE(lf1?acY&I&`Z#`r8Ad#?HgL7 zF}#4G3M&6gLj^Y2Fcbi-nFOoT248R9cN1z!f2qg6%=ps9;{EJ?3jlS(&q12Zkeabp zRgpGCxPsO2@>QbuFD{-(lsY{kP8*T`3A6_guj&M|oL?wc|LC&QXJ-R0 z-dCQ52MNnk^7~vemSaYfP2b$7(9N~AqF8a_Zx8tsh=8h1xLfL;VerNs&O8$H_5 zi&!<`q$fH5S4S0U@>3J)RF9pVIx{r*vczI*mfUp*_3mCVVW{+CGDRG zVFB9x>+mdypxGwuJ>np1`1kWS4c`mE+~mjoj0xe&R{tF%o~W0KXP9R-u8J$RC)16c zh01q~h-QA;?0i$)^T7C@I;$|CY#_ zobwywyj)`-4;|Bt1D^5xrDs>{l)Op$`hxo3)lo%9|E83mFNSw}R2K{T#4Q=qi3@={ z%|OwL230;@y%9yXQV3k2$~-WLX4B>ZR!IQ;^1FVTKTv!-=|*G8Oyt_TLp|^st}5H3`IRU++TrEqknwZDEI-{81M&YiwXr9_;nhN+RVov10U`)+ zIyAA{4pP8eNjn(g?6|VX6NEwC`A`ZX&ke`!B$A-$`WnmJ9~f_rz`QxS8;#&(=S?3~ znx(@r@+T7U5D(VMqH^~G4b77`weyM zUM)5MTnldVFwS&Q*Ch}5n?w*DvCtm6K;NM+osx>I8k0v$IfC5wisUT^-zVe(%< zG+_IEx)c+g?#1XE*XH{auI9Xb7=Bvt1)lUEBm^-$E#0Mg$@Ha!;mbWwOOa<+R#{WR zDJ0ejYl3Nf*RyQt?A`nYj&cW&tal+dx>nFfmW{UYV4)$%nQMm{SAL%zJU_Zv_Gcgm z@s6p$MP6Ut^empF)}Qi9I1qpy^KdCoRFS~4*(9Te*1oKSSrdUs0A7Ux9dPR+TCd|GI z-*(OmS1F@({=;Et4KqNEyt-k1L^vy`w%h~(i+ngFAZ8<|SBnkb(N506;cnNQ_|9dm zA0&_on1NG&#tM0%hoc4E!-%D?AP|}oGPfyjXm6Cj!K}Z)Q8`3!ftm2`ro}2XkD(i= z{o@Eutq4s{wzzh9uj!}?hbCmE-AcoadXxzQzl@v)qNxbhhxL@0H8Sgl2U(f%YW0sO zLbezjsSp7Vf4+sVMD9O+osfTC%Kj$q6k=dJD(k7ZkU-FHSZVmVu&88%+QZlCMNm1_i#h># zpp0kRGtT-Ss0w!jx-eWJ0l>A1bwgn>Fui^M{qP#^57;;9jKTxfse@C%v4h2iY-810*aQ&A+)O04A|9pbidhU+ziZnPy97?_^D zJk~&Vd3ocKe`}Oi7@7r{N?o8OgwoCe&d4tB4ymc5pmcbx@f(}~H6}*@($eY@KoIp` z;V?Z&>=aH2P{Yv}Ok_525c+DH_y93}$C~y277?!(?iky9&bLDEmz`E~AdcsgF?PVqHt z)C?LO$Hx6UOPw3`SFp+B9q~MCAuy4VvfG2VeoN8t4$v&`i8SHrg^90E*n~Em+IOMiy!MF#{tE8{EBr z@!iJ_r7dlnACs=+!k?9}Tg#h8q>0P}4>I8ipu$@MB@w=Q_oeLdy zo8b>ToTR7^J_Y>aAE&3IAm*a%P;y%Err5x8^)`!t$ z_EoaHm^g|t))5iX}pqEbUENtNju}oWn#*| z8bv25JNm<(Cnbl*LNTX-iJ-KAQ zj(dL2TO-z*YgGNLXW6UWlPo<65?*G9aox(R9(R0+taG=3m$-eM$zRw(UPq{tQa!;U zaELz-@{p2TB}10M{ag}4TksaM=KPx1UmBxJoolDfO~=Mr==__4q-c)( zt*}p1BD!4K%otTuNqMd_EEGE@a(~*sU9Lm#+$Q9^H=7CIP|!GA-uKMvv9Y`p1V(s@ zCm7iA1YfR8wWZn?VQkY!p*bIuB=ZW+Zt}C!-9GUiMItgE+R$NM6^S@xYF3KJ-`OPj zpp#laL`tfb>Q@PtWm2#v=&!ETw8oZX5}hPEQPlL% zz^wT*RL!S!IxJYp)y%Eg9K8Awj{_Yk46WE4buC_Pd>VM23zXVuapDyP2W8GJzeofq zLM?k0!j1OuHepeH>Jw)cL_9tn^+?RhrRDv#allTMw(mtIbirB}%2mqmw-8TGGlF?G z3=uUl-LUNim7$X{pH~@4N$;g~-ZxN8BMAZ)2k~MX+93aM!bZYO=Jei|h@mhegWxnC zJtLHhNdGUCocy|8tcVqJ&UicSdp=VJd%m@T=3c$o*kq^Jp>QOr?%sZRNB*_{{cI#P zXSHPWn*6DBTQ2_oo`)I01Rr?ubxp1iU@qHW087=hiv`2Y$rBsPZd1xwY(>$1;GS}4 z7m}j^2f)XkBVuvylIg>WLUsv}*3WfQn1M~Ib$8;#*g9D4U(oEA`7rt^kqtpa6D5{Q zEeeP<`urqc*hhNwpIXL~qY1)e8kRcKg9(>J6w4gU%o)wqVow_JysRSp67iZJUozBA zz9ZndQ_!MB(|lbBBSd6|=O+yz+Q1O^N5+hylZOqu-M4F^l-SOQ67ZX}1vl{;I#f2& z>hp8|`+dm9&BcYvY>;k((5Xo83TDUM$B=hVn zz8*<*GhHd;ux)^J4Y+2;ZS+vrSRw`0IU zjRk!uN2(YQVa^q3h8}XkH=h^GbB->eWm6J@~igSFKH%bHsWm1`UklC(@3foccZ=DZeuj#%fOAmyRhtEK`l@^-wJ^dYA6Kh7eZnzyG104`D_eSHk z`Y~{lgysDW;j&KW5}PE{2^)iNDmq!5Y!h#ph!4T(yiWE|d+q49!P}_{kXSFac{5*G zaN~+Rg4Xa*en3W<9w1g;O^;T_?)NjDb7=>(ofN8}{`IzB`=dcTwxUc?zzZ0oMN~%s zBkWU!Cj+S2mw2w`9Knt0A^o;!J{!;BZO0L`CwNpFg|L6_zRbI{zA=*hKt^ z4*jYgC07=cP@v>G8|&QmIaZQin`(gO)ywL(XIsz6&r=v8cVlgL3VHW1M)0_L7LiGH zKPe?c!IU%s@^(4_M4i$%Z9d{{b!%xTNO=wPQqS`%(&9vX$-# zAVKm<6WldG*7j#6q8ETJJn($yD&pEqng7Msa(p;d9XyLUvu)5-)$9cV`}>yCFDKTK zq?jZ?JR$}X)7N=tuQjCc7D!ii8p1|@?+bWU-r$j=(AID1@ts!3C~fzs?g6{8O| zcV>l_R6;W(x69YzOF$;W2x8C!AR=b2ePn=cln;4cJUbGq6-!mq6|fs3IDf_`NS*ui z74)^xBA^%5a}HD!oWBcHQ<0m!Mqlyk_LS_&xI9oFZt8stx58`!uk&i;n?XF$x0&NjV)ny6^5P-3L zZ0zPoawUV(?F4;MDJqPK1n;(q{>G%g><#HV0E55{4x7|6cQpAV5c6Sth!J&w-<29O zLkN~eljE~M%X~avZH9}v2IE!cXULMO=60tHYSJ2ootv7xzJ0Um{&2FXa;rDy318M-h4XvKPS{F8$EKZXijmc2(hCA;NbMExe8_SKD_!Uo$=jF7Ky|u<;<3R100w`b?@|qNI!#`@!jLL zXDp&8Bwgf-7>3o!8vm&Mc;JrH$O7i_gFB#VwqufQke4ILU^bHZ>}vPlI+41R6Mnii zn7T!K+5bbCBhdecXjm@%mmj*Px(~#p=`Fl40B1MUl#w(%e zvadEcb>MIu!%&sebGCRTgt$*%4}CQJ83QQSM(k>h`xs4Ns*4`79 zP_)$kzKs>mGOJ4x8q#G^%|@=_RPD{@Cm1tRQ3L?HIoskP4)Tt@*d}WvZHY1=Q72!` z=Y;9blM%5aB0ab}Nq;MIo*^=5WP>C`U{Bz^jWhcg&>IdM>(*l&h~E0$JgYOXZNtJ&?YF8fOLn#eVXMDDSQ4_R*)lQw6?^L0y;&3jp+QW*m2GGIK={LDSyGbb?f zY+jT9as<}B>q-2u@Sz_TNJBx1JYe4GY6_$;a}2tNt*wVOULcPbvh8Y^{qp+2x&v@C>YhwEBG4%Cr%Dtu7%Bg z{7of};1T>>FfX#J#CmT-J@yf($LZt&~0PI|w<1EHu) z!I+C64CvYu`kV)UR`2ZVe1oqj=_-7S;Fhav-Z7@&29XB$r#8stpxrbYrJZ+K?rpH$ z4tj(>Q{9Nk)N<*a4O11L#MC(JU5qO}VfOcs;q>gIJp^ufojp8iQ||3VU!dT{dJQZ( zv@v%apfFhJ4Tv&C_Qbv4%%;^zCS|Ni_GoOZ z8}t44ZRU0Xi4*ykjadsMJ;v9x%uR#{6XbcSaAPS73e)l)WTf;O@eTMOv~a7 zV1E^VV@woK^C4Vt&9;(=A64z7^x}0G!Y$Q z&ryUBeN44UOg(3{y_;gT*M1RFqC&AONI6f?9gZkA$YQ^y^PfyJp=ZC{Da%vt%x5%U zaHk&bKl#%jX^6;_0BJ>CvC~z7!Oc8wx1lJmhUm0qE%r@~hf*0vA_Mz~O6i zNMOE?%G&?}=tU?>dNYUtaRvxM!K6emiYmxMyPzPXDC4Lu<_4P0tuP@(t%pb(7P$T$ zGGppf&pAm-pG~*$+xb}!S(h)pM-J`QDS_NRDt+KJ!RFGo<=rsqE^hjz^}eY65XUalV#dDC?!u^VNgLxeq1Zas*61t4LI+u(1(o0UgE z_TbT0oGDeStxjq37H2;+1V{MBZEM1ybft+oBAq6^>^+f`%~oY`>%ijA6YTY)O+gZE z;tMgk+pDT0dWW`Vc(285V9dp0G5%F(F8`m_mMvwWaZqeegI0Q^othK$l8Kmh-K!s0 zn!gwG3Vl{aJk7{DH`KqDP85(q(xIDCwnTYsuQ{*c4c&g>yfn*Dn6XMLPZe&kl!%r8 zbj2mb)|1?mA~q0L51z_i4=Vk8?O6bfJp>PtHcwY*Z1NZHGfJ}p*T^ZvPyVto3>c5b zQB@5IG6iHM<+Nc;}F2O4@%wRNk zr4cs92{caW#jPK$lfvWOg79Z}FukP70F+&M2cctWXndHcO;7eWqt^Ed+LVE!FFsk_gx`e`@?n+e*#WP%me(aD~LoF z`y+pKow$CnHHbxET{QH}A^|zMg-_%J11eo4iu*B_xtSfrry9YD%AdBbhWaU z3Pot0qXhc$=vN!y9+K2&nikEzhZKu#I!`S#8&&a~Kx)*|Q}*J6vB2PeSJLs{MdC%p zX@VSG^tE>R!jY%eJ%TeY0-ut9nPqaz$sYv#)J;nF0a)h>omQ;vuF)>`IEJ z_WIGY2n6~#r5HYCcSMXozTl~5hnHJxdAFh}gt{f_d6|p9ZPsEc0x`hpyG)Dz+Sp%R z@69!NxC>Oaz@cjl<{;VQbL9lENE&1ci!ns7c-A@{E_x@5N|?S64odTU1#u31%K5sg zk)%;Q=h-m+wHt0Wr|DN6rnZX74S|o7DEnAyjP!;;fh&gy^jyFm#IynFB3*t_X==P& z>#npiH~2G$x%vz>k4R;M2-f=ofiF^oQP#C~oI~YRY9&V>tB{{_ULBmybg>v8MC34( zvkMgO6GskMYDmxmU9XX~YRy*^akJRH;(ttP(i6@(E7E_2#@f=}j9A(BLerXsfH>U6 z2Z^0|0yPw4PFi1HL3?7UnG1#Qg3Azm$ zByEePg0fXLO%gMkcgqBU7agr`ZE(N7V%ijN%(DujPiTV&I-Xw0i-B*4${I*lY4WRABuw~lnNT_qx#u87e}DN>J|-to8Q-Y@8&wR{M4DIn*7U1addj=x zQ;K|B9X=;nX6m7<^uLW$bv}yA)mWL9UrtDi3!kF>D_TMfs{iMA5g=bYT<9*nb%(M^ z9Zy5?@Ed1s%$4ZSuPmCIpV$YVn+%5Ka$Z5I7QCGksSX*J3M3E!b$bNk9o4Ll9%*4+ z3RN0Rx}2b99SZ){kBwjD)d`Pjdb$ogzec&g0+Gl&)#ITuiRkPgSYf%wdRL*Y(MvTj znmK(IVoTY`;)jN~mz0hOT&3#sEc7nGQWs&Z9Cu#d2TlD%v@%7UZuF2fVd&h};fOjG z@SvY_9I&wAEV3VLxP5#6o~^KIDEChk-#iXw5=&eHW=X46-nbyLv_ahYu)(RHOQs(K zc!KZ@1T-QpWV_Uo|M@*dc~MFOq!WBIf_+7W zP3{;EoI6sfsuXm?=b{c--*xMOBGv1>S)|Gei>9j-9gM2-($k|KKf;fRf86eH={sNX zH>|tfIwLaXnpQjYKtENX7Q44FsK^^YUh0TTj{VtC7^H_(T2|!W-W-M0$>8Ks3kHaw zq6hou8h?WZ^V`ktLFzEx#sU~Qc!(ph6Mu^9jPl9N-4N8QX4L}m!209v5qZa3MDA8E zAB2P>0PxOj%a7o_>J#6- zmIvm3V%c|@FTPeNcDA*>H{lDns2!hT5Zn>OKuB&aOHm4br)Js>e_=?PpAcp*vhkF; zhON$S!;16?gFj7kyJh56h$9ah<*G(L;m$lR;>SgUb)zU~gpQri_^N})F|ThOLyb7T z4<8|?8tBOB9Kzu^Z*|uf->;pYeB<#a&6#8aJE`@~Wi1Lj){nlDw=~K59*xdeIydM0 zw=?$D=X3ex!4nyC*E}r~+TQXqqigqotIYiYjyw&61)x1?&Mba_4tYyE#d8`az3%Za zo`o)ya$n>A2}kIv>Ol9+#s8F4_it6b`M?dMOD_vIo4SxjVe=%R$~SM)*|x4MzsD4A zDyQFw=eIa^B2?Q6a%F9>6U46nyjKs4aaUMT?}8iS3nqvyNauefqB&N-Rc7Ppn1UYizDXcnfA5o06S6`|$B>ib&;he>Cge=vbuq z^8yqv_^(?T6;-ck2i1hA8Av-}joL9J)Fr%$beCXm&n8nxp;YVvO~6wtElkPOxj z84_r|A4CsXe|dGwJb;p@d)zihi)z02e5e126ILloRSrvAcnjMS(h=PRhU13~U9$G% z*v<2}sM0hJ`kR>H^5HRbnCd{nxUNK$2cASe#`LqVYO2(D>(txoB-yf(e(5l}Z1S)( zhZvn>t2A?cTj3YgkRzV|dP>^3J&o9Q%N~q(g5IjBHs+2l19;KhobDO*!0i$IA%Os4 z_!{gt*kw(Sp8)d%!~)S&2dZHp;8S0hg%?rnkw|DW7Dn^^o;kYHhVVpqmk0bD$;a;+ zHC}Pykwx60NJZx(n(LGCa6sf_P#PSn4s}nK%zFh&Wj+Ar7u1{Ads-R-Z)okfpwR1p zG$tuE_-m`{x2v`NG`iS*GHQS$kPx_r_R);a7e_+Z*Sn7~{xH_)D5@u|MX#G>018tTqYlxH z6du^O8=~-O;=Fv0`~Xfhy^I2N#Wk)U?2C@hsSe0w)M(&K0*nM9*iFCY$kcrQn0h=m zEwdjZGjBk#8wd3}^$r0&tdGk8fYc1PKEg-FyXSkANNCoacQ#0rU)Jg}DShdxyoL?b zk3@5a)SdrOGe#(U9msEY$;wU`mWjowjP=)euaDPWyJ0asB#xS;B8WjW8fAcr(O0GM zME#q}xQgH1nJrCGidNEV9S%3A+i~!EvGad!wp}w zqgmoIve2wA?1qGKAMGNm8CV`zUQ|jcnxFI(wR0eWa_b-$*@++`M=iDW&+%iLd2iW; znIMf{RQ>*w*90M8QTyY{G2oehmbEjvwlC`v7-?+%;bhvW9tUP9h3r|oQ9QT|J~RyNTUAEha1 zXGB*HCufwH=lC`cOZhKw!?@FlraK-zqOHF7@}f37+&3_un9d#5QE<2!(^Bmyy^9M3 zW%%c=B7K3d)X6-nooHqwk~$wxa*yNPh~P`i3e>i8tzBcXPWu_9hkdoyBDIA(PrYE- ze1+q(5{^ISo0Lw|D8(&leTnR6J72@BrZKB(#6C(k#&g;>2F@?}KT61OMzYB|BQ7@5 zaNc%Ryi8$3UPGJ-lK-UG4d`d+DqTN=?A-7keKKXnOWHa#8KU2%+!1+!o|5vKLETY< z?_0iUx>hxJz3d{>T(9gffj6`~3SF{yO5Y)Sb0WIemP1o%paXU|@<9#k+Ak@Df}Eg0 z=fI*kE$ZuENFCn;s|MP=upsK<*-097S;#YSI~F_1DX!f+JQMa1$)q}Xq9hNaltZa2RIS9%yJ{06HE%fGbcPWeRAX#QtX3~P=#Tf+ z4P3WvL_KoU6rd%_6&n&(rJYI$r3MKU6q)LU-rnj}E)Lztn`>3M7Mdmgotz@Ech6&| zUezuui4I+27=(9b@W$%U8}5lQe{#yJrgZ7OdWGUD6%F+Ai&uh4UcM)8{pe@ zRP*3&(&9|n-hNM3oX}qw8Q}Y-ke-4#JTG3eQ+sw=pY16?Ju_6mBJ@F2)#^3(NJdT# zNHS6FRV#$L{=&&2+B_Gpm|8ZVJ5(Z#`9t+sS&@_*#$a>Wzjy7a{L8_l z>g;RD9{?8$#JGti-3dD}(-w=~Ot&6a(+1NeN^Vn52zBjPxfTR8PnY zIz0q+bAHN2?+aTIk58hi*ATc#C9?6?nWFDtno262!p82n7FXAe_@Kdc>DG9KKA^br z1HayCOjb0+??4FIm%smoJ8GLV0mgwYiKh&78Vc2?q$QQ$cJQfPT=M1yqOtR%gZIwZ5u5D)bp z7y)5!Fj{QH|9I)l9i!sQSGCeKbE#j1NnLc9`N04ChJ-O_O$fE&z{3JB`3Z-8?~R&M zOuqhY0n7NgIG7R8oMs_HH`SPfE`#; z^j=1Z47DSo!mWmtf048CO)*SdEoU=hzrYtjq|5i@JyAUX_tbR&6vFTuw&?=L&>wnC zwdS+-zu{{Aw6#s}o<8_i&vP>CDOm{C~Mv_eR5ctF7X+LC!x?flHOLNes}u?<1r z&<_rVJmOrv6ea14F=65Goez&dkJxl@K#S0uKUSZ=1V@AG0zNk{8B6~_FM;`Iy&K1+ zh5X&US76mds4*63=x45x;1|etX@2QBy6nK|1190;OZf(AQE&j5=f=kBz0_MXWC$OG zx@1#1vo7;exIXL%IsL2*(0YuesZ|dT-^=O_wy+TL4?|F!!5ckNCeO|^cN;hw5`=gp z+j0>84`%n}RH#Zl0iD4@$NhBrQ0UsPsDZ@|S+FwiU$z?>T|FdvpfqW-NxBhs7P7r<14iU* zX)di=qzs(UY6dfwGo;TKa<8f18n@`mC7>0M67IL%^2h!pr?H-o+Q!BgyO(~u|I8?6 zFAe;nb~#(j#>=E9LCek(myM)a(sM6~@eJoRO!A)M->cxNPq={D4K)bY<5J=}0wLrV zPb*vy(k{cQ^h6cHBybFxKWYR?P4$@9%D1}BL#2)iC*QHSVS$y_faHe=B}J*dOVDJ`?6GJNi!Rd--!$~KF&*6 ztwveEL7~d&sK9hS05!pqz7-2qnnuQ#;aTX=Qt6#NYvX+|*UzrYrBeqMY-vSq_Ift} z!!Be~hQ9Y_UL7h4bpv!)%1}p==fh=*QztoS6H-4J7W=p&Uy)J(Vvl)#0FPBSuX|BT z&{QT-+&Fn?>XmgGYX8Ac3AKJ?;R0`$moU3$@!F4?cZ~udfa_Rv#g?Y1?&uQGH{HaD z*#tj9c0+%GTgbYKx}^iLm4*A=MiV1$lK8SuV-L=qS#@XEP@A*s_sGo>%eZUlX+(lX zH?d0K>7;}%jy&E5GRS}$-yxBF7kBvG;k7ioc7c!PQ@i$QF5{091@gU3*z*6dg=i?b zl8f1rw@#u|9R%qj(~;__7L)59yPuFStpW40J?Z9QY&l#K2f)qj%(%F^URE(WIP9yOuHdZ7wfu1{i!$mcerGsksO7*@W< z6+{)#85>$NjXOPs+JrMDw)fz(LrhhN zTF^bcUBw22$Y6C-n{ox=aQj|73101Rj{2WmTxPIV6xiDG4+;Z0smR%LG^9T-8P;nb z0HsmgCBvy6QvRW%_iy&|`yO77^}Lw*n1LmYUXqRaE0BN{dg~DeMv(lvs4aS|K9s%m zST>Z>;ja-a)Gb`&i7frwHnb6dOfJEeP+r=jckY;Cut4JAFN~%Ck$%D_ zfy0=x{4`4tAaYUIfdn`5ZuJo!rXb7bD=1C?+KM<@OLyhRjZBz~1)xb!}+4*J>V{G6XWne_MSjQk=)Y>d?NCGqsW+p)|!isrw9E$HzoY zd}9r?{u>m~om2bA^TCr_+sfFaw`mWNO-}P^(z8F>{PMUPy{?8Yx&BQGdsUbMt~w^Nn`ls)+N6u1GF09(bzNAxk;;ApJc!ZIe^^ zff*GCQ|BEc?z-h7qW>1Z#=_1oO39$0Yx{TRho*;{8ESt$>Uc5tVqWbllAZ+T_{}~F z_(jaW;hHHAiQWPk4Kj>@SwnF17(;?TeHt17oi(@+*4V@;$#34tjWp=nF&L$Dt?3Xb(5t7a?cG@`>a@jeG+nPYHSKV``&dR=8MaDfG-JC9l znL7E%f}Hx{pi^^oD@*!EqdF4R$B0LN5Mqsa_l_;?p*o6Q=XUtxkWZR}8W~n=$-z7O z@k8_Y!bT!mtj#{VNqC9MNG9^C`8u5~cBKE{eH|#&!$cm%d+$%W?-KJ!_xbZuPO|;M znK(XK)$~uX+nM$x>+q37ao7~XHez@!$-B7 zzOE;Tk!@YOCQf=}&pNcw;0R%)|2xwthsF}$1(-0qB?s{^DTM=@ap06{>$zxk9N_t+-AU7_AK zFD@2T?-E-^>L@pWhOK4Y?M1a9vi|zAWW7-yk}Ytca;pn5TJ9k(PvG0Nd_@JM9VnrX ze{pi}br_8cJ;RUti5>3xa5A-bmwpRp9>t6*?i13mvw#HHZ1UER)Lf6zsBACV4M1#& zOHv@bd{JB@lb-Q{KGys@YDr_omiHQm`FEUKHyE&)b#pm?Xz`BTFxY;2^VOv_1pDF> z({B5%xu~Ix)$>?3Jk^WUM_2cBGOpOJR1!cl_B{d=NOZq^KPB{3dToRwt%wj`UgZQ5 z_<%(LY%rxJ&3UtuctN@tUF!%U^=X=dO(Bo&ptXmiONkdNQxK& z>mSw?*1>DJNf#q37|VUe6tYgZUXBH<#~!zJ*`U%Av(Ptv)2+BKt7Of6qmr!Xv8^8L zlQ5V_pz|~s@wa$Ya*aeFJJ|wZIRo%N2xU02l*8gtG_CLJdvg>CnD0M-(I*x5w`hkdy0zbn~q;2CEOhotb{yp6p0aLiP4G4o?eMRFlLz4cuVsUJxnyC z@rC<4v!u|H;OV{DsY%Scilt(iEI=kKWNEJTcj0YBb|(KDjR0h91{r_PSDFc`i==6rk+;I-~0J1 ztMFdDVz<5Rr?p7#>`sNqWb9WNU_KK8fvwpwlvYCtfUV1s@|~&+FvhU`wUWg5?IzuG z3XaaBRQLopw_O?25>mezHZlaLJ-D`J3foZ^F6|mI=?+H;B1(*`-00vXnM^M!qk(Wm zo|`zRiN(F|x!scfqh^wl8uQ>$-GxDab-<8UxWoKR`S?zzOtZC79F(dIkhQ3i3lQ%gP;H%Xaq0%0_VxI z%aF1m!J`L}IJr+>+Un#&P{W!GrwHhUsck_E?F(NeI+XZ{8X8)^T}<5>~EW~KUYiD`pu zxR2Vfvc5Wm@6kNltz05;1e%i5!H!nZs3BDRYPI}7g}#nZ^BIoag`u+Zku9SrAINZz zyLywwj%Zk)QCq8L3IO<~q8egbXGA}OMX_1U$5&bz!p13yiUZDcGF%X6BiCk5Ify+f$af%K~?GJHzQEKhz7Rm5o z`&w5~ZIdq%u9BrgNP`6eKIL*OGv9MCsuC4GM>OlbNmRljl&W*U*Yr2Uh*BT)b0!NO zQqgGDreCG|rG&-6%;#Jmry3CqPP9SuL6Wnz1X#_NlCz<%PfSezV7%zD_V(duNk(}x zP$;*$_lIF9m$=KfpsBw1b2>l_o@iM^YGp8>4myYFkG$Roo4zecYyrlI|42YQT>C+< zzRqt?byTwPnq8p419c&L2V6P;bGh$$AHb!+c^ufBZY2ZuiD+Qn*OX+y@ z;a&f1=d~sG`kgYw~c9L;cQqNZXg3$VC zO*~F+Ws6qX83RKh(G3%wX6_+oAk9(2^k}^ddCpU6oLbz;fJo+=4mdC3zOVf0BMvBE<$;g0ET^24`*T8 zlKndYRlfU+ncXqVY)~P8-BXDZ3R7=PW%z7NM0R!o62yqm3KYX;p`45EzYZMBD+9jj z%@G+Z?)wHfm}tk#^i~bxQepg1*Fo++^x-@_k!g7Zoz;@Hze3CCo<5WlW)3o@SITckNP6-_vy0ANIpYydQl!Dvnkn(uB)en>VIM3G^;_bnCu_cNKjf`bKfrGmk z`q(mTSA*id!El7;Syv8CYTNHsu&k>dq*FlC@&0{W6op=`BX-^7 zy3theQId91Z47eUj*BnNoi3c`Xn>Hw)ovkp7M*of%f%RbneXaH4LcG{6x$MLXR1~; z^n=VTD~c<)y4arWrUjJ#^Rv!|6q}x`0LEbN?w1|R#go(w!{5uN*I2}0gzK?n@e)Au zCoaSj3oThU25CN}_VSlH1>r>ycYEnHpfboi2_QuL4D3*46av?_7{qdQJk(DjM5V-Z zEbYvUKzv7nr={gid15J7KYcAFN;*2PXMk3!J#^AhED7vQW`xN-DWt((kN?5b{>QG- z{c<9mi5d;Kq4rBi_zAI+n*px$9!H{@9~Q+;==2p zM?G6kB4(H*oF7b;t9z_1iX*gQ@|HvqMd``bfRu>~J_ttyY*a6;nJc;Plsh&spfu@D zAb0N^2}&H~r=s|gY}$5lyx16GvyN->fI7+>A0tAS#2@>}N&73D)_45LD`M z<~XAZH8yzU6POfCLm4|QjJg~UaZDsRn)zYiU}s!b5blBme932R7uuw;3Q(#Z~>yWTRJ@bx~P4Ua$!q}0g?#~U98fk;~2#q$n3ihEm1-0b$rda#=t0C10;)=SluK2{le^_)9BsOB0Bf`P zAUI;3B%GtML+Y(48D{M;fb%~O4_fKV-3)R?d3H@aayT7nhetPJ*GfB-=`1m)d{fCF&gDvpaymFm%MU8wfFlmq?%>=>u*fnCjCr0xW1 z?2U}F=RVn%tinYCV>*!`p?9n`qE~>fG;DVUTc~>YUbMv&a6bcIr?r~6WRCSQx-@9y z2ZJj*jV|hVhI6wq)vJ;DGk#)`h+o2#f+$25?cY0Uf>6 z#_Uv=^f!~$6qr;FW=d2_fUTV0&yh9p7ilup)gdQJXHiY`OJ((QPmh_j64goCkUt(g z*54T$;AYW|7Pl`bFu}N=2t7=;q$bbNiUEI2lsw_s>0Ga97peH^UY^80A^!)D z@nH>u5mJr+4WzESowAf-o#{;oW_MfD(6AFsu_WB98E06aRsu5Hl$?>{p70{eBQ>1F zN08nujq=LTg9&J3|J5kna}&_P)-s<=RG%$$$IkLje(gEf$ye7|HHWuWdawHAzY+fso(nYkpXY1 zCSn^tf`oj*CaBm^+t}lUy1t(ROL&q~Lv&5;>~N;Gxa9L!i*Ln*CuP#vFBCsNf97hi zR?dx)(4K>FnX7vul;(g$RI;CLma&3j1PwG9kfQ7Qq;#d#soqW89=Yr|3O!lzp8VtA z(Vv?Sktd{G7Jwb zS<|(^7R(B2I&Ul{=GZv6s3nj7Nyelf-a5#eaUE=qhC0i&sfUJ{D|nF_Nynm?#9EhI z2pMQmt|A)sj2469fpo&bvjK4(Zq{*dBBT{Cu2=s)CIv#K1~&~i+XX8=^b~XsA9W_r zPt=G<`5vuqCJ0>iGeor9v_aoG;BJ9LJ{eOmor1Wl>sPF|H_iY8 z6r3>M$AxvW!^zy-cFF+2(rle7x}q%x-q!M;IlF*@^Dq5cG8Vxp@kpnpC^DJvHZJ1m z^EQmAjWG&+3Y66A*F9w>N<1;_vt)~|?9DaI_e4U!p4s(LdB1R455Rn%>(Ww-Yo4?X zMhy?*z0w*<@jVy&-5Q3R=R@%?emZZMm~Eon(`d{Qbq6FEsV%Kl5Mr-#;e0`-m`O>{ zxn`x}2L-vwu zJ|AWiTkVyZ7cZl4gw(d2ml#cbL2@%i&L8S>I93pIVKj^0g>u z;aBwi`+C?Mw^n_REe#jl6eys!VRDuBfW&4GTrUvkM z2L^!dqcnfBL@;6Z6~EpR%Pf$E$qUJ&$hfm*tEdlvh)Z;ZcLAZ07|Q-n{ftRE z;Cui}<|R;iNkoc_0Ki$TVPYqps#qPC>-qjwexM6n`Ek}u9>c?_yqq^qM@!P2rVYzc zOYmD&h(ckxX38y8hG|$LOwVp|GogHiuDy-s`feur)`Qh#e_tb_-h!*poav?XG@;jG zDU5Gn%?>P9_lJ-~lqfAG8AD$)2|C8>1hEi2;5<5cQ^_UYn%IJR6mmcGzI;Nf5%-~t z1^HFN;ro+}_k{|z= z@Y&DFfUuZq*3A|){2N2q8~ip|Vo&EpL0pOV$w>V`wB5*146Qn60>}PT)N8a<9%dgE zDX$3bGa=~s>+>i$qToJvAX#2{WLcd`|r%O}WZMdEo+Q2lwJ`YSZ& z>_-n|09g7ZrMeO4a@}H-4#0Rp;ipG@3%Mgop5XN;A5#)Yu@W0wMh zxyJx(PCb`Vn4Ki|tiO7#BMY!Xk#PJFzk$M9qXR*o2(%*JN-V_)Tli7@NSTgb}Lrd~;lqi|Qbp zTV2t}tte5#ExU-GqwYAxiQh;Ih@Q^#v|ZEwGbj%C$MMSwG{*BGWlW+h zag!L)+L0r}s2S_*Mg|kOeNF8uxhkmd}xHuXlf=? zmJt3#u>EKLeW8ski|@ON$sNl#?tbInUoAhyP9SIf0TEKQO9YsG)cbkz@luddEmA7L z{n(Ojz_2^XgIx;{%3;bB;AGZPaOXb(6;Ep2&QLTBNQ0k zD>cFMz+d3)b<@eP$Dt~G%vh@h7dw41gFTQH3oE=``*j62N1dk*SoZC3g9k~orXHAs z)2~a#4$pE8|ILx;!a3Uo z$j_JKy`Vz`+j0ri&Z-l8=rXyD8hSS{sF2wyeoTT6CXuE5>pWtYcP64-ZUfd;^e(Lr z(L%@uc&hK(+PQTEvIZNqfo^aVT#Kr9p8tBJlpSF>6Y>^-6lCP&dAeWVw{^XcE6xfx zolK6PTY>E-$SDf@(^6)@_c4){P9HEmrea73!Ssd~7-Yg7;gc@E~yu`l9PXj z;@@yLX91GVy38p+m7Q*oMd5J0cun;O+;LTl}1I4dJU)WM9OiVV5`gWb4Mf) zx;?QMb}@7A?33iLWz(-SoJjX)vaIKb2AuKM!ZSEK#xO#4ErSY+JQA{j$jqhbHs6q; z&OI9dTN=Gn{2CnsfP7{g-@IM=SuX%Nu4}fe3C(odi*exyy!OvPI1B5be{6l+hojD| ztyu^^uN(o;kBXy0Smc-L;CPy6f%z1wkDF^uKn+WRn(qdd5dRdm09YDeqLRd>$FyA< zIS?3(6OM~GBYOn-m0s0&V<76QuU3?Rk)81w#S>tQ6tzrnUCT%N=Xfzo+Vyh|UVmtJ za8U+EYGRXqDd+BOW)=$uO`Y$6E>mfFI7A{Ss;cl+EmxO*9qGDA5Yx1Xfye4 zpbt5_%?{!Zw<^SPGOMJ5^41TIzxYsr#Gek1DKZ!$AN8@uGz_jtw^1enGpaL{^qOT8 z4gbLdu0qReak+Qe9hupx0rLwGU@C$NyHfsY;pAto3%eMtWcZrH$fL+RFdRe0t!X>K(yA!Q@0Xl2cZW~0k%XNtS-n@-%^IWc%4nyF^(i;I z=tMA+s3$}fgF`$@dK?o+!~#D5Ko7a>rD-KPTt~gb*_q=5%tm}e(ht@^>I^G6`g1UC zzV!}Zb&%ajb8O}t$zX~B31ik7D83RjnOMR<^!-|~u{ljtK2iRa{3O+`roK7<&9rYd z{6&pIDCE8HFF%`EZuiQjGl_V~3Ii>9docM6{k7Iq$2?FFS-1-Rkukcp zDMp{1cpTSH>QJy*4IobSR%TO{1V!rVGifpQcWc(-8XmZ**pPz7tyrmMotr9m(5WPx z2VwI+CN~1pBgYiQ1GK=$QyOD>7T?emj}MXaEZKGB6WYTlLWVUw)Jvmx{mEK81t=Nu zXVik*T1TpxWHUlOj?yPJR*_3Sf4Y;4szHo!X@zGq%K9brS?yvJ(%S#QzcufrIRSTa zu4=5<@9>IXTgp0jhq;9fHf^l+N=y>V_o|mqcu*TN-W3k{LeHdojVm=FMdv9q8?m(E)GWNL`u_o@4qxDz9dl!|~w_%R~ z5g@CEgSRh3;Bh6!VA>u*Z;Fz1X<4T3{N;x}JdBD?I((E6AORJc%nAFQIgR)MhA2N+ zgSAJ`VcUSC+b<76PFpEjnWw7CbAq@OmUU)SWT3CA1{6EEV~pK$$bZm|t2xdc0&UM2 z0%?izZduVe!Y4qviQ2dMGySawP+xk=fz6eZEqu%^BgXb^Ff5bl@*3vjV+Z7@PbB@< zag(>U;?LYb?Bo6s=H9s;DGQS{5O?dP*{p~G_$jU3rL|%1L$D2KH?w2r`hJ$kj}Y2k z8Tu@{aH%r2glgM6iEazxv8744dCLD5){A?hKcW!C5#PF*ZeI{5Se@bM*TJ0T}1INLQ=xOxq#e zIe57uAGxs8i=GJ&?GP^4c3vqWo?6&zVcR?$ZTWz zirP`}4r!J4J2-qHss@%IG=o(*bM-3pvW!blJ^M`{nCR-C*8pw^PbOD-jm;)}b?{ z?5oM8o$Rcaw9~50v#41ZX1Qy5vpnT33U?5J_G6E?-h)_$Q_6%(#x&^EMQ^><0wt{0 zpr*+LFoi0Vh>57n`D98DKnsYr70!H=#CAB>s|Q!$Lo~?79M~UX+3#IMiyOF)NPDde zZPd)s`#%^7A7eod@wfuqV)k-fC1O{j_V@dA-QtvjFMv~+nSGtJ0WfL ztP#t+9-WK^)RZt2sK|G^@FY8qVNofjT&?6A?2Sc%^R)2RxH#cVdlcA^T}PDJXRD~i zWdRkI*a5M37}DcI9^u%w?1sR^zF){m&i0Xl35jKM#pCV_%^Es}9xf z`Sa~4^Ur=!VKdHI`cbpyNY(aLzj*d>a%J#MXs^$ri9(0giF+%mttU$Y%LmlQ!JTaO zknKPu%*mp%e|b~JZlN=dD(d%0tu6C*oUQw_qaP3T3m{0BF?UJG#xiW|*-dE5ODX*R zmd}R#JMu_bVt-7xD69jwe-U3cI5}vLn)Bor0HBV#H85-FPjA2FOO&xK(ke|QrRrYC zg_(KCJ%0$4TShGTJ5RPbZI@~KtLQis1vU+AP>oLhH2HUkQv@Z!;@P6|=b82!4Iw=S z#c*<}U_D9Ib2$j%boC`Ah!$jck%vZ3wU~Aif~f-jEJBx-Nk-3JjIz=?4=Hj_>4y2h zldnsUIGxlL@W%lEU0S`dHbXD*Gy0%&ZtlF$>%8-ENv6s(w1{_UbO<6XXFIbZq+Y!n z>stSe#Pb(Cz*Kh)$UuCsU8L+g<}QRw!;3JNPw+(&OWaQSWSKuK}Jg!>*DsQgYuZ6f*mf$g$b#*37n4$@Iu`TvQQyIoQQn_h(jBw*yA%usRh-wHmg-Np;t z!_$!8`VbZwTt%tI;*GW7rFyJvvj=^%xtjc1`>NL9!4Kmm&tH&@-gw=t=A#f}n6};M z`|zW3WRwsY0af6vK0?` zH#sDn%=dg!KNoJATQi>o1e`OEl3hM$Fmp?Yh}%PGDN8~nk#D}H%{$V z0i1i@K-VO-osG@i>F3obA@W8YXfb?xJs>G|hy0=Pc{w)v|A=61ve<~e#awR<2L&={ zAF?WfHVm3q%jS}Rj4x;yt4x%?gCxZ2$g(++DtXj;dedWS@+OjLsxuAey*LggHbTUj z?#{{?sW{*bGQ*&qFFFJE)OW?MROdHwTwf0KXVLLyA*u!ZEsVKL>`sitXW&k$F@z4< za!JXtC_Ul^8)Ez16mDX|~9~Rlgnpd_-nrl@g0aFLlT% z35dj7C;-McCQjk)t=X@bjbM_q_@OD3sv?p(aZMEHa)S`89n}CdI9j*q_t5@*ie1wy z#aTsBF6RNUB2e%3`@LlenCrY)dmX1OV{LEeD&9cBl2)dRi{Pm0pu=2+;U$O?4JBRX z$us+sY<=1$j^$?zhc(zRD|>ATGG#?h<}Gm z&oNCzd)VUa)|7v*mL91gyu~&E5f+Bgxm&yGCz{ig2g-_Ng%`s!&>$;Gx@yZ;Zapdd z0AFjgP)1wV!E&?q!fjv6oX{6jPdsskLmYrxJO|2E_Fl(BY_aDW|6(8NGl~0C16(n| z6O(`*{BEoeaIS2o5g6EwLlPBXS-lq6!lEUl>&V`=u$ZF{F0aa^vI zQYd#_X62VZYSZu7ZH&hkzfj=FpqgG1@lNlAmRn?`t>a6RG49P3Inmk=jAT9=E!)~s z1ukvpdjl1QT9-(R^}yunJEE=f-cEw?khJ^m9K^o|T_(%?7@kXZ+j)9r?pl`!IYqAT z)SrzP++fK%sK2{p%mcWpZbi53W`8d)_EgX|xRFQ7y~SfW)?M2XDCT<9humJiPCQ;q z97})Vc0TP4EB5-ZAwBdnwJRBUdz(F|F~At5E8jymtik0&4DJ@^V$8SL^pFf=Xd@NZ zwi?RiK~L+~Gw>g*Epb!6S4AQ=zx7f^1r|OU@kvdnPR|$F^<8uiEC;&3L3%$bl62*u z8ITZntWJ?$=1WY-Y{`(ABcY~z+b|IRz7mq$U>dD20?vjNG|SX$64-+{qPOVlT0o#o zF;*JG1(al3pXv*f+1uH_;~w`lB-s2!e77y5B~`jn=gh8TakGQcg8xB{eDF=vTqORv zD#KBt@uhb_$1og$ZdPXuyMHhnct?g3*wCsN^S&PRp1Y)Ph^zX_-#=cryq(uH z^^h+O2~n-C=yT*6asLwAc+A@_-mfsDB$iD5-~^9P-rSS)=l93BLd5J1w$Nh7#GE;j z{Tj(V)qc2(Hs??}_;On?0d}~v4U_lOl8};nWYwgXSAKu3pdFGB3SLB#3M>W>yYm;1 zU==F4#NC}+vUPuVRJnW3nu{G}{t5cHkY3Oj8pQUl&$(Ju) z7T*H@T@AIrDPuKb(vLSZK;{QIB#1y5fb8u9OxN(|)qyO}S(>k?e6;N)lCp_m-)rDM z^)iqI8-j=Pa5K_){#X@R28iC&zhVeW|NLnHI5^Xifm!0<(R!!!6i7B`rOse9rPtU| zR+iorw_x_4wj#NeuL_byXe^5uHL=4}a)hY;7J7U>m)Zejs?pUaT+aQmHL0NJ#QO$z z^M?akmXMy$nsz2JBze6Ge_hgRPmz0W2(5kiUNxxOpO%_-!NeSVPD0Uws z#Y>28Xu@+68KK-_HD)H3pi)U4VBve=AOBLL)PA@YJsI!7rX@n}2T>ODo!)+DL_Qzw zS#!lz&@gK}&9$2OR5wX-d@}Dsb*CrGo820Mz@P57I&D^C}gV?JZLM zt#-pqtMW^wYdICa3@K%Z6*rWA`SUO@+gNSeByns&5(ViEBi^tMi-0jkd$0^va?g6- zw}E;5E@68b5{Yqspec5|T6T>ms}j4a{w=f;02W1=$@p)gl5kJmlu5ng!qeVOrkoJ9 z$*r?Mj;vCDyWMpN?Bu&;A%|M}5;?$Th7PsXErJ$0I8%re07zE|V*ngxoZk+QCnlmh z8Oc&Wcu5q&05V=Vqu$+AV7Zf&M6Ly)TqS&0n)DoIB)`1%=w9r!Q%dma-_sB2O!bBM zxE@ly7UXNH?QVkzLs`;+TD?1(rf~sq6u3F!LsUw~@zSJuS=joI;6;_D;oMAhvs9@W zUCW$)gW2b+lucCikximUoqj+j?V}b2K+S3HkfZW+$yM)HT8~L_72h$D9{7@;TxsJm z!7)CekZQtX9zN2?`2Jv$QpcC(xZ|SlTpC2a&O0sKGfcnc1292y>BtQYf0z zNLg4&rqGC=#r)VBvC8PNvovhf!|}M9CWQs2poc4s_BS$<$P{n(2^)=OT097xy=94x zPqf0;WfQCQ0THk4(3XeSP?H-gL&fyW0USorGY!X^LO-x=&THe@|xCTZUkZEifURRIfIj)z=RB zLeSumdLYpPkEK=C{3ZE?NK(RQkZFyJ$X+^GoLYPiSK7TY3oTbo4swd+|n2VIs zx*R83C8mk1REyuY?TmlAb7D?Mw)fRbM_R0vSVsf4>3oy^_F7VR5&}fTnJ>>_(W%ld z^nevt-ABN{3G zZwK!*-vr!x6Sxn1t$IZ6#QhYuk`3hs-qRrxbc6uznrlWpc4jrFzAmVkyW_u1L+B*9 z%)Z?K)8h|r*2^%)e1%B$a%b&J=j*lj< zEt4)<@8j#SSfsg4*3Ze+v(wz>g)hcU)Vj+pJ7dBQ7fM=_Qj5p})*W)sNsnL40oB%) zid?iNIr+V(G0_(ox>Xu_41hy#xqsJw7?0s*L@nLgQZH_wUCSsAQ?l7%9*g9F%;N87@ zAw#Ev0j)~;7qARZ0Y%JFiGj|vFKAc;LJ9QJ%4@`<>cXQkF$hCLO0J7q)|tBGx+M*~ zWnL^N#fhA_saNuxY0J!lI~o<7+9m3(c3^8me(f}HYn?rpnSkRaDIJ_FLTmbPW7d6|2cRlJMX_(QImJ8EvJG2og@gip zTAN%g2?{Js>BpiP&EF%k{*3hb?^`DJTEX{e1d*H$(z^Ca<$m1WKXmV(q<`3XFUG#j z|JTEzXT7;Ca4omGBxa1j)a^g`f!K3X61ewIT0GZWU4x;!t_fup{}Zo+E? z(TD+c9ST?bt_sl;Eha7N&&uCFE zB^331hD`RKIY)0>28+#EIL@&RNbf~(el=#&E5Y&nQd!RhXzN)}GOXajT@Vrs$&DJ7 z&q)WU+I@6_IeruLp?d=quQccZRAwN8R@vpU5p`SxC$b+FS83M#;>e~Tadzv5pCgw7 zoDqSEb~yzV_k9Z4VVlodh$ZLrE*rkGGOWDa|>KqP`$%Tat`B^Mtt|o;A^LvEO*zEJso34P`iV57YXi zt%fowlx_1DkRa@64|z1#RDA^+$jDU8ssu0euEuY?adX29H%6sRFBajP?=+r>h#g|p zTN>8E;Wh)vx90EbAjgx`NWCb+9-==7>aL8bSQ-tZd=Hg>5B6D}-e#kE)nPeYvU4pZ z*rt#N#ujENx7~uDSAV)27W{mFWPeHRiPFxTLCFD+g@Z$B=J%-Y>L_*WY@!GdJvJ3? z`qwgGXV)hhnu${18x!%4u`-F~aG&`lCxE56iEr;FBH{`R@`D z-FZ{wTy*{xiW+JX_W9pDnKV>V|DMFanuu+UVtq$LH+A5PjVMjD1eG&3t{QKy*Y~5$ z)&9;^sd~*33C?Q{Ez%*s^Hn?1S0S_du!Fq-SS_rk_C@T|WMyfzYW}FX-HdA<9NS3O zg0hZ1FY3d}WJ&;g%fbWLQM`UY{eHiK@Rbf(6tO2k*J#*3ixe9ky0^jF!0SFOog!kUu;p2b=rlV0E9{Ble+FsiN=em2M(@~y zH?1<~_&9U}gKSZ8!Dl%`+I`ta!r{I_?$4oc%8Q)iq0dhMU7xoL`?~h0r@U7$v_iY% zM-AruBf)KCAsV8yE$Im1&>EI6zXk@>BRfVFkM9N}Zd+_zR>KL@ubx=J{P$o=V9P5N zdgcV;J5lr)VYZhNYU)7Vw(+b=xqY&1>AW^;0dN^;vM-7Q#q2hYx!wwsF+_Ei6oXjd zCNX9BJ!=t$|LEY%$qFNpM0CxmI)R7Fr9CA@i8#hr!ZHf;C$47F^$jAG^Xvrxm7*>m1%64LpWJA8vWH6CkFXNqbz zm@p4-!cU#Z#8lJK!?Iq>wXkt996srO!KSI)Jl^M#No)M&!Kq*)@d@5>>%VzjcU=VR z-b#@8ZeR5AuF^2^P1BF{ZkQ*;rn&Kb7ttM*&yYuJGAuO>NuyA4@+6S?#aATNGANs6ckx$t11Lu(uY(xmTR|xXj6q@GK>q zyEpXCO+CP8GXUm&bEX7fW^?RBT*5F()ecd9RpPqiawU^INweDJasFej91ny4B@6y{ z$hIkimPApV;}r;Oy!MkD&$1WhX{_bvL74%&&lRu*nJYE)wk~REaehpv=u+E`fxvVN zNeblR3O^NeP6GF?wE%}m5TV{L!Pt5Xx@WM%q7RBNC_RD*?q(uL(*yKw$-+6kN^T)% z>Z}7n_N%kdE)pyUa@MS!PIsk!jYmx?AIVOoojDJpQ~9-sZ)?Y|wW7nk(TVNhCv~+U zIdjJ5%*!_I`MZe3ry|oJ%Pu~8!;Kx4X{gd})(pJnXtGQba?0XO6V4zg>Bpxz07D``HZ&D`JI*XFJd9)`G~P7n z(OLMR76P0l)c@B|EFP*J9XRd_4GAar3cumXy~YV&;$-p{L_-zH?rU%jl{l!Q^mZR< zh>hHMTGCpH#NRFf+ZI-p+b2#90_wwPda7jS?@9A76Z-v0n=irbc2-WZmXn;$V7-*P z7tVndj*^wda)u~h?+A8=&w5Q62c+m>|0XHi9n9sx>Ui?uMQ@UUPj1;U`Eq$t&cQu| z5fxlGoXKN-!vHdbQI3B@8$8vj_9|l9-Ix95sCjdzx&2Lll810=n!wmV)nO;2ZmkI> za4pX8biTby(|898w~=+*KEY@DBK;IHbqDZwzdxfBny(26q@RvYY2N4hPv*OY$zPGq zE65)9@|YnIWt8T7on<3dLby2n>2*969s$-p&Mhc}HCK&Q#lXm#6~{(bY#b5tCkqM8 z>d>V4+KGRwjQ554xl#E9o4@zClDAy&Z6w7QQexuXR)HY1E83|-H! zGIlip3(nhjjVpjffN`Q7ypPQiGF@4iTpVhT9XLuU(L2i<zk0>X*Je3I0m7NRQ#(3PZ!&q^cw){Tph&E-h-35dRot>(u3HRNp z?J=L{_V29zPd6SgIpCENhFB$1j3>=p6HY6??EOc7)D8C0m^kSvjX3enfsOWpD`80g zlwqy@eTrt}W{I6FelwbUNDY7j!F8QTpbnOaAIe)Qv85Dy{5#|O!8gLO+vtfN8*NDC zZ~5Yahc78!8jBZ?=@_-tv}lpggXJ6i3pobw?&fj$rXY&06{u1uQN;f#Ey=QG6>18riPUy?&z@<@uA!F8j zheP2PluWlSo$YcoToDQcu;#Fs=Za!buxDG<0dU0I8_;?54V9r83G zZSMzwe7)^fTe&Yeb_jK?Izh_4;!nRm3xyFW{FZ7XPu4cF?AZ?#0Tsn7aqzS`(TRUM z^ZlG5GoJZ0GTmDYu$i=Dv}MDjvX)hSTdnbs5Iq{s;Y&kOA_nBr+9u@Z@%3-4K)b|? zBxh`6sb^jN4vX3;gohK+E+}@+;Oq(E=7@kiam1R~HjP_n90d`*6_Z#`kH_QSI&xCge%OrgHiB z+|kH)tUA{&3+YaP4|X^1(Jqe-Y7%Db^{Z976Ge5-OnFYz;Xb}y&~l#hd-d(hj%>O% z>%OfZBs6mEI?;L{xeie17cH@(b{*4i=`5+H>S9v+reKh}gVlVv5u5AQwITpJMmNeBFUXS{z@vT08>D$ zzl9z&>BoENwX=S%-m>@>GNMT9C3YcB4dC^ovOI}wy1Xas+g0OfEtnkNz2l1}m6)gZ z1k#r;1w|RUo=XiRxV&Gg+N4XBE>5bvc0_2k^UM8=2f3vTw`@%u7ZR@KHAzy^0tUPn zMMD#E-rY9ch248NdF%`?$$``?@X~^K0p|aWQeceQmv4p$iK<3auLgHjlU*-Hkl;)Jh6l7 zcZqQJyq6=!;F2^lk}pG#FEW9rVSZdq$y0^Px2j~%@Wld)G=MH4jSn{8ty%hF{0hvnUdE)$8>MHoj*wx(QwjpH_{nK#4q#4p_>=~jqPeU zOq6ORkxRzfhKt(Y-509|T)3OcS_2}VEHLqVpQrZ;19C}jlk0C zj3h2%7f@To=S}YL>&ZwqkVbb~@P9h)mY6nDg0%l4Y=VeY%I}8oD0I>!-r4nUq5wlb zI|FzM^t=Q$7a?eP34d{1IxhLBp|@iohyWtc$sLZpT>ChQH-us;F6nmDR*%)U|Amna z=sC}zG*ajg6hYWkcU(h3REi_xalcx?9cA%wd8a*LBdp?C^-c`)?O{9i;P)@K<$wHR z|M@W5Gw zVFPsIHRTG3!L#A;4~U1Gx%8aTc!Man9Ko(0`Bf1}?)4sv#r2GaF1oF+y&;~iNg_x6 zA?xjYmWvSoFoB3dIB4nrSuNGC9%)70IaJGYSK<`QHcOD+9N@^2_6$n{5Ns;`GJ^&= z3B01Mh!hZ*bu?}}W2=J?w750xg;^hr9PJyKPXw+QU&umU9&Cbk12@-NFx>z;Eq}$l z*1d%vK14SAEjIdwMy-AvAwF|O-5R*$A|p>q489!KSd@Bx3@RH{vud6O;9P%a zam^hlQA`{_!~-nWi`V-Qepy87I`$vLh>8^{VY`@x&zT6GCzIsRIrtn*E(~XwY z=h&aTNyk>MDM2E?w!oMu@Y^0wUR5VKgr+{CeSb}&O;YKAFRB=ViNbCWsK_%*BiI4>=m0z4C$6laY~^7{;fM2@?;LSGbK&gdb`q zp)$;d7*LnDU~eiUE@@0_+b<6)7EW%aG2|=Jb>a;kboN4|UMV#x%_+Ny_CN$&!SyVp z2P#!>X8h8mC6FiW@N^?a_3Bp9MxaO)h|Min-v_c50@vkkF7=ZEL!UCt>KeNT3jgQfX>g(O!m!x-lno6qm|N^Qw)LQ zN=VJqpoA~WHxFrGCO$1oqL&YI(is4g=AQzoCv1OsTao0&m2r-=XE5T>!V8sqRi9ar z24KSdP$~4C}BC z4c$LJ2MOH0V1t&R&vO2)A+k-gBovADFd$o(<3LAhm46^NOz=?#6Zk?-te}yj7Ew@< z{xcBcl*~zZL+g|T!e3=q{eP7xT2Lq;6%$=*TwG*#2|2QQ!`PF7nZEv4XXyiBJzaTj zka}!e%MpyxDP3Nt!{L13fJ~kqKFHXfy6b!^8x}cD=NWg1)L}PH~{XH79PLt zUh6g_UX!`MG?|o?Q^lfzRmgI8t&V)&Zi3<=`}q*6bi!1~7v_R`um*E)zN?@>#R5Q2 zRp@>97en>+vJC1SBs8P~mq zNz*_NxfAmHs1MqVQmZs`VR3{z#&L&1?es4I%-&bcy$N0b`10o5=bj+pTMs3$ zeGyU+beOiN=cs!pj-}uP)1?Nx_c$ATRY9BnzgLn8%8qv_Xk_lDd{tamlGuez9B1#| zOflaGqi5!cp)ep7TAfB*hO`}kJFkTztkVIEzPZ|Ocxk<>in-N1LL*nKZ64Omq-Nf`!nk)d7f(XNal-?@J`y8phI@h=xGwq$ zEnh`Y+GaG9?=`jshs`vX`21-uZ<|qSnqRFLkNH zX$SrdO!OM+&N!XVQ&{+Yz$KTx%vplPJD}N?BwyTFre)2J^)hM<)E*K-p3;+J&`0|> z18<`3z71Ta^5ptf@H@(aE$niWHT?hgB1i4y#!7n7F^OVI^Ls@h!2d-8LmUzx_D|`2EA8d*92c{ zpv~f1eJ*E9pKVj7FA{&nh?-ya-TiY$gBko!_$6vzTC#&B;`!*v01O#T=?*ns{+#Un64Nj~HWmxC1A6nF%}F&5Ty0UJKA*8SZ=YAX#@i z)psE_rS+trj%#v1Dt5og9@QI`Rir7WQc(+tk_z!n98{ajr>nSK@ZLVRWM8?fdNTH{x z1YYd)Q2+(>($b+0GUlz$^S?lim#7zyT%~0oRU0~^E<$WzTBw2#v*QDq6Kgn3*2}< zlU;v@Qar2o?C!}okF6o0ZN_O(nAK0A-CEuLi=$>VVBaS|KM&rWo%J)Y)ZSP(B{kuZ zQz&?Rl~$0-ujH>iIk7)7eSk`l~Ez!VqZ1Yo+E^Mz6 z-^xw|H+>hsOK%}=z`5#?+(lkH4$zGu64-l-h@w49gmdU4!Em3q`HdpXy>3tQXUtscUi000hU=@D zTNsy`2(?KV=Ul{_ulqo?o-c#rXjju(L&=rocT{^^be`H=Bu){^6Uw;6AOy4tdj}B# z6$D5`o>6d^?<6`gc1qr6%Q&tjD1s6#UJn}u^fDNp{H&lcx5N9jD#?ux?^ymxB@HHS zLEr`GCZWj&j$~^X@wb-@Ou%_GDnZQ$?Pu&Jukc#bobqD~b<<8sJ_se^+-6$wn;|Sq zMJFr$H!Mc@ecDV(Q8qwHRYqtWYmrA9C4oGOdv9Tb(9;h4l+=f$8q7)-YpOp{lfX64 z9@~C9zLue7L$5(8@JYW-NykkQI24Et|LO>Z4{YP58x^sC=8A;u^Pq~sYIPS3!D+Vmbq?FOqm!v+LyQE|(UQ2Mf9!hWV6 z*#06;soY|ki+FrJ!dhzo=o5~WPrQP7nZX>63xMC;eNGh|TKb!H@w^I$Q)9Srm1z_N z`Ccl&4Kxc&+6v#iVfAhC@@*A^1d1t2 zblcH-=r^N_^Hu}ZM6YRF;i&x}2j7Dm$PH_dIfw?EK5U4~dd|W_DApPfY8cfdYvTFE z8VKt7%09t8BojUNaczb?{_GDSis_|(?6&k`CBO${J1Z_=SJS0Tc%Mg`ZCg_WKqGNd ztTdB>lZ&ZIB$EW?`OoD|xsu5bvcG88tf> zIxvWw)+-gvTh3iuGXKv`O5e${LZ;wU94^CW+0mK#*eq*kI}{JFYVH6(XQ_UgJb5Xf zPqHPGE9F8=F#HM2Uk?DvDY$l+q+EPYlSaA*g*kPQxyva+6KA{)mhsSoJtj{GT(7XG za>Ja&#OBd>@2Nyms#^SE&TJnt*3IAsU~1~0mK%UvySOwiilab7y)iY>SAHXaHwtUw zer$3ubpu8W{OoRORyp!)yxU%vp?tck8D~H6rpL1G=mrbkc-3OQGuCCH{$kO>!?DCO z5$L&){0kro>hu~&U?psq>W49Y*xPy2M^;0LO@L%7EVXRx>ow=`5kW#H$%g++4~ql* z#F6S$)<50~DFxvlFnkTG*0LfaqZtfrnZFceaDy(pW8)hkrH!$xyP-RWPUTsuJ9mr7 z_O)E2bqE<)g9GVMx2m<0GLn9FF{lWnLSm%Y1*pnR&hAMb^W-=3{04%Qp%29}>=d{R z2|EL?opw}6SGv-dFAjRYj)MSMwbS>8z*&&7_u6uZ#o0#DPbSO@^&YI1DUY5}X3UwJ z{03egO23_b=W=^g+dpc!YJoJ3y0BgtW5Zr?T=x%Ba+ihU7mLtWOQx-FXO{?z2V_-l zK0^zI(}9C4z$L?TZzG&O0MY1=QVHsShkWQj$!XAXbluQn+g9+6g|;?a7~XKhK0 z9anmH5=hcH3X+7iwbS$4ORsk~1-p(ymxP8G4ZcmvgCdV3wVl2L3v)^V5XbM(B|U=I z3>LyJgIU#x3KTEnb3$15V)B2SbOT5DQ2WW0{X6MP{XgRKw!LAxy59^JL>gWNfTW3v z)gV!H?f{U}4~eHzk`ViV+dO?D1%-6(R0)djJxpG5uFgD~D9M>b;`l|vrM3&EdK4+B zmXj?13F2Xg&os&uH`$Ou)fR|}<nnP@C_KUdm2r5qPekyGq5v(cyP znW^o7azI3ZWL*fW(E>KM!IMsGF_C?M?Oi3vL|hm2ne35y^2v+sGF2pV$Ft z+_|dB2Ku}Fz+4`0C)i41v6E(JDwMZ70e(*n3p`vt_cXhNb{REnjUqNeXWMi=Xu6Rf z`t>>o8@MFs7w!x%m`Q7|_y|)Em7s(tDK^vFo2P@Gz4h<=O?7`Cy zBG$cxSIH{!l};JHfy(umG~F!_`ya>Rw6_|dgCe~$pxNa)RW~Bm+&>Kn0CYZIrrV%r z@L^Gd&#s`PUnW)a;rnX3Bq(8)*(2iea28*&uJMT$^uG^T4h;2&9EBl!_fY;o!&k1` zs{3rpgSPKWaS^8*v$I56m2uM%2^JY9^>KEk#SH`Rv~=%f+0r;hP#$2e{a*5=mp7b+ z-c7&V>bXgj_7v|GY;iVmE|^nyR|i|fh%(S+kSr7F_)DXRU%#5wQGs)60IlKL%0#Z+ zQq}>NbJK6&@FrvyqNq0Enb^du1^p1c9mV<*;9x63>lb%>I{-~Vhs=7%hhiUx0@f4q zWfV*LeHwP7c0I7kIA#GrEht;qZihUbHAtz3ry)ZTm#Qpk1b#`0M>1bjdn(Cj{@b2w zxlba)lzqQDIRS11X|K+ZKQPbx7mxSBfyez>XkSo5WFG8tgZCzyABmMDr$n@6M|jc4 zBSsY+D@Cu(maXjAN4!1d)5Hf0;YI=kb!usZG&gDqKOG0!vC!czkhbq(`G{dH+CYXupc5!l6v&%;Ob36_BYPZOFquK8oixQJb#XylM4dq-|l{tXu)*4prroRxU0c*v_ z#c{s&)T4NWOu*!qwfzNL<&1Gp+6gy@Ku%NHE(8lo>o|-__(n}|`f=`8Zwutz#+|ru zEULcWiJ%0osW&+v-0JBS#cRpk-Zw@ArzfGC{jfwXaM#++6lV z)cm^mLrLQkNDbrsGcQuG>scmsRA^fkcp>faeR(lqA z_K#>~%U#(bDC>n00t`Kz+$x|5Daq#9vXvIXiem<}`T$_Lf%9nT4UW}x#inEX0VowW z@1FG}`j?uiuHgsG(O);P@D1%6cwk4!5)!+>mcdLvZ7yc>HdEF7qb=F78+!(K0^UO$ z@mT7sMG$n^9FFj*cZ}2q!$`NFmAlA4NQi{Za`5-Ae>}YATtvE2&61kKU=ZSTBUTV6 z(RAbo;sX1q&ET7XP-st3;jC$r#&0#_Kce@9*eopR_L8PX9|b3@^!aC2{H^;%b3xD& zMcRbobr41k7N$!i87Q5>S|j}_{%HQ@C`#B|TwIW%-q5 z`c?{M;r90+<{W)!?8V>^4q1^1*Cd%c!zpmTow5%s+b0;j5hF!5(V)}@;RmQxo*|)= zEeE~Qv22PzYqnoq`BwiRc16}Yvy(h0fnAh^6w2e^M_b=8;Z?SjS8fREbsIhoK8gF` z0OZAC=7*j~9V*3D@t=3SHl`3T=kSb`2p*^mMBbl-?h19xpeHpd<5a{Had)6(!F#!= z!r&&+F4s@j;D>+8nZCM%Em|38OOqI@x&PdK6`<}DCzT4eXQul0Yx6Li-YM8y2bp|9 zr1`g3nlTqJRthDTv_WyXUn%lRmxRwspcIkgJ#f|90EVuQii|%2e0Zw@zU0*U1+M1| zRBm;^pzMB(H^YkB-^Wjj`ro_|m$!nZeRm@6v8)}+O^txbJE|X9Y zF!t=V&AzVH`xDkCa0|EigMjj&yD%o)fM9{Vh@ij#WO)!^&JpQVZx`u%=ja2czo{n@ zG|1hOaHw>~bs5blVs7w3Foc*r+MOfEeIZc3S{d0$#|y6i(1^N>4bI>~oi^%r+p<^< zrdT9ouGJDlg&c7t#0dmg4Vmo{7f5Ff{={6_Kha=gMa2WdaYv(hNBADD0|ustmP$kj zsQG6#`7UWkWwkwsWfo6{lFw+Kd|@ zGR+$!*DVsy7S`Rw*`>uxwYYWui6h4G-#$}wkhLa+1tmxs>ocmR07q(?)pkyQqu+92}DQmSzEVH{C0`!lZ|SRiwKVh8bV z5VMq(iVzv;H~!)^+>_tK#|V9tKP~@}!)5YB3-_62f~V~+x0GZ8du1~PK`LHZ7(k}R zE|`_98>9dW=ui6d8>x)8nXr?!*&`yHUuZp(*jh*SOj+VYjH&kjSKpUoK# zGf@Q>0r+E89UMXKME=8~r{B@AespO)gYQP0b7Kw$} zYx+R!5y%ZppTua;2I%1u&uN(;1q<=U@r47P3fW(ohaVI3lN~UX!!-!KkA(_0v zjJy*MEmw`H3-1tQ%4iXmEJ(^1a5ERU=J&2<9Z;;|ZW1`nyz4$Bd* z`TDQ(U-V&&6VwtMTXJjYKlW$7nJ*GQVY-iz~jpOhRHM1-0Cj& z^79|KiyI5vs0qKr)3YR-CWD~5?to~$ z&1flw^%=OrQ&pig7C3UXau~i6=R$ehvRnb6F=b9MD_FNQjyZV=7gwK-m)s)C6;QwN zB6Cp<&4&Kib;6M2PNHr?*lF1)SX|93Dgz37-TWI=Q087F@E2ksqQXsKR~E{R)e%B# zxohkZw`6dJABO3<`E9ScSRC5FEb@K)0wXy)A9z6~&i`70~fWI-(GHf!bveV+}tgca~ZgL`G}MiTgc0!N-&k>%_04o_zJ^SEj>l7zX16QVNhEUcrWzJ%T=J%r(vtlC78J{&d? zfu9Q(o#(29|813tc4q)Th3nL*CrcrB`GbTtvNB-##yAQ1UJSs%c+o{=pAr)QuvOc>MjJt&>z2T2z8xCoG>M`yh9x!{o)FS{_Q=s}fR=1wcX!O6lykGrNlBbJvf@ z3_op6Jnwd{bR+>()wR0lwZg|~Q=UKa5nNVIClCB)W)LEh0v$bby#KLB}hKbY!Gpa#@bve(@SGgqvs-B5d6 z>I7ZEK}TR85IV1vr9Ia`uqD`?jMbpQ^#PUuJ8rgkv<)FajNH(mkLPjEXL}kKAs5V1 zbqci1+0gi421$Z|J{fFs-SeoJ=yDdR*coq*HTb4^`pxJj;2KmWn7so=v?cQCNgvo!-U1oBtTmb_?iuk$1wu3BaqBc!_%ZP|c1WPEyFFqnOiGm` zK?tc6iSteicEZFM>LJ);1PI0fbb!C`*0V(lOyjj#3Ns1J_Vxd-^*E z%IzOf=_G_wa!h9%xlF!I5Gn@d0@_;|$s$!j-?FRqXraXC@j9)SYq&gZ(N%<+(r}-7 zOx(OVdz@7d*Pqa-7T|84AuhKgZcc%(gy~^|u#XM%ix3DGsGrt!0JfKyx`8<`+WM+r zw(fFJoijr-6wE|jS%?|uIl?l)?L9np+W_vx8pjX=87wq8tttUA7?=QKtw~EjQd(o+ z%`Fzy$k#$oz~I!;KBqD$%LRx0-zHXTBS*xpGa>Cv_%LUbh$OUmN;?jl$R5>weI1sR zy=kixj<}jcak}-RLUlOXiBHThj6mvhRNmljMxYD^D1%^jIuvMZUC*FYgJY0BaLWFB zhH+Q&-VAMv|6)BC;hi(r(hQ{S%DxXdQb*xYp14TEIEmy!LYQ1)gp(ID7kd;>{$pu( z)<4cY>PN3SsWa7k+4kuUvSETmL&0!H5x+k!{aN6aC#1ivh+gtxPVwG*N@s*?0mVrC zb7Ba(AA~jGsGrTzpRMS}E=NF);5V@B-S~-ZlZ8~i;xEdFlX4Az9&Y~l8g7#SFX8kB z6N?v|rmtEW<{Nsd)3aAfGhA#h@uZy1g-hy>;!KFFg!y~mMgaV!)dbB=O|z3r%L>|x zMleS_r{j*}7(^Q5aJ-b9t=3iG2tH$JEtPN9`sVC)YY~PbNR&{Ga!C%NDn6LAQB;S; zJz+>&$>{gDNr7?`!KVlj;QizuMSA7-Ru|NWzcL(NX_Z_>7o<-lGB2f|NNPxqm5)KhR>hpYgt6qcMBlM-)RJrnD-s^BMMKT*#1q2in6cOwh5Kb(KM#%(f{vI;#)*E5VF+`kDN(uAhBErB(_=Wb zIU>RWp4ed>)Y*jva0(Yp?IKz+5D26+EmVSDg_aXiMt@h+j>6)ezfSF1*1mA^>`lc# zs+Y$^He;*WTb8-mjjmj9_K(gGq)l{F79{r9f#s;y~+T%a5XWGU|gy z5=f-cNW^0}FKPv=*MbI>!JlCxxA}+McqzpF=;Zw}Z_EEiRMnzSg3J@u_Bz$?)+J&l zTv`*#easg{?q6{mUhU9xm(1>Bu9VseAa8Il{sYl00SVy8G2x@uRl-cfQ;#HNj4_6J zy*>^GQ!@4_l##{4!{5y+V0<+ghXr!w;>KGGDr9H3q}dURtz{JjVOd~on@YjrZ)(Gv zDg7ZMxmS;j90>L_(FBt_#m{5`<{UbI&GW4=&{`DWIX7Rgy zSWL}2xke9;VdQK~uX~HfL=JZ6fBPmHm&VhLKBaH;i;l~%?%mAJuvw&sn(g}XB$^uh zA~4WYDiFgCtfe?x2R01kD-RcJ1QxkS-OA{kfx=vHGUTjQm(I&5H>cJka7lb|YRJ=w zyO9FQ^KDKPKcjIiz70oV>CD(Qc+K9XNL0>>K5B)kFc7w;F z&0hQ17{%k+&ik;~@_c-ixHPIlWmoBv9%RgD+(wsnHQWH(e+0xyS$na7QqVQhM5*ur zfmw;g_5Ln$(o)7YKmoEm^=-`)%rAwE;OTu`LjF3T=sk9Ek}09~Wb@WE8AM`NE4xK2 z8Y;%vM|NZbn`TA80+9sYT z>@KXA@(}lC3QmKx2=~(Z7~*(0Vu8%XQ%y|dt9JgO!a%zvr#lXrL$gY`GpmSpj({GB;8!80fv*1i zRS2>n`U9_&bR`6@w!DYm+?^S{CT1HGRsOp9_IJM>3oBij8u&t2X@c0=P@Wzt^1S3h zSmz^KgSjREW`Yqc)u@*9t2az;furwgLo9HnWd}dH={f`a*0MigFiI|^HucLIMCi*T zcs#~Dq<);%w$KZ-o3mEOE__f__?&rFnGKJqnmP2*@45*@eMauRc^hp1w9B%anF1()r)Pc?6lG+)>u2v(5I{!|7IhEaarKF&%Q(L z0QSbQXCx?tL*RxEYDZ|tarLWzGFCF|&$!R6w<^XMITfAW;-Y;Iah39*$$9ua=?z5Y zNw9O2qY}N0KFQ}~>KA0y(=hTVIH(S3+|@DhW5wX&1L`puD!#72o<4*}HLQJzc2&%m z|JE$8{BNaNwq<>H1n*>0AmM^^-l#wjBrw5fqBEz@8$xg98Q`E!Q7U><1mWvu*X!i0 zFXYu%I|VEYjszhg%*eCVR6X4uDSV<_a5bL>lA|dIi_dR!8J!osHulKnB>`D!#yD+h zJkRc7o)!9a<+GD_?~J<|dY6TMoya16klSlyy!uBKAY{in=04pY>@``>wBH#5tpg84`^gb! zs{=AJv1Nc*>cBTu!Q|btGlT4r0w+BZO+?_`dd28f=W4BUKjl?L6#3GDlb)N1@(TCe z5A`ZOu^#$O%yDZ8v^8Kgpr|Px*%;WKW1qmk)2^lHyXJj3Inv7}4 z!yhccv^Uo-01d^*#+_N9 zkSR%7AVF_duSO)F$XpdvriBrQAG8>HF_}U@qu;m@;E**+O-c}FH;BqNGLVzs~sdhvdHnnlZ$)( z(If6+kpU)u=08VmH0|ZZ*H)1^mTojNGoUucW=?I)H+OcC^Sk5Sm?bk}(1A{9GAx`! z)lIK=WXiOBZ#wVdhC{@+Awx5lu3-|vbJ4Qz7K2FC^P7DUjXb{e1)`AJYXl(qnBD5F z|Bif?16_9mTkA~{T-`W%;heqA(R?KpZ|yoAU^z7JMsc15L)tdcv^*9ULqX^FO1k!*p3lUfqKi#w|B_g! z57#(Dy;koixMR&$t?InjH8|@n`S1ZIL7G3ABFC>bw_8k4b zX#<6U^#GWa$}p8z&a0~-I0dkz=xFR)DCd%D6oJE|z4^_rGee8N@aGYhx*c-TsIilr zI;8B*DjJ7>^^XF=G)F*S<-JJ!@amnJR2oPZ2BWgVgoXXYyFp;K6AWIv3ud3|KN0bO z+#65Mv`aw(yd8JE9FI5mrq)5z@r%*+?Qv^ zM3ofUm5Oip=708T!=!iGD4FuYbNBT9Sq`TciXjNl1psktvXh*!JicL9F_3Mo1%Jvef>hx7S17f0;81gNERy+CJG2yN*_7aKyoG| zn62rsATBcM8ix#Vf{EZ8%$+Vqe?4W^WG@IIi^P*il&rUT(qBBu4~~X^rxK@1%Qnl} zt#x*#R2Hg3uge4 zh*AmzNvxr%&Qa^*xcrKi-e}eZ%H1zr>3vLC&v;W?hlA}MS|v2&R}ME^cqvI;f{5Y7 zZ03Ud*SKwrKF;avjZ~y%Gzj!hj)}b|2+c;+I4TnZUi_4jCBT;+-8fmI+#-}>cbaw4InO(7_dnm-mr_M;=BN>}&_NQf-8fdtY7G zc2g=}g2cQ~gVTBvqVG$@e(n5y(IUO7u{^_%w51j*Aeoc6Do1J#UkfLZGuSU z@EiEh@1%dkN&g&Cw{J!#;2lor>8?J93iP-ZBcKgwpR81zC}Ta170_-OZ4Ok;bVEh6 z0+1-v=#}};58}P(WM<44pzCJ7 zKC+BnletLrt#+>zmz`RPL+)_&tA*c{3Gw~ku;;O5C;Z!u+|@bfhv_`f2Eq@1>+=Gx zz5*uSlPOicx09W-afEO*YE^H97XZh*PU}rEzo((f4S!L7ZKCf2G`!xn2s$}c;l!m3 z)`D=}O)o6mLcL(xKx-NcYUv*aZGB{YX4A>~@^xHI@vJoMZ#EJ>e!t1cuv8gr{{_Nq zsZPH#Vd90+xBs7=ir`Gj#8?H8-Ol+N!uKY>9r&4EzG0a10wA}QJ?m;A=BYDYcMNTv z1iQ2f0$*4RuDX#@GPkQLc~g^#|1qoACkPt#B&#*nUUOA-9vU5ZkRbMhZz4sQ135KH zV263~>&1TrEc#t5B66oK5>?6pAD>78xYXeJZH?2{$up-EJ|e)E?HwBv%=Ap7Kym1o zLh^P1E)uE7S7nISaE{!iVr!D<`ARBumG4QjSrwiz0PfHfrOy}$v)Ip5f=n-^9H0$U z`CuL46Z0*&ijhg(IEX+KG~$;{O6mt0Q;zfi3MBmWKM=on3M_!)J+R$y>q4`}S&_#` zWr@6An@0%)*mJ6v1K{C&#NyriFlCCfwYiDDphEQHR3JbpAQ9~>; zjj92Q2?6y!!CKAd_u4aK%mcAbmO&rWX4DU=aDe!B-p~08;iX+>1K36RBCH%KQy*|l zL-L4UvQ|h#^Hg@Y_DJ2yS1)0V6jML||F? z?QvTP4oXM!Yd7SW?+&@7(0fGw(dV?4ZhunTQKLawiHW+PVj(_2Edqi zCAw{wxBf(XXA(kB%GZmF{>69edKR;c72Q!u7Xq-*tdb?)I{xbu7~+p${FAMdSdf`5 zLuKKRn>toQ%cB1`W78bKjed-QCSLwPg;`H!^Xzbp@TM#$W>t9t}YYtJy&d!t720tKvDk?YC{z-Md*JmsC8;<&|2Bq>=Rgb8(&P`{O!^ zIKcz;cvDcR6xI>*fZcenA3F?PwD7A(y!A8GOW?{3U2cRb+BF{!gq@;^JWqk!Lr&do zN6=1iA3%w>;2_l@vinDu%tFI%#8R~cf3A;ou_cwI-LbX7oT46|4><(@nL%9`*s;kb z^sFSxfUvII2bB5fu0`DxqNo>}pTci%%D@TexJ87_C^Cp+dy`d43w|Qzl=^dOX8A<~ z$Yws%p;+n)%(#OC$h*$+516I_DC`k_nQG*Zm{2P|(gZgvKdDDMH&0(*2fTM%YtuKn zvScc2I?04#hTWyK4Y^BQg0LY5b?>}c{1dEKJQ_xiIgt~vSdBHbA0f9Dz+S(V5AuM%sQbW%=G&}io?_AF z_`(-8H^F!p0$@2Vhubu-D{mreDmRlC*uAdLk+AC86c_R3`$AsPKUoL*6uWt5;rbkm z8uxrBUrV&ecLV-NF}7g~q0fY7r2*}n;{thAJ{+!8rPmeaU4x4R@d`v1=B_p~o4BrT z_BPeskJEPK37!QvqPtr)nb6JD7G87NOblzJpO5Suy3>UeBOt979TFf6-hD}RO#O?j z*^w_xA6)&SH0nfetBy9r1X>(%hiq7{fi?Gkk;uGYW!Xq5x(|^1Cs;QM6>QQBPFz_p zp{HQC6320pnyq^Mz_A3pjW$N7e>2wbM6Eb-hBNXB@m%iR~Qcc}#d-zA* zNW2a}%h(m?L=j-vDqEygKk;hlxDV7!BVYXuzsBCT16-irLQah2auXxT@ zJfENf=w(6g`4K|9qo$8YZ)So}SB;OM9MOl*QnwVbn&&H*2v!*b?!|ADUfwyy`_z$5 zB({Y{pfre*r3*1{hgGz2bnLCHa3!#C!&0s5;I?&1WBuJ=OlX2;}QK0TF52z-HoM>-q%e$4Kus6zKMcdj?o2hVD! zdug2*t1VR9vY>(Yrg+6Ta2C+7Q!6=T6g#ryxQcJOEW2FWFPomP{TH}>t)3(2hxYbk zSXfMFrq{GB=bW^Zb}KbiR!L!-chz4%4OYIF7Zfz8A>qcGrJ6acz5!FGy)&J!`D8d1|LyeF^n< zj4nQ2POm}!!^nX#2Hq0LDQmry1DUS})P$k4CDXUYG_mYOolm(SZS|15JX}ehqAZs! zrM9)#=(I5%v3}6_>43;AL&K$-#$(h>o-xRRjk_o)%?MYWtLo`AcLjWwDN?ITQiJo) zjp)MGuaw}|qA?S45z}8<^>8k2cl!wiWcJ+5r90KRU6W}lwTzUEy_05?F$zZpI3IoxNO_m@lQ ze}@$-k5vaj*e$w_RvSk>(r8-yv)4v=DJx}jG7BG8z+A>|Ou8@_?3HzU41e#|j+BjsCd!RY4>+(C$WTM8Oa;I2n)zc)M8p3NgaUA#;R z)%`$6`0wrr(`$hDGAe@uRHf27ucBD_-UIJ4EMCKt@u(TiM*+j{n5b=h@3gIGe%R)g z_eEv>05?F$zvdG@ugoRS%#Ah!q(Lw)=?>wq15`-RAP5)Z>52dSYHdX-sn$QwA}8{{ zvBk)ooiwO}c7$19G(LAVGcujKl*eF8E%fhr#fZ?`G$6jQ55=ds_H^Yf1SdA|ry7(H zY@W)J1a*(D-)wE*N}m;O=Q{~nxB(azLh0M6<|5;?-|~u%I}1*<;hYp2=&{6|v9~ih7XD$^ml{^*dbm3s4vb zpAZOKAnM>En%*kTChHrfOB(h83RJ>2eH6w1pa)(f?&QZN0%zS07| zrKk8f!oJ@u+I2@o=drBmQcGGaS~_!NTMqCidt?lSldo6X1Pzg+yoewFTBlnZ?NG+-@1X?Sg{`iYSfMNcj?5RkJcXQ zFG?2Q&_Wn~cfk^AkAg-b2>c$@E9Cl52J4gIS3N}zPLX>_quXp7qF$lc#KDpyLMO79 zIEC^lp(e5Si3@PfxS2@j(dpd{kn4T;OQe+Wy`!JN5_^RWp02rsFe8 zw8pbOoe1D^?)1O3vIsXZnKdRKeQdPX%8*nEf(sfzfyRyT-xUyqz6aDA#xj-zg_=DL6Y)K; zTS@Q?GE$d*!ilkgc&7{~tmDu`Q0u3Exq5as5WXLG9e`NmEYqf$SMe?G(LAasZl{MT zLMZCPC}^O+&Mr@py>~Jw*z4&y|LMeh{J6x;gE3-u^JNfP%zd^@D`t8wg zpq4rC5oSyst*D-mgu`w$#;P=;8RD9pb3`*BE1x4b0)#Ct6GLaS@R}L}B(>A^kQzcC z>(=GV7%ScG&nH>^V`|RE1zW6{yKy}JiF^vzbwql@yG(+E_{dR%vuxtI!qvS2@kMP^ z*vR_6M)fepCpm!nQ3!m8(QOb_~1B}@2U%wh8a@-orR3E9bdcS69 zSytb;6w@4%L*D;MGO(!@w-70*=fqkYN3W~F`@^bM^rqk}d#J({dnbW6sgsUTeIyHQ zXMoV|CVa($c+7Mbtl$0~v`@kU45RqKS%jp?ohb*~GJ~=<9{_64$4`s5!Q@=G9l4~l zfGX6*usFQx>bc}CANb@LZQjAfoq!G3jikW#3z8f8COIU5{<(fn-HcR+IlCdScD$DkB0)afEt5sK68!X0t3 z*W_{e3Ao+0a%QJ>x9y^_zP0MRCoR0s5Z_}~N{Cc$fh>pKMvh}2p%I$B;qNA0SUdo^>g<7r`FhO`FTUrLV?&p6x zHziJP^2+2p4B}K9R(hx0nhda6ws%?$iHVCjZ2vy|@`$w}vRCW|R)UXhT7E257rpd# z3`12J%&K!bvu1jwu4+``pVp~84V%0i8O4vu9E){Q$csYlRNH7a1re_f{nQDS2JZpP zjF@-vQJU?P!bPb8uRM@4yI&dQ1?PYW7lyx*mjYE0oN>4``1i-5=L!~`5_Q+ft-Ov(c3Z9n@ym-P(`r z^ESp;M3sh}ksR1bCasFHIO){_9i7y7$4%SdtYt*|E25oS|4Vc9C|h<2FMH9~U+#U@YbmKshAtF+RPNWC1PDt-vRjkS{M>>A_UQtymzW2*J3FC zq?5qn(H11i*M!eM(PItUVMCvC+!NuIC^J5s69E(?f?bk!zSoNx;TB0a%k^6*XdT)m z$7rGIU0b@4jLfRgXHMKqpJ_-I3K@y4Ga_v}kISz~JDiDig8Ey{@Eo|&AyM(pxptpF z&U~e00J+H;c!?!o1q&uS%yZh$*J5w2PS~b87P3m|Yn64(h+BVFw9Tbxi&|+?l!^EZ z{wWcIQCz5ctKB0MRf8FgUUp8x<&&n!10vu2JSF(w!!?l!YG@L+6R9CUz2=3NIn+uN zTsz24_z!_TvGb(hGMT!Iua-5KBA~|39!0c{H!ILx0Mb}ujh+*fvi~poO+}0@fP|OQ zySWF<-KfB59pzOW>gvn&BlqVVQ(_@~4zph$4Rd@Eh9e!d{3E`^M%?v2s2U30EIW$> z=thtu)rejdrZZJqN&i;9m**`JiZC?ko7RR6xKcVsc0amcsz721LJ9P{TTBH>@CBD?tjCISJB~>z{M0` z_y1~=+C`HbJmQHsV+k;Le+n$x>U+#u4wv*&1~S8(u(_>0$sTC6TJ%hdF1*9cI*2)a zo^Wi4nE?6ky_Q;Vt~)M*$aN$uc-AhbxObbicn$rctvMI5i%v4w>6^S6$br*(wu<2+ z7M<&U>jJ5&nN2ZCn%~8Txz?6F;=sQgOt4e7S(gkfBZ{;`EetO3%a0B1Ik4tqBlOV@ zE^v(Az2-DbZk6pPkIQ-J_aTq19SaGgk&HnHQ1SZ8pgJ!$fMU_B1}wPsVra@jKr{iV zTV%Y_3^!L6n76HK$oqxUTo=cr0sQRB42$s)>30Hu4^ozy@OZ{*7ySLMV(glFFcopJ& z%TmqnRR>e*@+3O%k^85K2Q-MEpfG*ooH+64??>?sZ;0$yn|hDSI(W6=N1dNdU9hw3 zfS^b*$3H?p*d4_;V7ObtPGU_U%Vw2#KYt(ptKIt+B8MWUfnae=r?EV95rpGFAgpo!=^%2rFj~QQ+{9da2v-(CAA!+xw4z;`;fQ=LL9=lwom=` zG&eXx2kl9@F|N_BExv|Qm8O6I0o5i%-&_5dbwZHh93tC{$dJwN2OT_t`lG%%agiP! z(hn&3T)R%f(8~j%4>rGb0b83^*6t%}a6oNSW@vaB9b;oo z>xhc{e~4`R5t6XgPgPg7R=Pe%4?=_p2oK6sC(1!Y>B^F&XxBUmN4T~!y*?6fi5GdS zOvhU}XyJ1TJL&98OAfiE>|YQuZ-Rn0Cb+d%5RuqYwyKY*#h+=8y4oHQJ(LE86|E8{ z4+U&vvT(J5*fQdiBPz_#?@Oz3>F}PO?1)W_&rvBeNHaiAOz8y^{nX87?j=o)<~mRX z`+cd+!*OhH6iW{As|+vCh`icM)Ehbg5*-X4BmA* zMYrEAkUidXE7@RqZIvW)vtDCC4Z@-vAxXy1Pi#m!#>1s5hdG(q)~eR6H_y3W(ylv> zA-wYhSkTNc4xDj}D)Tdu8m*u}o{ZcR9d1V)^r?Mb`b!6P7a-AVVO@p$WQkAZSu%rl zq>sipMW|<=jF4I%3ruD%eR5MdG$l3RhW@;ro^VAeK-x&GdG(OlZD4nGRG9y64p8Hq zPC(6iru^y^V|&FLXCV-VVAFGpyQ< zez8-CcZsRI=$}rfVWdTgmbl0T!bQ@^(A zO5EKRl0UPjQ?mid{e+hSHI@Ye^jtmt`Rdvg1M73g8Bil2a{Xt!Y2Y%3rq3yEJHZNh zO;ZU4*es-sobs_dk-i^gV;E{aFN>RBl?dZh@uThzTZtEjr#bP~`Y3+`l5>U)*+Tln zCm{MQ0%P`Qa9!$x!mJY!T%geS^W%sy&+jNbDe+gz@|vYXLIS{oT68aUHU2sOyCdXA zLTjsX-M#X!d0q%+HBbpmu{R#`39>OJ)kp_f7IDxFn5yurgA)x6Os|FT^ISR~Zyc^g8#HWw?k|dzxl5+)7>854Dm10FL*Rmu1p_K$XVwRa#=K=yv2Y@U>Y+J7TI* z$4J_$8wAyKEWbq3ZwEpZ6cnC4%n7!M4YEHjV1G>TH1YGx@%1>=@m*qlZd-th<5gK; zwsk6(3TWgxcQvKT>>X0vCWT)T|>OzR2!0Mz^x)D4;R(Cxae60Tkln_i_$AcGCBQ3Z~4o=FJ|2lz8VBuzOKF z(=#RFv6ue})APokI6<&z8ichh|HT48;9E2Gt7ZaAz%2qb%zb17jH_@6NL^Hu5eFTz zvI-{Ik{^NdFfO+XKCkZq)Q}m~bX8=kTc1;OYsd8=Tn;kZ}r*o}I8etPdP z!Pyh3E(We)y)<}f;joak{ow$&DK~r~+4+^&Nx}7fNelguvsCD2RS9B9@$0^IqF#EO zUI~_UPn5bVauK6d#L#uILoTNokGdy>`XOjASF+Y!mRu{?BLwFnpo0(}pWDy^y1HeS zC9qH$D+-z!`c^f_k#ldXkE0Vu#)u`E$kTE5VKJ)|*r>F3y5kaeyq1i2m^AYoP}c4y zIChqn;qZCL#R4_0?>K~|(1fTiv5$yZ#TQ|tM2Y1zbgH==OO>>NIysud!~@&p^6?gx z(}4{v6^Fij?>@9)kv90obKgvN%cQ-!qz9Z~*bui<{wJ+fjss@t zkO<0jXdkjBj+I4>_}7mI5rZM?ixV8o;=6EnG8HGcWmyHFsXSHIGEMhnslq$0ACx zWmbMiUbG2FTjz5;+ffP>zUDP-P?}~<6WbE8#!@5oSCBA%>AcbkaO}F{VZW#81;qwF$U! z4{sIyJMNrqhheo`;4+E$Cl-|C!)T=Y->lsQ?FZggPLE_thSH^0y6aeZq9xb;m>0pc zuu8Ax0#*;?lrcFjtzzLf%rtd72r#HC5?k06uT>2Bi87Q4q>oM)1Xs{G)(F^Kjviui znf{cp|Lv9-UNR9){>1+|^egFY3C1HDdxcp;$?Nq|0k(kF{uc>=6N^9|h+{ZP{|?XF zPVuEgvA9!bd#sSX*_x{kLS%``GB!pZDE^Ec*L2WIL|#P5l_{%f91%7z7o2rvWjb=~ z_Kkgcrs7~iB=}>3VQAL{eLnIj;{`d+sn)D;W5Ccz++f(g5VOX-TDqgCOeu+-hmx$T zsTkM}A=JiU)*T7dOtw{FYAzN7oQ}hePwL=#WGRKtE=$LhYLK--buVM2IITA7EN^>!%FS?Uv-hxPd!16rm+KbZek|C+Mb)0}BEFU*Y;@pDdP|m18DTP~dHZ0e$P`LMR?tfe;LaH8Z@WacUBv z_aBN`Kfc1x+4`vd}>E3p#Mx$oL5k>`V&Y7%$o!me!=N$X4{6w36W?# zIgm-`{66eky2`Mcw4KyXMSCN>-FonezGVsTHpWr2tVhzXq@n7_jvj(f`vSI$5}&7r zWdd6+b3*rs@^kdA?_J{qRO8~`)H9q7)Pb5CGOtV9g^4?A1`vfZo!|ZI_;@{$sXY4nCJ5j`KHcy6eXm0rVyLMJuZM>E#0<;m2YUMEi@# zC!__M*)V@@Mq6p!fX3d;`PX)ndOdR{;Ezj zCGPG>yCq1jAB3vrrG;iBoR@SNs!A4Zu1ex_81>p-J;krqATNc%9L9YKw^EARl%nV7 zK@S-S+TrZ#dDow({~v!+1xfWbW2FzPJIg#IcRq{VUWYq}NSjoQ*JF56G>b`nn_4%L zKg3mJo!cLSY2*BN)hkIIy`XQcN_v$~a?|r$2~?U-;V{g3mA!$=b78BU4=)Xcf@e#D zVM=k5?1C;Rq&m8j+N&Jgi&*M!01DGVOEor(!`{*BAO;O`DGG*(Xbg6@Ml*;e)G3q{ zO$6EsqoO7<)$Hcd<};B~ir5p~)~^12zu2k&N$9|}@evRSRk=u9Uz#{7HX#fxdX)Y8 z(Ym&3U-j)miP9LiP$_HKL1m3CdTtDZXR1@M+7Ln>&~Q2ae^}_tAAj?dY9C^OpB9?$vg<_@15?78j*@!%);FJk})!8YY~K z?zvd3et;-8z0F@ut_62jgfXKCdAwAJ<-YQ(ivbGo>Rs$J|1az$4Du-Us5s?F50dMG zcIg@A-%gI{Py=2gKz#{6hc}uEV+gsXX6oflKSBc@J)!i#CQ&n2*c0wH4%ut>A~Hj> zM_Dqa$DMC3`If4rey27$+fickrRn=fzyUpkgFfmNR6i|x3f0`_>i5;|aVGPU6sd_7 zw@=;UyucjI);1-vfLtfnOC-gy0;*w(Az%vejie;Dj$n%It~7r~@6Lok`vQW$9N-q? zTzTWk>&lQw5QgagbiHb`7=vn<-8plJGQAX6ul-Mee`;WSjnY*kQj%GctMsK?rN#uI z)(Z;S!EkuhdeKFAtwdiu(gMigij{vxVdN(2LiVGkmP6h8H|-$3$RDVQT7&nUFL4xG zp!pj%*-s!*FGBlvVZV2WY&at5P#faA;HR10-iJ=ElHtq;aR8U}o-jU#j10z z$`cA%ryL+WCaRwj+w+o}Y@zmj#X}$_vq8Cu;6X|hGunPuaH;^_L-Lds6)}3*XG&7v zjjAu*U{oSoTm(^FEYdopPW(Y#^B&%IP^}*#3o(@imB=;y9;C@rZ$3T@PRh;Yz z*V|m1nXKqzz1uYvSf)j(_2YnL*ZDpusxa^xMNRd)LxPyfz}75XI|{&Dh%lX6&KyJJ72RhdN}_h!$fs6H^p2^(e}uMX}NPqgz=^jyO6OS z(GDh|!Ue>o3&w^9TSC+514VVor?kQqqGtlEq>!EanJONq1+%14ru;EI4K&!~0;8&q zxIos{3yL|&`2tl1YXg`y}yNU;Jiu)xm;U()zapuNKHMfD0b)Ae!H zk9n`$f%L4XxLwf<0W$4p8isqb_kQh}434(kJ?536ykg|e_xxu4nZp?@F*x!FX4i14 zifqKa3HFqbJXC+!wAYD`$D#&jrq-7KytKihT!)7kF4tN6cv` z?R-#q*>!qphcWIk>i5|0Wi(7yw)%@Nk}=@|7Azcu-w1STas#l2{3w#-fr2{^Z$zIF zGUWPA;?)hS(|Vhzx7=?C@dxCapU9?u!SO)fyJ-v&lhDN*gh2wZS372U?S?>+S_gwD zLLfijj}t6!5SqU>?BE~-<||^IZo+a;QxOVkCBWl^CQRx#R)}7X-WG*$UX}qJEjCy% zU{0rh0L7`MDgZM2?)x!{{pVdl4om}8+x9Q%O&Ykf&15)1XqiHNc=(dboFoG-gMH$a z@;Xbp7ptk4KtZzVLUSDhuCi8;{})l_`ve=#qVg0NMCh^7P|R!8OxcY&r$bijP&yD32igiJx^mp>UzE~ zlwn9gJ{Qv0iKJ9&`Ia>$$4+6=Riq_{`4RwGZ#w8tYXk8+8Sx?~5;C-v>j zPE1eFHcJ7OzIri>Y8T>@$lZK8k z8iWV6FWt?c7uofc0Q4mqV$wai-wDYFfzEt#;I8i_ZAh4A1oQy=@2 z7F?KhVrN?I3i~jooBbE-4pJ`lq3j#>FvA%qO#YcgU~oNBnScuECFNBM>CR1)q1CaD zsW`sbOO2$5*BnUP`AZIj7%*o|I7Z}_dZg2Nq7hK{DfZZBAK0s)S4^V z8OPbs1di;kS4vE6vAtu)4a-WwvY+arOqw{zJ%yLJNuqFCwiJik=QfU#(>omkA|JMz ze3$`9E`PHJy4LR#Yxrh2l(r!bROHVoS{xIc@@Nb1ALS^3FJ%kfEGEK-@i5)%v~tmp ztd*Uf@6;~^RbMV#RteH3W}yWbD_IL7U6TnK7#@!MQ!z^zkQ0KTQKP?+O5of+SR~(N zuKO`SSmSb>88?sEO1_-K5Gm<>o|q1*AtCwkZ~K0_zQaM~x&oE9#5- z<>1WiiN$d&HB_ekBisLvcTm%N;AyeO>2)b<7@bO@E)|8zO}L_BjmiL*155M_2RGrlBhVg99fS)joqK#jY zhc>UUgEYTzkfFGsucI;Pw=@)=hXUSK_nz7A@ps%36dF^z-b6X{cLG?1M2ryg75! z3T8vG<|nl>DQsP3WYD&3@OXoXeO^6HG_Qo!r-LaTa#`H+h^7bpcd>LvFNHZW%&!Sm)mj0tSen8OP^Fm1Kf#n>r^m3!Z@TPdqS%BC1OL` zelcvH{j5*>s4Q8pFf{==QW(1Q2%|+unQ}yd;!qmu8-VD~gH7+h0d9NDeA+@`)N&Eg z&zK*elN~8L7X&qZ<7RpG&xjJ{Rz8p(H*s2#ZMG?164lB{{kvdyX*0n&Yulna#?^*n z<6X6yAaJ227QWWaU_81`^CdP5eOIUd1Q4n3$>nKpO%IFU^DGH`+JG+5Cp;Q%qpm_AiOBr%pvUTotZK^pFW;s=xb28{+?tJR8zn$sXm@?+9~ zJ>^eYwSR&wz;Yq9RNFS)2NRA?Atzm+TvyXs?4Ka^C8iEBGjo=96#Yx}7%Th-iLUfg zFNzeD60BVooWHzjw%8e6H%ZnrOR(VAB|`Sv(9ezhRlYr&gS@_9P=}_*9GUm)y~(l zU?4wa#uYQuvgJzJl6=z_W*OWnsYal2k{vna?3_%$LeLvqXV zA%-t)GC_5Lp`b_{kP{6xfBvPz!p5=jf4H%Q`zB@SwCvABuNC z5*hXwFOhD#ARN{``Z|vbPV+vjgX@5N=zBVf_!88g+g`b{`d=6GZd996A0#dF`^yY=(k49bwRzXz0A@;46PW`~TQu-jOaIT9)Z*cZdwYE**Z?ow5 z>76X~4brII44Or%7syPliWAmt3D(VrzvyMvOc+F9{ZmK77`{Y>p5BCU^Sw(JDPkSM z0#pPJDN}U1J*wT<=+kIwxdA#xsKNu9++GIh?Wq#-0pt(OW7{lpeVge}`1R7mR&UOv zBj{{?KZ5Tx>}GAD=T&0U-NWrR*p`-;XsA43)x{9uV^F~P{bEPsvJH%e3FpeZ zut9Kn`$8w(CFbz^kUn2vm<(!)b^7^6e_n=UsDDT6TgKHPP*81#$9~e!Ys-3l;kgN8 z*Eh-BH0g!5%2_VF1eip4g0{8sHd=*9r64jpu2zx2XeRuXC!=QXw@a>7ys>s}nbG+y zlgU1v@F%ToSGL$5r9>v> zEb5G3=4C$)QI&?IqxTfNtbPdw{&+4Jl^+f7`s7MRbDE4Gxv@9_`digcYztwG5nQMp ze0R53u9B*uTw)1c-4Q;+D%DvGC^+OW&X)aIqN@GTsnBdpyv*uDAyko(+4=TAFu24! zL2XL8V4KvQ!7qxS2;yk1)BV~s2e}S5ppG2VN?b8=OJ^Q#oe*=m`08aMVvyMYmN45F zQb_Tb@C|1YiM_m`mueU>X#NVB*cwwR!3FYq4c+TG$Tmsi@qk2s>?_Ve8!_xDP&NdM zOnQK0_FJB>=4+pA_e%#tBWgfOzfjoGC!`yP8p@w}{m_UV5H_&s$So)9%l#{ffWk>eerJAbCO~|N*&+9oq3M%92AANw@GuOig)~Sdr9?=h zw!aLlGSs-nhCCu@_r7MF4LbqC6cE^R5M;vh{ohVP^`OW#po+A4dTn)FsH)Hof+5!o zG$b!5TPMOmV+4c2nWt(#6EmhN;m)3k^E>nZ|fdslo6xX2<>L zm^yzpdR9uEq`afQEJ)mQA9;*C@*J?y8CGWzOK*RHhEks4vy@!V6pr_$v$Gh1a4GmN z#0{q`gnHMEECbyx=W^EjK_U|RY%NVEDchgU%pbq#(l?;UwN`N z$g3faa}pg%cnpi4FSR>YcWVO?0cA0vHsV|m157vhpUQ+N-dVpOS*R?GN+k+34sfJyWc;L3hYu#xHrisbmQ zv|gkuj`kVZG;pn@Q0}bl+5s`dxs$M@)VD@?LpyhHYe>y_`0FXN&u+^lUf@n2*tMCL z5k=h09qj45QBI#z?cPsWimh%as?tTX4I(d!)7D=to9_2A09fNVHS*!)E_}L(+m`p*_hRX>2~&s_P+Om(d94vzatt zptzPKo2M*N&upjoZWFy+&Q+Oy3FW5k(`39YpZ4f|jterV=K?I|(3oM}hSy^`6GgIN z8)lyTaAx)CI=50mA_FI3tNRpPAo3vJ%f=|T!TWzc2(i)XwRo`1M+?6FM?}%`gG)w< zP`fjzkiKAj5_^z;8rLoojHeyx6h^gMh4W+c!c#7cE0A9P$#!Wn3o^_WDsACKNJ{sa z0MbTjxI-nN28j$FZXQej!iJxJ)q>H-nhI<cDyJ|D;xh61BtnLY8ktC_yarV>(`lH>v&*4abRN`+weRT(L7rQno# zUjT{Bvs2MjImR@3RL2%qe~Jhg$0QB(%^RCp(|6~6U~`zw?pr3)Q#Lh7j2froo5Zp? zl|u^<>T10w&k7#t*J{k8<|-MxDQJK*@yH8dI6uD`yIj3SgHx9*c^_^-``ZLACKnC7 zS^<2mc5^1dwo%XUlmM)NcOP$Z??qq=DdT80$y+jLW-^2WRG;y8*WB%n5Wf`(B~ueH z{e7p-qK5Pr%L~^*C7mhr(FtvM=eN3U{)L+f2^e!&6JNH()sI-H6Bwh9dHEc^w zJB^}P(2R4v=l+%a;Dd~hnl8l>KtLWP&!61GsS1L*GUmUfHx!1{kq(~1Fjizyka}_S<3(3Xd0Y>&ml{C<2$!qJ5b7ouT`Ddd#y-vq zZIQZW9RvzFmm0|4hWhG?zeOE!&2v6`59(Q|yYIczlJ^_Hi>E@m6-pCJa}yR6(@`yi z!#)I5-wnG9Yd;@kPLZW$tDu+U26|LT)kJtjg4ugjX8gXWHbo@mq{<)`9q&!8GA0EG zmxucs*y-veQ!{g~;o#Dd!H{su64xZ#{~tJt_b-3xkb9)(DH8hK_K)2Nvjc>I+Av|A zq_i-dMBX#nP!cat>l;#g9_YPlx@vX3W}lQxmTrDuKoK~pQAccDd-kI z-h~WCe@&noPyBFG7@!cL8+TPJLH`HUBa5o8UC=<0L>K(Ni7L>*F~$xGDld&bic>AJ zi29b08@ToW)D5UYypQyJ$%~a_;?XV<@Eh;{yeOmcsrO^ayBdXeAvJ&PKE{4MRZ*fE zrVADod!6exz4WW;sM_}#JYdxZK0VD^7pn9aL0<8uJ#E!Km{J=mUG33Z{xRP*ve=M7 zm>hvOaPUJ9LpXmO2R#rhTwL{cB`~c7pk5hqNZJ5ow4PW!t^6_~d(G{DnYhYw8SJzJ zAv@e|`bCsNuKkuoJWz(}F$|_>G#p9)#t?rV46_d@#o&~^bxeWJa}VQB9`P4l!3^zv$$mAEh#fF_oKKt1Tj z?5m_3yz_>?bjetXql%$sPsr7TT3*&Od!@VYB`z_Ra#1h@mV&D$!qYnojX6O~(b_j@ zGUtH?9k}Yyb3qO-XC+ow8O&y*EV0IghGNM{+&6=p3uM=AMh$ld7-Atv1@#Imyj0nk zg)*|Qfkm@x`tK4hWY!N0?)s$r4XJy$}?w+TZ!zUT2zaNFDY1e1}Lqdw~8wNsRr= zOy45}Yr@#!OQnf8+o|JXp**^Wy9vl}MA63;zy1tLN8h!GPr}+N2zI&VH79!uf7Kfu z{k`1zBG{-N&X#|@U>P$AAtw7sMM+j;Qu~zV1C`c?PlGD7s>FyI10*&zJqP>MJHyVS z77paq)0RDbQvTp*eCe-Bsz(dctsGW}hx7r8*a(w!g=P%Hl~9H+zMCFe`IgX@s=(ct z$f$lmpoc$MOVKjk8xJ*^*tyeQznv}GPT_v?E|`l?EeI_k?%XxyyxTJvH*qc|{tk~_ z(_V1lmER5mGU0f2BL9qCMj6|7I+?Nf+H{mGH2wYOUB1G7){3JdVdsYfGFeItvwp;u zz?R@X>KV+HuedDm5~2u9`7*6k@YT&)!cGoDT1Ek#Zbn(hRFx%LBSZb;-io70+ix|L z_8k$850-iNEi52Vmx-}Qo)??^_@GE=UN_tExkRou`T6 zvPr&Yd6*ha08gU+EtI-6ui64-&WKKqe|;+RDj+Q}?ETEXVv$4&6vk}Cp$IJybG^soXUBsgi=qi{k z2uSi^uf!TkC{~T6_ZbkDA;zV?<8Q(Ya{j0wi9>>zG&_!uQu4nRr!3FTQN?HgZF6>W z#JhD>2|w|pSyyC@+7m!Y#3y#k-KLHMPjn}-qNb2z zEAPPX*6=F?Ef-hQoDOL+XT=ryOs zzY5;d4cyn2Alasqm50l`-tYP^s`5!*g^VMUkz8OBD~}JIT>-Xz%9D^-5S1_~B!{BT z6x}g6{}vOQs6fR3E6PKd@4*J?f5WVS2TO&mIkfRbww40BE(xE3F73o0p92| z_YP?o4Ufq7Cu&|O9+j9f=>h_9Y?&)7@0QL9NUvnL?F+gDe?7uuvB&~_*e9C9gQ&LUZ2Pn;96`VP zHiF5#CT0L8x9LS{nO_Q~WQj{eKYgVSG?Zy3qI zP1utM{Ub)b4xEDaFcIn|a_ETMHv#D~xYFP)g^?ufYu1w>O=CicQD;>ttVF!-$ru7X}#tY^o?Yl5s zkF((zxk-WaHmgzoCSGiHL*ng3XyynNjZ@$XEcL}mv+Jd4IIYWhA~;Mj-LR@(>NLoT zVlN|S!!ZpBBLdgr5tbwx01GDC8faxPHaMQgyy)qvx-+;{0l zv0XTivdHs{{~|XqTNg1ZqN%JZ4&RhZ2@$3u$Tj#zPxFpZKk@VFjK)@h=P8o?JGou! z#3NnX?*dE0v=;`-fW6CUq}4$W)m5V{294cHlp0>x-FPcaRY2tv=JDr|TJWUUdBB$r z7zC^TjI5h`dM55MU#|$hJ}|ynm{s%#=Co|k|z2Dm2M4XhN?Kyv3OE~18D zWJ5Zo(zSJ+)U#9|wStBf>icg%(nO8|%AYrQS^@oL4!Q#?i5=H;dEgaP&e$=KB7}oS z>x2HF9uX`JsNQswocw^^#0BfOMk#h^a=|nBV~*&DrizhOQ7R=Mew2R}ynF{L6tGMh z5MrUdr{8nq^F(UZ4msw!kK)O$UVym)V+;+Yu(FC5Qb=2iL`7$9|B@F;)M#TaK`F<@ z4c!x7FF;e-D(}U-E(9;eqqK3=mQRSP{qlwe|6h2dO>FqS<#g&as_kk$s~?=lMNfq( z^-M%Qz~+>M1$lB_^R74WOzF+4oi`E-h_psiY5t@8(R7e;2wVmV|GFw zk2z2kYyphZcrLsFnGd0(GBm3=bp%{lIyE^qDsRXI+>l|AwjRU*jK zkSb{;S5W4NF!k<|RZ`G0l@!&I8cXj=9Q@hy2*Io1^VCYJZ4fW@Ae60`b?$9!BkiYv zP;!ZONdorPKTCBK7@_+6zL2yl3>{Iet>6?)4v9DFS(RyYEVy8E8w}Np=?whDE zq>;etuUjMM8nO_-rf~n!ext7k6-K6lEv(yZ$%h?8uL|bT%lQO9w8Z`()*CH}sVrQ( zRw)5XK#o{K848)0!g+vcwkCxuq`~Z3|JW{RZm=P^n_z{$4^3R+098P$ zzZG&JaEw4d>G$#Tc8`H1P7t$Ly4VvNf$+vS^_F>PseO_ZpB`{@WS`)vqz+#Df2Lrf z<2znc8RS+@m;CzA_L^a&SZ7KYVwAFxQEq?WsgvTD*jbgLN5T)l+@{$LmRcoZ%bWDh z=4rt#Z81vAj1SE62?8K0OwFOU>!PKw{vLxs(bRSNcEhb})q7Ecwy$lRzC97rsQ!kl zDc^r5dPvux#mp_8=86_)Y?>&NFbs$(DUSRVjc zn5K>DcsD}&vMG1TFq_4wvyq?>>b&$7PmhnJD1)R^#f-d!JOjW{)t@BCz@r?o4diPR zuVcv3q+Xmj7gx(}`q`iVDbD_qi;-;qud;wjy{rv$vsAClAH_@Bxs$Pi{_k=t6v;@~ zCT0syD23dJo~ia?_TV@>8#`B|+`Xh>Y0#d>8(d}_|%i+~lsHG{d@*jY`_TM{f+oJ{oBCLLb0^}G|eu0beLpgfc zXZO2OEd^MFt+yef062>UWgm$5NWmxH{MVe)akEQq89FqSiSb|iUtPDoJDX4~Th=e( zqY5CRts3(qajkbZYvJzShiIp&ZoP8C{eFDIJW%7J9~QupOrC7f(kO&z|RuloTeSln|^HFMgv$_EwS=C_f zz)!jbKc*Av9?ik@sQ$6S(4xle>RJxqA$@Zw7^x@Qj^Id+?rZvb((6@+|AKky`;ikZ zkHD})EFJM`gfd;D*URF(nC%E*l*~06_@AxEuW8};b50aghu%%Ix9$&_BZSROC#;zO zVm6Uwg9$c-Upprnsm`ajKli2{hn^W29@=fH^WTiY&(3 z3`NOOF?e-;op4UF-UdIT5pQ2vB@D^1b50M#g#45lGj$uu=6I+juX#?x;u*)Ll1tT;mB^t`6UcCRFbBXTSAge&7J0e%#f#OH0*(qs#CvVRNZoD=yfYtZkfGkXYH9f`_oJyV#9@s`h{=JU6xa3{z`RICtoKI2wDN`tS zZxLJ|WxmU4bUDc+@tUzev#rK&l27QwX&JYbJ!d$|LFhq&EDufF;d=YY<*VsC*iVc} z_^2HVNEAj7VTlQ#$r&q|Qf7BdaW)jIMGq1<++jc>(of`7Zg--}L_Czz>?nSJNtjBFgKqyT;TeFYf zR5?~Ig>FDxx-n*Z(vb(ms4?1rH6nWX2f>-`M~=#KstxC{{E5)*khBAK#zt8|EJ3GQ z4a)BT?Qe3LKLUg{Zo!JIZvdj=9s-h2oK|Y5lD035jKQJhKz^#6Vu5egQa);sDhXKE z1-5clgBu(QUph&5czH`)vIwN#v=fpMTnj5fE48-7A$@2K-jX!6;5uKv=mwP2ZqRmZ zuwYAwduzu5UvN zJ%X*iWu>|f!~iYzTq0V=yR32_eD*B2@P8xXt4g7P&=V{k6kHInlhf9e>!bK;V696Jcca3B+?V z5I3%l-zIzmLh5|Kp&(XIsZ4Rn*VqDIdgA-4U8xxBLn|w+bgfs<-v*|nx~h}^2XM@< zcDim%F(K4ub8FXtr1Z$osn90&hP=Ei4Ydo-7;nAa_Tzx}QM_3qOWcF4RJ^tSzvlcm zng}18lDA1X`LIKLf}>gPAZK73dPC8)e?G*go4SdjIl7aP@Djoj+SX*kI-K=zc7ii+ zLXgSnRB}_8cx2Y`36<;_@P;i3{EGCIu6>=?C)c1O2^~%gUVnTE1d|t z{YcC%{Qj@qMF;5W1+u>6zD|z$xbd{~kqD=jl{3$ucWG?5pGkc-*aPM{cZ1 zo^`jGRSMhU51LzF$)uTVitc7ZA!ksCTMPB3LXca3JHp?0 z@)i;6YdbN)vg(l1E$8=b6vPSR2X}tU%z1AddNLgCTFM27H%LSy=&==(;gZhI!GvJ& zaxkfSh$2^mTW1v8nWwl%BHX9z>8nA1BSS$c4i`LL*Gy zJwIOtTitB0JQeFoY*i7C5!JolG_t91*zda11H0qygrzrtA?w`iBI~5yGa2Od&eoLm zOSRe`xy!~r3lLyBbo`8pGh(Op5U;asx$G#~!~=sO7Q1v>;bML?w>pwH1(>j&L(PmZWwb0GO+?6P0Bl)FrFt_jjr_f|!Ai`9e>NZAn!z2UfjS>q(>;@z1s#Zjg*ZQ!k>g zfE1U*)>SK&bpkDf(eh+}4S!sg$+@CYsdi9eoF6QGS=(B#pM|a@v7-xMdLq|_ZwMH# z@EHIWBPcU_fja_x6j3vkxg$oZKZ@s4y0pA;pk8f(yedJz6e6%cBW3DD@^`L6heCJo z1S^u4DCs$AEulFBTO^J95m78sdFRw>w$4DfS2+*Q?lB$qiSep44ngLg1RUH&?8Iwp z?WF?=TK3uGyUYd~3NtvgUgQ6Ej%^!7=?y#@w0rS13dN)n`n!r|z8|{Fn zS*eEIZ~XCYcjhDPR%v0nlNN_Zy01)ICqdXJqzG3?Fy62W<5rXUo^`6a>8k9w#=bfH z1-oT?+IAP-jlX4;qTuj+CigiNfM}So>)twRXAuF47)Maj?82>`s7Pan;P33ycq+_| zyHv;qPIA0P6y2zJVM}AqfnjdCU}80IE+Q4F_{S%5%;k3Mc`WN+HuU!j#+mLpu0q!{ zj8f;+2P`p71IG|8anId+A*e(&GY`L5frV8*0hmoz7z6ntIVPnz-QmjSVn@+J2#&tX zFDhw5eqehcr7HX`@aF_f#vPQ`h9N7Y6{orZh09!T1&f8<%|=)09$dRKGsCfMTb&ej zCwt4?3q2Alk-xSrS-Rcgb0bDQbt;5+$2O8#J=Ch)3kj~<_joh+&hmhN22^#kjT26p zy&<$qRqO~>ED%mH8@Ra+C^^=M+HDZ=o7XxBaa6agS6>%5QuxJg*01<^7qzrUrNRiw zGsGNk3YY0}ejTIA?*N>=dvZ#~_^*sCPv;6Ezp+9IAN&fyZ_;K)#}mB->Zf@U#@q{d zBXm<6eubh8$9xkrOvHbj;baHg=C2jx{(6zE+zC_60%ROQWtO`3)6a zjI?za5?{y=ta?bZ#sE8_H44QVMRZX-Dm~UR&}5?)V@CrtGS~r3NQ5G#gI=fQ^jVq{ ze+mpCtW#Ijk_OJzCHVAqfDFwBxrCGhA9+^R4qm|0cwtBOeEZ_wqs1F4|M)KCTq-(| zxOk076>Rt;F4H)Tqpj9L!GRaeD-avSKj{2dmJMmTt-`>Z`GQXSw+BW4D}_h^Tu||< zy4LF*PX;m^6mKoxxT&*UyQAM_npT4K=88G%R8~817i8j08_)Q65(;+O@`>JL)iWl^ z3ulR;Ok&INkR8-^1y~=!y9ZyhZ$(4*h z%g25Xlt23NbEW*QEG3!^UV5^dQLk&Cfz{e^*;4BRf)6jTp0FY)5+5W?kEC$1?#BxE zrhZ+wUeDF8O8iW!*9wDhCxA~Z$@xHb*JXB}kg!$k$_}7}*HgW>#NH^^O`*KJ(`NY^6UBy21mdUOG#dZyq+41J*DIi-MO$p~w>g zOP3bIB}L4So{y|Sk4eyR??xm^4axIR;w`%La0JfSFG`=(i-aC^2)C3SdZ|J^{s7UU z=%|hRfA`lJR%jFksnY|pv;n<8xMzX8dOWC`?PxPN_{c|VGZJ8(k=0SSMGD{lT!ck0 zO!nnLojl=|6a%)yXz0L58_4@sfiQEXC40p)!ZTusf9E1^>xAccWBW)zlYXSxD3_`+EN;muL!!A9QIXvvu6NhaC9 zU)PaQYru!juKtaeWk>t8+&HGfBPQ**+ZQ{NrTLOUccp=r{xX!(fuh4Fr#qd{(yF_& z)$p0Y5IworYCzNE0|}WQ%5$d36F5{r;fz9$V-ORhr67#jNEOa-~ebD6Ifz(YI^$ z(DabBQ`}HGN^ZI@q{+Lf_051H^1M9+z>2@}j|&3~xEQ7UA4A*#GF*Nab@%5ZKE6>! zJOg4O?YadoFanZ7yHTO8hVAU4Eu!N)S)O17MN4}8=>K={1H5=x{v7s9MXj@?y~mn2 zPzs5h)o_ zQlNqmTw=B_WDTV6jwXPO3Y?^19XV3fB}%iO1OSXyws z4!^-6)82E|37I-0`3}r&J{R$Fz-*pA0%$4+j1pCeV$H3TW z?yyyGdo=i}%I9e}uf@E?Pk-j;F|lZu2RJqxvh#UKx@#M~Pk1Wn=Jv^ZSyGkzTrofu7q>c01?~!-}(}06fEC$+x%u>A*W~UzfQW_0@MUsQGj}MD@>z80EsXX0#PC+JDB{^MsN)Y zP}HpiX3#>bsIs*4AE-)8xIr|o&49*G4M8*(a`EWD!;xAtyZP)SYJl0+@s{RLO`vgN zBfb`;QVSv>eIYfu8j(CW4BwMEa67XLFouEo-QnejZQpOT9>k>0=FFpzn!e$O5fTZ( zr<&$G`9+;C*za{)nsSQCMl)Y@KI|+TRouRx(69;(p^e;gkPsiG0hP;$rzcE(vkkZ< zPh574A-~k9pxQT%a(@HB=BgISH#(G6*M8}aE1e&MB*$6= zf{k^AOXw9X#qX9CC*=kUxe657++rPu)A^Mdb4ZE)$dYNjFn9nesYHeQQfC z7SK%H!{0Rp?u>%ymIjLtNsb02Jci#C;IYUO(-=OfZ|X3PN<C(P%Qb%F!zutzv9UTdb0kj_&}Dd7iq5Sf zqpKM>`YOW(aMgjK0vQ)Bg~(T+ZDw+I`KhEC^xNuJZJkheFwZK*oyFZ$9u$y-y`R6> z0@C~W!n~pxGttTLS|P^}ybD=<vn##k84T7;Km#GY%hf-FF*y=ILJTYM znG$vv;`vke6-4Y`A21Nn)R}4l(L5M-=CdFsM_8~@Fy-#hN|GPNaLbMLRg}|*j;m4T zlpQbfExKLiI~HMsD3wosirWzuH56tIsNj9#j#z?yx8yZUYTswA!5!h!cf!=vJ&IOn z^)xW3+BacuG{_r^FMi5#F`2IpReJUL7{xPbKsXEu)p`{ zcXlB1+^*_h>Fy%1cp16I3mu5*vUVQM`^jeRpI`sS%-8$wU%@=NA5%^goi=+2Qxy0` zlT9*ppw0dri{ef->HV>@6+Brqx|y_^S&;`tuR=D|`5=_>C9Ztrpp>xJVrt=bh=a?riKpKnWEkyUcY0Pn~lL#ptFn^Na zK$JNNE$h+q%*Wj}z-rw+lpb@69WOAX{=`NnWj)@FY30ar zICpN1Qf{S2r=S~|{N4(u(@zlWb`*~1T}j7S(JsmSKmniouD}gAsOVrE3X!0U31Xyw z_y5AC!;UVC>c8Xq4xrT1fz#F5H=|Sfl@&VRd4$C#HK{*JihAaz4um!!55B zNMed=c{|l)CI)7;Jj?-|1AtYE-24|{uirydgh-K^2OrcqVUvei(y@r7%aYB?8qI*X?7eGI zTt=@tS5cSvj2jR0GY&dt|3U~`S9wSWWJL|qmCu;!&VI!1bsqz-ZV1#_uv<$w^mB3U zd@bcwPsAB@ti;2uW5fZN$Wp#&6_eZ=t^98M;dfk)tjM7Fg{?*aTSS9T_WgR)uWsn1 z(4H`*t_@d$Yh{So6d!j^0_0n1J4{#&I);kK0DH-!v6QrJyZ&-C#}o1iLZVCiC8+o3r$7~ZdD~VX>wU+N6W^m8hJk{k4o6kP+DyN zBN-qr0qT=t-r?7bRqS4ce%}KF?)irCiZ*zLBV!9bNKzxjxR1$UAIx%1G(Jdle}rVt zd?py3c4WLC&@I5ndnpu-PjB>o}bW%5oE#}-(XYE^8mG;;K17uw%@Pq@moa4 zw2FfUJG&i^Z#A0Go9=PvI z8U81O+0%Vx9!^mwgd)(SJ`OLit2s~zQKSGk7}c?^W`|TLp!b6`iXM?$M=5Lh+qi6*w*R?v68tAGWU$5_~LJ0R%o_%wmp8DGpJJ(3CTG0 zpxkzPvW}5#Um%Ik8~Nbe;q56bQp>hSc&c>TFNIsN|HNhH3aVF;5>?NAVg#F_`g#mn z`H%)xaS{_s;^Sd-2HxlbGxE>)N621)R~{Z%tK#a}9g1r72O5sp>nQv3CPuEooz`Y! zc8;+Wx3=C=?BgPhi6|xMJcOP~fE+NC6{hvgn7p^i4V)T*;+q7VmR&z1Mzk7g4?vIO zpp*-6urGpa^RxYF(QM|ttsB4(U}C~Co7UW#j1kDcnBRY-6p0g0fB^YA8zx!JY5Jtc zJ)1CmqWPyx`lmWHT=+_3#i4Jy48c!rljA{h2$~!=G8{~cMmp?Ck#{j41oKUO%SF?E z67E`7cPLXKrx6%DwL;NrbTL_mI+^w;hH7heBch*-&t{y4TF zpQlYs^G#Ji5@hl5g!W#4=4Aqwz$c19oQS)2mZb7)3AI;UR)+0!=Y{LuL5xO{CtTUSs^h z@p6NTLpj_Vzrp@DNn0gg0C*tA5Jo7g_UN{(1%x2}?Awh_rF)!7-q{#2XY2jt{`ZF%`O@+lrxxx2mNbseE?VWB2 zhRvH5N{@f0)#52D2ojM6$YY!g$oey*8UiZs;4TaLHgMQwLaqGNyvX?#2v7{%rB>07 z%Pv|TywLEM&$gfBeTWx z)1NDOj1;_az_2b6K%j+GW?JpD_tWf(I0`f}j1&iPN*3RVS3B~wXwsF9=~QUOUSFUK|;dHB={`FyNddpE!F^B^FWQ{quZxO zokxNdiypdNf&ANB5sAM*jnRvJ!51Te&mo{&l#T*-Wyv9ay1{V^nYjCP3)Pq9uwG0* z^U$Ukbi7ktheiuDS1F@8BA!8XamqDzW0km-B!wfUYax5mK#Zp8uUx_#JfW(bgX1U> zm7`*o0(f2n?0?*++%}fsC0?MT3LL^1>rOFQ{9-sxl>LcOZi+&QHYw%Ac2zIh3_G~n1?NAM7Lk3S16xL(Z4}*T65>#F=j+f zj>`vnN2RG}!6S}YJVGzJ3W+-Vjq=ZvbH|OVBp1^3cW_Ci3AFY)2?c7{cmO>2HvW)a z=z?w(KSc}d?%M5tHFIE3oUr(SINTwL>0kVh)QOeyZK)4#-M-4Y2#-dFVhtxuYgs=h zW0XjfjQGSr5S6|wMd@6_dduXu$HlGlncI2hR~uJ1w*r|KTWV#3(O!VI`7{5vWI@nN z*Ut`WF!_Q5(Y^y2N^6TWJS`#1d6NTqpNjW`ooE#jYn5VNY(Rpw z(3lY!DB5kyTH8Wbq^zcPP+K8hm!=8{13(i;Z7JQc3>)@}ruIH^$l-<~YV}%`)azlW z$B=NSD|l=dP6&ewxPE~&)RJD{h?O|6GQ2GOGZj4onB6<=*;d4?E`+(p`{QXp+6UK5 zJK9h#HKs$8J8vp{rQS2@uOjw@oUltpepfKlm=PBrBFOt=;>Is-#Cad8(d*b*W zN4zzmI2CC2&Q@ulc)Ad^9DesOKj|uzI1p61Z#byZ6V&zlv!#{V!XRrjtFqqMO;CE4 zU~e$5753ffl2wVJG&8#rq6t@yiI3ah97lFLJe7G}xi>2F*>jsM`Lq2- z1i&C}wx3q`s*IX!U2)T<#ob_!gDB?W#dF%{*NXWO_acGcKrcYY?e5lvLE?o7M#TYO z!%ODv)!m%#eOs^Juzi05PB`GKkWuO;IN3kWc9Tc}?0grT_=d!($m%TNL*eOEDcofy zJ_2te*6Lj2z11>d?PLj%3b11V_2SFqFh)!fJ8lP{u#)DN9$|VS84aWilAeEP-}`!T zMlsHm+0baLOsE*k1t-qh^uO5(0IbA|-`aziPG9o`bDCENhmjILg;~TQ`Xc5`ed!hA z(LXK%T;EhnKD@6cDj)~t)$Bg+Yd+i%p*UPCDcQHgbX#k`eOEwkMc(F~H_it!;$wAR`r(==;z>)`dHlL~L(aumsDKqNx+622jBY#^9!|me(zsLAI0M{WLq^rS zY>`qSbg<~du<5=ne6<-YwuQ!}Ad-Yn_;6MLZ;lD}$2TJ2wb^*{QwX7{GE(bCa)sF! zbhdzW{CWO+wXS#e;-Fn&-YeAL0YG?FMMC`FGF?j{8X|Yj>7|5gkbsF|Hj7%LhPdA6 z@kq}IMUr^{rdN_uj}UdYvY42{wm_Sz5&-`Q^+q=z_yYcsTPF8B(28av3xyzda6x1* z)oO>+eb;7G`8D6cQOu_O&{O?n&{W^eTi#N%G`W~F0b7XsFNge8W}j+2I0`f-fH{~~ zP!o=JQf{GjOc>&<8KFh&2Cd4kf6~t1vh(P!p3mv9Q17%XA+DS&!>o)V7PVaSei4(_ zsKEI1+=`_}0i!kT1SU$Cib2;zNndW-FmpkPOVwlmi2LLBzgOVIq-)ByqaO_Qg~HST zJ=z%=W!!8Y^Mhz2?p+ASZ|%F=@xjpeQ({du79w=Y8rvxWk@uhIB&Tqjur1qiKZXIW z1wBA_;eKgG^_m~*fw03r;GofcT-aI6xeNnn)se#V;22$QvUUTFCP9X`NRm_}gmuKr zwsF`MX;@e4+vHcibJCcVG8*{SJ5`AKwL@<9krF0~V`p&KQ54cOszHp>hIP*XKi<|O zz6Rx{2yqo9A-`1AzkwjOG7SUTO+}Hpte;G&v`!nDG!y2xhI8XU!;6bl&H%OAYOBB& zDIkP&LfuH!qQB4ZIc+7>Jxra}+AQ}LT1r!#^Pk(+mTvsW3gk?dfj9T+mdWzzMP-32 zIWiWD{u$wK9xDfnv1vbinu$^!2&L#+4x?eDwFJ?HNq!kBu2H;WUs=wioyaw?ZU&ueYXz4)Ht4TJp1mf8%e)LvO0)5Iq*{0lsFH zXSuH8e;?X;zhTo|t{ca!VIgw5*h|eb*lO=I$`u-(ys!dq!fb_I&0C1}Z|emgw$G!= zCK0tOW-T%nY^C4e5*@v%_&s&?bpTS>b;CI4kbG0LVuI8mq%_96sX1R4-*a85@NBn! zP{a%a=&X3>;2T=|VgS8IugkGES8oH>64to2zZG&$s#zc1(`B#xOF7uDOuwGm7XhK7 z+K67AcN+48tvww!hYU9({#`H5)Gs`2X%oYOi0*B&08c?mfVOaoS$`9v%R;jdR^H-L zHcd$uaYvTATi`k#Q8S?19)(a;Im#@w_v8^F!L*lO7`zX=#WxxNJ(#~>T9DZP z`+Em8eU{N-YUT^Io{wgJQKv&vh4sx`@I=)hh`7gj4vxO%nIgo837PglP*^*>3)3)I z$1oUKa+bK-VB0V(3&Vs>{Qjm(M{u<<%0y$Z=284NMeowh=z-ADGjfRLa8voszHp7> zu^x1CjZ3xus((ETLIJ}X0^$v#);^|msRYT@jf~}Jp-Q3jBD;c{lCP7%3Zn3TOZ>fZ zKe{Q9QlIU^9wXt=oYMWrq0M~8O-swfl}7c}XTBOJ3I7&yi`Mz*il6bawE)V`{e9GN z&pSA=2f860f1%>-uE`zQf9BuFV=^hl^h0ftr=d_%)rxRWWA%syVyqoGk0LAVJ#Cj$ zy`UbR;2Yplg+RvhYl~aVREZ%}?$tpPE54_#K4p0CODxzCR(lV;;7RVdxV_kVYMar@ zJ)LzMN-IX!T?AA-v%F@1>aHo4hdFkgJ*1}4wPS?!Q7+0~X9Vj#zFwhy)PmO=gIBsH z>;=yMXBCID^gPk~7a-wpF33Q9(~=T@;clLxRkof4GAm?;JA zGl*Pl11e|Y3k?FE zpD80w;0+!H#fZ9r7DxNXVHERDhJh12YXIUEbPr^cQJl>r=+R=)j|FtewRQ==Gm>1_ zb8ghuCTp{$E2^W-8_(UfAHtC=zIyZOCi1bZs-26Ugy~MI!Yr`J?v}sus$xe`KmdF=I637I%I-_-15571w9j}mo%Lh6`owTrx5*5Ls0m|IAtuc=a#6;65kfln7>=p<<${CX|?2C+y`sgSzzbstw8;l{hcd=!rfsVg5rxcq(1&AV_J&+M4v) zW@_nTGa8Oo{Ixd9A+AblER1VRR*7Mqv<~;TS~>df5c8T`vRE)+J(%8LjtWb0LKqHD zT#oFKXux}xiF2P1bF^4w0?AL7g>D1Epi^ruNkLOmV8E3jeUx{R26SB7F-GLu4_Ehx%d?Kf`ZPK6g zzSpwK=5K4bOYp5Xl(D?5%Ps`rE8@6RxyaHuRUUgRU6%lCd0kF$HR8FJHz^ zG?9-_d_hO2Fo#c-+tIa=t)NwAAaQ=bP=U{m`abwHbw=NTwjK%8lcRI7sDLzC zIN)|6xsBw~Cnz0C25vFylfG}{GiDErJl{xfAi#hbY0T1g`G^HJoU|wN*H&4bPhCk) zK%TGL!_xd#;bK(huHZC@iCqiZQ&D?F)_r`tXpey{yztR~M2~~Z7C917*uH4u%DF}A z@=t3Ev6!)fo*X0TO}GOyG5iFhWEJIvVrxQf&6G8Nu@a7nlk~@zkkSbRa9KXtqUS{@ zX}I15E*$mfm$QsA5L{v`y9-Nmn(5hqO=4>ZrFO^hIt3zc71n_qZbM+MNzA=yw|Q*{ ztN4{$DQa!jC+=#~>imFUCk||H(_Nbx+dZ^KAKPNvUN_~>NOT7APg#o=gbW+dbyEyEF@&_ZI;v`tpLLc4Z3V^oh2x-Yw)dA_>K zk-+*g!XRr{y(4L$*32qgqhI^5USz5hXF-(-tyrEY4y`WAWXzy_Ve^l^6ygaj<^f*P z;jrro%cZf}X4;VipEcDCSL3cNdj1gyrU!bcLorp3`{8;v zad<>qM>v8ZnqPQxG9>o~Y{du=AdThe2Yjp9>{sOUc-58fL>R7*Co>m z4C85Y5o$885d?$#^JsUAYaIOa*O0T*6sNDq)tBKBn`zL8LFB zY;@g47;$%5Gdn$I4V||%b_UlaYyx%sb!@MrCGLnB%=2CCTv~*_03dn$;8tSB<>x6Y z7KStA{xF_wwMnxWeVz8?=77}l?A1TVcu0YMp)+WdS? zozE`~at;P(ofr1A?n9&Cci?F6Gv)m<+{yJTcK; z%~GnjLU}7Q7xnb|%#Od8e#ned#G;U{fF z>3bCh|Ke&H=@Na9bTT6;UW;ua%gD!GK)Pa9{JnLe|I=tA5mEKINGrz{vdFfuW_VTe zBv_45g4tY;jnje1UkoHW5tu4Z4F(Yus{GMe1QDu5N#yg_x9T%${2-a1F={QpzMvwo z{cmmru%F(^T&%Zs^9Sh)#+xs`YfM*M{*F7kn`OW7aA;7}xb2C3A4G>}Z zhU|7S{L*oPs&jzoz-dU!dOPwyt3^5}YkdPDZS|~gBgk$j%RSa{M*90w?=DY22R8d5veKJN-BXvw;P(veM=_e?TpT@ZU z+7qqGW|f2HhOk1SBBEo=TosH=lWY*ZK0q`CY#PDXv9)I(jgPq-*|X)(I`^a|N{5yf zo75zHV`XM45#b&8Yu-d3*X(W`EKa$;bXb{S0Vo--L2z#^$z`OJYF`_e4HDn|Gwh(l zYj-h&S)y;!VAHUpXytB<{p|aTq2(aG?HuvA${r?=!yXL>h{cdIrn_Uq!88l^W}s@$GBzFCYfU)g>C_$n zJ4c?u^K?04WbK($>5Qt&S;+x}ae#vD5$o}M*&C=G4a{eAF z67^D5LfYRr>QA^x?31JYWg+kP=|=h%A+6%Xr+qo1A)-cAYZ%?pc4&}Usb%ge+RVz~ zRQxAMszpOh1ND8md4n;h#a5SI-mZ)+D1O%FkfnslRzQm>>~T_4bh$4ao~8WtecF$z zu@qmTztE;m-m@-jS~~-cy=p4yGb500~zKl=M)}~xMRy&T#Wzn8lMo< zIi3UItEgat#iY)9-GfJ?k*1qp4k2FmJuBq+ z5~KCO23g@DBOpt;_}9i%v6mA(NoSKHuc(-rz#+Jp6xJl}#*Q=Qan6*ioHOm*)6dT_ zSLxn)rh|D-{C%{SGAK_^b_nx0z#L_hpVp(~4ptF%J zQJvK$MBE`mu31a0owDW$$<;)$d_7>+%kdR6tn*fa?K`9ueytp>n@qwN7Hq<_2#f~j zZ~dX7k`E6~N7P4i532Y?^$=TL5&plV@2 z{c7Iq+dsEDOB%{QFKj*4^^iY+DS@I&BnDTQG{YH;`P1{7}-#r$JMO9)BuD?l%aRlQ{QYI)*r24)bxwBqp+LY`E!lvivE~5y8Ui+` z{AY)qd^R6#`2UK|J#2a#of5{3QmtXgsQ230)l0RDoL9~G`uIl^!z4*_AG`kn7^zDx zDPA2kb&h~%CDTgYGS!8Q*yi9_g-DR1TRZ$A^j|f$(6FzOMhCAb=_^Gdln-`ZELjby z_nXp@3vVN_w2x7Pt3w&9Eq4|H%GtFQq0sEBH#Uz`;eDHwa*Os~$W)08@dZ$rV5ASE zjZ0CIfi;PSLLG7+1&hoJ4e6Rc9RkA)Qz$2WQ11j1%K8VVi-Cu_KwjXAU3U9tQldgO zm0Z?=EGwcj5pRpU00LTZCe_Aev~6ze%I+IWVHc-TFs|{p1a(?)^GyL<1sd6KXOave z<1$;jF>i*86#6b$5N}@+3!1t5^uX)p?(a&%rw7>f|@U1K|_ihL9b+dQWn zOsf|aSPg?4Oo<=yr9m(=XhgjEQ6A_$)vf7Kv_9o^`h#6b{TCy^TGZLhmB$xgLCYCn zfU&l)6GMN!et)#kIGpctq8%!RT&h!r(~jQHE(;p9c5&m`gS;E{F3}LG zly$D+g8hR*UMqP`s|^eCO+Ty9-& zh0&NsA1hi+Pm8{nU7=ZIVFwj`LF{b-0T0`E7z08w69*#)9`LrrS;PyKlURzn_Kr@e z1sguUM`lfX^g0n7!}uxQSR3{99DT7$8TCOjQ*;M$RKz0fAcbH(wiMsyCZAM}n$fMG zLke z7geoQ#siWrc|2Y8LIg{u%Mi%}>i8}uk0=Z!&_4*}!q^*ObYxcm4v90=_>*uhVIrPw zYF72-j+!!_q=1A&nIo0Us}Dk=bA~RaN#*A#l2J%-oq@A#Dwx_pA58XNFwBHXos7Vl z8mUlc`5C2^tX>NJvV!QDPc814Ve=jZgr*^xrya$qV-i|?W0;n5FDzExPMQ++>HD_#vn_GT*-HCx>9cI37gRSAB5ZJCrot)9`-R*8E=ARgDbK zNLp)BqH5Si0PFJuj7!Ylg`_&`B>C5i|m6 zcYJUK;L3e&&k8eS;*NAFm}*Mld=39)C422Amk3iw5o2JT7eKaVZEPvFVG(*%O-qvE z4RmX#+6h~~CWdU<2J>(3(lsn|2n}H&;fuu}OtV!v3h04NGd+Z@e_P2}I0mibUErRL zuQ8YByydY(`qnGR&u$EB>p)~fC_R`1GEM+@$bojqcfA8LI+Qpm7_J%+C`-;V zELUO~o?m&H2Pxz<9@lSo&TbeVkZ2dlfHJ5TJ<&Srh+vyS@CfAl+#HH@{ecD!&y}q3 zT@ifm$2(E?Vc@Eoyw-wxWH1wR;X-dmllk)V)^#bEbusHA#>%w)TaCpuQ#SFM)2Wh( z_Y7Jjl^Sy>yB~b0SIy zyT8OKn2$?-I2!;@YzfU5*Lb~5gfO@I!@L&_)8YniW^nrM=SW-)QG{x&r&~dUt(72} zN!~=S9SVxAZ~;NIU=bv7-1|va8d`(@XKPcLs+1vBj%8g4CY5(tBO_j~gOa2;P>UWy z2&zY*KLmhc^Y8vIfb}pc06Rd$zu3g}xrM%@v{bN!(>o7sc;ES|hjaKn&(;I2IYA2! zAL4s)SpJf^yXkwi;LWC+AyM%#5LdNzz+_;?JGbR}0%gx#-4!PfGV=c}TN<2vaF4e9j$`~0NN zEG_W}*P1@nJL(L-;)RMn)kDuY#!$=7z9F}ZKjTM0Oj8)w-jy)l^>%-S4mW)yc36!s zZ2z@V`IV!eEm77fz@ns3%myq26oTUY9fiLOd*sx}X8Z4KENk~6 z8LO`;r$r>J9(a$9>4c=;&&oQAh}>Xj5XFIs7Oxo*d(}sp3%cdJJSoK)QzEcCGK=5t z0qjP)gMye}v58S4o(L@H*q;S7_LmF73Q}y9r}_ZDvsraUeXT!ORbDwW$}xF z47|!oi^g8feR+DBx*n!O^rQb=m3&eC8l+7ovM}{f$!^;tv z&Svwv)uQCEzfswKOS6ZeO)nmQ*?Jmms2Y_xFmj~7n(L^W$ zYg=7tb#%pqE#RYdWc;?OO@TwV(Uz_K^tXey6Sq>M zUJ_mDzQMcudMJFQxvo*oXn8}ZJDM{m#8n)ham_+}Yd|zK&m!?lc~3xtjpkhp_59OG z{wXfGN?&0mojZCy-@D30PT16(vOtt1UAsC+0vqD?C*gQ#`)D)8vkyC!h~lG46a@X&;@i)FcTFSU=}stp`+EivoudlCIt7U&E^?#=IdnlfP_ zdRio#OddozG-UQ`;?(fZfLonO;WU~F4<=-5+|x6JI!Dl$m6RR6W`d z@|o8%tfq~n*qb1hp)AgUl~98y^dO#uwOlWfTY%j#vn znxRjD+!LKEqevHlBb7w14vxxU=KGE*a@-M~R9sUZf!d3uRx&;OwcGfwzAtp0D9D|A z6Av--$_}f2?olsF2~m4-RQ-d$O76q^?iu0pE>O+<%I{rz;66Snlrq<4imc_zGVqa2 zU9dAA@5pen1>jb}&)@#Q=!Nofkl3CN=0^?Hhv|F&l%S~2IaCevNu6?_dC$nzkOlZ{ ztR8-$Z|^H~*ki`Cy|>!sqeFYCRLQuDZ;Bex&JH&m+{NT_EpG?+%_JYuE*e^2qb52& z^sG~2Mc2jJ8Dj2+KS*lIK546}950uVDaXYtlJ-0ayQFvTOVft2d{=ERXOrzu80syC;VGLmCcD+hZQ%EaN|O2 znnV@og~&>Mew#th8p?-K-rb1qd6Y44L5*Ti>Y@1L#{MZwT!kGVH_k}L&JbdYoq6feZgC3Rw3*I=c zJrUS&V(PsGkA{^P7`sI{52Hc1LmVrmEz>@$v)(+Q82S6fJ>Nr%4b{$jFbXStXH`id zYuDxt9c=Sk>okrD(L?;nIWcLyhM%M5Umit_jA?GTc_zGBMo*Ew{LT|B8}dd9=U)*> z;%-GCeq+Im68UcC#HLm#pIi64HWBbw6Yx1?Rx$$-;tq9b`Z1-1e+x*gWPS#O&0{O| zgHo$DXLjp8h++T!vn3&NmskU$=vWPa5dVRjKglz;dI$vK+W#=%LdHtAfb%Le<t%rnv9oAKOSJE4uqxj?d)v z?y`acI_b>5a;v>Wwpo^h2-%+fi}zqX$QJwY4BDLzP;f!y73{;WVwCs*gjqCpy&@~P zotn#j63DO92oVLBA6!MJFz069#~117R}{@uj{~=Y=v<|pkpd`-q0D|$VHgb3XUY{8 z4wrGPNg|{3X(S77)F#H6^{A3%!#%A@>3tHkBCLUeL`7UEfyzm8UyBH@3xdu~!xHQe zdPWS95M94s^0y}QfeK(+AF=Uz*=W>d;ZS<4gCoi$;|?}<{AD%NA&KnaKXBMh^r zB{aJBenm57K$N!|&88AxJuwwh=nA8LE~VR~Yij+ok%<5O7p^QmYhsQIaCk7MY!IZ- zN|t+*kB)eBz+`C5R<&^Hr!HvShZqb@wOna4X=1IHnIL^Xqow3|m8S+DtoGLC7+$wq zYhz~szWJ~j0b5Rn%Fo{Yy~UJdFNl~~vMBT2Y?+)v{qgD;+0VWzmH!_yW5tCHAiP|Q zPw6$x4OAqOqSwZIp(Q>Vp}RwWhzgplrS9;r)7_EHNM^x|Xgm5vI9|pr-?^Mq0<`k`zjAw$c;z5t20qal zy34J&{*Qw^dJv8xUg;BM=yIt1PlYPA5G*h zddQ?Xu#Vc56!&AxfRjtNufMcgY)=&DCF5G0_uY?A;7Z-V}d)*|(@ zNc;-#82Ps2%LDf*zAas;FA2(%0y{GRD;iV!zd{)rdk0PWng??G!wG*65Y(G>WkKzs zW%HF%nl{OGj&5!0^#qpzop>2my#brzWe4x%s_f9}xNy^XEUqqU?MW{tpHd1Zt9Pg{ zu2QOHUHRz(UvVd|f)ln!d6qw~6)tuc>uO;m^no3{BB&{6)O?obnT&*^l*A$@N)Nrq zv~lzPLo)pU)!R3dwdaLn&r)ZOQQz;XcRw3kDdk7*TVnf;D)3;K>QyR={ z1ecXD$$BQ{AeqNiwSsHpOTEASpdY`mx^A&*{<2iL;pf_5-}M!Uh2t=*GZZ&e`-zL% zn=h`I41$nNv{-$3UNC{7n6Hbn{0THJSKxhLJv%Za)~cwMJ}}lr(kIbpNdR`$(O97geA~{w6k? z1Tm3jBk*u1g2&C2*~}F(VSq_1&?SiNjQLu}_stixm*Fp@O=UpJn3y%0>s3+V``Upf+Qvt>ISFGF=N8!{Beg{$gBf-HeNpZ!j&lc15X(q`6!ws%p}9t+0!OmJJR1qNI+)23%%2#k>Q?i zrgzZUr`w16V#If1U5Oy2Tqu<#XJ2HL&>Ng!|BWI{j}-uB2rX*RR4`KI+4~nkPK&eC z{&+m^%E9Oel;>=}?;8z3R`Y^nmr>ygv9fSljt##3wt0>5ikR)HyPsOhTjr*hpsowI zB-K@d;6(l_R$FKg^RQ1z`648iU;GTanIhm7puW7LJoS`%M(qB|@tP;N3!K36L5XKq z#%iPT$Y?QSIsiUQwHThr$a5|)>2$7|nsf3m;-z3qXZWa04?&%A4^D$;3I0WweaTs< zC_P@|tXM*jwGSspf0rDRq>7pwZOFk6HF!WFp^jIA8?r z$#J`9@S}_rL2%DT0OIy99n`QKtQBZDzh~OSLprjOs3kk&uD?(50~6rxQ`QlAE!o7y ztCJXptvEwey1(wn#Us{x9^W1a|6(=iqO-qu>>GStMH~g_Enh@fJq0;{-G9((z{(aV zQJE&xst^2iGg4qqNk#hf74pl>*=v70cRXE_KV$cUWS$?PReUxQ>ek0GV=1N{$ZbAs zRDv62BsZwrui0^1*t8a^`EMOnjAX=Bh~gVk%+p40B#&eI*m%=wcj(yE1sdfmXG$@U zyN!WjdyffHFt{9iyx#OF^|=fL^(BgEA#=op=a!*jMV05+naW3Iax2CYOCKRb?T7bw z;SiMpjaa$`q8PE@gLZX54-Ej+#`xM2CE! z6S^{_0wIrQlvHz*TZWu^0UWn%hMtLxx%ZXs{~1KqAe4TFJ1M#OqQFU>r=kipV^6@K z%ES6rL5BW4>{2-s&)67J>pOL0`Ra_5C*oTtkY}#8+xy&VU%i{AP+}TQZxw`M zp1IiYx++uuo@^;?S+>nxjkyoZLj~g=$PH+K_{%B}Pl#X--O~JMxPnhbv(!ED-RWER zKyEN z7Upm0MPd`~>4H;p`$=a^|1CZxEn}WDD+E z=V{2I7Q_i^)n23@qrf!-*OqC=2hTgLSde73*a&pfBAFtTk$b5(hn(s;WD9V5x`CZQ)E@u~7}EUWsn|%Ev~t$zKEJ?XatX3nx%-Qdeu4 z9%g2y_9@5ZQd%JHDO!7mKJ7cm^)i|&qP~8h&PQYYd*}7{ky8b1JtDom6dV_9%?HSc zIHTF7uZ0LePUh(n@YV6ZIXn+bsh&Q0;QrQa~ ztpd}wPhG_9q?SX^u=R-(-QzWwV6P@~gX=6Ww<)$n*-{=2{lp5Z$~Ma>QR;Fs?`q1# zuOUg6pzN7VR|T2whUu0D3U(h2$CyJc)t9Y`)Z0?1E?VrPpIA~BRmgZXal8LrYucT6)mx&seYu~@9^_^paei!S+I+gOm>@02xm9O-3Z&5I>3y5J2uguD0~z` zc{i=USdTM5>|u|bHxuhFB^=%+)FqqZlC|m+-&akTA~b5#Xg-b4>7y9utC**Q@v6y4 zm7<-QQMXd*RV}uhB7hGK6Iq6srrN=pgCNAu3c?)~hJrgGGK+4bd$m9e*yb$@iiL~e zqhFw4GO4&IZ9(u< zf7IT}TbWwU^t3B$?<(6rJTI^>8_*A#rwO&e@5lPs7T-zg6tiaO9P?OU1SXRdFr?QtKR)P={dC+7IHlfSEpM5W?DnjI|tQhA1X zc9EtjK5W?Ivs~g2n(p*wB!xbr&d!D@V$AD1b+v$TAPH^fNFR5?AlO;;q^F>3n9Q18 zMMkXG;vz3O_1x|_w7DAW>1h=+@sm{~00?sXZo=q2p?)pG{xb{+W`PqX3W(S=@#T^S z{j6~x3jaB=Xp-Zc>dBJCV!=h(Gsb>toqeQ$zLQUq>U({diVV<`uxhjS6Hob8Pq~4~ zcR(S`m*hnZBc8WUZ%|l>ZV)S2Z2wZOsj%3WOu_hPbep2?6%OFlqu5+CM@+#(B3)T~ ze`&}Bk-y@NzQhM9mipPW;mpgzAkU7M`{tK;<+PQo|$o0}FvN$pu&RY zjs3m$<&oOFB!g?&M`#D9V-k5xPR|_j*rltYekH;U_H?A6{_J)<|NW5Z5D_x&B7kw^I+OKAaRLm^ zG{qA&!!DN5|%G$M`wHngzaZTDh9NL#nL7qWTo zZ=em4ZqKuc1DgCcLCxWdl3_0D5d}BH0npVjILSxW!~NJo5MEta{g}M+m zm4DHx$M%THf10LKNx?wk2KNrm(=9yfJ=xxE1&yzeHV66=<9mtRFZZt$8GXm{<(6Xq zHF{fl&5Qi04l-z`#06wFCBHxJ$;u>uTI1;UE`_Q1S?={()Q-%_`JWMcKPMzxjKlB? z#y>0R7X|lsIgz!zx7J@zMwn6J7?+eG?s-OgNVk936z;HF%530oP6M$)0^+WfAuMI( zGtszjvUTuW#y4cy;`z<4Ft6--ExDILz63Rv6Z$f+XyNl6MV;#@&$-M z9?uFv-j}hH>qk%l1yYS;Xvg~lBgrc#LW(6Yp-)Ged4GG#m-htN1RIh+e}zL@=%xo! zmTs87n-#&`K_Q4EEx|wxblJS$P~h`vaHH%V$1-sQiTL0Foys3}I3tDBEtR;pJA}BH zU?D5~Bb2-)ioa)JW^}}?X7=JURm~VK*S2wuhdDue#;Mi{A|i7Hqrlw0n@}@^9h`z& z{>LU+y#|{hxa(44bJ15$N#sC0RPonKc~6I~m#uNkCu|D?PDc@eX`~ zC}D0_s{n|3ssBP$4VNB6vZC0oFs8+Lc#@d$p zJZg%&C&ekctEmk)@?ZPLs_%=1i?~j>&yw@GdhK08hs~x{vIx_a6s|awu8~IT8VQ}?TNOq3n9r8*l$`oI$dwPW>VPcJ4a>RG_^T= zqNw!~FdfA{MISkora#aYox5$L01nWu!>aFU9~@XSW;I?4yKDL(T0GQzUh4u=5RH@n z#)n7G=21n;h-hlutPS$RuzAceSA!B<& z3qo2yk0|ckjkb)2$y5t6Q!$NCI{bmIqodg0*0toPey(FY`ZH+D}+?tpe>{i= zuzg2~`+E|?uUC&SyKAQ_PPADgohwPELHu5=5%Er_=*>`+X}_a|YdoYQ!tew@5;2GxJZ?gClS)7^kuvb18|A9gG@w_xur3fQ^kzUjYp zN8)pS2=13~k{w5sW)2hw>cqO29XoPk%WL$MLAU<3otTjkB^!|NTFz9EtBAtU1rinCT)7he zKb=mC7Wkb8gB8hOS0Tm8QT(ns?yx#MW5v%xhn$MW(|>SG^V;FyXT!piSh$O`(gO~0 zMXj{JtXW#ES3-sg`81XQaVkBj7{KubrzudWZ#(bdVNubl-%P{EY0HMpfo1FqU2yo2 z#3#JbV;AokJCY5eG1XG1HXFlMc>(oQ{;*r<_3zZjUk)6vK6nZ%zqR|&nBUF3s~(<0 zAY37HQr;O#%kj9I9JKP2DvPJcZL%?yO@O`V*K0*aOD(SaBD)GO2|e`08LjCZCzO8y z?WS{LJ*wS^c(Y+%TMwz*`^#v_d_}z6xi*m6hPoopKu-<=2tUwuOp-tR9q22$f=}KP zvhJX^6Xl@w{&c~wbiRH4e++=8<1|xc=>vsy<^SrPa5!w6ijVhy&I95ahXHurdI_p~ zYcQpy1BG-m;$0|`7H@D1S5T?2ZM@f zu7FE;ld0;xLlLA^^|l9p;n1{Z{qK~nK?Fk0^!y{ZbK>kP;v)OS1uN}-fuViH|n$*v5d z7DB*Qf|hhtU-gsip+yy<&;g-^V*HTek*Wc9EQbd-Kecv?jG=)+kKsnPYmXvMO4hI-wta$0Ew_6nbEOyX%SkqnW9N}s0Km;e<2`d|nPX_wlPDFz- zvLvY1dE_8)U69%ahScG@q4yQz2b?Uj3D*$-t*qUdldjP%uq8Z!RgegvFyN`s55tHm z@Y|~2#<1WO9X4FGCr(gf3EN__Gpaq$%{Jd0oog-+A#4YBf`WJnX&2C;vd-)>j4eY> zmKhN?#>acZwDQL_q#~y}Xnk!q(5Wfe;mEL7FbYXc5bT*BDTvgxX<#NL5=|vg9dvYY zN#`G;g%lr+(eDe_U!yy+>VW(zs>sEYprsf%K+o`yc7Y?S1ys4y^}S@)OI?m`X_m<< z>ObN5&}r`IMQtU8Y6YqNo_YwtDbW-fDN(S)k+9E&Hz&%OQZ(@C3mE0)y7G(`64f-3 zgK;N%K@IuG%t5+KdWL>E$y%3WKv(i#f9pT-MMJ7H%#Uj@RT$Ezv7F%yQGw95--xh? z)oa%k5yB{mj$rZCN&5eQK!^t2=1J>hfmxQR7zWU>13n^*ab!XZMmbe9{3#&Rz^mPu z2SG=IZ5f`yJg(bnZb134G20&z3b6QFQ3PM%edzrMbw!E~ogKy_wDx$y`o09btod># zWSo(373Sh>)``kawnB9BgrX*e`9HX=V!q&$=TuG6al)O{ho6vHS$vy( zg+bUaJCpm&N);c){VkklsMN&Hs!yHI1@v|DP9xdAETUVi)JoGl15=+RY%4a5RibI! zIdS{1y#B6l`K0<)VMyQ-pzUBpMY-`oo}t~u|Ei7wQ`S>{D$bfwuqBsSl4P^>(oy@u%n{-Gpb~b!_KOkc5p7vegVHfU!-wg>lk(*O3 z+Jxf@B=lM-u+94hyhuN-8DV%nNZj6vf36RP(keITA3Yi(rZ6 zJx1kVIhe+!qxCR>6i!=O!_$HY(gmT6QZt&1G6sCGIGLY2(q#SoustvS18@lVP3GMV zM^zot1~uwZg}H;jwkVO-Ub@H^kwCKkX#86X9d?%;0G)VPNOAeUSICW&;cxQ}5SqEQEw9pMgNEJr5KINhSjI zfCfDV%!xG^CX!OzCmz2X?soZ2JENT8r`$wjloDavHY$*nd$$}Bx*9!P>F+uVtz_SY z6%Qs?wlf9r-c2P*q#&EQ)n#PzF?}|J-#4o;HSIXC?p_~^OBi-FT2KF{k*!I7pi-g; z-PObQHbN+6^vBnV1(cDv`ANO{2@?N?$)$o`<*Cq$H`!F6JShx& z#a{)1^}Y|)!N$lZ7V&B1k9uj9DQWts6=pgo0k)KBZ~8mqkE={C#u11+h4u?{J>qR)kTAl zB4HN)&uGOP<`Z$~Xw8Oae>F2+u)Jdl#{3jv2c8}0=GR^i0WEIr{soBzKZ!MARsM%RNyfl{k~yPp#pW>Gk%5Wb$bq8dr3}Thixe}&)pJiq zTe4#>;LbE-Ssg-HZdO3z*Qnr%Tsh^*JY;@C)MhMv2hF=5f>kO#LM3g<6#=$ zEP6*zhY<8ypX*cIE&nk+PG|f```kkSkb!|ox}p?gp*HJcDkTES$$BIL)>j5<20q{4 zGJj1{MpTa;K&$=%x>0Ct@Mxj`3}C+*pNgKWrp;3`qH^u7Y(mJ1aCG7eO{GF|oC)6_ zIOWxHI1|}`L{3Ofi%cXv{c7@0EUsp!?uSy`w;C|JK8!?>0?GB#_@PF%US#k%2|UG# z0F|`-qGjXLTBayWvydzb7yTB;l9L$TRw!Gt)?E~p>>D=c^<7;tXhdwF;Bb9kHvJ4j4BsdB-B?Iv4iW2 zkdJ2LGHmeOxYDGc`x=%1o0HXnBLO#8L=Z%fp-!*WyIpYQ5b#8a^EUY=3fZI+KsFp= z`$;}L;Mo}1g;3cg&Ft728W)^kw^ubq66Ool#dB6<1a`ni{iBJ8yBG0Jym$IYP9o@Q zow<$a6qqVK2dSmh-d}Az5utJ3YCD&?s>r&M4Mt8fUsVKt4LB-IdXCUDPdKw;j@a*n zTjgW|z?#ewVu^fQ5D)^08WMj8?Reg1aXY=X&tyr>NW>VsJF(z@`gWU19lxmwDNlP%}?_ zSX;}P!P6i|;aDcWr^wlu!ed;o3=po($=Cj(Fe7gqLkY!tkK1k5FN;i!M{cpT9U#U@ zN_ieY>-{o0Ym(e14-YA5BAYg>9jp2X z$WX{hw#P65z9TKoAr*B>Ve2jGzUn?2Qp-N3{Z)Cwe#AqmlXK6+zd*j z97824so_Se9>?2*H&!PCpFL@5zFoJ+(MBfzf*M6x_Xb4NPsD>mgv^0|*;myJAXbyE zXm7TxmhnA}(n-d>)Up;a-x+yDlX*T%Yesxp2xP(7&U-bA-AEyC1+HQnEVqvw{N6lD z>o%n;8i(Av@|o7?$xA-3TMmq$l|=&s{b)cEbGGHND?bPaoH#DcuyvkL{)yIjZ(GLa z2L3&sC%&W=OcY|!S12ZO?mBt}1mbnWq_?b~7uMWN{X=8Q1ZuNt_01x8L{Pf~9$Z*t ze{hg!`^!oM34jJ*%68W+C@OdlIc}=b*iEqZ8dR)Ylp(pNX+~S&FTrOsx}_fEFwU_2 z`seT!BM1ZFT2iSxB`_Q(RKjGZCalctxiD!V{xx(3jwzQH$48D#s_pSUH-uw}xtpdZ zi9V{g$`cOE1v*B-&~88%E1hOvYvc!mX~<8fBDF4g+FD@4)G)h)E)~rICg~G#k-3Pj z6{?WWrymX`G$cBkW+Ai88KZKo!=B#%mx#$M7i+gZq2W`XOWZ@4Xd>vHvy z9Mc4t==BsVqUifbAvsh06-;WX+$#ig=Uzu|Xk%H3`w5tDMlGuytSv*q1TSND%w?l?*a7hI4K3?FR>ij+__C56^soRvM$B7I6p4 zi>!eW6Hz4H3h{wk>PUL6Mcb-9!FG!v8qv*Hmd@h?Qux4PAJGeavO#%1hH~ zy4J`LV=+ha4A%)cc$Ek$ry(w!;q=VVmK+j0pI$>Jg1}~oe{Js9ny10HV`5BzY8U*% zmN-^iNgx0Er*^YCg&Vuxxk}qXSIp(uhVowy3mdz8&`^#S3@l5U%hZm}03R6en9%R` zM{l{y_oucVIO&kb+lGzj=yPSzZE@fnG{LUmMBP21=evF(J(DCqNaTF4gKB>tUd!f4 z=EOCwX>-ib+JonKjd9Rn^V*=XzwIEaSQ6>=7BRTQ%U4M>CG6BM!l_3Da_7n8NHaRG z`I5ATVUD~)LF*jns;0~37zGc}arefT`W5mvngD{XE#aVOWrHpS%JR*A7|T%)1};j# zx=a^0^&`L7dHT<9x4^6`<)cFwq(i7_$^hp1OEmDLUWL)%bowrr4_%=EHEq7}kxn#z zxUNyKdjHiPxesM-I57)*lG?B@Iuuqu6opx@DR2RqWmayoZl9jitlOFsjRSB`j1E6M94k}H%?ntt z7v5!~KbkXm#dssg-X2d6UGz_bUP~5&<+)<&ox=%il!b}bc_@_7(87V#r>R>DNM?Tp zk!XMsJ?AvDnduN(lf$57F4bw}&fuu7YpNM8ExN~LnOiWyp3hg|bBEJEA|O*GThRer zkb*+5$iGAREe`lV5-Chev~|@RcRT=K{_cQyKC=1Cv&~eoLtx+p>`FyAMT(G0BD(m! zoaRgl`pqV{{tCq-iVFMEebvjM*B$du{5K8kBW%ucU?u~O^Ohj~#BsBQ|M%rUOx098 zC|O!j%SG|2Fxy+5nVR}18hy{FYq83KX`)In$C`kH*bqjl#{!Fh7+?AKAH3m?n(I3# zFXbJ$HysdyXO!)VR9;AZO{rXo=J-h;%~`J}P<|=?G^Bamrz*`hdmX@3k$m)1fyAh-^y1cDgSo<=#6$q&RC!ZpM zD?~rVdYZF1PVk;l*KGlT zl*G+cuhgumtwcHB6j&VzkVg*9#Jl%_xn=?R0~VbVtm_tZX-b-n`W#{BzyTzT+*?VM z=Lcm#IjGJ@!(N*z;B#l{Ks4B>(0stRZqw2|RTu{epQ3gEBq`A;dbuxQGE*l| z&Ry=N=o=qCGf_;OeL?H<%XwZtanxrcb?M(M!|z*5Vw>?=irmnd#A;Pw_}6=0QxAAn zJz18f;6H|r(c_#CxC0a6iU^O}y8Kujo-O_{nFF)L+9B)NJ&KN-7z0Q6Z|xH0qq+IV zJts*4eAURs2N`vZM>tHx5Y9&l5>0(daF$4M$I6V5H*)FB>#8Pyo}yFnY&*TFq_yEs z0gPsG-8_8mCsJ9IE{PONnVkQh_A+aro6 zS%`0=YN6!QnE4Y-5b60rU!6o7yZuy7P1v-Hj!h^qD{L*t0;Pb84a&zpH6EsD=_XxT z5f^fJ^xcl`BFG!80|10gDFEeF=kn(FDH8~uU|XcvE4be=O54uL1m_R~rFHG^j}&RF zVB|UD2y$*HLy~;Sh|zOaVWF(T{Jw;vd4%F%+AG9}mi7h)&*^ua4T} zd2D^-5Fid;zYq2$tO_^4>>MeX95*C@1Z(4;2LCHyUJAyL?YG1SyDZO*iB}LPs&)=x z%<|c585UrvI4#)k92~ZF+h3=feCu=Q(n#(cPm;`S{IQ<&4CdOkrND03Yj+kyEg1aA ziau4yzD-DA1re`xn(Jb%z!0F~}FA|SO5Yr5+OCO+(!4eB+g zDPBMN+YCj9Y_oq?cAXM2>Svt(0^(gjdnb)1MIs(|T!(3v5v~dx7%!r<_e_n6*-~KXoiv_tO zG`ca$2ICG6vpT%HdWugmwiw$0#0r64K#dta_5KusfsrTR1mftVNuLikHh(g>_*$V< zJ~zOI{;p{%B@ei2re4&G4b}7)Y0n>$vj-I=AavOUG23RxdN!MlcE|BA5V+Q)Ne#k6 zz>ybkxU3fP|G)IdRdD8ZSrvKI>xi&R-x2%dZ2rc0eq{HM>VCx@8uSjAn>zjZ`kZca z=x3xa*fwe%zisJQ9xtjIJ3;nFf(N>7%GzX2qN>2GA_k26Yg%s>$s>SlG*+{0$wR``v#8! z6B4h;64-U|2MdZOD{`mf)Pikf98YruzMKU843g|@4OHX}`okhrM%MB+$IpvDvv@Fw z=JgC|)f`0l6?15BzafEMnD9>J1uw22fXo@AHyxumtH;fE;wp7Q+mKmo9cdq4ncoQt zsFfoJQqAz0q#`F+6BAC(gyAy-<2%>Z$FJ+oX}JO@7Z#cukd&%m@qt^X&kATr`16Zf zA3@C-fatiI&QnpZ{yGyakTA7@croRTH&*7_q9p-zMTpdZgy#5C(k$AN!Zvmd;bq5R zksK&)Pw8|1FU8-~)Qd9HwW8M>@4`1BFZ~8qh|-T;asb5?OPA%PD*A3Q=SF;t5X@1D zoE?wSu|L%q#+(L8shM(FHlJo&=Bz}|M}8`hcv&^aKZ~SbpYR&86>DvPlSwn_^T||`%!V#NbFhprX5TO>i=rC~% zKMo>_K#xfii6Le?X@Adki>YOLHr zy}6aFzq7zmCNEf5-FF@FaKNOi&KP^9W$|@AY2@S2QU8qnnNVex2h=ASkvIZP4y71l z5FX~`Od&&nqZTv)f3YZ8e(l#`<8PX|p1N;QjSTSICgy{B* z?-}PYQ9l*m(~`kD>y``FuGAtdj`sHj1Bx}i-m$8ejS|19O_0RbqJExjbWkxr&(w@^ zoB{H(bt#83GCJY^ddDstM76=^v65E-ho%O<13h*6wZl(%>G*N`?u{<=0mp4PLc%+V z{Dig|gsTj(9vq>8n?Le3icKTCk)Dew%gJY7;%E$YvDGSSmI8y5pUEB^Q=pyX;HwHpYwRZFwf%FN|tL6fw1 zI%*Hes+u--L1`{eIJP0ijm~3*W5%~G$bEgCBU)^6IuR;1GdD1F7lMV5=fHAD8|VM# zb-=YsZ2Eeu&t8!$>!%@D(1?XSJu1x0I|?Dkv+7xz@62F`sD@3~$&0a(jMN#}-f$~D zhLiJqw6&tVz3r3M$--@zF@+1WHtQ30Zy0ynm^?dYGyhAcLNAwMaqxI|xcWd)h`a6Q z%@-Yk{yzbIN*nL@dmvMI7ura&UJJ&s5)kCvMdr|MZHA)^xU9z<+1lR#awLM(NB9C- zOvFiJQN`L=1~o5|SPd!tV?rXDbx1#IF+R$DWAbj&ee@<|%K0D4E8-5KG}Nd(QR)#&YE6bV^m$93zck5SQ6Wt;Yxj9IZ8|d zF>;6M{1lU-KV1xog)vM<9RIQS{UvcHKZPjJ_=u4Q%HA9iLuEaPka?+17b^7MroSb0 z5F5lG?r1dxTUQDwmIR#jct3HKPcK|f*6wlxln>~v#~s<5WTCnGfA_+FQg51UDEBBn?2D+AOTWsK!7luRKs*i&r$LvAK$l~ z00Mtg-Mo;xZKR{L{)|zJ)8P^Y5D?j*teI;QCpdiL(; zx5BJx*#GCK6f#a@4h2UP2Lett=M5%3z^a!LOdS9}nfiz*GGU=EvHSS2LzgoOV`H z0q3j7GAb9%IJkH{h1qRQ(Gdqyl$uJU6RuDkev?HFy;E{<4Q!LLtMtD|H8H0galb)Y z>4!r4Wgf7zTYzc@8BjZ}s8_d)OdVw(3+>}k80r@;1AJ6UoV>?|Ii#EzONwf-Dp)El z8W>?dyHA}XWhc$O{(JGZ*502&5;A~0N0Iis| zRZ3tFpDXJvR8Ux1G;`i{Ij-`>bLSD>j~jhw^LCAL!Ofq{A>@MRFsI_nrQ)LqfOCj* z#_P`0N15r+hRGBA5y8T+sW=VWA^IZegJaZMu{nQ;&``jBq+f`GN8D%-EVy<;vrxbc z(~EyX52}Xt^_n`h$z1CzFQNTqzlh?KDhsPGvP9hWo=;=TFm!AsJlvX}z)Q+^ghyG} zG+Y2xK&rp&zmes(>|G^X2xa?1z%I_1AD!doUMx&zDIO3SFkY1b&P^IdD$lsj&42Ky z7grPb!7Jt0Wz%}T$>4#wFK@)4cOPky_wF_pb;CmK<|NItB?gk6+<-o3li61_XJL=* z(zqN_4gzK&MmVY^&3->EkhrA()DuQ63ZOVrHt?jsK4>c(#!o_lI`=G z6JX?^%7JCg=9Q%(7vHRSb{PGZik1UWGc?=w&iKKAVN0XTW+_&(FdAj<`GtRc0*=dSw0A2_pUXRt>|PVT zB9Pq1YOQ~y+1gbA-@XUfeWeBr_#qEz?k5uak3f!9V!d$MWfYH*zz&M;;3~TGiQza9 zEG$wOFbzaXLb__|yB}G|KZwXEl)Rh9QQ1IUaV#7ymU2(=@10Ji&HfZwd*z^Vqp+_?RxK^;pn}@ao`AM=MyJ-v!M0V;U zk+O#K@k3ZvXlRWU`^4U24j6^m%+B-`i#HJma0aW zV1>aM<5)2)?Q>z>c1V2o3xpO0PO#Qls$Nknv_Q^-;lS}!Z?L@0CsCxp<7DnW*wDE7 znh1WPdOd!j%VEixos0vgTgXm6{k#}%j&;_i7X!DF!$c7B?GOpqvV%48CZ#x!on#$v z)6eNz;csQM3-U4(g`K(?)BK%%T)!^L$X-ad2&c;OL?-3S8682FcQS#U9m`l1%z*wC zzWuyMNoxO;K-B@_cD&xI9s{vQW*oX_0~mhp=g#jqosts(`8uIHjIn+b5e~z%L~Lrr z^lrej6C027Z0M$DOxlo_CQk2?6c9nj>4Yl1UAM?3wnBdFvI}%Y{M}#M4*4f zShdx+B4;8<20Q5KosAqZ*?Jtx z@74e73iX$+TMDVPDkOkq8Np|&)5+P|U)2AZg}C)v$PWZVrCxrdjf4n^?^wY&ulO=- z)76qtZ}r3g>9(4lF5Pnpok&8?NegLUfdKQKAq4ja7Eu^?chTiMxqho-gkn^Zs6Nt| zP#&*YAdI`hON9+AePf9vm0ESdYJCZQe6EIQkob>)e~`3W`{TRp!&WkdX_IxsDvMuU z0W}CNP&&sUWYfbr^B3A4_{Zr|GGSpk-|UnkF1g7+_9m+^A`MHBi&UG>fBBVXc|J$^ z2H*_a=uTRj5DfgSx`9RQn4bh zk>n6u5$Af9+&CX0e4QZfqJ>|nREciL8B0iAI!P7fKPW;Z>SBp$E+B_KXWr5z<~u1{ z&VI*1{_!}v81m%WFwSDuZ*MB}4xz;pj%%0q#KgXE>!IIaeyxqnI)~gPMvb#Zg3!5Zf z10rJPO00s3f`m(25h8)wX@N&)Ot7KB$&g#{V5)AbV|>MjJ?#Wxf}7L!nWh?eydUYZ zl&&CB9xwbGolL_S{ie#! zNOD-&8~Vhv!E~GQ<*fGeP~`TIl|3WDjN5lAL4jv&J|TuYoL1`Z1-kq7Z!W&t`bkcs ziQU5ttg5u}5tS(K_(Fr&N?-+5_#bEY{Ll7ES4Nh7X*=7V$a!ysB|q&oA5(lX7*=qx z*B9-=O-xT(H_`$(?ij9#aC2vAimHh!Td0kf?c9)3x(=draQV>&bX*(;=hCV0JnS!SH2f&X1+?R zewXuR6HqO(arb~y7$NTWV=2hvghCbfh>^V5+5kvcC&a?J%O?PdPP}tN`_l8&GWFpzINMjJ&4eXR2%a}&HYZDc6&&gpD7-5xT zU3{)ty^5s-2&f~ysK8zJKUZU^{T2VmFZig1=k$G^<;2ypPrnb9WR}hB)9kY)L4fP8 zLpmh>2fN@rGZYVLy&jO@;_rXYO$8{$B2KUUYH=2b^Z&mFieSwe41jt5Qm+>s{lK*{ zce3UH3jg$rz^sWPgsVm3+bVKGW3tTfq<-J;fyD*Y<4oh)bni8A z`M%B;@D#LNI@q@d$K+QrI#oAgj#QwV?|{RSOz6fNCVmO+#=WRN*r6@!T-=q0crtSP zDP)|)%j5=8piasXBJUKbqZ;-Mmk7U%{iU?PyK{a!(NUn`r$$dWfw=j&SmFJA^xBYh zf9~s3FmSj#Pe(emJroqxd6@OOzM{K75(^n5bBp}r!;MbDGl|e1f!LE3X+I^~f6cRGBV(e(OXne2X(!*%n zNU^;jn7b@|0(qS!n4n9cd|-7rbT()FI?l!kgMcD6T$;TqSqOt+VymUCY+0s@BPkEP z#ZETCVnX>()9J-O)RsMCqu_g0{Lf??Uus{$nKoAHus2ILgN91v&0Jh7FHZXu3U4@! zOd*&TqLkzo4)xl3MKfLiIJk>AW)?7-Vi*2%qrxTd{P6M zpWcQyej+o27EfjY{F8xJxe6h~>|!E4OSv8*B$B}VJ0DIBr5nXbe>7%C0B|6;N7_&e z@gjI``jGiI;4hBnUco&jVr^xPaW&vXJj2i^tDhgFfO}kKDa$5remQG*O-)b%D0?H% z{yPv&T9gY_CVb7)Q$S?Jw55LM^TB^BuSC0O2W&V074L30E_R=tgjww{k8e(JAl^WxwIb1*_7MxSjDtmpqUsDSL8yVbpUDt#qq@KfTV+4ofBq)UnpRj1qvA{CCJTO`64S*zdH7s)vcb+)DprB|@e_ zr5RyBpVKzJV&kY~?!c;&28whK90rHmYV`oySs^-UQ2XuRkz?_Chdx5X&BVj;tJ5`< zG^S9yvMrtGt!Cf=yrk`!ip{C3td$uoLsYyYD-#=v^!Nx*!bcs#M4O>w25NcZUgg5B z-m&~ABR*CIv7Fvwh#(|_YHcflPlAOhAI4mNXyn8Id)^?gHP6~xT;vw<88USPM?dRbVp83=_eOWX|9KTxROV=}C z3_MM~zPTA^?wS~5tihIX!SBzzU(~hkr$owxmOx-b-&MJkGkd3zay4ZjV>VhgVjJ~O zi5`j{dl*qH{Z`zeM-pvmYF#_+Mk_64&xeB)=UB=ywQPy4z)Tv@95T^L{US9BxBEF< z|8e!B^4v4ZXpOB6(q@ulr{NuPKf1_>Pq+khg<#Zujt$Cr(@g7?1>3nE(b((Yj!|)) z@((NKs6Uwt{KO|QzT%NIEQ^ibE2WTR+nl)4PT(@$Q|sbZ)n-kJEi>QOya-Q|@%L2y zGyEl1#8-9L@ot!-JLgWYM9h3+IZC9VL0E^G0~^el9Xs!*Y4kZ%VgM>l5We#Dfr)uD zvYoUc@3J4+@=z)#f5QXibj^$3m^Tn#=2cq7joq3;*|L7%-Nt%^!nNLrkpA0&3==fw zg)CqT|EH0r-6ZT6aRit3YFrj)1Qt+OPzd6*2x|s5_Tlo=Fi50vd=$OwI}Jyg*J>ev z>7wa+dU7;Y_Zo3YQn?JFjNZkyWwUbONCgqc6o%AD*143@)ug!xGr0;{BBOFBPgh4L z)c#;i^i<-w(K7&Rfn7vP9Y{SPIY#5skvkKHwGsKN?twfGh?hHmSyZ`l>@i$;1rHAJ z_c;Y%KG`B(rDhAGsSo!*Tu>Xxj@)5cXinC|n_~JlneH->90BcWej*8Ji`R;VHZLEf zNcQM3e;JekcUXpnX1osM2slAm*{=q%y{ES6nog69S-m^+cV!2s^X6An2cObIbp z%p6UPp6s#V{`PWBUMmB)Ke8UHJ?gkDsD8bEbFV6Ggxo7j)g%Ug=PhZMVfBcxAMQKu z>D57$txRIwvkBxc@U5NW_h-MW2A6O&bk8m;$?glwXwen>aeXXa+pQ*MR-8 z&Q?F=6-75Zyo(p3#Zv5uuGTS7h=aQhlMD=}N$UA(&~6$xwlIc?heBeE zv9G_sCqa*#-S&0vk4J)Vm~>{^>X;Vnh`HB81tY4_V>nBYQjDgiIv8a^Ke_3ZMAb&8 zYasS`Xlm*ab@6Wj&E+`h;vciv9WF1L@g1dv#q2F=)LTXhKH)oq6%eUc;A^I>JL4$A z47aR*RUd__$-?Rq>y5hKH5uyb;#U)7N|T}X@GBY3&GJ$PNR{StAaXC*IrF7r!l%Ib z!tCY^?tU7w*dG;>2h@yu3uAWJwna?horvER6xTg-4S7FeHlpRwusP?b6M6O={<`=S z4zOfAf4_YdLgJrF*|VB-m$6b|UKdx&Nh!O_KlE`aRZK(<%+HQhDM~m#Ts^p%o4@K& zJP)~3F}j4UcbV2x;NpuhjLdfch*&YBsp-7g`pi3UyN#4g(L~ z&Q=4ET*iyutNzSA&zN^z1nzR13Jr-foWjYtQuTZeG7xA}z-^qYH-2^NZ;Sb<*8wn} zwLq`Yb*i0TOcG#yQ*QBkQMsn2545dn^NpiVUCY?YhqH_^gk7KNY9@j{ep#6Fo~kwM z)u`H3-1jun&4Rl%$o%m2=k=OTAwo*q) z68P_>>qaL|0=Hz^V&+fhc*?!s+S}EV@?A!$uu259{66Lq2 zVJHPoY1{7+Hd`Z(oLXItXUJoInYMt}hjmDLBi=q45oJU;dWElJINHGK&Nqp^@~BM(?DmK;N^gB7Y7KS zFc52hluK?@Z?T-iWfH$$xNc%w0Xk?PhnxgWhU9>4H(B*LEse2p!HjF!f2XJAY)-Zh`CzCk9s@5S2Ye}Dc z?WLEt%>!hME$UBDK<6zI8$$R^0saL^PZL+Hp4Spn?r&qK0RK><`(ZIDI&+n@fR=zd z#0=$_;3lTmjI-X_c(Jim86mb><#dfTh_bls_i2_-Ikm)DWXGQquvd#ly~$`cqK6qe zG~xN{rnM}ZQD9^?@6?Fv;WGnrFfGkbmeH^>;}e?B%Q8X-^YKfJHm{hK$UVhjA z8=`Z)p@q)N!|ABG-TsSF2>> zGgiJ(i@oZ(tsQlaDQqhqtMfl{UI<{r5zChWFCC~&>E5U;0)N8ejs@u$vY*f_DMSaI z;^)6lh~3c*W9Vj#2l>teYwqGvb~4Qi|2y+t(0ca-$FX%=_PgJn+k1#wXHG|^r7uu zhyG@dMIKwtcAw^>BI6o})hs-A#T*kY-@&ropV^;Q{7b641|KzsT~MjZ*{i-9cr2ph zkRlpBVgyc7BbEd>@g)FCFpmL_@cv{Ic=~|!NzPZV6J=KY;Xjkh04z`)*B}7&7#7Z- zt_75Gpl;&rL94%4w)j?odLb&*zxIE}{B5%!vAux?0M#boy1Fh$&F(4$HmJej(}ls^ z*_$INjF9VBGnb5EwJ4P27IZU0?)~?!aGGQ?XuLqA_e)iOF3j z7O?EPJ(f*_`$MsVagg8xHgtc83hY|83#OIqCVqSA_yN65$YC0wQ>#2XnGs4_4p^*b z9Q@KhQe2i?P>o1`U64%4-up-X<8W;0fnac48=0(4DupP@CmvzwVv$~uZFa20y{}Py@kBk2|mJz{i_;3i0vt9al!Q}+;(sT%C}mlFEC__ z8m9S$MXxGp?P9s2d%3~%+;Zc9td6o12j?;QKXQGR&k%m5hdaAad8CN8I4))_EqB7# zBTYY2Sce-wV`s#k{Tsx9)*omkLS>Ju$-?!ra|zSA!6oq~#_&y&5c&^N^EX>hy3rSD z3?#&{>){Fs3rekx6FG6b_lalrx8h?GZA3Bnjwds?z)X*p2~|%~29b%LqFv{R9Hu3y z2!_9rQ(K5e8GZcdD`;a?0H5Gy>(#Oq7TGZTHD-2WsP5-^+UWu#lJkC6Ay~I@P=*t3 zy;N>J=T7V@{2E{Aynp>k<>Kt(vNyOP9PO9HE;KyCb}y-0k2Yxid=oO1yF-RwRZ)O3 z)H|0L{B`k)0U>lyeB~y_awyUcr8#p*@mP1s2EQALjnn>zNhDV!;KuuBbl(>2up#PF zK_UG@mX%v@S69O8$!FugO_2sw#NP>^0`GLiyuCEVN>YRnVn!1k7@-3FmM*?S@^`|r zCxW1?NtHH(a(PFY1*y>DMnPvENM6TNJ*W@hL!+5 zQ>7C@E4>BE{xBjdaSd%oU2IxLP``5Rr3kze`6Mwk+)m4LbV?}=`t{iCPKOi94$2oi zP+1us5x@q$F%R7tEIJZgL3d!5vg|@Ius?bS@wz^=^D61wXVt4us_fP7RW@}-foB91 zwmm^`6GO|AP-%a$r$U?!E#nFfZ#FtV%@SUWr2~4~;C<*T7FvtO1B28Fl^RDEu}%>4 z*pfsZWUpjgQu;J=ABi}x#q}kJxhXNqll}WA*4)chgy9w$p+6J>;bQ*%S}7xaw?;!b zzDqAhd%~#d*a__*Q&;QSlSKustFD7XXxJKre5iu#skQp?89*j!tOb=S!cfNsW;z!n z1gZK5TeF4Nl;$1ed&RGXSE|XQFc`70F}729&7Z+D)P3-b13qni$$UlSlRk-x(kFeq z32I8>567S3ybr0LsimpwMn|mym+YO%xOzX8Hld`8u+~%JXft(*bn=%iw%}>Eg9ic9 zv$Hn~3)$wOZOStP!VNM$BX_WN74a!>8 zpo#pjR=Ib_A(;<`6mC}S{SBLW@*j_UMGN{z&KvfJj~g#b=BhYv<6ziZL~4!=k`2=e zJ$B?-C$^<^Jip2jC`@v)U3AkI@3jFiM=f%=Q=3ZEwah z3A^(oIJLPVC_Rw=?>2tRdKj@CZuDspt8$Rkilf_ea{?g#x}0MLJL_p*9{Y4c$#b6C>#VF6AHnX}@FS?&#=vch{OlvU;vEvr-8_D@s>;mhGjQe^2saU3- z1a*+MTr79M;Zd2CAax{drxDGmAHm!N%ti+=UvHTR@6m7n1l5m!jEc#Ys5B&pPo|FR=FPCYvqk{1Opt=XfuuRT3zQqeHWm9-$Z_`FyHfzK< zZj^i(-L%-uO0{jTOPVWNd8gbxo0dKI_+dxr-pJa1Y?*gsUbpSB0S}C5;R9&|*P&f) z5er5pdS-+*{2oQi`Ty8(YAyv4=K)Hl;Kdr85_SLFBs=tc$rB|}Z)C&A7|iO9H7?Wg}QXFCmpr4V&po>$)=^_zMq7P$R1r|brH7{E4uG|CSL`h2@!dht32i3 zTjx10u~ZFfpc$?6Q=fV^c)#l88aVztF|4Tbnm;Yt_cDm?(B?h)up zYWWd(kq`ea@d|W3GlW>K+T$`T+(W}l?amc4b*#=)<4z||KU;pOs7P~rnijliNhu08 z@Ab`hw_!CxF`=#D+9yGaZM`1det7(>>bnWvFvx^RkiqQ-(@+G>8SGK-Gr(g2R|fSm z1rK^7;8F8S?^W4}EIi>LMAH6e2R~*yeS_|fQxRTM0yOJ`T;ejV(8omrdLcR#BY2YB zY1qsjPv~hq))kSX*TtCHxPc=sQS9Z}ak@Lo%y!IhNC`>4OdG3w-79AaH)4#RZlWEJrwLq`koe zl}o@VOLjJ&waJZ)cG^|Zxq(H&@4c0`7>JfWr_qVa>7($og`i*^1in~+efs7U^rlAW zX9Yjdw~`ie-kkXp!oQGIL3x>{>3~g`v9Z-uR5Pm-de6!hG_v_WJm{Wpj@7P;7skM; z6vh$1TU8;}khHF}OqY24Rj*AwMPRh@X9fP06-ISu7%R3z)PtDv4NT14|`g zKp8)iwi*4nQRk2*$l93l*_M@(vu;$CYU++;YLhr5UZJv8cP0+!t4kl z>xJCcz*BoF5JrL>iYMFiL`!H0CGDz`7=iu8MG3vm%jO;dJzaH?^+&lV zkCJblan8*=o+-{3p8dtf9%UugY+GBgk(P6QFo$q6V5K{kBaPpJ7eKUx+B zkKNNt#K`oR~Xrpq*t&#+8Aw3h-uuCPF}s6p-c{0Va#$S4ALZ6Ktvg6wNPSahrRaKx9= zdsjsL_&*X}TP)a@%~lhwZpXuRruqz{wH~YDwPxW~Wphw+fjphwY(Z8zUd!Xwx!1t+ zdAxzNEz15Qt^7<0#kd)pDfyG*o|;jaRO^Ng>O)+FnzZ1bolth{tVr(m2>Ny8B|PDQ zfDD#UADP=OkvCDJK$+El^tfEwOu$yc!H_SHnHXQ52S8ExNq6aSqGP!VPV{8vje6uL z^Ep_lE}9M5?iEx*6p8_i5=XW^b&Y}+x)Q&;yuUfP`y=*?dQXrmua?X5Q5u`H3&Vl8 z9z7|kYRAvG`&f3v=pOWCScr*M5+n1tOFH3ouP$$%YHb$EiAb7Rm-5wK1x2r>iWE_ilvnDPS&NP{vcH>_osVLe5@% zs$cJ?H5d^Xdz}XV=dOd@#FIke`OjveK69$E-UAJC9G}>slp>L*n7yu<>oIF0Bg8@) znuDgMz4BF0l9HI!naHpieXdG3XqgNIh*HJeb3|Zdh%DVOy`$=BL7_gI%NymuG|m)O z2AHh&dAg(y-~N@m#n$osoU!G);H7(iT%jiGaL{Jb0~s_4r~S|3ff@Xqx_vasC7BQ{ zWjF?L8*Q81^iVHJvT&G9O_$6CvWs=E?@WAAlTR`$M^VaUTKK$LPB5f=^d$`S*kY^Eg{wMHdyXeI}G!^}G6 zj5a7ex|h0d68gj{gs@8m@nwOaF(I4(I2rO3s}}<_;GWWSDGPO&MR!H!(|>xmb3yu| zi{Ndg;8|*Dz}a2zp=R@%JueO7g4RCD8R>);-D96mgiEwc%cTWsYW&INI`xMR6}1?7 z|1OH(XMm1$8FMY#piLGNb=#9=*PV@l*-P7aQL=u~fS7=!>nbITnprXfA}n>NHMf+V zZ79$}K7~{NiSEXvl{Lmb1ap(zquL=xqh#3?14`4+oyqTeC>?NxOX>N@+TH(w6d*-i5&z9$=(ZrJXi_mc`*(|Jn_#k)mQThlB2eh?{7Y66O8q;S%g-~4BnpO#qF+C3Izu4dtN~L)g zP3At9r?1>EhJH)4U5Z2DU+$XcH8xi+;xb>-O)_M%a65gY()MPumA-$JnvH2_irm1v zCou>go2@cqP5W)KrGwXI&DJ*Ef`nvWW92(<*US^Rr^4Z4QN!+1Tt4s-C6~`aSj9S%q(Lt zW3}npoN}H%w#XiKz0u4O6IlIQ1*=q`@n&VKz066HMAkp0WqHcUeU;6(1jxr8`FyHZ zw;QeJj~F{Fy&H=R5y69=yuqBJVEfN;A4n=Cni4ELwT4X^_ypArutXb4+C zz;_L83}dG%2|KH8SH2)J2}AdfoU_2%>@Y6RDO)bk$ew@6sBy zPbTek-8%`kh2KLy?%ns3fJKEHAbNeS{F%Wr`OVEp1~&8kP8~>V{Y8XHQ9Y)dJkRWt zXLWOT9CE{S|YhH(q^0doU1O*Em)`r_>~}In`+oL z8iQ}rReuNS3G4Jl*$5dtfRl60_uO&p?u-C*zDNfq2Vu1B0_X;O`WD-J1t^^D;_Rc- ztKlNX+#-IJo76@Vt8=dsR#Ux)HAdr&TC1@&ViXVbwirNBF45!xtLqS}IJ0%x1-s#R zn-s3_=6H?S$h5o=jU?EK7U_021s2S+d^fhfSKl28thQubvO1M<;410Y55AI?ehlli z2S(-oybW5$bxUyw<_qkAG4YpQ@;i!(dM3HJ>H+M*NZC3JSq3|TFo+{M0aV);nX}`xQG)B=fx?f@=D>Bs^pRz~dUl0^)yEyb& zR|14ZajMDe`k_Fy4c*6?zQ`Up!6IJL5$10XgQbQ=vHCPqu}&=bkvpSsf>{~GSC0U zgBVrbQ30`irZnm6KaLG!En#<`jn+4) z$)rgwp3;*E=(q!oWkMF!ptfL<7|7%d0l@{@dcPFlG7~yIgyfIaxc2NEWNbqz>h_PIIwZ=nPh~hCOozb>B{PMcHGDjRW@+3 z2kz}sNPgBmP`QsimYWi_g5LpnQ*fr9jXLiQVYEjjy7r9_s68XU;G`#_+Rs()v}*)) zAPvAhU_6c_uz~vJ+57T;hpMzVde$eVad$QGFM7@KMKU{3 z8m0dhG4ti%R}wwL+-pU^&KU|FL^}%z=osQ?@{Pw*r@W?&_smW&UgKR`$}BZ_>n>R$ z)K7iWERAjM29+LpYh@5767=06TD|LB&H|6rxUHrYn2&%Vd3F}TB^eT!g((wcFG9KO z860&I_cluP*qY~vsoN;ZV;g=s)RiaJvV1Tz6J7J`AS^#r2qJKm6 zze%0EV|^GYZZ8ItT!&UkVH<)K(%_TqS3;#Cee~F^33kjT*YHJ(w;wyEWvL?P32%3Gz?A z&EQy3(7Z2{av@ELQlN^p(Vg8BO}6%E!#+$i zXS(9smMF27wGHftCc_i&V>yqPdWj1^d;+nK;2%z%eMb|zp?oD_y!ck)LjjzTe2i+F zknps|0}Pqx_Q1lW5wnL6kqo>4o(nMtg2^#t6*x!{>q8OqER`06bTTSgawNPT$z}vy zA91!r{66iTn*%ic_(!GMk9;XV)RElJKHU|~Cp|1eLHSa2CjKd$RyRaOb@M9Y&KPVq566pB-o ziq^*+d<|bf?kfcCM7|)ylr&3fVLgw)vp0XKXY7c(Ub%<0963k z(QO?%6JD}I6gf!{!25y+-=P@nVP(bBx!REJw?m#kwCP*$%waBQl?`%nb%lZQ_Sx?R z9emYAJ6)|J&{}p$s$%fVM<6|nga&D|6}3pK!q^#aO&GqzqBp+(-35%Q#<#erCY-I~ z%zp8t#0B)sjqif3g~HS?!fkTBL6_)n6*3&X9YDs9Li9$nlvL3Ee+I8xRLN;i9lWFt<75uChI(;NoBKFgmGTSl^O~z%VxGB+2AaEed?#bZ8uljMaIJ1J@ z2$_uD5rdN2c3Phqe{+@^xYqy89rWDDnD9xBHBU|j{>&nWd}C941uMo2HS?6%qCw|C zvd#Yk?j)CK?N@wzW(Z8j9mbGx(rDgH`K`ke{4q9!o+X~v&mW5=zolRBC6I~qAiGkb zM{rh<4~8jKs*0ZQ!IBu>$9D&OFC0=0)5m!|61mBg22OWy=WM!G2$HG%6C16~j^0u= zJh5?{4qB)p&aO9T!_Ia2fWdn%8Ddnfrw$lp-eDze?HCz)?3Wd+DKgR-vYqM9(!oc_ zB{r$bOJiS*o&}Kg!9x`l>gUs^ACb&y{}X)oGCco7%n2dP@GEPpsEhzgYz2@Q((&5 z0Uo>*OGh;X2XL~o?sV%mN&+Fcsqt_`$Xh*DeyKZx7!8SB=P6r;ke9KwA)5iqjOOch zbIwQ0lhj9iQwznQ#OZUJkkvT+k98h4Nc7LmRgMkTD}3x`ld*Z4znMsf&9H1K@|DgG ze3dLGA%|35jEcLn@iVJ`YK$vF`bu0NWcqlQ4`i@+9qg$Ez^L+jxG!wWvF@*=Wxk5a zl~e2Enui{?W%;o<_*Z+PD;Z*!~PLeU=D zZJJou3)&&9rmq0ThCTMi2OLc6FpOx=?=Pt+m-G4gtLl8(|? zyic9*qBInwB$B)y0z@0x0=Fw8nV1skiyI*6qb80n(w}oBFGOK|dJ|y?U`Mm)fG9}7 zJWn1fpD)I~3-a5zOT>pcpJx(;btx!nlcaYWh$-m-_MgP&f&U0GdO(u1-5-{p>u3%E zq87?Ze3{U!@BKJQjm|t=9HVuq=i7R zmCDVIJCM#~(AuK<`O2y;{#w0dExhCY=P<54!4e4+6f46fVe?`|7&UXYAv>;rN8BRD zbr`7cFVW!gaQP`Sk!u@UZm;*&)D_pR*R(Gf3yR)ZH@1cV?F>Th7>nft*;_Zv-9gszIQ|S6**A*D9;NloA=iCrzfq^~n0rby)o1nI&Gnby z;p>lE4j!yL)*u0ZnENIN*F zLL^PsV9b%UzC-?K7OIOXA`TkmyBf*~aH|pirSg$F(7P>ptxR0F=f{_T zpLW+i4)1?L{+(@=8^%24e}N|MxVe*hepQvcqjI7?Mc+>p4q`OU1GdwYGCN`BO}0`; z6;6bQL@$LX^{P;OGPn}dZ8zJoe&5P%c5zggB_K?k{N;AH55zwolYLu1- ze+4lH#e00_zYLW{qWN(G?lQ~iZw4SK9Wiw`J#|A-WJnkp+3L!v#MI@(>j|+J!pMRB zj({5(1P>~Kp1iflKv`LmyJnZ}1m4)>)-33Jgl}nSV{U9;#_B-a`Q{Zdu4b&v#fy9Z zOH#H6aoKLWlinKfh0?yV4rk5Y#;S4u)?;Pz3@?IloQ_8j~KI>Z{E%m98m=o@R zUPwXZSwA(^b_dj(Nea)YO_V=868B=t7t{t_EEO5@y}Z0nV`~hBbuMgl6>4Vdk2~%> z(JqP3bjNfwwjnC-6aS}dHHZ4LrqQ2lqb0C!X7Ag-FKfqH>b~&X2dJn(kaxv{gl$Iw zU}Fv0IM@$LMiiRkwG!22^2_M9Q6G%*e_)sCptowrBUrpd8@TATD_)VAY}vJT8U&VQ(vzT^)Y&eQMt@r+0~l58O#<1q)Gtu|&9TaZjDBdK23?gONW+X%j(xWO zoBTZ#fRGQxnlf?L*iyy5YAv@H*G_Ch5bg0+wXg>4Lebe!ADRd9ckK;&CSMrAFtOP8 zNlrW)+gqhOVZ)LZ6P+xwIbd05_%kwCs(L3NzF`0oA6jP*#E+g*+4bch1o2QTe-78) z^%#S7nA!K$hH!IomfL=LM^LNWAcP@O2m<{derHC_KC{e-fD(7A{4;VQ%XZ>7=^S#-7;Lt4-&VkQLic)yHBtuaPa{!}E*ITPgyeO6wFwu?)!)q;8T(t3Wf!c?OqLRDPWJIEO<;w zOs*8(6x=)7m|TH4dU^&pbc4prQi*{r=#qAS1Kuub{LfaBpivOiOTb}tt@xPXcqho^ z)^Wqd7pGXS!{t@H$IO$V#DXY!-EXl?`;8C9r!HReAY;mwyS-ym0C83eluv@SRR6%O%C&^;d?Tm7kkhv@Px%sQb2Hjh9~klxeFph`Zy?MO zZ*lqp&qyZAqgmJUB=+Tl@720Ls-DC05$)!Rl*QcJubu4HiV3IB0vy^ml>e{5Bv{m_ zJURvTY)8?>*^?aHb$4+Q(W&rFrp@h=Q>5VcVZm?MO#u6mK8P!d|A^FY?f`3$RK7!s z&Cr0kMSn8%sy_ZTV=Bp0gwRY@m^Nb(Sd9*?Klb9x!e@u~NLT)r`!nsZ<}dM&=eRT^ z;D2>mT)uKv-Kr7C!)#|oV?%7Ib9O{3{ZD4)8cos8J3%-bi|oaVUQYo| z?9(Q^wpdOMC=Is;UYt9hT!4S?F!@t$vr#Lsu1%Usj|^qTl3!*$MOc8}WUdKLpy;Xo z+$EHrf{v1t(2Evt@P6L5zUgr&R<|3d5=-==9q!XRG`mBUO#hLpgw(%K50mcPBBt5E zF{uIt6j@voP7}N;tSqW+K>k*jtuGo$^BjVx2T^k~0GN2>UnkkXF>FeQN4zU8YSZHx z?s->`%si$HN4ShPFQ@sNj>_O^<%Nx3I<$teYH0bv9kJ?`tj6doYK?fD*%Vi{-;~pf z6)>TJxNnn>b{|l;4*K)#>V9CU*b&$&TlKz(mx8gHk`sKL)g5#YzdW2g#f)VIb|d2T zO1!?i@}c09`=AXc*%~6pp3$Z|+A6Wcr`@=poT_z5Lf4ysSZ}C3B&Id z#O%?aD625qyfLAVWe`bt4H{<-%m<~nGZ^>o)+0*wTLHjM!j(+hE$l1@Il5EAOMf7R4PYAX%~*0I`I%YXFgue7upzGrtDYD4?nzn%3Qfu!#X68K|Saan>=_piN^_= z6!7|gK&&uId~B&yG{TgHe(6Zx`AveivJN{kuUs}r$-G=ZZ+1Z1ndf?Fu%^&T1J=vu z>1n!CB3U%`3-%B}hqyP})XG@7G#U3j5u{9-oQKbO!}!n3K=b?fVP7Fu06##$zaI3s zh)BUbW=#S2tCv0hwQQHi#t&eV@jA|#{8`(y(8c)4ZVSD<4n1Jjq_RBvKEJ@}uHU2n z<)c`GA%xZb9(k~R!`n%1T%>g>c`QXAh$wgeiW|dT%7RWP*<4G*lHz=7=t<61@YQNr z0fiw`rbK6Ed{*w{q=ayu0#!|mO-$o3tY);|itc#q3daj{OpxdgTT$Q#hSIwdHICWY z2+BERt=dV?SHg6tZwCfGJN5yBcJhEqdDU*<$#6b9E2aQHK)}CzzFm&uDTGa|%I3Hy zPoMV9;kn7*(4Dxj5c)QQ7uE_R7$x@X>mai9ZM|L>l5Qoim@-Ry5b9?M1?be2lWySZ z$W9CB1o{$1z>ypzi%}pbtDsv-(B+mj-95L4Z>%}gPr%kbW!uUrA@gI9g%;c3I+IHP z(QA>#VsQ5e5S=g7`Q;^ z5z%Qi^DX}`9O*i&SzjhOT=WmZ<FY>($dY{6eFk+^;OWvE z0CiK}>ZJ>dw$A1Z$R=Ip{9(Oisw)_5y}WN}?{Ni)e7~MaSjWmM=kmHYwd`{dvn&_6 zxx@aAy_r8^B$a|LsU#@F0j>y6U3i`#NGGue0odDax@bLGO{)*aHyiWUfACI_`Fzap zaw1Mib0_IBqU|>A4*Yo1Ln|iJmh@BWu7+V03)lI}rB~2H=;*Ivq02O=&QvtTEQClt zzapV^kG1l|S5Q?G`qZL9z3E<qu zQYhSSb!;{}O{Q+qd!l2P_Y@j23QthTX+Wjs7)C5md_*GnWgrkPvAsjq0;^fu<#-hvU{eDLv`*23TCx$k;Z)2-bLiKql95$3C!XhipsMUgjb;@*(U z)ESH&8@YRkFKZn4@oiri}bR+HQarrt?qW$M5m97k~Vc|jg2FinF0K){ka}B zYOldw)=F6UMFVV?YQV#$TjPWQ#^hMOVl>BNe~iQ|ELCXYAdp-4B22Tw%cTvQQj)Bq zU*G6oV&LV>>b?mYBv1M{RQb8-+xsRS$Ag&@ zgw;X_dkwGgJGgDDx;z)QNQbgVa%9@!(sM79muYtq9<_8kdm6b$IngV43f#5j_rzzH zj_ZNPwH@1({Ny0|*m5e3F40in;BtHTEr5qJr7R)T9tG@Ds9C=zPeNjt&LrG+oc$18 zVwiBolGz)yIS99BsaJe=pxV=cvqdL9-_`hBxcyHt^2L7T$4j)bX&dFbROBdaLCy49 z_17;dT>XDi;+gtD%HLCBD@Umu+eoXO6P1TFg;L?sThvL z(TXe5u*(uPXC@Ae{fvUsWQ;?~w4r$XsGlW{*z$0l%BNO*B%-{p6aeUlFDUM;Jy9U` zlV4(d{5qWRdgw*7_L_Ie99dQy*czs6Y_jQMZ`8S)<20j4l@HJ#4Z93nz%y8sAkOI; zbt|OLDa(APlHq0}>?g@0y#G)oWeV1vWTt=}tYHqd@BE2qT4=OHk53WZJ*iCu!2>V` zLRsVP4cTkQrVw`h@`n$({9yC8je;7aQisHN>hZRNDoyjS50S*LdBxcZ0%zSer39Lpw<=>5 zOmRq;imBi{G-hWb=@{hZoPyC*E~qcYLVHm(SA=K~PyGD(qJdw)2B>%#+SrG!EO-*| z3VOr#k-Cn>uLo4WeOi8@P3NU?hZs<|2q3i5SyI+%vV!=k!bi&xwuF9XkXyfxFREBs z1cdE%D?$OG{jT`M6#OAwhjE1VBcD)sPs*I6 z&dr?KWj^aSLExp(mhY+8RSc$As&jDbL2qMH|LS>j6^!XlLY_{#j|fj+}fwr zrIe=5qfQGr11Cn--iN?0r)R$E=#pe$;H=8G}8?32ag|cjUQL zhzvq7mC`3~LQMtJUzbKAqU!fTF5HaP3CH@d$j%{0RWPhZ>{7!hWIkl7oa)buScTXq zT5sT0IDSwZ_45T=_2eyUIY0aYp^k5=sThdGZ&&PI@Dgz~I^Gh-F_^v!LMihrj6B;I zD2pt9Pg;6!E3O)LJGeVD(wNvUAs*ixz6IH~b@j@hGI zyydEXd|bw5+~OD;$h0EKcykS3mtnbYiE>j!pXwIlCvyvyJfJ0j)Y`*w+(g9uzk92Q z)%V6uzW^Qpu~TDxiH+b9ARW^#HZ7!vp`Ogytldw1i+1M%v8FQ92i~hrX0?qpnj~y5 zd)#ww_GNjs|2DUAtyrx`e$-MVuDSd|E_{_Q1RpbqZ8)=amU{-uf~0@Ora=d(tUsR-4A{f2iubh zYI>1(51_QyxWiK!X=mz?nzr9Kx zKB6SqbhWNZjZIf7&S1?gA#cNn|AfO~>gbJGzyCe71?symxM5P8F2R(B9a z7!)hxQD^*LXCAV-Pn-22J>B?Vi>Ni;gesj9T?LBkcMjHe0>7fclbTBLcAeMonR2fb#b6p5FPe&E9NsDoR(Q0=@qdjblL2&IfMyOW;w8&N^9!i zM9{ROXGHajrT8XBcI9#H4j23c92eQGQ;mN(cnQ6`&5#N$r_C@qotHHrBbiCaFbbUR zOwc#$(Y#t&Z#s)Vy75KYOYbQ!?z= z_Vs~m4zBz87z0efW#@WcsY(@3QS7q_)?T>`d1PMSqG>0zkP7;2M0P^}_~&V%xLsrK za+Hd;jNq?!;%C7jVIL+-l()n|IXG`Qe0krzYAC8;mIci*6$O+FEqtqF#F4dz_GBcf zAYX{r(el8jPwl(+9S!Pba+)dKx6gO11rANuX9n@%uUkQ!+{C3skBZ6Awp=<)FhY(h)2Vx8YtMZo%NGW6!eZ9MMu1cF@4D2b^Msdg2pZudDsU)xD! z$E>2VtXi49AHH%P_6wX1R-=r)7Lp6|h{ObES8nXtixOHaNi})A>C_p=X@Z_F*4_oA zM{Ln1+QXZ=MymzeY!@sq+~Cr;%LQ)cH@g5#K%^QzkRynf0xmR8mkH}(l1yPp!Tz081 zfHNk%M_G3Kq81TG-}iylZ2aqzv`prxAax@P?h|4-!=9e0nA`iBJJ&l~hP%&NxuAVRLljPj%H1hT3-GYJtwX9~?#7NS!YzaH ziV}RORC?lFQAj9&6w{ssnw9GWWH=jB4Xwef*JLCL-BlpnyVk+Clzm|)i=SUL>gkmQ z5RrZZgWbatXC}li8c+xF6vxhyMwz)*Q-ffrn%lQ;3+E6dG9(bC1$^U z84?HFYG^FMsTsK!B2MUJs899>QPdJSVhXU zP`p#plXfH>-V}1LF!{T7!FPK`VI9}43$_pfNX6sHlfU|YXJ+Pnv?;@-Q~bz#6#AJ{5BRH2 zX2jv((+8{CI5)h52Vvb(A&Scn;bmfS*!~DWPr|hoxN#j$qKtv#&$NrQ@bf_Z@=yX&|UtfsxgI)h(M*w`7I&Gw4=0e42vZX zT;Q4dcid<4VxWpro3XDJV1Zmpz`msgp`fv?s^-!#U;F=*LhAb{~z5_fyPsQgR86UWOv_isSM z3H5ru#NE-{;`m%x_w!-IqOLvzf<6PkSxN`hzkHUE{!pG=}G2c`jB+C@%}V@fn(xa7<# z3MKLmG`s!eB)ds}9TI_MybL!5e|s3%wUhq4-(2!yQ1QRT$fget?Y++(pJiOHy9Q%j z+_emzz!O5%MmKiYP#M!@iTa#Fj_!4XqV2LMF#OYAL~bS~^K$_$6+d;8W&tRxrH%5} zx@2#)ufG!_)g>43rSV~5uc)N93$19I@d+gzyxeeR2EV%JRAG0Zc9QDdn?$1%OCt8H z_|4PSnxlWJj&{7NlfTnFJ>>&Sj`q=T8Zz5w;Ea#4$tK>ANRmZuOcvU3orGUW>{2?~ z$3{fNQ;A1aUrTZh^_d3C<&RHc>E~Pf_j)GQ;iqQOb8ka(-aAjETojt96M-I{@c3b-6hM+R1T|?I!~2R(5IZ%we(yS#OY-8Cow%S- zjd`yttOMGT`PVtT1x8kYP~Bl)k1=I36m8b|3LWwJnkwSSz^V}eA{vyeZSTzS`CC1w zux{w}3tFnr)y^Fg>>&@(8~nVyR)|@7lT3J$_sN;RCtAgpi67i&Fs@1YZHwrDSeXnKDJ9E<$c&@lR_dAg8UPov*k5{`aeg z1+e`yT65nwtnDf*C{gcI6H9yubo-m>r+w|n$QWy9dy&Ds|KkxwdZ#(m;(s*Y@y)*L zz0P1#wtr3;pSea#;rddegDrJ)G}PfQ??e{XKOwyoKgr2@R@Fr|*YA2G^|J1i)x?_R z8+OIjF90mDmwtIf&OjX&CAjVd++VY?k42SlnOW*YaYe*h>9ukJd)_q5SzdGy@DI2I z^hUQh?jgPX0;FpJy&v22zj;g2v+yj{$Jt>2+bOM91hC~G*sDmee~}hDg2rfKv)1TB z7AE;_R(w7GLY5c`bpcHOcj;%SfVE&s(t|R$h(2ex7V)kDE#3)tpy0d);7IckSZWAaVI^cTMN>p7tTw)QO{cdK=H(`n#6Idw1L=R!r|~#LPCQ z3hY{`@~B`44lPbX$X|o(T4;uh$!=%y!ldeb?6E z2g69Z{#F%GbM`Pr-c0c?Z2E_ zTx^tC&R&?#iTNH{z}%|94Rf|}u05~M%A&~Ht;0I?W^#jLhQy6y9LTVa2}QPZuU8Qe zIi%EAP(!=^@##JN?N)2P)TtD&ixu;u#gwP~NWC`&na6Kk zcszf~$T7PyM%4@0^mFD}LNgZ?$1n(OPEJ-?Y}P^G(Ml#0MQ=fuB7cz7yT%M-_<^qC zH`)W-UAimKU=^Bz{|;(1#uvl~UMVhR&vKMv)>V}#jS}^LOOyaDT~(l^*)LTrHkiq6 ztUcrb?>uPlwo8nmlZ)b}GT6pMCtsfwio6aql!@%j=;1Yk9@C%_dK&~xk(w*oYm+T7 zfJWpE*Km8ReqpJ8gLV5bzQSI7D>&K21~LE5C0k!Yt;%RT(#6{of^^0UctXI_%meKkvj^L z+Q$sN_TdBT>Xt^#aGTG~@hMNjPU<1*$0L=eW64hBONefy-ZZo0=ex$<3{!0R;6;ES zXTTm92H)TF^h!)T=s#G1NQdAze9|%?`zn<^ntZYH?Q#3r3gB%zCAZG$QHnLyK6fub zl-#wTxiPyJxdxkLzOclj^F58afeU`uU{7dBH#qg$B#F5m7`RekBVA=7f%o9EZ6p>Y z8N}3VTUBdvVh1OK&-^kCNsT|H{;EorDm8DgydJUC@=<=(bmsU6((bWt0#d@8r`W=J z$l4%MJcVhO?5KC-M?xL!5YqjU=w{qirb;o`3MJ=-z<7N)4DcFvT0OLDQ5UAPU)Mkt zzjvzGD`4BQ1HNS|hV2|@@wCV{GOY2NASQr=r{9ER82*qbGL`A&EiR;NYk4U(Z?k0O zjsd1Jvox!la1;1M_~D!ICdz)sz+Oligc@{cOEk5%$x8|h@rHyLx=g`ZRfhr3EDU90 z(56koU6fDlHJ07KwejG!jeoJ?fwMhovV9941iixuI}1I$mLr`hDRKl#R$R8H@&0584zlPT2IBD<>O zB3z8hrthNsXM5Os>USgr{-Dh%H#rYWsV9_g zE*-lomI$zNbJF+7m4Dw2CXYpNqHrWgN9oGM$<;nXJfnrG#E904y<- zMFuf(KFMRb7|ARg=S{cTx>1k$D9pR9;L7b@V(xL0XJ*!G1wq^b;|oR0%ACf-l#*PF z6v;NH{O31*;v!upqVsDu*-)^is%y-fQ=Z~72J@VXlxHv)T$qf5*&Xv5ao~msIf4li zZv_-xN=`jYIck1tzWip=O7x`xg`*w80BtzD`e<*LFj4;LWlw*U&&hM|in2l0OTI5W zEAYTe{Yi7z1Cvs~DsmgnM;dSug2PCx`FA%qaH$<9G}cwgj{vt~?sCnB(&7KH2GTFy zv|-2y{j4UeE}Li8Lj3G@cBZ(KS#<-C{$1-s9^I}h_7T`38_m1mlZTK165tl6VJfWoM%PnItDi3iXdDZ^`SnDf#V2 zg46)2YXSCk@4!+6u+j3m7v=*@@O`p5?~QVRss(P_kjN_|WhBab!`u{`kg94hKEALA zY|LKZyRWz7e<*w7or}GBC@51s2n>pkv{(dUY#QDt>!o59d*KI27hRJcSR{~K^*c$3 zpPQ9SeE59eFNufBsoC>Ff3{Fe0KzR6?Ebjk$1Hh#F$gp2Lrw>58v{$BX4I}xhlPu_ zp$-0=$HnKj_@S=g(eq7%TCwKZ@oMcXnYHG4ZJc~kptq3A;0HYps5NIw3rqt9=0f(~ z%&Io9j6f>)z!~`HPOz;8Kwp2}nNATbl>W1Lu=)h&Fb(0}dLyQwe&)mUfhl%?_pcdI z7;V-$x0ZsWQ+mS1?k&SJm~-)}&ogSL7Mg&)H7r1OpN?rf$%TS84?fV2-=(Yv)8W1& zZ7>@|rdvZrr_lT=5W6vkM9FF89r1>6;(nDIUA-y79fus0mj0bsLIBl-^fr7!2%~e#J_0RyzRe-9lhvF& zfdjq6Dm@3Fn#suxg8t>y5!E~s7}tApF|7!v{R(t1J+pc8x9Q0bx(pT&Rhnn@^?TFA zv2C3Y)=&5A#yC56x2hAM_A#`+U9I%`MDQF%txf}osMA9wx>wpiKc!C9TY^9x0&sCb z^(>$WvZU6WAb80PEq|B27Np5;xW9jykxkYT>jN>+qF(p2wjU|TF<7=fSAf^`*Ojyn zL3oH=kaT2r0N!9{S}jS7w~&!P-1?)=8P)&lll69UfOFUOi3Kt|<8_9MCxj(hFWZIR zZ~`b1(v<${Iu4=SJ+8y0&8K3$lRm3;L+SiB~=2hG-MB05hi(Eh#U>kEgp7K83ahk?U^}*Utb%%%#d<^=}fmz0# zUUJo@0}oCEkk^g}Uy$k2B{*Cyx3hdj9Fzr8ax_rmxuMfET39Jt$Tu_FNV8&72w z6>1?5$&5f#D6hw=p)7`i{leYt{0_f>4eWjs47wwRm+o1ma$ehzYKZ>!Z~bLmPFi|8 zp6{?|+RzrTjKn$ zDEtuT?6-D6fT*U_F@>^;gn{BaK0S(xa7=X6s02tT$61P4z%)9lIy?;^?h<# zBU9{cw0{JLzx0|9(2oqPKTb?hw<7_Ge~JyF??8xn;AfLGMSXi4n3(Y6vM?PRaI^ene3UQ$3Q99f+&|Ff_k^ zw2GxORx|aqLS4pJC!DEj23HI)9k6WcMXAhg;L3ns)aY~fx<=j!iO!IjLAHO8q|5rqRW5Nm8lgsI&IV%A0;iRwrsMrHw5#r> zVmQ{jHlwGI`nA0=d@-^1CnKz4TJ+(&=aXgbU$Lq`$qW^;NJ>ZENQ!fkKA3!ZvfatL z_*6ZtfX~qB(P*&<9*y|snTm@T?K23+CRZX;E6ONJ+xKz5qjdG#x(@uPTh_RztNNvX zy6O60O>5BOoy91k!BN-#5q_wPsIRaF_)4e!cDQA|*Npo5>oD8Z*M zthL#pw0$BWvuAU$@LcPT><3*CInn$P{h+3uS+rHxykP21*V<%eggDmkv!MjiytPr# zG(P&#R)+UPtL5S=yWriGYyqikvE+eU;H3cS8(cJhZV^+&CLyUqNeTPW;y>hAMG8@O z*BfWsOtQ@v-Ghw7ubH40es@sqZW z-9#YIsb|TrxS+-5+oPWSU)~mDRxMZbcN-j)nuP$k!J}%MKkc*u$Unu&aq_9<%j!>7 zFf;l9NuParrgmj%q+m`?B1(Dnx^H=MJD~PH4&K;}W{s*(#8{fNGZUhN$t1tQv0Um^ zGxmglto%@P4iMXNu1y*b8dI6j5uyV?LPL2QZl}3G`vUqQU?JK@N(L@$OJ*w=#;og5 zVY>j`Vn#xX?p3WHB6Rl%6KE=&_w?0z^A1MB%748unX}(W9KXVEu}7Sy4XPy*&iq+i z7Y%KA8fl=pWDQ7FPz6sz4?bt0xPR$LWVoGN3-5%vMlM;H?Vl`X&)?=6iQ`rSNsJUu z@$%-qRAy|xmfqkfiw z{jme6WlEc=;W$h){;b%(^-?l9>G05l>_9AK>gPd;`E(a3O=2adOr57O-N{p}G-QC1 zcZ~L+m{Q(l3$QB!V0ka3emHGa6w$-PqxnSTkz3|Yw%@vc4#l>C>3_UK5{en(T|h4Y zrzkSk5DnrpzKg60%OpwCsRx9&O<;QNaHahhr(DMvL<+y#7%6`^=S*gSOl+M69t>8- z&Z3dae-FJCHJ}q|ftMMP`pTxpwKzGAM-GY4ukx@V<7VjEyFax|IEM$!HDv7GxKy-) zxySbTDvpT->O(_fDki#x$?gasOX&JauX&KeMpy*39ArI`Jr#y)0YMt$XaIDh{D|Ob z>AA2E+*^kn*9bFTicby{2UsoHSfD_PxKQs*FO00kSCJRMAkQ^$oN&iR2cww4e2vyV z+5^d=j4>>hI>~_o+iq*H7X~=Voh0t29*1ezv(Eu5lVwd@u9ne?B?}MxzBuwegSXXL zu?!R?(G{-L`eZXgQF$v(GpyLc+b?o1y_l9gY6Q_o3>r>tp!L2@;NU_XZy6HD2$fh z@Jj%!x}Hz*|j!vaPz%Q0ff z%th`ExhZF#F0I1*F@hg<&cMQ&w7cjqlyDS;FML~eNi5|H+|O>vUL5r5l5TD6jEwJ^ zQ?vgisr95Ir>2X~a)Mm$sMbh!I!CO0T={OEp`FAJHyTxV<3HJq-emPxv;x|v;yCGS z0Ar^#bK^gGwR*yWYreitDYrCVSQz&Nl2mYSqS%&Rb4esH9kS03P6iD33veU2OxR^R z>-v%`9IZW>v#T6lzS&>~zf6*S+gz97& ze=u{zv1l4xsJFZ1VB= z7tY2y{xV+qTPqb3Mqc2q%~SC@q3belO?I|vGceeb7x$maAi^9rVrr+aItk|=yV{qF z+@ZZLoI?W&XPjd#e${v}bz<2ea=~56S>y^>J*a2p#pIH<1cgZ2>x!r80et6Rbly3tP)p-mE4Rt?qUYcQt_Y*fl$h!FYw0d4t$xV7H z&3w71q;}!~2>V|&2f_duxc1=kEYv$5A}|*d1!OoS0Z9?9-3~Mk(n8H54GcvN1;z{f zgyu#1JMc2G3gbi;nr;Guq8%9$jgJ*V7{~?iqT^;6MdM6*X6>#q6=ust6OKJzW$RV~ zRjW;62(xA>(f}Iu0ARDueh>|$Oc#2ZSxzN~fP5%ppo9nkC$_ET*Rrna48hrKMj}rq z7kGtT&2ks|NLkln81%p7GS#i6`uIPXGzuVnCbNqK&@j` zp_^9Txre3*0Dgfz)p_22wY(1VDmgvakJmBI+ul|QFc!?DCABi5tGl@?16qMQrssdb z%v@pafA!-D3LN(=+^>3jNu}B6X%|zzl>SCulXuRv*tXI&Zb;MB#Zdu7Pxmku#(~8= zv`gb}pI>jO18fCIB%#j4s-e$8^Fz#Am#6XrS3$78(y)&NQtf8|l%@T5iy;Mxaj2N! zxbsu*1_=Oal82UiuddRg4`&rKRZ+9)23!HV@2>APfiXe8RT6`{z82tYSv+0AF+hQ{ zMFKd!XEFc2VzP28oX0m?fkG%%F~FD@9!o=N`mf6|PxL}o9R}lK$$Hm5QkTADJHvMt z0C3<@JWi=tJ4e{3)TNbXo<(O-maqqlN+027Wv2B+%sQ3KA7wG$HX|#*#T_@}N#@z= zGb7mML zfc1>G1A-$}#Kceoj*qBOl_~>t8;R78tzw5}pf;npYSCQr}aMj2D8yGO=BS^Eo!Z;Ul8g zVFT`Ta}S@A-;k5gYHxGnlwmuUsAmb*8x$Xw4YLV$gF+1K{rVU+9~yCWro# zzqB&7M_Dh!l_n9Uhnts+)=pOV?OC&C{}F9Aj|cQs{XHbpc^&6BjD>H{^Hues@C)DdF4UR#|6(FbXSAL)ED{9py5`0TFN6PDTeXpKDy}bP@a%T%nUj z_%cbXMkfoMV?fgm6$*eOWP-wFxn>xE>AD5js)UNzZ!ymSM~p`OJ)5`JUt+$=R_pEtNyQL5UMwDQ7H@1tn|hFV&` zvQZ4OZbJ=Oeb#sqD4W4`7{*7KFj|ob!2JNx5-%!0v)j zK9RD}M6(^_L}5(a^uOyDJR+c+{nUI$>muIF^9#D|y?r+67uE%*;;~k_px7V7P_E3& zwR>zcDT*WD%P!McFBG`1@!gZLCW$b3;QSucF1~cwUE9R~U{GR7?SEevwUs9gEA^&= zkCBWEKV|_7P9BAS^Rg%K-~Nif`(;P9I$;)i)5`s@NhOCc65R)wF@^Nb79LHL1q3O= z{i#c+KA1;`4M|YgdUC711z2!>p5%u>9ZWsmU=dy2r%u%?4oP&?19dBl#&?Ctyq$y{ zfqt8l0lKzAjYamCqMYh{7to(9@o#y7cHZ8KrzFs?lo{YTHYCc0b!4I2uPf&+o9+({ zpA&MC+VVvtH(Z%XUXQuscp7tme24W*U}3K&tHs~R);KFmfD03W;uR{)>C>Qg;i#|n$!%HOr2Mvc$OC3RYZPi_3BW(F|Z~j zjl!OT6572CWq_Q~5{f@nHPNeFCLi2`<`qcbE&&9@p34F9R(v-bfouOFwAZ4#rXv2Y zyIOtFVhr&w_;JSM(T8pb*vGN@W8ds&PiF?)=7G>-#>BON89>JeLM4BLYW)I+CO7^Z zZhrH#z9GdTpQdJ$YGeyJR($;=6by5Hy73%uriC%Hahb*pRX}Vt2W|sNp<)HtD@#=c zWK1WXku`G9{hG;|)^JWiAyw~hb<2u2QOvFWpVv7M#0AX8jbeBiiTQikxl&=8cRshe z8o`&j?n0Ss=p{$cE1WTZ2>ZQ*fAI;mVBgJmiug&VdJCO8K!maJ6ZY|c91?AGx@SOZ z7pu^+5=AST;R$qkXnIAMLC)UPDy3^3Gvtp!Cdu&9K*QDE1$`4IwIdKt7K75?A_a{j zgINkkv8|&-ncX<)R7u0NwPjl{eL0AlC2RqoRBAOzx3{eh<6PKawoLa^fcq1iQ`ioF!~MpeD&HIM& zI^{5Mn=dtJ0DEI@)TFGJyNZ{R7Ys8M7(YJ7j9GCQLDVrN4jPq72BuT>8eZiKLkO=+B~m^cxQf<>oE^|mapG3 zXI{CW?UM-Q?x@lZ#}^iafys7rL`f7l#WS}VuGyAhC8-%>|G$>e*?NH}54VW0sw`Gc zlCzA;Bh}gQT2EGOor*$;j^JdIPF`#C=q`urDK~ucM3yXith+#Pwf0g-k$!eMkAnKl zaMtTG8bcASM$ytTAm92m`~{HFk~7{Td9t2D#W80~4CafM{Lu$>rTWK*I`-f42Wm|D zCg?;@mUJ3|50D-X9P3?{02`~bQ92`RZvIJM;mC(q#|&P56V!A3@s+#X(_pRH!RPt- z<03O`?v)FnbtIyv>@g{;$GlB;2$rt2SFS%RUPu+Uy?}01F2U5ErD+ZIX~bKy2EQVA znhl?Z*@1zb&o0#&q|-a_FAW=o93C2E0=iJ>FT}hu+14Zq!)oQns~TF*#uw>6fWM4W zy~afn48z_CoJ*o|oFLn}l7y+$d($R~_@>@%6QP;4 zIOsK#!GSZw)ew!=vK>Zh4p)dEhqhoBQ#+5b2>EziN<@n%X_)aj*<#o}IaLaO_x0h^ zVN`N6cyr5|EJqpjxohgu+7ZWONcgi6pcPv>{}vPeqZjuf@bXirzr)k3*VcK^?&jda z=S6u9VGs5wTq;s;;&L$hsp#LJF{DCRDwTSZuqnX(B)rr(2Jo@fg<2%M$0a3|6{Hv~ zJAnEAX8t;E9b3>vHobq3#IHM5-}FD^oieynNyftt_KsPezT~#GVt4e=mD!>PFF1KE zoo;9CL`w(8U)Yjv!B{oaK!5(`r%WYw6N^S}aqrpT6O@6(I0_feQx|Yci0Twdy?-7U z$MUg4pqFso%wDaU$d%eI;v^>?iL5brf}*iB;-hxX5HIvPF2ngrhBQrij3|c`=W3dmvA$XQbLl-RHtvN?_h1nB2EQ~`aOq#(dW6Q# zIi&EXQ8LJIIRKsTx68hcZws!zegIwVaZ^$vNSPY=O~!bvCdl$-TDQMAn4c8Dmih$n zeS^og{H;j_eh$WYNV^NzBLh+?La&K;6*x9zmf^0Gwx_&NN~FR?0v6&kmEtmH?W=8S zRbBLn{`sEHlct%&SxI^lodpAr9cpHq5D}F6KKT0UB#CIe1kx!Y9M*sp*S@mlt?&FE z0N5<^eF61`Noe7$fzI(l!c*H)XB3b&F*DtXQ;;@ykOY4nL8UfUespP!u}`@KCCAET z0)-)j_kX6n`F{uSYul?^nP0IS-_7%$Js^bg}}pv38#tu;`$lP_UiK4H?gE=Ay3E#k+xKsy=Jc@5Ax)do%eS zO0gBUAUySu@(3+yWa>edTMxa}f8@4jk?|6I>I^oiEezMMwymYnCjx=in%rV%b6Ufw zbx>Zww1x)RBH>OFEW^B3eS)-cIMdG1B|r&Iz{PI#yr&*<5%@SRxPv3`bB+z!=>F!< zTNkmZdPjU8EO=t|-Rd^57k5C>YH@7tneMvlqosLYQSkfz!@-sE6~uvBpd%bubpT7P zIWeyA>S3=s0j4@Eot$Zuhx13#E<5njy|K`dFdh8C0m>SCYAf8#nn|oX-{4@)Dw7Rw zuyug=ZvIdYWxrOd71d)Ph^9~dj6Z_EII>we?B?E6;J6}r7HgS7q^r+yj=DW}c@N&< zSY4;dg3U&W-4y@dkfyVAkTym-q%WvE3>qSdJI5C|XGjVhIMZRmdc5;`^wWd4^r0-E z%hjH{f)D5#Ey@;0wM;5f*%$;kz1TG?Jr$;+ZNI4~I2#@Z5~itIj{5UVghMB3Uaa|7 z3;f27Pw43)F8)n2`rX$+M(RrfAR3gn5uVV_Ti{}j^2We2FDlL9)s3yPS^%SpXE`vS zKxorPMvMyucrt34ZsEeXuWH`{RPB}95`03ZMSO25Nr1reV{wb-R^un z^y-oJ;_72=!peDd37}dO$Nu`u*dnq{=vacso=1Yy)0}`LMo`Vx;m_Yu)_pLt7=)wa@f`|7hlboZ9n=D!h6uzl;k+zzUBw| zYdGz^7pp9cdu}*#lMiHzc@vzd7+JILck71qSl@`sd z_!E2(53-8BI{XsVfca4N6SX-`T9?!B5QG;02(I9S6y5JBz$@xXF2e*y=5$m%Lp>AX zYdxaS6c=95lrrhTuOIjw7#pKUs#Zu(*?SH-(XXU;xIP!$liy0g$5CgeK!%l0|BQxZ zKuWck{oApTIqEOX%@uaq*98+~aI82QKo#pXb7@f~my;n12u@>vhIm3G*&Pln{Pt2QGKG_^Fj zk+G8Ol#Swh%qdfEvH?oACkCK+v^9d}eKD6BzbluOd06pgw#*^@A6;55?-1p00`#X_ zIR8nv%zDs+8cNqY_ZW1~E2Q@p!9W-Fa+tW;PA|!O6n`NvAKs0V)JpdRWfU7ltqyx^2Kt3iFj{+045-dHGg_7yPIA_AP|-@i zX6$hSC-Z<%rIO7K@qxa*cavbcd^e&L{7(u(FN9&_8*RM-_S&Eh7v62O<4IxQfh;W1 zf!LH~vAl6`2d4bQ^o~3C+TCJA0K&LC;Tscx^7HZ-M*IZg6uQj&cZ*8A=!%~ zR}NmpbV?lz_})a%B8%FdKGiDI8YOl{FAhs437zf&fm31L@r?a`EPs zxOEUPtVsZ>l1pUrmp`09A$LE}%y;T}%AXiQ! zTwiv({-C(;6Zr_mc*4~f{;`!UM@dv8Yqgw0;83>E67(m0!(hyepMEu8#txk#H;glvr?m{tJ)iq~dQj!* zet~ilMG22Pp-GvgsX-j&{K<*BV{c$xNz~M(3`o5n>6>Pc|ae;?DgbN$qFwc4ME3gs$TV z{pL-%P-9lZJjnAd05w3$zl%Y%by1pTkuJ=suiDY~D%(HEkn4D?;2}y9_jJ)T4<9$# z09f`{R&TkKN*kYbmHxf@@TRUWv3K}88EMnIS}scM$s{t9>HgtUiX9SnhrAK!p_O9s zVvN1DEwgcY!5c8^zGIS%AO;T+c>YGs`PB@u)H_lYV|(BDBYATvYJ7P+} zJMPT}Br;V1H9*S08>e6rWSVoxk&F7s6F`ENrIG@G=caPj<_#0)Uz&CtmiPu3Yv^?_ z2Zb^l3E&w@L&nCUqf zise9-`o=ptE>J8)%ypm4Z3gs~M5%6o11c9hCkWATqh*-ezXeAtN&i60=xk6&Qr9Y- zFsQN8eoR1yk9(VALcP{!WKMvDp+~E_Ena@Kmgzw3vX`mXOux>kD1yIB;MCed?2m+t ziQ(82X`l&QvGH)te%fInNgz&!2*Btg31=@oojdPQ_pq z=#6{_4>-XI>n%|F!}l92)cxKzt-aJjpP}R|b^jae;S2mz!T>092fXRh&OTza=ImVV zo%jErqD%PZMCdDGk)fs63uR{4sFe2Xb6E;QS`2q3SdJZ3uBYiLmM@S z?>j89*}D7hgX?|xPJsfi`0T#u=0|68o{cNc=DV%p>d?S5@@*b|h2x3@u}@3;jr|DX zNbIpvW+g1X$)7(gB)!bs66)2|_J!ziE~LT;>eG%?}C6syCjo% z#?cSDjIn2!^9~ivCkdRio~*?#Z!uPJ`KUP?MDB3W62#uhfCO5T9q`O0(VofiW>b$5 ztsRf)t6En01gAYX!#fZ2eR;^&HM9xLbuHixh@gDIHRl-)mFrc}tGvFc$E5|4d1c|l z-Ki^nd1vtd`>(s?y1rY{(@T3I1B?H37%vCd-gc)5Zw0%1C(YPA+UrlO+Nc6`Z-e|| zj9Co%b6CNrW%A4#4p~@Cw~h~I=?0JYe1~C46)kahRtg*MEZWNC@I09xSU}ouq>~qM z4p|KaSXX!D(Dby`9~OY)I%ZI*vjQoHsBK?&x ze32?0Rh)b1DEc|5*yVJWyj1RLJ=eRI*|&GRNOfv+j^1iPry z@BJ}9(k9E-NejbY-SR}6^4?pddlV07aroIMAlghiuy6N+FO4BED_$eFVyAfB{(N9V z5&HPTIYR1PUszY5C*KPPK>0l*S*5#2a7ZOI1SN^FbXuET&@()a;vT!dy}uNPcDZH! z4LN9s25lVHRHprLGsQY^C%x5HMP)|o-|m+F)Z|mv{;q;J0glK|P0a+0;lzi5k^>>W zj$#)Md>5)fRWD8avqiRidY-01Pmi6-^?L7g(Q4GmN(*`?;wUTHI(`NQLf;i;B`|(K z)_aw3U@JZF6-5DU260uo1p{!+3hfniM0BJ6Gj9z^D(ZISAvU6?s$HLU2mu4owX%4W zu=<#v?7oL^T{IZAkAbc-pq1XG%s3)$x)ky4MDiS|=|o!-O(ixjtgF6J$bhSp?}a!{ zey4jW7#@D%?js5QC>yaMRvHq+`j-G)uyx{`8LHlc^7-u(6)TZ0PgJf(K76XLa_`5Mh2#A%NoCza4?Z$si@ z0I6nSVh&bU>)*qhvg$?zWih}N7p*3e7gizfOF|$*D&%V)FE`UzPLGuItgb4`0m^Bm zW4)|fQy_tGxqsPy&FDt&UL(s?!2AgT2E@VMFT{rTOmm5x)fj-&ng-qmsdgDy%GXu4 zGf@KbpM-7(U8}XuZnu2D3+f5CzYj&CQceMS1&hCp;H6VZ`pJSnJ@Jq?+`i%Y409F= z{o3ib>S%PZFkx$fgLZysJ86R~^^HmR<$r(*S&)9St0nQDwe-}nya&n-q&t>QkWJD; zL~7RQwhJWSGcld29H*tB8*i1zvq&mGJ7+rM*52WOLqbq>&YO~*MlI4vf+{{n;C>^q z#P~S{pr*vgYwPy~`VQL)r!CG{@+b!ss+>-`?UV8aUREY@2LmdrX0`b;!%n~ol0p-R zeh06>khCDR+l!1V`^YkF#F82!Tx8dMr&`WUn2>cM z;p`D4Q3tybU^UN*TL(aryQ!~0Ba6tE)kQvndCGitk-4u-BBe}GkLEzKUQV-WR{R$g z?8#*sfXaaY2@TgclSV9P9B7!}gc1nd0iyWw;OTol)siE*3Xet*SOX^NSAb4eLUNk7apeegx594!5@mOS64<6tB(H)BBZe1-p+bg zuKt5<&r$YruGgje>t#@$9#px}-@pG-gVLFNwvdiL_b*1>QdGn+vMntsZ9~#TSu&?$ zMqMQV^nYtWvYUhsGM19im+ZEjwY1Jiczf8s=ISwR-0Bc5&MHx{akVEslh3{9l{egV z0W6oZGQLqyh#V3mMmMQ=EWp2e{8`cIb+sx-B4;uq`KNt6Fc1XaWFs{!mnyHP;n?iOu5#6?IAGU5QvbF8Km@p7cu zRDWiZg{^TzC@38b@|*SI`?pVO5EDp2m40Ff%Bth?-wU;to5)O#O*r9IBccBbrb5jM{sI@>P>!|7sg__Py86>2`)o`@M*Di;2h5+M z89grbqf7bW70*oT=azb;yw7KU-5@{-4bpA&rSxnuC*aBH_aU zQbxxV0siR@cf*UpR6pGGy726+FC@^24h{2VS~zThyIvDNx#6tBvI2kmH!Dl=*lsQY z3!dS7*wsa>BH}3yOKM?BgUTBgTuO6KG#%z%UGFc4S=~Wt^vUHkcpqVPzl{Ak%6Ox! zI}a*bG5TQ$vC5qJht$L%`ibpPkoc38?vk)Lvg&%<^4cxJ1r;cnM6|ypW_ow<|Ew;} zOix8A=9xU?T4sxSgEH!Gc^nUAh@`h0-u*vi%;n6%`i^udZetpNX z7Nw7}?KV@=hVk=x9hA;iZdb}WDFqqC8D-7+&x1n#`xcqSgWvNnzwtL(@8kNS@B}|! zqA`&XOOXV!*%t+}Cpowvr4?W4qNBkxuFBPoKp_9WmjGYm=+_Y_Ws92~>pe8OT*|?Z z3A%p9)fg3RvLGyvJ?qkeUg0n3{E$}XEx*O3_`C4m1D>K8v80*;)8HFF#YJ2QypUHD zanUi5BeKhiiK*Sh$kTF}tDG+NC1L|hsy5^yr76s#w{^5A+8;p=k32P=>Ujx%&rzZKs^1z0NQSD`udNc~WR? zuTIgu%Bie|EhSs;KfgCG$3K)}hz#p)xevP0y)!UNKSA_#`qav!^*qpco$Epz=f*kH zI|!#(<0>q?22?O^HzKx#?(_MI=G71)q$gb}Bpla{@w4eY7tEf#rcI{DU50MBJf{0l zanHxZ=NAr)xs`jm2Ms;9q7qHk3ORW~F<40@>l!DsihjnRc!G{KE7|75Aq5gVQz27$!}gwjla*oKws7ilX)4O)#54`U;S1KlzCN@H7g=d_ zj;yV2=%pgHMqa#IFvaU0mH&*&mL^jCKA-qzkLJ`=s?`T<2;it%3-v6a00ciK9Jf^9 zL$5%PQq}K(%~G{hHOdC64hERh{n3=G*X2~y2|`P!MN~-PkI3!60nO>N%;3b`nngku|ZiK?wlx=h7g;2$Pr72dkNn(ssWXMzbqy(+t(a4_(Iq8Hfq)SA8_O!G`N3lEteiiL((mP{iBV~1g(u`qzS2W%heW_ z%1`d$9D`)uH8Hhz(1VsSawf=k?uwZ}#oYRXbKF^wXe+uDhMf@l@?IvM;*CP^vb#mj zdVoF5KftZu4x>q7f6c-ijW99HsLA)d9wY6;tOeQW{q4_Ca+!G0AD_^bwUW@73MZ)x zl#Qi=@3ROIpnh0I#V}Cbt!RIa_cz<#GmEwXYhx=9adHL${&Bn zLtRFci`uiDQKfZpCXJ!DJ4EYHJB;BsLzw!Dct!f&Ch=ZEM>17XCljj8iDyjA;UoTH z0sQTlSR}m$1_N1C?T6aj!8~O;uE9^cjo%yDJV6{;r?3qU^kqKivc`qh!KT-j^CG58;Z=@NIjy zlHR2RHHlgBX)RaffP0>5U?Oouu8H8(-pP_g(YtDGNG}jp<2qPO^;1J#VMRz~joL{- z(l5I+kdq||wPnF4vpdM-pdA7gC@!^Uiw7HUgw^FpMBT#2OBb7>Z@ywb{Y0KZZTndf zufSZga{S%^gMRQsn)c?dk%Rq&o?Up!?8xb&h!Glu;8!E!R@3XP*&0s{{iFW6xxpa6Xaluol zoi?t03cI&w7M8k=rBNY|#XR}Ei8 z_7aM6DM~W?Kt%$vgn;Smx1k2-j717c6}?4o7gl#3#56|)QyF-)A+BJ!b`ym;A#}XD z%?Dj~>X$8sLR0qr{-u?U{qwnYhXOWVaCB?+u;j>4 z9#eD_8L2tdM`=BSxkzk`#KtG9LPs8Cxxx;#IRs@Y^KqeWd~Rk##7U*6ksqmR(o@R2 zt0SvaZQNil=8$U=mXx!6RJXo`gLhac`!wR$tWJTG!$0}e4fD^NE<(KyFmY-azHE!l z+@T*fd}|Rj1QvJ!>TMU++#SmbkWO;)JYYfNjz&Cx5z=0j@;;sB5!CP4(yb74T4;4^2 z#7JhklqtAZhE9qd;F4C>@h6B;CN08JJjsAxEVH!2A-b!nH41VD@|wsvcof(W*s=d_ z78*;hWIXq3pGFf=u@HKAl0j-UHd5BP#mtW!O?>eomzD*c63gg5PCSGUb0gU=(iF}J zJ(p?va{*WqB_P^`&mXa&VcP18C?mlU1=iYWQUW#_*Cjb|D&-^uuP@UYO-F+b530Ls0Gsts~ve*)smosyd^l* z417zq1lq($hDeRsyk;1~d8hio;FOL?8EsRB6r0!gO0^{D37fNg?{&7KZvg)NdR9Lf z%kw`}4L?7aL16Pgc!G)#zh&L8d{-`AmQyz6TB*7FbL@DwU_6FJD|- z%D^A<`v_>AFbzV@Q?X=+3!GcHERYjw+7y~_NaX1HrqPIq(Ap~jqu@)X8rwxTSsq#U zfR+*r|76PxLymQb$Ly_g)GJMiX(Lull7k&Wy?}LxD$`1fa65v~5{&m;N2mY?Q1Gn^ zPtBxe^}xqzmhejWe+L6Xu&^u(_uVpDBM$Jj9%H+N8HX6nq0`ave~muxYh`uznq=YA zW?aS;pD3UTZ$1BQEfTpB46dVO>@qQqxvM%5662ADuPAj^f0N`+5liMgFHWSeH{pRw zwRojRKcX1NVI*W4Ip&{55XRKIZRvvR#&TH;BCPVapKw;%(7YHf1$69MDu#lcM}^Jm zB+pSTT=FN6x9CHEEBp!Wta|3_Z_4cp-)^fYGD`9OkVraS;Ld5x`;D$$pg3q57sblA zZ0}4HJHetFGVm~8ak*5%Kg#ePh!D^%3o>Nyyxg(!8khvjKeks7N0bBVB++C~C?WJC z)6moUTC1#)wzr~bSxBOSQ-hrQQv;KZ8Zhe((ol_

V9Ze!Ps!;R|8K5T$*3av>em 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%0Da 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 D?*{dP literal 0 HcmV?d00001 diff --git a/x/wasm/keeper/testdata/burner.wasm b/x/wasm/keeper/testdata/burner.wasm new file mode 100644 index 0000000000000000000000000000000000000000..6639075611b73e21f3d0045d772ce84b406718e4 GIT binary patch literal 127528 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 OE3W{~0~P?eROl~tF*(Hm literal 0 HcmV?d00001 diff --git a/x/wasm/keeper/testdata/download_releases.sh b/x/wasm/keeper/testdata/download_releases.sh new file mode 100755 index 00000000..27576139 --- /dev/null +++ b/x/wasm/keeper/testdata/download_releases.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -o errexit -o nounset -o pipefail +command -v shellcheck > /dev/null && shellcheck "$0" + +if [ $# -ne 1 ]; then + echo "Usage: ./download_releases.sh RELEASE_TAG" + exit 1 +fi + +tag="$1" + +for contract in burner hackatom ibc_reflect ibc_reflect_send reflect staking; do + url="https://github.com/CosmWasm/cosmwasm/releases/download/$tag/${contract}.wasm" + echo "Downloading $url ..." + wget -O "${contract}.wasm" "$url" +done + +# create the zip variant +gzip -k hackatom.wasm +mv hackatom.wasm.gz hackatom.wasm.gzip + +rm -f version.txt +echo "$tag" >version.txt \ No newline at end of file diff --git a/x/wasm/keeper/testdata/genesis.json b/x/wasm/keeper/testdata/genesis.json new file mode 100644 index 00000000..08969c7d --- /dev/null +++ b/x/wasm/keeper/testdata/genesis.json @@ -0,0 +1,219 @@ +{ + "genesis_time": "2020-07-13T07:49:08.2945876Z", + "chain_id": "testing", + "consensus_params": { + "block": { + "max_bytes": "22020096", + "max_gas": "-1", + "time_iota_ms": "1000" + }, + "evidence": { + "max_age_num_blocks": "100000", + "max_age_duration": "172800000000000" + }, + "validator": { + "pub_key_types": [ + "ed25519" + ] + } + }, + "app_hash": "", + "app_state": { + "upgrade": {}, + "evidence": { + "params": { + "max_evidence_age": "120000000000" + }, + "evidence": [] + }, + "supply": { + "supply": [] + }, + "mint": { + "minter": { + "inflation": "0.130000000000000000", + "annual_provisions": "0.000000000000000000" + }, + "params": { + "mint_denom": "ustake", + "inflation_rate_change": "0.130000000000000000", + "inflation_max": "0.200000000000000000", + "inflation_min": "0.070000000000000000", + "goal_bonded": "0.670000000000000000", + "blocks_per_year": "6311520" + } + }, + "gov": { + "starting_proposal_id": "1", + "deposits": null, + "votes": null, + "proposals": null, + "deposit_params": { + "min_deposit": [ + { + "denom": "ustake", + "amount": "1" + } + ], + "max_deposit_period": "172800000000000" + }, + "voting_params": { + "voting_period": "60000000000", + "voting_period_desc": "1minute" + }, + "tally_params": { + "quorum": "0.000000000000000001", + "threshold": "0.000000000000000001", + "veto": "0.334000000000000000" + } + }, + "slashing": { + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600000000000", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" + }, + "signing_infos": {}, + "missed_blocks": {} + }, + "wasm": { + "params": { + "upload_access": { + "type": 3, + "address": "" + }, + "instantiate_default_permission": 3 + }, + "codes": null, + "contracts": null, + "sequences": null + }, + "bank": { + "send_enabled": true + }, + "distribution": { + "params": { + "community_tax": "0.020000000000000000", + "base_proposer_reward": "0.010000000000000000", + "bonus_proposer_reward": "0.040000000000000000", + "withdraw_addr_enabled": true + }, + "fee_pool": { + "community_pool": [] + }, + "delegator_withdraw_infos": [], + "previous_proposer": "", + "outstanding_rewards": [], + "validator_accumulated_commissions": [], + "validator_historical_rewards": [], + "validator_current_rewards": [], + "delegator_starting_infos": [], + "validator_slash_events": [] + }, + "crisis": { + "constant_fee": { + "denom": "ustake", + "amount": "1000" + } + }, + "genutil": { + "gentxs": [ + { + "type": "cosmos-sdk/StdTx", + "value": { + "msg": [ + { + "type": "cosmos-sdk/MsgCreateValidator", + "value": { + "description": { + "moniker": "testing", + "identity": "", + "website": "", + "security_contact": "", + "details": "" + }, + "commission": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.010000000000000000" + }, + "min_self_delegation": "1", + "delegator_address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "validator_address": "cosmosvaloper1ve557a5g9yw2g2z57js3pdmcvd5my6g88d76lj", + "pubkey": "cosmosvalconspub1zcjduepqddfln4tujr2p8actpgqz4h2xnls9y7tu9c9tu5lqkdglmdjalzuqah4neg", + "value": { + "denom": "ustake", + "amount": "250000000" + } + } + } + ], + "fee": { + "amount": [], + "gas": "200000" + }, + "signatures": [ + { + "pub_key": { + "type": "tendermint/PubKeySecp256k1", + "value": "A//cqZxkpH1re0VrHBtH308nb5t8K+Y/hF0GeRdRBmaJ" + }, + "signature": "5QEEIuUVQTEBMuAtOOHnnKo6rPsIbmfzUxUqRnDFERVqwVr1Kg+ex4f/UGIK0yrOAvOG8zDADwFP4yF8lw+o5g==" + } + ], + "memo": "836fc54e9cad58f4ed6420223ec6290f75342afa@172.17.0.2:26656" + } + } + ] + }, + "auth": { + "params": { + "max_memo_characters": "256", + "tx_sig_limit": "7", + "tx_size_cost_per_byte": "10", + "sig_verify_cost_ed25519": "590", + "sig_verify_cost_secp256k1": "1000" + }, + "accounts": [ + { + "type": "cosmos-sdk/Account", + "value": { + "address": "cosmos1ve557a5g9yw2g2z57js3pdmcvd5my6g8ze20np", + "coins": [ + { + "denom": "ucosm", + "amount": "1000000000" + }, + { + "denom": "ustake", + "amount": "1000000000" + } + ], + "public_key": "", + "account_number": 0, + "sequence": 0 + } + } + ] + }, + "params": null, + "staking": { + "params": { + "unbonding_time": "1814400000000000", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 0, + "bond_denom": "ustake" + }, + "last_total_power": "0", + "last_validator_powers": null, + "validators": null, + "delegations": null, + "unbonding_delegations": null, + "redelegations": null, + "exported": false + } + } +} \ No newline at end of file diff --git a/x/wasm/keeper/testdata/hackatom.wasm b/x/wasm/keeper/testdata/hackatom.wasm new file mode 100644 index 0000000000000000000000000000000000000000..baa03a853ac6b59f7b98e7fca62b645b90bca024 GIT binary patch literal 177474 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 Q<*WH!!>@y1!`hbrAG;7^s{jB1 literal 0 HcmV?d00001 diff --git a/x/wasm/keeper/testdata/hackatom.wasm.gzip b/x/wasm/keeper/testdata/hackatom.wasm.gzip new file mode 100644 index 0000000000000000000000000000000000000000..3c95e9b1d4cac2f9f0623b3336cdb068744e613e GIT binary patch literal 64560 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 Bn7IG| literal 0 HcmV?d00001 diff --git a/x/wasm/keeper/testdata/ibc_reflect.wasm b/x/wasm/keeper/testdata/ibc_reflect.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ec737104c434584f9e38d4aff968d29c128c3cc7 GIT binary patch literal 254798 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 WrBhPB_oLIkiQnb?+W9r~w*3DY_Xp+x literal 0 HcmV?d00001 diff --git a/x/wasm/keeper/testdata/ibc_reflect_send.wasm b/x/wasm/keeper/testdata/ibc_reflect_send.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0f7d7e45936babe22d78e6fb33c0661bafb49546 GIT binary patch literal 269429 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�qd$b8;*CQ*wnE>W=6jPr;l^U# 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