From 0a74d4601fad66128b67c6d01722457d42f3564e Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 15:00:19 -0700 Subject: [PATCH 01/20] [1752]: Copy the quarantine proto and module dir from our on our fork of the SDK. --- .../quarantine/v1beta1/events.proto | 32 + .../quarantine/v1beta1/genesis.proto | 20 + .../quarantine/v1beta1/quarantine.proto | 73 + .../provenance/quarantine/v1beta1/query.proto | 100 + proto/provenance/quarantine/v1beta1/tx.proto | 107 + x/quarantine/client/cli/query.go | 203 + x/quarantine/client/cli/tx.go | 305 ++ x/quarantine/client/cli/util.go | 103 + x/quarantine/client/cli/util_test.go | 328 ++ x/quarantine/client/testutil/cli_test.go | 20 + x/quarantine/client/testutil/common_test.go | 121 + x/quarantine/client/testutil/query_test.go | 312 ++ x/quarantine/client/testutil/tx_test.go | 528 +++ x/quarantine/codec.go | 55 + x/quarantine/errors/errors.go | 8 + x/quarantine/events.pb.go | 969 ++++ x/quarantine/expected_keepers.go | 22 + x/quarantine/export_test.go | 12 + x/quarantine/genesis.go | 41 + x/quarantine/genesis.pb.go | 459 ++ x/quarantine/genesis_test.go | 257 + x/quarantine/keeper/export_test.go | 80 + x/quarantine/keeper/genesis.go | 82 + x/quarantine/keeper/grpc_query.go | 149 + x/quarantine/keeper/grpc_query_test.go | 553 +++ x/quarantine/keeper/invariants.go | 72 + x/quarantine/keeper/invariants_test.go | 192 + x/quarantine/keeper/keeper.go | 422 ++ x/quarantine/keeper/keeper_test.go | 3787 +++++++++++++++ x/quarantine/keeper/mock_bank_keeper_test.go | 68 + x/quarantine/keeper/msg_server.go | 118 + x/quarantine/keeper/msg_server_test.go | 544 +++ x/quarantine/keeper/send_restriction.go | 38 + x/quarantine/keeper/send_restriction_test.go | 289 ++ x/quarantine/keys.go | 181 + x/quarantine/keys_test.go | 1134 +++++ x/quarantine/module/module.go | 176 + x/quarantine/msgs.go | 152 + x/quarantine/msgs_test.go | 1102 +++++ x/quarantine/quarantine.go | 326 ++ x/quarantine/quarantine.pb.go | 1525 ++++++ x/quarantine/quarantine_test.go | 4164 +++++++++++++++++ x/quarantine/query.pb.go | 1756 +++++++ x/quarantine/query.pb.gw.go | 792 ++++ x/quarantine/send_restriction.go | 25 + x/quarantine/send_restriction_test.go | 77 + x/quarantine/simulation/decoder.go | 41 + x/quarantine/simulation/decoder_test.go | 107 + x/quarantine/simulation/genesis.go | 252 + x/quarantine/simulation/genesis_test.go | 500 ++ x/quarantine/simulation/operations.go | 449 ++ x/quarantine/simulation/operations_test.go | 223 + x/quarantine/spec/01_concepts.md | 49 + x/quarantine/spec/02_state.md | 60 + x/quarantine/spec/03_messages.md | 84 + x/quarantine/spec/04_events.md | 50 + x/quarantine/spec/05_queries.md | 76 + x/quarantine/spec/06_client.md | 222 + x/quarantine/spec/README.md | 45 + x/quarantine/testutil/test_helpers.go | 261 ++ x/quarantine/tx.pb.go | 2209 +++++++++ 61 files changed, 26507 insertions(+) create mode 100644 proto/provenance/quarantine/v1beta1/events.proto create mode 100644 proto/provenance/quarantine/v1beta1/genesis.proto create mode 100644 proto/provenance/quarantine/v1beta1/quarantine.proto create mode 100644 proto/provenance/quarantine/v1beta1/query.proto create mode 100644 proto/provenance/quarantine/v1beta1/tx.proto create mode 100644 x/quarantine/client/cli/query.go create mode 100644 x/quarantine/client/cli/tx.go create mode 100644 x/quarantine/client/cli/util.go create mode 100644 x/quarantine/client/cli/util_test.go create mode 100644 x/quarantine/client/testutil/cli_test.go create mode 100644 x/quarantine/client/testutil/common_test.go create mode 100644 x/quarantine/client/testutil/query_test.go create mode 100644 x/quarantine/client/testutil/tx_test.go create mode 100644 x/quarantine/codec.go create mode 100644 x/quarantine/errors/errors.go create mode 100644 x/quarantine/events.pb.go create mode 100644 x/quarantine/expected_keepers.go create mode 100644 x/quarantine/export_test.go create mode 100644 x/quarantine/genesis.go create mode 100644 x/quarantine/genesis.pb.go create mode 100644 x/quarantine/genesis_test.go create mode 100644 x/quarantine/keeper/export_test.go create mode 100644 x/quarantine/keeper/genesis.go create mode 100644 x/quarantine/keeper/grpc_query.go create mode 100644 x/quarantine/keeper/grpc_query_test.go create mode 100644 x/quarantine/keeper/invariants.go create mode 100644 x/quarantine/keeper/invariants_test.go create mode 100644 x/quarantine/keeper/keeper.go create mode 100644 x/quarantine/keeper/keeper_test.go create mode 100644 x/quarantine/keeper/mock_bank_keeper_test.go create mode 100644 x/quarantine/keeper/msg_server.go create mode 100644 x/quarantine/keeper/msg_server_test.go create mode 100644 x/quarantine/keeper/send_restriction.go create mode 100644 x/quarantine/keeper/send_restriction_test.go create mode 100644 x/quarantine/keys.go create mode 100644 x/quarantine/keys_test.go create mode 100644 x/quarantine/module/module.go create mode 100644 x/quarantine/msgs.go create mode 100644 x/quarantine/msgs_test.go create mode 100644 x/quarantine/quarantine.go create mode 100644 x/quarantine/quarantine.pb.go create mode 100644 x/quarantine/quarantine_test.go create mode 100644 x/quarantine/query.pb.go create mode 100644 x/quarantine/query.pb.gw.go create mode 100644 x/quarantine/send_restriction.go create mode 100644 x/quarantine/send_restriction_test.go create mode 100644 x/quarantine/simulation/decoder.go create mode 100644 x/quarantine/simulation/decoder_test.go create mode 100644 x/quarantine/simulation/genesis.go create mode 100644 x/quarantine/simulation/genesis_test.go create mode 100644 x/quarantine/simulation/operations.go create mode 100644 x/quarantine/simulation/operations_test.go create mode 100644 x/quarantine/spec/01_concepts.md create mode 100644 x/quarantine/spec/02_state.md create mode 100644 x/quarantine/spec/03_messages.md create mode 100644 x/quarantine/spec/04_events.md create mode 100644 x/quarantine/spec/05_queries.md create mode 100644 x/quarantine/spec/06_client.md create mode 100644 x/quarantine/spec/README.md create mode 100644 x/quarantine/testutil/test_helpers.go create mode 100644 x/quarantine/tx.pb.go diff --git a/proto/provenance/quarantine/v1beta1/events.proto b/proto/provenance/quarantine/v1beta1/events.proto new file mode 100644 index 0000000000..01151d8c47 --- /dev/null +++ b/proto/provenance/quarantine/v1beta1/events.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; +package cosmos.quarantine.v1beta1; + +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; + +// EventOptIn is an event emitted when an address opts into quarantine. +message EventOptIn { + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// EventOptOut is an event emitted when an address opts out of quarantine. +message EventOptOut { + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// EventFundsQuarantined is an event emitted when funds are quarantined. +message EventFundsQuarantined { + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + repeated cosmos.base.v1beta1.Coin coins = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// EventFundsReleased is an event emitted when quarantined funds are accepted and released. +message EventFundsReleased { + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + repeated cosmos.base.v1beta1.Coin coins = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} diff --git a/proto/provenance/quarantine/v1beta1/genesis.proto b/proto/provenance/quarantine/v1beta1/genesis.proto new file mode 100644 index 0000000000..7e8fea369c --- /dev/null +++ b/proto/provenance/quarantine/v1beta1/genesis.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package cosmos.quarantine.v1beta1; + +import "cosmos/quarantine/v1beta1/quarantine.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; + +// GenesisState defines the quarantine module's genesis state. +message GenesisState { + // quarantined_addresses defines account addresses that are opted into quarantine. + repeated string quarantined_addresses = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // auto_responses defines the quarantine auto-responses for addresses. + repeated AutoResponseEntry auto_responses = 2; + + // quarantined_funds defines funds that are quarantined. + repeated QuarantinedFunds quarantined_funds = 3; +} diff --git a/proto/provenance/quarantine/v1beta1/quarantine.proto b/proto/provenance/quarantine/v1beta1/quarantine.proto new file mode 100644 index 0000000000..c89e3c321e --- /dev/null +++ b/proto/provenance/quarantine/v1beta1/quarantine.proto @@ -0,0 +1,73 @@ +syntax = "proto3"; +package cosmos.quarantine.v1beta1; + +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; + +// QuarantinedFunds defines structure that represents coins that have been quarantined. +message QuarantinedFunds { + // to_address is the intended recipient of the coins that have been quarantined. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // unaccepted_from_addresses are the senders that have not been part of an accept yet for these coins. + repeated string unaccepted_from_addresses = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // coins is the amount currently in quarantined for the two addresses. + repeated cosmos.base.v1beta1.Coin coins = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + // declined is true if these funds were previously declined. + bool declined = 4; +} + +// AutoResponseEntry defines the auto response to one address from another. +message AutoResponseEntry { + // to_address is the receiving address. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // from_address is the sending address. + string from_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // response is the auto-response setting for these two addresses. + AutoResponse response = 3; +} + +// AutoResponseUpdate defines a quarantine auto response update that should be applied. +message AutoResponseUpdate { + // from_address is the address that funds would be coming from. + string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // response is the automatic action to take on funds sent from from_address. + // Provide AUTO_RESPONSE_UNSPECIFIED to turn off an auto-response. + AutoResponse response = 2; +} + +// AutoResponse enumerates the quarantine auto-response options. +enum AutoResponse { + option (gogoproto.goproto_enum_prefix) = false; + + // AUTO_RESPONSE_UNSPECIFIED defines that an automatic response has not been specified. + // This means that no automatic action should be taken, i.e. this auto-response is off, + // and default quarantine behavior is used. + AUTO_RESPONSE_UNSPECIFIED = 0; + // AUTO_RESPONSE_ACCEPT defines that sends should be automatically accepted, bypassing quarantine. + AUTO_RESPONSE_ACCEPT = 1; + // AUTO_RESPONSE_DECLINE defines that sends should be automatically declined. + AUTO_RESPONSE_DECLINE = 2; +} + +// QuarantineRecord defines information regarding quarantined funds that is stored in state. +message QuarantineRecord { + // unaccepted_from_addresses are the senders that have not been part of an accept yet for these coins. + repeated bytes unaccepted_from_addresses = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + // accepted_from_addresses are the senders that have already been part of an accept for these coins. + repeated bytes accepted_from_addresses = 2 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + // coins is the amount that has been quarantined. + repeated cosmos.base.v1beta1.Coin coins = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + // declined is whether these funds have been declined. + bool declined = 4; +} + +// QuarantineRecordSuffixIndex defines a list of record suffixes that can be stored in state and used as an index. +message QuarantineRecordSuffixIndex { + repeated bytes record_suffixes = 1; +} diff --git a/proto/provenance/quarantine/v1beta1/query.proto b/proto/provenance/quarantine/v1beta1/query.proto new file mode 100644 index 0000000000..bed3dc09e1 --- /dev/null +++ b/proto/provenance/quarantine/v1beta1/query.proto @@ -0,0 +1,100 @@ +syntax = "proto3"; +package cosmos.quarantine.v1beta1; + +import "cosmos/base/query/v1beta1/pagination.proto"; +import "cosmos/quarantine/v1beta1/quarantine.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/api/annotations.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; + +// Query defines the quarantine gRPC query service. +service Query { + // IsQuarantined checks if an account has opted into quarantine. + rpc IsQuarantined(QueryIsQuarantinedRequest) returns (QueryIsQuarantinedResponse) { + option (google.api.http).get = "/cosmos/quarantine/v1beta1/active/{to_address}"; + } + + // QuarantinedFunds gets information about funds that have been quarantined. + // + // If both a to_address and from_address are provided, any such quarantined funds will be returned regardless of + // whether they've been declined. If only a to_address is provided, the unaccepted and undeclined funds waiting on a + // response from to_address will be returned. If neither a to_address nor from_address is provided, all non-declined + // quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. + rpc QuarantinedFunds(QueryQuarantinedFundsRequest) returns (QueryQuarantinedFundsResponse) { + option (google.api.http) = { + get: "/cosmos/quarantine/v1beta1/funds" + additional_bindings: { + get: "/cosmos/quarantine/v1beta1/funds/{to_address}" + } + additional_bindings: { + get: "/cosmos/quarantine/v1beta1/funds/{to_address}/{from_address}" + } + }; + } + + // AutoResponses gets the auto-response settings for a quarantined account. + // + // The to_address is required. If a from_address is provided only the auto response for that from_address will be + // returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. + rpc AutoResponses(QueryAutoResponsesRequest) returns (QueryAutoResponsesResponse) { + option (google.api.http) = { + get: "/cosmos/quarantine/v1beta1/auto/{to_address}" + additional_bindings: { + get: "/cosmos/quarantine/v1beta1/auto/{to_address}/{from_address}" + } + }; + } +} + +// QueryIsQuarantinedRequest defines the RPC request for checking if an account has opted into quarantine. +message QueryIsQuarantinedRequest { + // to_address is the address to check. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// QueryIsQuarantinedResponse defines the RPC response of an IsQuarantined query. +message QueryIsQuarantinedResponse { + // is_quarantined is true if the to_address has opted into quarantine. + bool is_quarantined = 1; +} + +// QueryQuarantinedFundsRequest defines the RPC request for looking up quarantined funds. +message QueryQuarantinedFundsRequest { + // to_address is the intended recipient of the coins that have been quarantined. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // from_address is the sender of the coins. If provided, a to_address must also be provided. + string from_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // pagination defines optional pagination parameters for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 99; +} + +// QueryQuarantinedFundsResponse defines the RPC response of a QuarantinedFunds query. +message QueryQuarantinedFundsResponse { + // quarantinedFunds is info about coins sitting in quarantine. + repeated QuarantinedFunds quarantinedFunds = 1; + + // pagination defines the pagination parameters of the response. + cosmos.base.query.v1beta1.PageResponse pagination = 99; +} + +// QueryAutoResponsesRequest defines the RPC request for getting auto-response settings for an address. +message QueryAutoResponsesRequest { + // to_address is the quarantined account to get info on. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // from_address is an optional sender address to limit results. + string from_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // pagination defines optional pagination parameters for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 99; +} + +// QueryAutoResponsesResponse defines the RPC response of a AutoResponses query. +message QueryAutoResponsesResponse { + // auto_responses are the auto-response entries from the provided query. + repeated AutoResponseEntry auto_responses = 1; + + // pagination defines the pagination parameters of the response. + cosmos.base.query.v1beta1.PageResponse pagination = 99; +} diff --git a/proto/provenance/quarantine/v1beta1/tx.proto b/proto/provenance/quarantine/v1beta1/tx.proto new file mode 100644 index 0000000000..9b799e8ba2 --- /dev/null +++ b/proto/provenance/quarantine/v1beta1/tx.proto @@ -0,0 +1,107 @@ +syntax = "proto3"; +package cosmos.quarantine.v1beta1; + +import "cosmos/base/query/v1beta1/pagination.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos/quarantine/v1beta1/quarantine.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; + +// Query defines the quarantine gRPC msg service. +service Msg { + // OptIn defines a method for opting in to account quarantine. + // Funds sent to a quarantined account must be approved before they can be received. + rpc OptIn(MsgOptIn) returns (MsgOptInResponse); + + // OptOut defines a method for opting out of account quarantine. + // Any pending funds for the account must still be accepted, but new sends will no longer be quarantined. + rpc OptOut(MsgOptOut) returns (MsgOptOutResponse); + + // Accept defines a method for accepting quarantined funds. + rpc Accept(MsgAccept) returns (MsgAcceptResponse); + + // Decline defines a method for declining quarantined funds. + rpc Decline(MsgDecline) returns (MsgDeclineResponse); + + // UpdateAutoResponses defines a method for updating the auto-response settings for a quarantined address. + rpc UpdateAutoResponses(MsgUpdateAutoResponses) returns (MsgUpdateAutoResponsesResponse); +} + +// MsgOptIn represents a message for opting in to account quarantine. +message MsgOptIn { + option (cosmos.msg.v1.signer) = "to_address"; + + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// MsgOptInResponse defines the Msg/OptIn response type. +message MsgOptInResponse {} + +// MsgOptOut represents a message for opting in to account quarantine. +message MsgOptOut { + option (cosmos.msg.v1.signer) = "to_address"; + + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// MsgOptOutResponse defines the Msg/OptOut response type. +message MsgOptOutResponse {} + +// MsgAccept represents a message for accepting quarantined funds. +message MsgAccept { + option (cosmos.msg.v1.signer) = "to_address"; + + // to_address is the address of the quarantined account that is accepting funds. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // from_addresses is one or more addresses that have sent funds to the quarantined account. + // All funds quarantined for to_address from any from_addresses are marked as accepted and released if appropriate. + // At least one is required. + repeated string from_addresses = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // permanent, if true, sets up auto-accept for the to_address from each from_address. + // If false (default), only the currently quarantined funds will be accepted. + bool permanent = 3; +} + +// MsgAcceptResponse defines the Msg/Accept response type. +message MsgAcceptResponse { + // funds_released is the amount that was quarantined but has now been released and sent to the requester. + repeated cosmos.base.v1beta1.Coin funds_released = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// MsgDecline represents a message for declining quarantined funds. +message MsgDecline { + option (cosmos.msg.v1.signer) = "to_address"; + + // to_address is the address of the quarantined account that is accepting funds. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // from_addresses is one or more addresses that have sent funds to the quarantined account. + // All funds quarantined for to_address from any from_addresses are marked as declined. + // At least one is required. + repeated string from_addresses = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // permanent, if true, sets up auto-decline for the to_address from each from_address. + // If false (default), only the currently quarantined funds will be declined. + bool permanent = 3; +} + +// MsgDeclineResponse defines the Msg/Decline response type. +message MsgDeclineResponse {} + +// MsgUpdateAutoResponses represents a message for updating quarantine auto-responses for a receiving address. +message MsgUpdateAutoResponses { + option (cosmos.msg.v1.signer) = "to_address"; + + // to_address is the quarantined address that would be accepting or declining funds. + string to_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + // updates is the list of addresses and auto-responses that should be updated for the to_address. + repeated AutoResponseUpdate updates = 2; +} + +// MsgUpdateAutoResponsesResponse defines the Msg/UpdateAutoResponse response type. +message MsgUpdateAutoResponsesResponse {} diff --git a/x/quarantine/client/cli/query.go b/x/quarantine/client/cli/query.go new file mode 100644 index 0000000000..d61f83578f --- /dev/null +++ b/x/quarantine/client/cli/query.go @@ -0,0 +1,203 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +// exampleQueryCmdBase is the base command that gets a user to one of the query commands in here. +var exampleQueryCmdBase = fmt.Sprintf("%s query %s", version.AppName, quarantine.ModuleName) + +// QueryCmd returns the command with sub-commands for specific quarantine module queries. +func QueryCmd() *cobra.Command { + queryCmd := &cobra.Command{ + Use: quarantine.ModuleName, + Short: "Querying commands for the quarantine module", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + queryCmd.AddCommand( + QueryQuarantinedFundsCmd(), + QueryIsQuarantinedCmd(), + QueryAutoResponsesCmd(), + ) + + return queryCmd +} + +// QueryQuarantinedFundsCmd returns the command for executing a QuarantinedFunds query. +func QueryQuarantinedFundsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "funds [ []]", + Short: "Query for quarantined funds", + Long: fmt.Sprintf(`Query for quarantined funds. + +If no arguments are provided, all quarantined funds will be returned. +If only a to_address is provided, only undeclined funds quarantined for that address are returned. +If both a to_address and from_address are provided, quarantined funds will be returned regardless of whether they've been declined. + +Examples: + $ %[1]s funds + $ %[1]s funds %[2]s + $ %[1]s funds %[2]s %[3]s +`, + exampleQueryCmdBase, exampleAddr1, exampleAddr2), + Args: cobra.RangeArgs(0, 2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + req := quarantine.QueryQuarantinedFundsRequest{} + + if len(args) > 0 { + req.ToAddress, err = validateAddress(args[0], "to_address") + if err != nil { + return err + } + } + + if len(args) > 1 { + req.FromAddress, err = validateAddress(args[1], "from_address") + if err != nil { + return err + } + } + + req.Pagination, err = client.ReadPageRequestWithPageKeyDecoded(cmd.Flags()) + if err != nil { + return err + } + + queryClient := quarantine.NewQueryClient(clientCtx) + + var res *quarantine.QueryQuarantinedFundsResponse + res, err = queryClient.QuarantinedFunds(cmd.Context(), &req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "quarantined funds") + + return cmd +} + +// QueryIsQuarantinedCmd returns the command for executing an IsQuarantined query. +func QueryIsQuarantinedCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "is-quarantined ", + Aliases: []string{"is", "check", "c"}, + Short: "Query whether an account is opted into quarantined", + Long: fmt.Sprintf(`Query whether an account is opted into quarantined. + +Examples: + $ %[1]s is-quarantined %[2]s + $ %[1]s is %[2]s + $ %[1]s check %[2]s + $ %[1]s c %[2]s +`, + exampleQueryCmdBase, exampleAddr1), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + req := quarantine.QueryIsQuarantinedRequest{} + + req.ToAddress, err = validateAddress(args[0], "to_address") + if err != nil { + return err + } + + queryClient := quarantine.NewQueryClient(clientCtx) + + var res *quarantine.QueryIsQuarantinedResponse + res, err = queryClient.IsQuarantined(cmd.Context(), &req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// QueryAutoResponsesCmd returns the command for executing a AutoResponses query. +func QueryAutoResponsesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "auto-responses []", + Aliases: []string{"auto", "ar"}, + Short: "Query auto-responses", + Long: fmt.Sprintf(`Query auto-responses. + +If only a to_address is provided, all auto-responses set up for that address are returned. This will only contain accept or decline entries. +If both a to_address and from_address are provided, exactly one result will be returned. This can be accept, decline or unspecified. + +Examples: + $ %[1]s auto-responses %[2]s + $ %[1]s auto-responses %[2]s %[3]s +`, + exampleQueryCmdBase, exampleAddr1, exampleAddr2), + Args: cobra.RangeArgs(1, 2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + req := quarantine.QueryAutoResponsesRequest{} + + req.ToAddress, err = validateAddress(args[0], "to_address") + if err != nil { + return err + } + + if len(args) > 1 { + req.FromAddress, err = validateAddress(args[1], "from_address") + if err != nil { + return err + } + } + + req.Pagination, err = client.ReadPageRequestWithPageKeyDecoded(cmd.Flags()) + if err != nil { + return err + } + + queryClient := quarantine.NewQueryClient(clientCtx) + + var res *quarantine.QueryAutoResponsesResponse + res, err = queryClient.AutoResponses(cmd.Context(), &req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + flags.AddPaginationFlagsToCmd(cmd, "auto-responses") + + return cmd +} diff --git a/x/quarantine/client/cli/tx.go b/x/quarantine/client/cli/tx.go new file mode 100644 index 0000000000..210c712c67 --- /dev/null +++ b/x/quarantine/client/cli/tx.go @@ -0,0 +1,305 @@ +package cli + +import ( + "fmt" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +const ( + // FlagPermanent is the flag indicating a permanent accept/decline. + FlagPermanent = "permanent" +) + +// exampleTxCmdBase is the base command that gets a user to one of the tx commands in here. +var exampleTxCmdBase = fmt.Sprintf("%s tx %s", version.AppName, quarantine.ModuleName) + +// TxCmd returns the command with sub-commands for specific quarantine module Tx interaction. +func TxCmd() *cobra.Command { + txCmd := &cobra.Command{ + Use: quarantine.ModuleName, + Short: "Quarantine transaction subcommands", + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + txCmd.AddCommand( + TxOptInCmd(), + TxOptOutCmd(), + TxAcceptCmd(), + TxDeclineCmd(), + TxUpdateAutoResponsesCmd(), + ) + + return txCmd +} + +// TxOptInCmd returns the command for executing an OptIn Tx. +func TxOptInCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "opt-in []", + Short: "Activate quarantine for an account", + Long: `Activate quarantine for an account. +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message).`, + Example: fmt.Sprintf(` +$ %[1]s opt-in %[2]s +$ %[1]s opt-in personal +$ %[1]s opt-in --from %[2]s +$ %[1]s opt-in --from personal +`, + exampleTxCmdBase, exampleAddr1), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args[0]) == 0 { + return fmt.Errorf("no to_name_or_address provided") + } + + if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := quarantine.NewMsgOptIn(clientCtx.GetFromAddress()) + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("message validation failed: %w", err) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// TxOptOutCmd returns the command for executing an OptOut Tx. +func TxOptOutCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "opt-out []", + Short: "Deactivate quarantine for an account", + Long: `Deactivate quarantine for an account. +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message).`, + Example: fmt.Sprintf(` +$ %[1]s opt-out %[2]s +$ %[1]s opt-out personal +$ %[1]s opt-out --from %[2]s +$ %[1]s opt-out --from personal +`, + exampleTxCmdBase, exampleAddr1), + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args[0]) == 0 { + return fmt.Errorf("no to_name_or_address provided") + } + + if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := quarantine.NewMsgOptOut(clientCtx.GetFromAddress()) + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("message validation failed: %w", err) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// TxAcceptCmd returns the command for executing an Accept Tx. +func TxAcceptCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "accept [ ...]", + Short: "Accept quarantined funds sent to from ", + Long: `Accept quarantined funds sent to from . +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message).`, + Example: fmt.Sprintf(` +$ %[1]s accept %[2]s %[3]s +$ %[1]s accept personal %[3]s +$ %[1]s accept personal %[3]s %[4]s +`, + exampleTxCmdBase, exampleAddr1, exampleAddr2, exampleAddr3), + Args: cobra.MinimumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args[0]) == 0 { + return fmt.Errorf("no to_name_or_address provided") + } + if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + toAddr := clientCtx.GetFromAddress() + + fromAddrsStrs := make([]string, len(args)-1) + for i, fromAddrStr := range args[1:] { + fromAddrsStrs[i], err = validateAddress(fromAddrStr, fmt.Sprintf("from_address %d", i+1)) + if err != nil { + return err + } + } + + permanent, err := cmd.Flags().GetBool(FlagPermanent) + if err != nil { + return err + } + + msg := quarantine.NewMsgAccept(toAddr, fromAddrsStrs, permanent) + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("message validation failed: %w", err) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().Bool(FlagPermanent, false, "Also set auto-accept for sends from any of the from_addresses to to_address") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// TxDeclineCmd returns the command for executing a Decline Tx. +func TxDeclineCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "decline [ ...]", + Short: "Decline quarantined funds sent to from ", + Long: `Decline quarantined funds sent to from . +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message).`, + Example: fmt.Sprintf(` +$ %[1]s decline %[2]s %[3]s +$ %[1]s decline personal %[3]s +$ %[1]s decline personal %[3]s %[4]s +`, + exampleTxCmdBase, exampleAddr1, exampleAddr2, exampleAddr3), + Args: cobra.MinimumNArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args[0]) == 0 { + return fmt.Errorf("no to_name_or_address provided") + } + if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + toAddr := clientCtx.GetFromAddress() + + fromAddrsStrs := make([]string, len(args)-1) + for i, fromAddrStr := range args[1:] { + fromAddrsStrs[i], err = validateAddress(fromAddrStr, fmt.Sprintf("from_address %d", i+1)) + if err != nil { + return err + } + } + + permanent, err := cmd.Flags().GetBool(FlagPermanent) + if err != nil { + return err + } + + msg := quarantine.NewMsgDecline(toAddr, fromAddrsStrs, permanent) + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("message validation failed: %w", err) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + cmd.Flags().Bool(FlagPermanent, false, "Also set auto-decline for sends from any of the from_addresses to to_address") + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +// TxUpdateAutoResponsesCmd returns the command for executing an UpdateAutoResponses Tx. +func TxUpdateAutoResponsesCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-auto-responses [ ...] [ [ ...] ...]", + Aliases: []string{"auto-responses", "uar"}, + Short: "Update auto-responses", + Long: `Update auto-responses for transfers to from one or more addresses. +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). + +The is required. +At least one and must be provided. + +Valid values: + "accept" or "a" - turn on auto-accept for the following (es). + "decline" or "d" - turn on auto-decline for the following (es). + "unspecified", "u", "off", or "o" - turn off auto-responses for the following (es). + +Each value can be repeated as an arg as many times as needed as long as each is followed by at least one . +Each will be assigned the nearest preceding value. +`, + Example: fmt.Sprintf(` +$ %[1]s update-auto-responses %[2]s accept %[3]s +$ %[1]s update-auto-responses personal decline %[4]s unspecified %[5]s +$ %[1]s auto-responses personal accept %[3]s %[6]s off %[5]s +`, + exampleTxCmdBase, exampleAddr1, exampleAddr2, exampleAddr("exampleAddr3"), + exampleAddr("exampleAddr4"), exampleAddr("exampleAddr5")), + Args: cobra.MinimumNArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + if len(args[0]) == 0 { + return fmt.Errorf("no to_name_or_address provided") + } + if err := cmd.Flags().Set(flags.FlagFrom, args[0]); err != nil { + return err + } + + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + toAddr := clientCtx.GetFromAddress() + + var updates []*quarantine.AutoResponseUpdate + updates, err = ParseAutoResponseUpdatesFromArgs(args, 1) + if err != nil { + return err + } + + msg := quarantine.NewMsgUpdateAutoResponses(toAddr, updates) + if err = msg.ValidateBasic(); err != nil { + return fmt.Errorf("message validation failed: %w", err) + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} diff --git a/x/quarantine/client/cli/util.go b/x/quarantine/client/cli/util.go new file mode 100644 index 0000000000..7b8c861d8d --- /dev/null +++ b/x/quarantine/client/cli/util.go @@ -0,0 +1,103 @@ +package cli + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/tendermint/tendermint/crypto" +) + +// exampleAddr creates a consistent example address from the given name string. +func exampleAddr(name string) sdk.AccAddress { + // The correct HRP may or may not be set yet. + // So, in order for these example addresses to use the chain's HRP, this just creates the AccAddress, + // allowing the .String() conversion to happen later, hopefully after the HRP is set. + return sdk.AccAddress(crypto.AddressHash([]byte(name))) +} + +var ( + // exampleAddr1 is a random (but static) address to use in examples. + exampleAddr1 = exampleAddr("exampleAddr1") + // exampleAddr2 is another random (but static) address to use in examples. + exampleAddr2 = exampleAddr("exampleAddr2") + // exampleAddr3 is third random (but static) address to use in examples. + exampleAddr3 = exampleAddr("exampleAddr3") +) + +// validateAddress checks to make sure the provided addr is a valid Bech32 address string. +// If it is invalid, "" is returned with an error that includes the argName. +// If it is valid, the addr is returned without an error. +// +// This validation is (hopefully) already done by the node, but it's more +// user-friendly to also do it here, before a request is actually sent. +func validateAddress(addr string, argName string) (string, error) { + if _, err := sdk.AccAddressFromBech32(addr); err != nil { + return "", sdkerrors.ErrInvalidAddress.Wrapf("invalid %s: %v", argName, err) + } + return addr, nil +} + +// ParseAutoResponseUpdatesFromArgs parses the args to extract the desired AutoResponseUpdate entries. +// The args should be the entire args list. Parsing of the auto-response updates args will start at startIndex. +func ParseAutoResponseUpdatesFromArgs(args []string, startIndex int) ([]*quarantine.AutoResponseUpdate, error) { + iLastArg := len(args) - 1 - startIndex // index of the last arg. + arArgCount := 0 // a count of arguments that have been auto-responses. + arAddrCount := 0 // a count of from_addresses provided for the most recent auto-response. + var lastArArg string // the actual arg string of the last auto-response arg. + var ar quarantine.AutoResponse // the current auto-response. + + var rv []*quarantine.AutoResponseUpdate + + for i, arg := range args[startIndex:] { + newAr, isAr := ParseAutoResponseArg(arg) + // first arg must be an auto-response. + if i == 0 && !isAr { + return nil, fmt.Errorf("invalid arg %d: invalid auto-response: %q", i+startIndex+1, arg) + } + if isAr { + // If not the first arg, there must be at least one address for the previous auto-response. + if i > 0 && arAddrCount == 0 { + return nil, fmt.Errorf("invalid arg %d: no from_address args provided after auto-response %d: %q", i+startIndex+1, arArgCount, lastArArg) + } + // The last argument cannot be an auto-response either. + if i == iLastArg { + // Slightly different message on purpose. Makes it easier to track down the source of an error. + return nil, fmt.Errorf("invalid arg %d: last arg cannot be an auto-response, got: %q", i+startIndex+1, arg) + } + arArgCount += 1 + ar = newAr + lastArArg = arg + arAddrCount = 0 + } else { + arAddrCount += 1 + fromAddr, err := validateAddress(arg, "from_address") + if err != nil { + return nil, fmt.Errorf("unknown arg %d %q: auto-response %d %q: from_address %d: %w", i+startIndex+1, arg, arArgCount, lastArArg, arAddrCount, err) + } + rv = append(rv, &quarantine.AutoResponseUpdate{ + FromAddress: fromAddr, + Response: ar, + }) + } + } + + return rv, nil +} + +// ParseAutoResponseArg converts the provided arg to an AutoResponse enum entry. +// The bool return value is true if parsing was successful. +func ParseAutoResponseArg(arg string) (quarantine.AutoResponse, bool) { + switch strings.ToLower(arg) { + case "accept", "a", "1": + return quarantine.AUTO_RESPONSE_ACCEPT, true + case "decline", "d", "2": + return quarantine.AUTO_RESPONSE_DECLINE, true + case "unspecified", "u", "off", "o", "0": + return quarantine.AUTO_RESPONSE_UNSPECIFIED, true + default: + return quarantine.AUTO_RESPONSE_UNSPECIFIED, false + } +} diff --git a/x/quarantine/client/cli/util_test.go b/x/quarantine/client/cli/util_test.go new file mode 100644 index 0000000000..140f175e83 --- /dev/null +++ b/x/quarantine/client/cli/util_test.go @@ -0,0 +1,328 @@ +package cli + +import ( + "fmt" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" + + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +func TestExampleAddress(t *testing.T) { + // The only thing to really test here is that it's consistent. + // So just do a few known values (known because the actual values + // are logged out then the tests are fixed). + tests := []struct { + name string + exp sdk.AccAddress + }{ + { + name: "", + exp: sdk.AccAddress{ + 227, 176, 196, 66, 152, 252, 28, 20, 154, 251, + 244, 200, 153, 111, 185, 36, 39, 174, 65, 228, + }, + }, + { + name: "addr", + exp: sdk.AccAddress{ + 162, 89, 60, 152, 108, 134, 202, 50, 58, 51, + 157, 119, 129, 204, 4, 187, 47, 209, 90, 195, + }, + }, + { + name: "exampleAddr1", + exp: sdk.AccAddress{ + 199, 131, 86, 61, 89, 233, 25, 212, 30, 112, + 118, 234, 154, 3, 90, 170, 220, 156, 233, 166, + }, + }, + } + + for _, tc := range tests { + name := tc.name + if len(name) == 0 { + name = "empty" + } + t.Run(name, func(t *testing.T) { + act := exampleAddr(tc.name) + t.Log(strings.ReplaceAll(fmt.Sprintf("%v", []byte(act)), " ", ", ")) + assert.Equal(t, tc.exp, act, "exampleAddr(%q) result", tc.name) + }) + } +} + +func TestValidateAddress(t *testing.T) { + tests := []struct { + name string + addr string + argName string + exp string + expErr []string + }{ + { + name: "exampleAddr1", + addr: exampleAddr1.String(), + argName: "does not matter", + exp: exampleAddr1.String(), + }, + { + name: "empty addr", + addr: "", + argName: "this is a field", + exp: "", + expErr: []string{"invalid this is a field:", "invalid address", "empty address string is not allowed"}, + }, + { + name: "bad address", + addr: "bad1reallynotgood", + argName: "something something updog", + exp: "", + expErr: []string{"invalid something something updog", "invalid address", "decoding bech32 failed"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var act string + var err error + testFunc := func() { + act, err = validateAddress(tc.addr, tc.argName) + } + require.NotPanics(t, testFunc, "validateAddress") + AssertErrorContents(t, err, tc.expErr, "validateAddress error") + assert.Equal(t, tc.exp, act, "validateAddress result") + }) + } +} + +func TestParseAutoResponseUpdatesFromArgs(t *testing.T) { + newARE := func(from string, response quarantine.AutoResponse) *quarantine.AutoResponseUpdate { + return &quarantine.AutoResponseUpdate{ + FromAddress: from, + Response: response, + } + } + addr0 := MakeTestAddr("parufa", 0).String() + addr1 := MakeTestAddr("parufa", 1).String() + addr2 := MakeTestAddr("parufa", 2).String() + addr3 := MakeTestAddr("parufa", 3).String() + addr4 := MakeTestAddr("parufa", 4).String() + addr5 := MakeTestAddr("parufa", 5).String() + + tests := []struct { + name string + args []string + startIndex int + exp []*quarantine.AutoResponseUpdate + expErr []string + }{ + { + name: "start 1 not an auto-response", + args: []string{"arg1", addr0}, + startIndex: 1, + expErr: []string{"invalid arg 2", "invalid auto-response", fmt.Sprintf("%q", addr0)}, + }, + { + name: "start 1 two auto-responses in a row", + args: []string{"arg1", "a", "decline", addr0}, + startIndex: 1, + expErr: []string{"invalid arg 3", `no from_address args provided after auto-response 1: "a"`}, + }, + { + name: "start 1 two auto-responses in a row but not first", + args: []string{"arg1", "accept", addr0, "d", "u", addr1}, + startIndex: 1, + expErr: []string{"invalid arg 5", `no from_address args provided after auto-response 2: "d"`}, + }, + { + name: "start 1 ends with auto-response", + args: []string{"arg1", "unspecified", addr0, "accept"}, + startIndex: 1, + expErr: []string{"invalid arg 4", `last arg cannot be an auto-response, got: "accept"`}, + }, + { + name: "start 1 first address is bad", + args: []string{"arg1", "accept", "not1address234567"}, + startIndex: 1, + expErr: []string{ + `unknown arg 3 "not1address234567"`, `auto-response 1 "accept"`, + "from_address 1", "invalid address", "decoding bech32 failed", + }, + }, + { + name: "start 1 bad address in the middle", + args: []string{"arg1", "a", addr0, addr1, "d", addr2, "bad1notgonnadecode", addr3}, + startIndex: 1, + expErr: []string{ + `unknown arg 7 "bad1notgonnadecode"`, `auto-response 2 "d"`, + "from_address 2", "invalid address", "decoding bech32 failed", + }, + }, + { + name: "start 1 auto-response address", + args: []string{"arg1", "decline", addr0}, + startIndex: 1, + exp: []*quarantine.AutoResponseUpdate{ + newARE(addr0, quarantine.AUTO_RESPONSE_DECLINE), + }, + }, + { + name: "start 1 complex", + args: []string{"arg1", "a", addr0, addr1, "u", addr2, "d", addr3, addr4, addr5}, + startIndex: 1, + exp: []*quarantine.AutoResponseUpdate{ + newARE(addr0, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr1, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr2, quarantine.AUTO_RESPONSE_UNSPECIFIED), + newARE(addr3, quarantine.AUTO_RESPONSE_DECLINE), + newARE(addr4, quarantine.AUTO_RESPONSE_DECLINE), + newARE(addr5, quarantine.AUTO_RESPONSE_DECLINE), + }, + }, + // 3 addr + // 3 addr + // 3 ar ar addr + // 3 ar addr ar ar addr + // 3 ar addr ar + // 3 ar bad-addr + // 3 ar addr addr ar addr bad-addr addr + // 3 ar addr addr ar addr ar addr addr addr + { + name: "start 3 not an auto-response", + args: []string{"arg1", "arg2", "arg3", addr0}, + startIndex: 3, + expErr: []string{"invalid arg 4", "invalid auto-response", fmt.Sprintf("%q", addr0)}, + }, + { + name: "start 3 two auto-responses in a row", + args: []string{"arg1", "arg2", "arg3", "a", "decline", addr0}, + startIndex: 3, + expErr: []string{"invalid arg 5", `no from_address args provided after auto-response 1: "a"`}, + }, + { + name: "start 3 two auto-responses in a row but not first", + args: []string{"arg1", "arg2", "arg3", "accept", addr0, "d", "u", addr1}, + startIndex: 3, + expErr: []string{"invalid arg 7", `no from_address args provided after auto-response 2: "d"`}, + }, + { + name: "start 3 ends with auto-response", + args: []string{"arg1", "arg2", "arg3", "unspecified", addr0, "accept"}, + startIndex: 3, + expErr: []string{"invalid arg 6", `last arg cannot be an auto-response, got: "accept"`}, + }, + { + name: "start 3 first address is bad", + args: []string{"arg1", "arg2", "arg3", "accept", "not1address234567"}, + startIndex: 3, + expErr: []string{ + `unknown arg 5 "not1address234567"`, `auto-response 1 "accept"`, + "from_address 1", "invalid address", "decoding bech32 failed", + }, + }, + { + name: "start 3 bad address in the middle", + args: []string{"arg1", "arg2", "arg3", "a", addr0, addr1, "d", addr2, "bad1notgonnadecode", addr3}, + startIndex: 3, + expErr: []string{ + `unknown arg 9 "bad1notgonnadecode"`, `auto-response 2 "d"`, + "from_address 2", "invalid address", "decoding bech32 failed", + }, + }, + { + name: "start 3 auto-response address", + args: []string{"arg1", "arg2", "arg3", "decline", addr0}, + startIndex: 3, + exp: []*quarantine.AutoResponseUpdate{ + newARE(addr0, quarantine.AUTO_RESPONSE_DECLINE), + }, + }, + { + name: "start 3 complex", + args: []string{"arg1", "arg2", "arg3", "a", addr0, addr1, "u", addr2, "d", addr3, addr4, addr5}, + startIndex: 3, + exp: []*quarantine.AutoResponseUpdate{ + newARE(addr0, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr1, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr2, quarantine.AUTO_RESPONSE_UNSPECIFIED), + newARE(addr3, quarantine.AUTO_RESPONSE_DECLINE), + newARE(addr4, quarantine.AUTO_RESPONSE_DECLINE), + newARE(addr5, quarantine.AUTO_RESPONSE_DECLINE), + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var act []*quarantine.AutoResponseUpdate + var err error + testFunc := func() { + act, err = ParseAutoResponseUpdatesFromArgs(tc.args, tc.startIndex) + } + require.NotPanics(t, testFunc, "ParseAutoResponseUpdatesFromArgs") + AssertErrorContents(t, err, tc.expErr, "ParseAutoResponseUpdatesFromArgs error") + assert.Equal(t, tc.exp, act, "ParseAutoResponseUpdatesFromArgs result") + }) + } +} + +func TestParseAutoResponseArg(t *testing.T) { + tests := []struct { + arg string + expAR quarantine.AutoResponse + expB bool + }{ + {arg: "accept", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "ACCEPT", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "Accept", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "aCcePt", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "a", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "A", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "1", expAR: quarantine.AUTO_RESPONSE_ACCEPT, expB: true}, + {arg: "decline", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "DECLINE", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "Decline", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "dEcliNe", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "d", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "D", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "2", expAR: quarantine.AUTO_RESPONSE_DECLINE, expB: true}, + {arg: "unspecified", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "UNSPECIFIED", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "Unspecified", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "uNspecIfiEd", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "u", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "U", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "off", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "OFF", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "Off", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "oFf", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "ofF", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "o", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "O", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "0", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: true}, + {arg: "", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: false}, + {arg: "accepta", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: false}, + {arg: "declined", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: false}, + {arg: "uoff", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: false}, + {arg: "something else", expAR: quarantine.AUTO_RESPONSE_UNSPECIFIED, expB: false}, + } + + for _, tc := range tests { + name := tc.arg + if len(name) == 0 { + name = "empty" + } + t.Run(name, func(t *testing.T) { + actAr, actB := ParseAutoResponseArg(tc.arg) + assert.Equal(t, tc.expAR, actAr, "ParseAutoResponseArg response") + assert.Equal(t, tc.expB, actB, "ParseAutoResponseArg bool") + }) + } +} diff --git a/x/quarantine/client/testutil/cli_test.go b/x/quarantine/client/testutil/cli_test.go new file mode 100644 index 0000000000..3fb9f23836 --- /dev/null +++ b/x/quarantine/client/testutil/cli_test.go @@ -0,0 +1,20 @@ +//go:build norace +// +build norace + +package testutil + +import ( + "testing" + "time" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/testutil/network" +) + +func TestIntegrationTestSuite(t *testing.T) { + cfg := network.DefaultConfig() + cfg.NumValidators = 2 + cfg.TimeoutCommit = 1 * time.Second + suite.Run(t, NewIntegrationTestSuite(cfg)) +} diff --git a/x/quarantine/client/testutil/common_test.go b/x/quarantine/client/testutil/common_test.go new file mode 100644 index 0000000000..e41f5254cf --- /dev/null +++ b/x/quarantine/client/testutil/common_test.go @@ -0,0 +1,121 @@ +package testutil + +import ( + "fmt" + + "github.com/google/uuid" + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + "github.com/cosmos/cosmos-sdk/testutil/network" + sdk "github.com/cosmos/cosmos-sdk/types" + banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" + + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +type IntegrationTestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network + clientCtx client.Context + + commonFlags []string + valAddr sdk.AccAddress +} + +func NewIntegrationTestSuite(cfg network.Config) *IntegrationTestSuite { + return &IntegrationTestSuite{cfg: cfg} +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + s.commonFlags = []string{ + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, s.bondCoins(10).String()), + } + var err error + s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg) + s.Require().NoError(err) + + _, err = s.network.WaitForHeight(1) + s.Require().NoError(err) + + s.clientCtx = s.network.Validators[0].ClientCtx + s.valAddr = s.network.Validators[0].Address +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) stopIfFailed() { + if s.T().Failed() { + s.T().FailNow() + } +} + +// bondCoin creates an sdk.Coin with the bond-denom in the amount provided. +func (s *IntegrationTestSuite) bondCoin(amt int64) sdk.Coin { + return sdk.NewInt64Coin(s.cfg.BondDenom, amt) +} + +// bondCoins creates an sdk.Coins with the bond-denom in the amount provided. +func (s *IntegrationTestSuite) bondCoins(amt int64) sdk.Coins { + return sdk.NewCoins(s.bondCoin(amt)) +} + +// createAndFundAccount creates an account, adding the key to the keyring, funded with the provided amount of bond-denom coins. +func (s *IntegrationTestSuite) createAndFundAccount(index int, bondCoinAmt int64) string { + memberNumber := uuid.New().String() + + info, _, err := s.clientCtx.Keyring.NewMnemonic( + fmt.Sprintf("member%s", memberNumber), + keyring.English, sdk.FullFundraiserPath, + keyring.DefaultBIP39Passphrase, hd.Secp256k1, + ) + s.Require().NoError(err, "NewMnemonic[%d]", index) + + pk, err := info.GetPubKey() + s.Require().NoError(err, "GetPubKey[%d]", index) + + account := sdk.AccAddress(pk.Address()) + + _, err = banktestutil.MsgSendExec( + s.clientCtx, + s.valAddr, + account, + s.bondCoins(bondCoinAmt), + s.commonFlags..., + ) + s.Require().NoError(err, "MsgSendExec[%d]", index) + + return account.String() +} + +// appendCommonFlagsTo adds this suite's common flags to the end of the provided arguments. +func (s *IntegrationTestSuite) appendCommonFlagsTo(args ...string) []string { + return append(args, s.commonFlags...) +} + +// assertErrorContents calls AssertErrorContents using this suite's t. +func (s *IntegrationTestSuite) assertErrorContents(theError error, contains []string, msgAndArgs ...interface{}) bool { + return AssertErrorContents(s.T(), theError, contains, msgAndArgs...) +} + +var _ fmt.Stringer = asStringer("") + +// asStringer is a string that has a String() function on it so that we can provide a string to MsgSendExec. +type asStringer string + +// String implements the Stringer interface. +func (s asStringer) String() string { + return string(s) +} diff --git a/x/quarantine/client/testutil/query_test.go b/x/quarantine/client/testutil/query_test.go new file mode 100644 index 0000000000..a3f0b52f83 --- /dev/null +++ b/x/quarantine/client/testutil/query_test.go @@ -0,0 +1,312 @@ +package testutil + +import ( + "fmt" + + tmcli "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/cosmos/cosmos-sdk/types/query" + banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" + "github.com/cosmos/cosmos-sdk/x/quarantine" + client "github.com/cosmos/cosmos-sdk/x/quarantine/client/cli" +) + +// These tests are initiated by TestIntegrationTestSuite in cli_test.go + +func (s *IntegrationTestSuite) TestQueryQuarantinedFundsCmd() { + addr0 := s.createAndFundAccount(0, 2000) + addr1 := s.createAndFundAccount(0, 2000) + + // Opt addr0 into quarantine. + _, err := cli.ExecTestCLICmd(s.clientCtx, client.TxOptInCmd(), + s.appendCommonFlagsTo(addr0), + ) + s.Require().NoError(err, "TxOptInCmd addr0") + + quarantinedAmount := int64(50) + // Send some funds from 1 to 0 so that there's some quarantined funds to find. + _, err = banktestutil.MsgSendExec(s.clientCtx, + asStringer(addr1), asStringer(addr0), s.bondCoins(quarantinedAmount), + s.commonFlags..., + ) + s.Require().NoError(err, "MsgSendExec 1 -> 0, 50") + + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + newQF := func(to, from string, amt int64) *quarantine.QuarantinedFunds { + return &quarantine.QuarantinedFunds{ + ToAddress: to, + UnacceptedFromAddresses: []string{from}, + Coins: s.bondCoins(amt), + Declined: false, + } + } + + tests := []struct { + name string + args []string + exp *quarantine.QueryQuarantinedFundsResponse + expErr []string + }{ + { + name: "to and from no funds found", + args: []string{addr1, addr0}, + exp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: []*quarantine.QuarantinedFunds{}, + Pagination: nil, + }, + }, + { + name: "to and from funds found", + args: []string{addr0, addr1}, + exp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: []*quarantine.QuarantinedFunds{ + newQF(addr0, addr1, quarantinedAmount), + }, + Pagination: nil, + }, + }, + { + name: "only to no funds found", + args: []string{addr1}, + exp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: []*quarantine.QuarantinedFunds{}, + Pagination: &query.PageResponse{NextKey: nil, Total: 0}, + }, + }, + { + name: "only to funds found", + args: []string{addr0}, + exp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: []*quarantine.QuarantinedFunds{ + newQF(addr0, addr1, quarantinedAmount), + }, + Pagination: &query.PageResponse{NextKey: nil, Total: 0}, + }, + }, + { + name: "no args", + args: nil, + exp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: []*quarantine.QuarantinedFunds{ + newQF(addr0, addr1, quarantinedAmount), + }, + Pagination: &query.PageResponse{NextKey: nil, Total: 0}, + }, + }, + { + name: "bad to address", + args: []string{"what?"}, + expErr: []string{"invalid to_address", "invalid address", "decoding bech32 failed"}, + }, + { + name: "bad from address", + args: []string{addr0, "nope"}, + expErr: []string{"invalid from_address", "invalid address", "decoding bech32 failed"}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.QueryQuarantinedFundsCmd() + args := append(tc.args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + outBz := outBW.Bytes() + s.T().Logf("Output:\n%s", string(outBz)) + s.assertErrorContents(err, tc.expErr, "QueryQuarantinedFundsCmd error") + for _, expErr := range tc.expErr { + s.Assert().Contains(string(outBz), expErr, "QueryQuarantinedFundsCmd output with error") + } + if tc.exp != nil { + act := &quarantine.QueryQuarantinedFundsResponse{} + testFunc := func() { + err = s.clientCtx.Codec.UnmarshalJSON(outBz, act) + } + if s.Assert().NotPanics(testFunc, "UnmarshalJSON on output") { + if s.Assert().NoError(err, "UnmarshalJSON on output") { + s.Assert().ElementsMatch(tc.exp.QuarantinedFunds, act.QuarantinedFunds, "QuarantinedFunds") + s.Assert().Equal(tc.exp.Pagination, act.Pagination, "Pagination") + } + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestQueryIsQuarantinedCmd() { + addr0 := s.createAndFundAccount(0, 2000) + addr1 := s.createAndFundAccount(0, 2000) + + // Opt addr0 into quarantine. + _, err := cli.ExecTestCLICmd(s.clientCtx, client.TxOptInCmd(), + s.appendCommonFlagsTo(addr0), + ) + s.Require().NoError(err, "TxOptInCmd addr0") + + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + tests := []struct { + name string + args []string + exp *quarantine.QueryIsQuarantinedResponse + expErr []string + }{ + { + name: "quarantined addr", + args: []string{addr0}, + exp: &quarantine.QueryIsQuarantinedResponse{IsQuarantined: true}, + }, + { + name: "not quarantined addr", + args: []string{addr1}, + exp: &quarantine.QueryIsQuarantinedResponse{IsQuarantined: false}, + }, + { + name: "bad addr", + args: []string{"invalid1addritisbadbad"}, + expErr: []string{"invalid to_address", "invalid address", "decoding bech32 failed"}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.QueryIsQuarantinedCmd() + args := append(tc.args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "QueryIsQuarantinedCmd error") + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "QueryIsQuarantinedCmd output with error") + } + if tc.exp != nil { + act := &quarantine.QueryIsQuarantinedResponse{} + testFunc := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), act) + } + if s.Assert().NotPanics(testFunc, "UnmarshalJSON on output") { + if s.Assert().NoError(err, "UnmarshalJSON on output") { + s.Assert().Equal(tc.exp, act) + } + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestQueryAutoResponsesCmd() { + addr0 := s.createAndFundAccount(0, 200) + addr1 := s.createAndFundAccount(1, 200) + addr2 := s.createAndFundAccount(2, 200) + + // Set 0 <- 1 to auto-accept. + // Set 0 <- 2 to auto-decline. + _, err := cli.ExecTestCLICmd(s.clientCtx, client.TxUpdateAutoResponsesCmd(), + s.appendCommonFlagsTo(addr0, "accept", addr1, "decline", addr2), + ) + s.Require().NoError(err, "TxUpdateAutoResponsesCmd for setup") + + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + newARE := func(to, from string, response quarantine.AutoResponse) *quarantine.AutoResponseEntry { + return &quarantine.AutoResponseEntry{ + ToAddress: to, + FromAddress: from, + Response: response, + } + } + + tests := []struct { + name string + args []string + exp *quarantine.QueryAutoResponsesResponse + expErr []string + }{ + { + name: "bad to addr", + args: []string{"badnotgood"}, + expErr: []string{"invalid to_address", "invalid address", "decoding bech32 failed"}, + }, + { + name: "bad from addr", + args: []string{addr0, "notgoodbad"}, + expErr: []string{"invalid from_address", "invalid address", "decoding bech32 failed"}, + }, + { + name: "to and from accept", + args: []string{addr0, addr1}, + exp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0, addr1, quarantine.AUTO_RESPONSE_ACCEPT), + }, + Pagination: nil, + }, + }, + { + name: "to and from decline", + args: []string{addr0, addr2}, + exp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0, addr2, quarantine.AUTO_RESPONSE_DECLINE), + }, + Pagination: nil, + }, + }, + { + name: "to and from unspecified", + args: []string{addr2, addr1}, + exp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr2, addr1, quarantine.AUTO_RESPONSE_UNSPECIFIED), + }, + Pagination: nil, + }, + }, + { + name: "only to with results", + args: []string{addr0}, + exp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0, addr1, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr0, addr2, quarantine.AUTO_RESPONSE_DECLINE), + }, + Pagination: &query.PageResponse{NextKey: nil, Total: 0}, + }, + }, + { + name: "only to no results", + args: []string{addr2}, + exp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{}, + Pagination: &query.PageResponse{NextKey: nil, Total: 0}, + }, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.QueryAutoResponsesCmd() + args := append(tc.args, fmt.Sprintf("--%s=json", tmcli.OutputFlag)) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "QueryAutoResponsesCmd error") + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "QueryAutoResponsesCmd output with error") + } + if tc.exp != nil { + act := &quarantine.QueryAutoResponsesResponse{} + testFunc := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), act) + } + if s.Assert().NotPanics(testFunc, "UnmarshalJSON on output") { + if s.Assert().NoError(err, "UnmarshalJSON on output") { + s.Assert().ElementsMatch(tc.exp.AutoResponses, act.AutoResponses, "AutoResponses") + s.Assert().Equal(tc.exp.Pagination, act.Pagination, "Pagination") + } + } + } + }) + } +} diff --git a/x/quarantine/client/testutil/tx_test.go b/x/quarantine/client/testutil/tx_test.go new file mode 100644 index 0000000000..caa33d9cb5 --- /dev/null +++ b/x/quarantine/client/testutil/tx_test.go @@ -0,0 +1,528 @@ +package testutil + +import ( + "fmt" + + tmcli "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" + client "github.com/cosmos/cosmos-sdk/x/quarantine/client/cli" +) + +func (s *IntegrationTestSuite) TestTxOptInCmd() { + addr0 := s.createAndFundAccount(0, 2000) + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + tests := []struct { + name string + args []string + expErr []string + expCode int + }{ + { + name: "empty addr", + args: []string{""}, + expErr: []string{"no to_name_or_address provided"}, + }, + { + name: "bad addr", + args: []string{"somethingelse"}, + expErr: []string{"somethingelse.info: key not found"}, + }, + { + name: "good addr", + args: []string{addr0}, + expCode: 0, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.TxOptInCmd() + cmdFuncName := "TxOptInCmd" + args := append(tc.args, s.commonFlags...) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "%s error", cmdFuncName) + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "%s output with error", cmdFuncName) + } + if len(tc.expErr) == 0 { + var txResp sdk.TxResponse + testFuncUn := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), &txResp) + } + if s.Assert().NotPanics(testFuncUn, "UnmarshalJSON output") { + s.Assert().Equal(tc.expCode, int(txResp.Code), "%s response code", cmdFuncName) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestTxOptOutCmd() { + addr0 := s.createAndFundAccount(0, 2000) + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + tests := []struct { + name string + args []string + expErr []string + expCode int + }{ + { + name: "empty addr", + args: []string{""}, + expErr: []string{"no to_name_or_address provided"}, + }, + { + name: "bad addr", + args: []string{"somethingelse"}, + expErr: []string{"somethingelse.info: key not found"}, + }, + { + name: "good addr", + args: []string{addr0}, + expCode: 0, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.TxOptOutCmd() + cmdFuncName := "TxOptOutCmd" + args := append(tc.args, s.commonFlags...) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "%s error", cmdFuncName) + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "%s output with error", cmdFuncName) + } + if len(tc.expErr) == 0 { + var txResp sdk.TxResponse + testFuncUn := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), &txResp) + } + if s.Assert().NotPanics(testFuncUn, "UnmarshalJSON output") { + s.Assert().Equal(tc.expCode, int(txResp.Code), "%s response code", cmdFuncName) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestTxAcceptCmd() { + addr0 := s.createAndFundAccount(0, 2000) + addr1 := s.createAndFundAccount(1, 2000) + addr2 := s.createAndFundAccount(2, 2000) + addr3 := s.createAndFundAccount(3, 2000) + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + permFlag := "--" + client.FlagPermanent + tests := []struct { + name string + args []string + expErr []string + expCode int + }{ + { + name: "empty to address", + args: []string{"", addr1}, + expErr: []string{"no to_name_or_address provided"}, + }, + { + name: "bad to address", + args: []string{"notgood", addr1}, + expErr: []string{"notgood.info: key not found"}, + }, + { + name: "empty from address 1", + args: []string{addr0, ""}, + expErr: []string{"invalid from_address 1", "invalid address", "empty address string is not allowed"}, + }, + { + name: "bad from address 1", + args: []string{addr0, "stillbad"}, + expErr: []string{"invalid from_address 1", "invalid address", "decoding bech32 failed"}, + }, + { + name: "empty from address 3", + args: []string{addr0, addr1, addr2, ""}, + expErr: []string{"invalid from_address 3", "invalid address", "empty address string is not allowed"}, + }, + { + name: "bad from address 3", + args: []string{addr0, addr1, addr2, "stillbad"}, + expErr: []string{"invalid from_address 3", "invalid address", "decoding bech32 failed"}, + }, + { + name: "one from address", + args: []string{addr0, addr1}, + expCode: 0, + }, + { + name: "two from addresses", + args: []string{addr0, addr1, addr2}, + expCode: 0, + }, + { + name: "three from addresses", + args: []string{addr0, addr1, addr2, addr3}, + expCode: 0, + }, + { + name: "one from address and perm", + args: []string{addr0, addr1, permFlag}, + expCode: 0, + }, + { + name: "two from addresses and perm", + args: []string{addr0, addr1, addr2, permFlag}, + expCode: 0, + }, + { + name: "three from addresses and perm", + args: []string{addr0, addr1, addr2, addr3, permFlag}, + expCode: 0, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.TxAcceptCmd() + cmdFuncName := "TxAcceptCmd" + args := append(tc.args, s.commonFlags...) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "%s error", cmdFuncName) + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "%s output with error", cmdFuncName) + } + if len(tc.expErr) == 0 { + var txResp sdk.TxResponse + testFuncUn := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), &txResp) + } + if s.Assert().NotPanics(testFuncUn, "UnmarshalJSON output") { + s.Assert().Equal(tc.expCode, int(txResp.Code), "%s response code", cmdFuncName) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestTxDeclineCmd() { + addr0 := s.createAndFundAccount(0, 2000) + addr1 := s.createAndFundAccount(1, 2000) + addr2 := s.createAndFundAccount(2, 2000) + addr3 := s.createAndFundAccount(3, 2000) + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + permFlag := "--" + client.FlagPermanent + tests := []struct { + name string + args []string + expErr []string + expCode int + }{ + { + name: "empty to address", + args: []string{"", addr1}, + expErr: []string{"no to_name_or_address provided"}, + }, + { + name: "bad to address", + args: []string{"notgood", addr1}, + expErr: []string{"notgood.info: key not found"}, + }, + { + name: "empty from address 1", + args: []string{addr0, ""}, + expErr: []string{"invalid from_address 1", "invalid address", "empty address string is not allowed"}, + }, + { + name: "bad from address 1", + args: []string{addr0, "stillbad"}, + expErr: []string{"invalid from_address 1", "invalid address", "decoding bech32 failed"}, + }, + { + name: "empty from address 3", + args: []string{addr0, addr1, addr2, ""}, + expErr: []string{"invalid from_address 3", "invalid address", "empty address string is not allowed"}, + }, + { + name: "bad from address 3", + args: []string{addr0, addr1, addr2, "stillbad"}, + expErr: []string{"invalid from_address 3", "invalid address", "decoding bech32 failed"}, + }, + { + name: "one from address", + args: []string{addr0, addr1}, + expCode: 0, + }, + { + name: "two from addresses", + args: []string{addr0, addr1, addr2}, + expCode: 0, + }, + { + name: "three from addresses", + args: []string{addr0, addr1, addr2, addr3}, + expCode: 0, + }, + { + name: "one from address and perm", + args: []string{addr0, addr1, permFlag}, + expCode: 0, + }, + { + name: "two from addresses and perm", + args: []string{addr0, addr1, addr2, permFlag}, + expCode: 0, + }, + { + name: "three from addresses and perm", + args: []string{addr0, addr1, addr2, addr3, permFlag}, + expCode: 0, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.TxDeclineCmd() + cmdFuncName := "TxDeclineCmd" + args := append(tc.args, s.commonFlags...) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "%s error", cmdFuncName) + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "%s output with error", cmdFuncName) + } + if len(tc.expErr) == 0 { + var txResp sdk.TxResponse + testFuncUn := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), &txResp) + } + if s.Assert().NotPanics(testFuncUn, "UnmarshalJSON output") { + s.Assert().Equal(tc.expCode, int(txResp.Code), "%s response code", cmdFuncName) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestTxUpdateAutoResponsesCmd() { + addr0 := s.createAndFundAccount(0, 2000) + addr1 := s.createAndFundAccount(1, 2000) + addr2 := s.createAndFundAccount(2, 2000) + addr3 := s.createAndFundAccount(3, 2000) + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + tests := []struct { + name string + args []string + expErr []string + expCode int + }{ + { + name: "empty to address", + args: []string{"", "accept", addr1}, + expErr: []string{"no to_name_or_address provided"}, + }, + { + name: "bad to address", + args: []string{"naughty", "accept", addr1}, + expErr: []string{"naughty.info: key not found"}, + }, + { + name: "bad from addr", + args: []string{addr0, "accept", "notokay"}, + expErr: []string{ + `unknown arg 3 "notokay"`, `auto-response 1 "accept"`, + "from_address 1", "invalid address", "decoding bech32 failed", + }, + }, + { + name: "bad auto-response", + args: []string{addr0, "not-a-resp", addr1}, + expErr: []string{"invalid arg 2", "invalid auto-response", `"not-a-resp"`}, + }, + { + name: "simply good", + args: []string{addr0, "decline", addr1}, + expCode: 0, + }, + { + name: "complexly good", + args: []string{addr0, "decline", addr2, addr3, "o", addr1}, + expCode: 0, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + cmd := client.TxUpdateAutoResponsesCmd() + cmdFuncName := "TxUpdateAutoResponsesCmd" + args := append(tc.args, s.commonFlags...) + outBW, err := cli.ExecTestCLICmd(s.clientCtx, cmd, args) + out := outBW.String() + s.T().Logf("Output:\n%s", out) + s.assertErrorContents(err, tc.expErr, "%s error", cmdFuncName) + for _, expErr := range tc.expErr { + s.Assert().Contains(out, expErr, "%s output with error", cmdFuncName) + } + if len(tc.expErr) == 0 { + var txResp sdk.TxResponse + testFuncUn := func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), &txResp) + } + if s.Assert().NotPanics(testFuncUn, "UnmarshalJSON output") { + s.Assert().Equal(tc.expCode, int(txResp.Code), "%s response code", cmdFuncName) + } + } + }) + } +} + +func (s *IntegrationTestSuite) TestSendAndAcceptQuarantinedFunds() { + toAddr := s.createAndFundAccount(0, 2000) + fromAddr1 := s.createAndFundAccount(1, 2000) + fromAddr2 := s.createAndFundAccount(2, 2000) + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + amt1 := int64(50) + amt2 := int64(75) + expToAddrAmt := 2000 + amt1 + amt2 - 20 + expFromAddr1Amt := 2000 - amt1 - 10 + expFromAddr2Amt := 2000 - amt2 - 10 + + asJSONFlag := fmt.Sprintf("--%s=json", tmcli.OutputFlag) + + s.Run("opt toAddr into quarantine", func() { + outBW, err := cli.ExecTestCLICmd(s.clientCtx, client.TxOptInCmd(), s.appendCommonFlagsTo(toAddr)) + s.T().Logf("TxOptInCmd Output:\n%s", outBW.String()) + s.Require().NoError(err, "TxOptInCmd error") + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + outBW, err = cli.ExecTestCLICmd(s.clientCtx, client.QueryIsQuarantinedCmd(), []string{toAddr, asJSONFlag}) + out := outBW.String() + s.T().Logf("QueryIsQuarantinedCmd Output:\n%s", out) + s.Require().NoError(err, "QueryIsQuarantinedCmd error") + resp := &quarantine.QueryIsQuarantinedResponse{} + s.Require().NotPanics(func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), resp) + }) + s.Require().NoError(err, "UnmarshalJSON QueryIsQuarantinedResponse") + s.Require().True(resp.IsQuarantined, "IsQuarantined") + }) + + s.stopIfFailed() + + s.Run("do two sends from different addresses", func() { + outBW, err := banktestutil.MsgSendExec(s.clientCtx, + asStringer(fromAddr1), asStringer(toAddr), s.bondCoins(amt1), + s.commonFlags..., + ) + s.T().Logf("MsgSendExec 1 Output:\n%s", outBW.String()) + s.Require().NoError(err, "MsgSendExec 1") + outBW, err = banktestutil.MsgSendExec(s.clientCtx, + asStringer(fromAddr2), asStringer(toAddr), s.bondCoins(amt2), + s.commonFlags..., + ) + s.T().Logf("MsgSendExec 2 Output:\n%s", outBW.String()) + s.Require().NoError(err, "MsgSendExec 2") + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + expFunds := []*quarantine.QuarantinedFunds{ + { + ToAddress: toAddr, + UnacceptedFromAddresses: []string{fromAddr1}, + Coins: s.bondCoins(amt1), + Declined: false, + }, + { + ToAddress: toAddr, + UnacceptedFromAddresses: []string{fromAddr2}, + Coins: s.bondCoins(amt2), + Declined: false, + }, + } + outBW, err = cli.ExecTestCLICmd(s.clientCtx, client.QueryQuarantinedFundsCmd(), []string{toAddr, asJSONFlag}) + out := outBW.String() + s.T().Logf("QueryQuarantinedFundsCmd Output:\n%s", out) + s.Require().NoError(err, "QueryQuarantinedFundsCmd error") + resp := &quarantine.QueryQuarantinedFundsResponse{} + s.Require().NotPanics(func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), resp) + }) + s.Require().NoError(err, "UnmarshalJSON QueryQuarantinedFundsResponse") + s.Require().ElementsMatch(expFunds, resp.QuarantinedFunds, "QuarantinedFunds A: expected, B: actual") + }) + + s.stopIfFailed() + + s.Run("accept the quarantined funds", func() { + outBW, err := cli.ExecTestCLICmd(s.clientCtx, client.TxAcceptCmd(), s.appendCommonFlagsTo(toAddr, fromAddr2, fromAddr1)) + s.T().Logf("TxAcceptCmd Output:\n%s", outBW.String()) + s.Require().NoError(err, "TxAcceptCmd error") + s.Require().NoError(s.network.WaitForNextBlock(), "WaitForNextBlock") + + outBW, err = cli.ExecTestCLICmd(s.clientCtx, client.QueryQuarantinedFundsCmd(), []string{toAddr, asJSONFlag}) + out := outBW.String() + s.T().Logf("QueryQuarantinedFundsCmd Output:\n%s", out) + s.Require().NoError(err, "QueryQuarantinedFundsCmd error") + resp := &quarantine.QueryQuarantinedFundsResponse{} + s.Require().NotPanics(func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), resp) + }) + s.Require().NoError(err, "UnmarshalJSON QueryQuarantinedFundsResponse") + s.Require().Empty(resp.QuarantinedFunds, "QuarantinedFunds") + }) + + s.stopIfFailed() + + tests := []struct { + name string + addr string + exp sdk.Coins + }{ + { + name: "final toAddr balance", + addr: toAddr, + exp: s.bondCoins(expToAddrAmt), + }, + { + name: "final fromAddr1 balance", + addr: fromAddr1, + exp: s.bondCoins(expFromAddr1Amt), + }, + { + name: "final fromAddr1 balance", + addr: fromAddr2, + exp: s.bondCoins(expFromAddr2Amt), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + outBW, err := banktestutil.QueryBalancesExec(s.clientCtx, asStringer(tc.addr), asJSONFlag) + out := outBW.String() + s.T().Logf("QueryBalancesExec Output:\n%s", out) + s.Require().NoError(err, "QueryBalancesExec error") + resp := &banktypes.QueryAllBalancesResponse{} + s.Require().NotPanics(func() { + err = s.clientCtx.Codec.UnmarshalJSON([]byte(out), resp) + }) + s.Require().NoError(err, "UnmarshalJSON QueryAllBalancesResponse") + s.Require().Equal(tc.exp, resp.Balances, "Balances") + }) + } +} diff --git a/x/quarantine/codec.go b/x/quarantine/codec.go new file mode 100644 index 0000000000..c52e954984 --- /dev/null +++ b/x/quarantine/codec.go @@ -0,0 +1,55 @@ +package quarantine + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/legacy" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" +) + +// RegisterLegacyAminoCodec registers all the necessary types and interfaces for the +// governance module. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + legacy.RegisterAminoMsg(cdc, &MsgOptIn{}, "cosmos-sdk/MsgQuarantineOptIn") + legacy.RegisterAminoMsg(cdc, &MsgOptOut{}, "cosmos-sdk/MsgQuarantineOptOut") + legacy.RegisterAminoMsg(cdc, &MsgAccept{}, "cosmos-sdk/MsgQuarantineAccept") + legacy.RegisterAminoMsg(cdc, &MsgDecline{}, "cosmos-sdk/MsgQuarantineDecline") + legacy.RegisterAminoMsg(cdc, &MsgUpdateAutoResponses{}, "cosmos-sdk/MsgUpdateQuarantineAutoResp") +} + +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgOptIn{}, + &MsgOptOut{}, + &MsgAccept{}, + &MsgDecline{}, + &MsgUpdateAutoResponses{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + amino = codec.NewLegacyAmino() + + // ModuleCdc references the global x/quarantine module codec. Note, the codec should + // ONLY be used in certain instances of tests and for JSON encoding as Amino is + // still used for that purpose. + // + // The actual codec used for serialization should be provided to x/quarantine and + // defined at the application level. + ModuleCdc = codec.NewAminoCodec(amino) +) + +func init() { + RegisterLegacyAminoCodec(amino) + cryptocodec.RegisterCrypto(amino) + sdk.RegisterLegacyAminoCodec(amino) + + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + RegisterLegacyAminoCodec(authzcodec.Amino) +} diff --git a/x/quarantine/errors/errors.go b/x/quarantine/errors/errors.go new file mode 100644 index 0000000000..25fffc66e4 --- /dev/null +++ b/x/quarantine/errors/errors.go @@ -0,0 +1,8 @@ +package errors + +import "cosmossdk.io/errors" + +// quarantineCodespace is the codespace for all errors defined in quarantine package +const quarantineCodespace = "quarantine" + +var ErrInvalidValue = errors.Register(quarantineCodespace, 2, "invalid value") diff --git a/x/quarantine/events.pb.go b/x/quarantine/events.pb.go new file mode 100644 index 0000000000..bbff480e7f --- /dev/null +++ b/x/quarantine/events.pb.go @@ -0,0 +1,969 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/quarantine/v1beta1/events.proto + +package quarantine + +import ( + 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/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// EventOptIn is an event emitted when an address opts into quarantine. +type EventOptIn struct { + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` +} + +func (m *EventOptIn) Reset() { *m = EventOptIn{} } +func (m *EventOptIn) String() string { return proto.CompactTextString(m) } +func (*EventOptIn) ProtoMessage() {} +func (*EventOptIn) Descriptor() ([]byte, []int) { + return fileDescriptor_33c74f079d23a045, []int{0} +} +func (m *EventOptIn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventOptIn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventOptIn.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 *EventOptIn) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventOptIn.Merge(m, src) +} +func (m *EventOptIn) XXX_Size() int { + return m.Size() +} +func (m *EventOptIn) XXX_DiscardUnknown() { + xxx_messageInfo_EventOptIn.DiscardUnknown(m) +} + +var xxx_messageInfo_EventOptIn proto.InternalMessageInfo + +func (m *EventOptIn) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +// EventOptOut is an event emitted when an address opts out of quarantine. +type EventOptOut struct { + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` +} + +func (m *EventOptOut) Reset() { *m = EventOptOut{} } +func (m *EventOptOut) String() string { return proto.CompactTextString(m) } +func (*EventOptOut) ProtoMessage() {} +func (*EventOptOut) Descriptor() ([]byte, []int) { + return fileDescriptor_33c74f079d23a045, []int{1} +} +func (m *EventOptOut) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventOptOut) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventOptOut.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 *EventOptOut) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventOptOut.Merge(m, src) +} +func (m *EventOptOut) XXX_Size() int { + return m.Size() +} +func (m *EventOptOut) XXX_DiscardUnknown() { + xxx_messageInfo_EventOptOut.DiscardUnknown(m) +} + +var xxx_messageInfo_EventOptOut proto.InternalMessageInfo + +func (m *EventOptOut) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +// EventFundsQuarantined is an event emitted when funds are quarantined. +type EventFundsQuarantined struct { + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` +} + +func (m *EventFundsQuarantined) Reset() { *m = EventFundsQuarantined{} } +func (m *EventFundsQuarantined) String() string { return proto.CompactTextString(m) } +func (*EventFundsQuarantined) ProtoMessage() {} +func (*EventFundsQuarantined) Descriptor() ([]byte, []int) { + return fileDescriptor_33c74f079d23a045, []int{2} +} +func (m *EventFundsQuarantined) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventFundsQuarantined) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventFundsQuarantined.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 *EventFundsQuarantined) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventFundsQuarantined.Merge(m, src) +} +func (m *EventFundsQuarantined) XXX_Size() int { + return m.Size() +} +func (m *EventFundsQuarantined) XXX_DiscardUnknown() { + xxx_messageInfo_EventFundsQuarantined.DiscardUnknown(m) +} + +var xxx_messageInfo_EventFundsQuarantined proto.InternalMessageInfo + +func (m *EventFundsQuarantined) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *EventFundsQuarantined) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +// EventFundsReleased is an event emitted when quarantined funds are accepted and released. +type EventFundsReleased struct { + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` +} + +func (m *EventFundsReleased) Reset() { *m = EventFundsReleased{} } +func (m *EventFundsReleased) String() string { return proto.CompactTextString(m) } +func (*EventFundsReleased) ProtoMessage() {} +func (*EventFundsReleased) Descriptor() ([]byte, []int) { + return fileDescriptor_33c74f079d23a045, []int{3} +} +func (m *EventFundsReleased) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventFundsReleased) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventFundsReleased.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 *EventFundsReleased) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventFundsReleased.Merge(m, src) +} +func (m *EventFundsReleased) XXX_Size() int { + return m.Size() +} +func (m *EventFundsReleased) XXX_DiscardUnknown() { + xxx_messageInfo_EventFundsReleased.DiscardUnknown(m) +} + +var xxx_messageInfo_EventFundsReleased proto.InternalMessageInfo + +func (m *EventFundsReleased) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *EventFundsReleased) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +func init() { + proto.RegisterType((*EventOptIn)(nil), "cosmos.quarantine.v1beta1.EventOptIn") + proto.RegisterType((*EventOptOut)(nil), "cosmos.quarantine.v1beta1.EventOptOut") + proto.RegisterType((*EventFundsQuarantined)(nil), "cosmos.quarantine.v1beta1.EventFundsQuarantined") + proto.RegisterType((*EventFundsReleased)(nil), "cosmos.quarantine.v1beta1.EventFundsReleased") +} + +func init() { + proto.RegisterFile("cosmos/quarantine/v1beta1/events.proto", fileDescriptor_33c74f079d23a045) +} + +var fileDescriptor_33c74f079d23a045 = []byte{ + // 322 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4b, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x2f, 0x2c, 0x4d, 0x2c, 0x4a, 0xcc, 0x2b, 0xc9, 0xcc, 0x4b, 0xd5, 0x2f, 0x33, + 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x2d, 0x4b, 0xcd, 0x2b, 0x29, 0xd6, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0x92, 0x84, 0xa8, 0xd3, 0x43, 0xa8, 0xd3, 0x83, 0xaa, 0x93, 0x92, 0x83, 0x1a, + 0x91, 0x94, 0x58, 0x8c, 0xd0, 0x9c, 0x9c, 0x9f, 0x99, 0x07, 0xd1, 0x2a, 0x05, 0xd5, 0x1a, 0x0f, + 0xe6, 0xe9, 0x43, 0xcd, 0x81, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x43, 0xc4, 0x41, 0x2c, 0x88, + 0xa8, 0x92, 0x2b, 0x17, 0x97, 0x2b, 0xc8, 0x6e, 0xff, 0x82, 0x12, 0xcf, 0x3c, 0x21, 0x73, 0x2e, + 0xae, 0x92, 0xfc, 0xf8, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, 0x46, 0x05, 0x46, 0x0d, + 0x4e, 0x27, 0x89, 0x4b, 0x5b, 0x74, 0x45, 0xa0, 0x26, 0x39, 0x42, 0x64, 0x82, 0x4b, 0x8a, 0x32, + 0xf3, 0xd2, 0x83, 0x38, 0x4b, 0xf2, 0xa1, 0x02, 0x4a, 0x6e, 0x5c, 0xdc, 0x30, 0x63, 0xfc, 0x4b, + 0x4b, 0xc8, 0x37, 0x67, 0x33, 0x23, 0x97, 0x28, 0xd8, 0x20, 0xb7, 0xd2, 0xbc, 0x94, 0xe2, 0x40, + 0x78, 0x00, 0xa4, 0x90, 0x6d, 0xa4, 0x50, 0x22, 0x17, 0x2b, 0x28, 0x80, 0x8a, 0x25, 0x98, 0x14, + 0x98, 0x35, 0xb8, 0x8d, 0x24, 0xf5, 0xa0, 0x1a, 0x40, 0x41, 0x08, 0x0b, 0x57, 0x3d, 0xe7, 0xfc, + 0xcc, 0x3c, 0x27, 0x83, 0x13, 0xf7, 0xe4, 0x19, 0x56, 0xdd, 0x97, 0xd7, 0x48, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0x85, 0x06, 0x21, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0xd6, 0x2f, + 0xa9, 0x2c, 0x48, 0x2d, 0x06, 0x6b, 0x28, 0x0e, 0x82, 0x98, 0xac, 0xb4, 0x81, 0x91, 0x4b, 0x08, + 0xe1, 0xea, 0xa0, 0xd4, 0x9c, 0xd4, 0xc4, 0xe2, 0xc1, 0xed, 0x64, 0x27, 0xe7, 0x13, 0x8f, 0xe4, + 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, + 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0xc4, 0x6b, 0x54, 0x05, 0x52, 0xea, 0x4d, 0x62, + 0x03, 0xa7, 0x21, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x10, 0x51, 0x65, 0x46, 0xd9, 0x02, + 0x00, 0x00, +} + +func (m *EventOptIn) 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 *EventOptIn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventOptIn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventOptOut) 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 *EventOptOut) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventOptOut) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventFundsQuarantined) 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 *EventFundsQuarantined) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventFundsQuarantined) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventFundsReleased) 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 *EventFundsReleased) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventFundsReleased) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintEvents(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintEvents(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { + offset -= sovEvents(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *EventOptIn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + return n +} + +func (m *EventOptOut) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + return n +} + +func (m *EventFundsQuarantined) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func (m *EventFundsReleased) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *EventOptIn) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventOptIn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventOptIn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventOptOut) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventOptOut: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventOptOut: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventFundsQuarantined) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventFundsQuarantined: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventFundsQuarantined: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventFundsReleased) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: EventFundsReleased: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventFundsReleased: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipEvents(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowEvents + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthEvents + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupEvents + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthEvents + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthEvents = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupEvents = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/quarantine/expected_keepers.go b/x/quarantine/expected_keepers.go new file mode 100644 index 0000000000..08468b3919 --- /dev/null +++ b/x/quarantine/expected_keepers.go @@ -0,0 +1,22 @@ +package quarantine + +import ( + 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" +) + +// AccountKeeper defines the account/auth functionality needed from within the quarantine module. +type AccountKeeper interface { + NewAccount(sdk.Context, authtypes.AccountI) authtypes.AccountI + GetAccount(sdk.Context, sdk.AccAddress) authtypes.AccountI + SetAccount(sdk.Context, authtypes.AccountI) +} + +// BankKeeper defines the bank functionality needed from within the quarantine module. +type BankKeeper interface { + AppendSendRestriction(restriction banktypes.SendRestrictionFn) + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins +} diff --git a/x/quarantine/export_test.go b/x/quarantine/export_test.go new file mode 100644 index 0000000000..7f2039b218 --- /dev/null +++ b/x/quarantine/export_test.go @@ -0,0 +1,12 @@ +package quarantine + +// This file is available only to unit tests and houses functions for doing +// things with private keeper package stuff. + +// Expose some private functions so that they can be unit tested. +var ( + ContainsAddress = containsAddress + FindAddresses = findAddresses + ContainsSuffix = containsSuffix + CreateRecordSuffix = createRecordSuffix +) diff --git a/x/quarantine/genesis.go b/x/quarantine/genesis.go new file mode 100644 index 0000000000..9f2dfc3232 --- /dev/null +++ b/x/quarantine/genesis.go @@ -0,0 +1,41 @@ +package quarantine + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// Validate performs basic validation of genesis data returning an error for any failed validation criteria. +func (gs GenesisState) Validate() error { + for i, addr := range gs.QuarantinedAddresses { + if _, err := sdk.AccAddressFromBech32(addr); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid quarantined address[%d]: %v", i, err) + } + } + for i, resp := range gs.AutoResponses { + if err := resp.Validate(); err != nil { + return errors.Wrapf(err, "invalid quarantine auto response entry[%d]", i) + } + } + for i, funds := range gs.QuarantinedFunds { + if err := funds.Validate(); err != nil { + return errors.Wrapf(err, "invalid quarantined funds[%d]", i) + } + } + return nil +} + +// NewGenesisState creates a new genesis state for the quarantine module. +func NewGenesisState(quarantinedAddresses []string, autoResponses []*AutoResponseEntry, funds []*QuarantinedFunds) *GenesisState { + return &GenesisState{ + QuarantinedAddresses: quarantinedAddresses, + AutoResponses: autoResponses, + QuarantinedFunds: funds, + } +} + +// DefaultGenesisState returns a default quarantine module genesis state. +func DefaultGenesisState() *GenesisState { + return NewGenesisState(nil, nil, nil) +} diff --git a/x/quarantine/genesis.pb.go b/x/quarantine/genesis.pb.go new file mode 100644 index 0000000000..c17519d745 --- /dev/null +++ b/x/quarantine/genesis.pb.go @@ -0,0 +1,459 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/quarantine/v1beta1/genesis.proto + +package quarantine + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the quarantine module's genesis state. +type GenesisState struct { + // quarantined_addresses defines account addresses that are opted into quarantine. + QuarantinedAddresses []string `protobuf:"bytes,1,rep,name=quarantined_addresses,json=quarantinedAddresses,proto3" json:"quarantined_addresses,omitempty"` + // auto_responses defines the quarantine auto-responses for addresses. + AutoResponses []*AutoResponseEntry `protobuf:"bytes,2,rep,name=auto_responses,json=autoResponses,proto3" json:"auto_responses,omitempty"` + // quarantined_funds defines funds that are quarantined. + QuarantinedFunds []*QuarantinedFunds `protobuf:"bytes,3,rep,name=quarantined_funds,json=quarantinedFunds,proto3" json:"quarantined_funds,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_1a60633c09654351, []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) GetQuarantinedAddresses() []string { + if m != nil { + return m.QuarantinedAddresses + } + return nil +} + +func (m *GenesisState) GetAutoResponses() []*AutoResponseEntry { + if m != nil { + return m.AutoResponses + } + return nil +} + +func (m *GenesisState) GetQuarantinedFunds() []*QuarantinedFunds { + if m != nil { + return m.QuarantinedFunds + } + return nil +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "cosmos.quarantine.v1beta1.GenesisState") +} + +func init() { + proto.RegisterFile("cosmos/quarantine/v1beta1/genesis.proto", fileDescriptor_1a60633c09654351) +} + +var fileDescriptor_1a60633c09654351 = []byte{ + // 300 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4f, 0xce, 0x2f, 0xce, + 0xcd, 0x2f, 0xd6, 0x2f, 0x2c, 0x4d, 0x2c, 0x4a, 0xcc, 0x2b, 0xc9, 0xcc, 0x4b, 0xd5, 0x2f, 0x33, + 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, + 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x84, 0x28, 0xd4, 0x43, 0x28, 0xd4, 0x83, 0x2a, 0x94, 0xd2, 0xc2, + 0x6d, 0x06, 0x92, 0x6a, 0xb0, 0x31, 0x52, 0x50, 0x63, 0xe2, 0xc1, 0x3c, 0x7d, 0xa8, 0x99, 0x10, + 0x29, 0x91, 0xf4, 0xfc, 0xf4, 0x7c, 0x88, 0x38, 0x88, 0x05, 0x11, 0x55, 0xea, 0x61, 0xe2, 0xe2, + 0x71, 0x87, 0xb8, 0x24, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x97, 0x4b, 0x14, 0x61, 0x6a, 0x4a, + 0x7c, 0x62, 0x4a, 0x4a, 0x51, 0x6a, 0x71, 0x71, 0x6a, 0xb1, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0xa7, + 0x93, 0xc4, 0xa5, 0x2d, 0xba, 0x22, 0x50, 0x73, 0x1d, 0x21, 0x72, 0xc1, 0x25, 0x45, 0x99, 0x79, + 0xe9, 0x41, 0x22, 0x48, 0xda, 0x1c, 0x61, 0xba, 0x84, 0x82, 0xb9, 0xf8, 0x12, 0x4b, 0x4b, 0xf2, + 0xe3, 0x8b, 0x52, 0x8b, 0x0b, 0xf2, 0xf3, 0x40, 0xe6, 0x30, 0x29, 0x30, 0x6b, 0x70, 0x1b, 0xe9, + 0xe8, 0xe1, 0xf4, 0xb0, 0x9e, 0x63, 0x69, 0x49, 0x7e, 0x10, 0x54, 0xbd, 0x6b, 0x5e, 0x49, 0x51, + 0x65, 0x10, 0x6f, 0x22, 0x92, 0x50, 0xb1, 0x50, 0x04, 0x97, 0x20, 0xb2, 0x1b, 0xd3, 0x4a, 0xf3, + 0x52, 0x8a, 0x25, 0x98, 0xc1, 0xe6, 0x6a, 0xe3, 0x31, 0x37, 0x10, 0xa1, 0xc7, 0x0d, 0xa4, 0x25, + 0x48, 0xa0, 0x10, 0x4d, 0xc4, 0xc9, 0xf9, 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, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xa1, 0xe1, 0x0a, 0xa5, + 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x2b, 0x90, 0xa2, 0x22, 0x89, 0x0d, 0x1c, 0xb4, 0xc6, 0x80, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xa3, 0xc7, 0x7f, 0xa7, 0xfd, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.QuarantinedFunds) > 0 { + for iNdEx := len(m.QuarantinedFunds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.QuarantinedFunds[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.AutoResponses) > 0 { + for iNdEx := len(m.AutoResponses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AutoResponses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.QuarantinedAddresses) > 0 { + for iNdEx := len(m.QuarantinedAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.QuarantinedAddresses[iNdEx]) + copy(dAtA[i:], m.QuarantinedAddresses[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.QuarantinedAddresses[iNdEx]))) + 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 + if len(m.QuarantinedAddresses) > 0 { + for _, s := range m.QuarantinedAddresses { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.AutoResponses) > 0 { + for _, e := range m.AutoResponses { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.QuarantinedFunds) > 0 { + for _, e := range m.QuarantinedFunds { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuarantinedAddresses", 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.QuarantinedAddresses = append(m.QuarantinedAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AutoResponses", 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.AutoResponses = append(m.AutoResponses, &AutoResponseEntry{}) + if err := m.AutoResponses[len(m.AutoResponses)-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 QuarantinedFunds", 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.QuarantinedFunds = append(m.QuarantinedFunds, &QuarantinedFunds{}) + if err := m.QuarantinedFunds[len(m.QuarantinedFunds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/quarantine/genesis_test.go b/x/quarantine/genesis_test.go new file mode 100644 index 0000000000..fac0d97131 --- /dev/null +++ b/x/quarantine/genesis_test.go @@ -0,0 +1,257 @@ +package quarantine_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + . "github.com/cosmos/cosmos-sdk/x/quarantine" + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +func TestGenesisState_Validate(t *testing.T) { + testAddr0 := MakeTestAddr("gsv", 0).String() + testAddr1 := MakeTestAddr("gsv", 1).String() + badAddr := "this1addressisnaughty" + + goodAutoResponse := &AutoResponseEntry{ + ToAddress: testAddr0, + FromAddress: testAddr1, + Response: AUTO_RESPONSE_ACCEPT, + } + badAutoResponse := &AutoResponseEntry{ + ToAddress: testAddr0, + FromAddress: testAddr1, + Response: -10, + } + + goodQuarantinedFunds := &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + } + badQuarantinedFunds := &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerBad(), + Declined: false, + } + + tests := []struct { + name string + gs *GenesisState + expErrs []string + }{ + { + name: "control", + gs: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{goodAutoResponse, goodAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{goodQuarantinedFunds, goodQuarantinedFunds}, + }, + expErrs: nil, + }, + { + name: "empty", + gs: &GenesisState{}, + expErrs: nil, + }, + { + name: "bad first addr", + gs: &GenesisState{ + QuarantinedAddresses: []string{badAddr, testAddr1}, + AutoResponses: []*AutoResponseEntry{goodAutoResponse, goodAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{goodQuarantinedFunds, goodQuarantinedFunds}, + }, + expErrs: []string{"invalid quarantined address[0]"}, + }, + { + name: "bad second addr", + gs: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, badAddr}, + AutoResponses: []*AutoResponseEntry{goodAutoResponse, goodAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{goodQuarantinedFunds, goodQuarantinedFunds}, + }, + expErrs: []string{"invalid quarantined address[1]"}, + }, + { + name: "bad first auto response", + gs: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{badAutoResponse, goodAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{goodQuarantinedFunds, goodQuarantinedFunds}, + }, + expErrs: []string{"invalid quarantine auto response entry[0]"}, + }, + { + name: "bad second auto response", + gs: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{goodAutoResponse, badAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{goodQuarantinedFunds, goodQuarantinedFunds}, + }, + expErrs: []string{"invalid quarantine auto response entry[1]"}, + }, + { + name: "bad first quarantined funds", + gs: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{goodAutoResponse, goodAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{badQuarantinedFunds, goodQuarantinedFunds}, + }, + expErrs: []string{"invalid quarantined funds[0]"}, + }, + { + name: "bad second quarantined funds", + gs: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{goodAutoResponse, goodAutoResponse}, + QuarantinedFunds: []*QuarantinedFunds{goodQuarantinedFunds, badQuarantinedFunds}, + }, + expErrs: []string{"invalid quarantined funds[1]"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + orig := MakeCopyOfGenesisState(tc.gs) + var err error + testFunc := func() { + err = tc.gs.Validate() + } + assert.NotPanics(t, testFunc, "GenesisState.Validate()") + AssertErrorContents(t, err, tc.expErrs, "Validate") + assert.Equal(t, orig, tc.gs, "GenesisState before and after Validate") + }) + } +} + +func TestNewGenesisState(t *testing.T) { + testAddr0 := MakeTestAddr("ngs", 0).String() + testAddr1 := MakeTestAddr("ngs", 1).String() + + autoResponse := &AutoResponseEntry{ + ToAddress: testAddr0, + FromAddress: testAddr1, + Response: AUTO_RESPONSE_ACCEPT, + } + + quarantinedFunds := &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + } + + tests := []struct { + name string + addrs []string + ars []*AutoResponseEntry + qfs []*QuarantinedFunds + exp *GenesisState + }{ + { + name: "control", + addrs: []string{testAddr0, testAddr1}, + ars: []*AutoResponseEntry{autoResponse, autoResponse}, + qfs: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + exp: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{autoResponse, autoResponse}, + QuarantinedFunds: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + }, + }, + { + name: "nil addrs", + addrs: nil, + ars: []*AutoResponseEntry{autoResponse, autoResponse}, + qfs: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + exp: &GenesisState{ + QuarantinedAddresses: nil, + AutoResponses: []*AutoResponseEntry{autoResponse, autoResponse}, + QuarantinedFunds: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + }, + }, + { + name: "empty addrs", + addrs: []string{}, + ars: []*AutoResponseEntry{autoResponse, autoResponse}, + qfs: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + exp: &GenesisState{ + QuarantinedAddresses: []string{}, + AutoResponses: []*AutoResponseEntry{autoResponse, autoResponse}, + QuarantinedFunds: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + }, + }, + { + name: "nil auto responses", + addrs: []string{testAddr0, testAddr1}, + ars: nil, + qfs: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + exp: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: nil, + QuarantinedFunds: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + }, + }, + { + name: "empty auto responses", + addrs: []string{testAddr0, testAddr1}, + ars: []*AutoResponseEntry{}, + qfs: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + exp: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{}, + QuarantinedFunds: []*QuarantinedFunds{quarantinedFunds, quarantinedFunds}, + }, + }, + { + name: "nil quarantined funds", + addrs: []string{testAddr0, testAddr1}, + ars: []*AutoResponseEntry{autoResponse, autoResponse}, + qfs: nil, + exp: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{autoResponse, autoResponse}, + QuarantinedFunds: nil, + }, + }, + { + name: "empty quarantined funds", + addrs: []string{testAddr0, testAddr1}, + ars: []*AutoResponseEntry{autoResponse, autoResponse}, + qfs: []*QuarantinedFunds{}, + exp: &GenesisState{ + QuarantinedAddresses: []string{testAddr0, testAddr1}, + AutoResponses: []*AutoResponseEntry{autoResponse, autoResponse}, + QuarantinedFunds: []*QuarantinedFunds{}, + }, + }, + { + name: "all empty", + addrs: []string{}, + ars: []*AutoResponseEntry{}, + qfs: []*QuarantinedFunds{}, + exp: &GenesisState{ + QuarantinedAddresses: []string{}, + AutoResponses: []*AutoResponseEntry{}, + QuarantinedFunds: []*QuarantinedFunds{}, + }, + }, + { + name: "DefaultGenesisState", + addrs: nil, + ars: nil, + qfs: nil, + exp: DefaultGenesisState(), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewGenesisState(tc.addrs, tc.ars, tc.qfs) + assert.Equal(t, tc.exp, actual, "NewGenesisState") + }) + } +} diff --git a/x/quarantine/keeper/export_test.go b/x/quarantine/keeper/export_test.go new file mode 100644 index 0000000000..7ba420daa2 --- /dev/null +++ b/x/quarantine/keeper/export_test.go @@ -0,0 +1,80 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +// This file is available only to unit tests and houses functions for doing +// things with private keeper package stuff. + +var FundsHolderBalanceInvariantHelper = fundsHolderBalanceInvariantHelper + +// WithFundsHolder creates a copy of this, setting the funds holder to the provided addr. +func (k Keeper) WithFundsHolder(addr sdk.AccAddress) Keeper { + k.fundsHolder = addr + return k +} + +// WithBankKeeper creates a copy of this, setting the bank keeper to the provided one. +func (k Keeper) WithBankKeeper(bankKeeper quarantine.BankKeeper) Keeper { + k.bankKeeper = bankKeeper + return k +} + +// GetCodec exposes this keeper's codec (cdc) for unit tests. +func (k Keeper) GetCodec() codec.BinaryCodec { + return k.cdc +} + +// GetStoreKey exposes this keeper's storekey for unit tests. +func (k Keeper) GetStoreKey() storetypes.StoreKey { + return k.storeKey +} + +// BzToQuarantineRecord exposes bzToQuarantineRecord for unit tests. +func (k Keeper) BzToQuarantineRecord(bz []byte) (*quarantine.QuarantineRecord, error) { + return k.bzToQuarantineRecord(bz) +} + +// MustBzToQuarantineRecord exposes mustBzToQuarantineRecord for unit tests. +func (k Keeper) MustBzToQuarantineRecord(bz []byte) *quarantine.QuarantineRecord { + return k.mustBzToQuarantineRecord(bz) +} + +// SetQuarantineRecordSuffixIndex exposes setQuarantineRecordSuffixIndex for unit tests. +func (k Keeper) SetQuarantineRecordSuffixIndex(store sdk.KVStore, key []byte, value *quarantine.QuarantineRecordSuffixIndex) { + k.setQuarantineRecordSuffixIndex(store, key, value) +} + +// BzToQuarantineRecordSuffixIndex exposes bzToQuarantineRecordSuffixIndex for unit tests. +func (k Keeper) BzToQuarantineRecordSuffixIndex(bz []byte) (*quarantine.QuarantineRecordSuffixIndex, error) { + return k.bzToQuarantineRecordSuffixIndex(bz) +} + +// MustBzToQuarantineRecordSuffixIndex exposes mustBzToQuarantineRecordSuffixIndex for unit tests. +func (k Keeper) MustBzToQuarantineRecordSuffixIndex(bz []byte) *quarantine.QuarantineRecordSuffixIndex { + return k.mustBzToQuarantineRecordSuffixIndex(bz) +} + +// GetQuarantineRecordSuffixIndex exposes getQuarantineRecordSuffixIndex for unit tests. +func (k Keeper) GetQuarantineRecordSuffixIndex(store sdk.KVStore, toAddr, fromAddr sdk.AccAddress) (*quarantine.QuarantineRecordSuffixIndex, []byte) { + return k.getQuarantineRecordSuffixIndex(store, toAddr, fromAddr) +} + +// GetQuarantineRecordSuffixes exposes getQuarantineRecordSuffixes for unit tests. +func (k Keeper) GetQuarantineRecordSuffixes(store sdk.KVStore, toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress) [][]byte { + return k.getQuarantineRecordSuffixes(store, toAddr, fromAddrs) +} + +// AddQuarantineRecordSuffixIndexes exposes addQuarantineRecordSuffixIndexes for unit tests. +func (k Keeper) AddQuarantineRecordSuffixIndexes(store sdk.KVStore, toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress, suffix []byte) { + k.addQuarantineRecordSuffixIndexes(store, toAddr, fromAddrs, suffix) +} + +// DeleteQuarantineRecordSuffixIndexes exposes deleteQuarantineRecordSuffixIndexes for unit tests. +func (k Keeper) DeleteQuarantineRecordSuffixIndexes(store sdk.KVStore, toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress, suffix []byte) { + k.deleteQuarantineRecordSuffixIndexes(store, toAddr, fromAddrs, suffix) +} diff --git a/x/quarantine/keeper/genesis.go b/x/quarantine/keeper/genesis.go new file mode 100644 index 0000000000..946453f63d --- /dev/null +++ b/x/quarantine/keeper/genesis.go @@ -0,0 +1,82 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +// InitGenesis updates this keeper's store using the provided GenesisState. +func (k Keeper) InitGenesis(ctx sdk.Context, genesisState *quarantine.GenesisState) { + for _, toAddrStr := range genesisState.QuarantinedAddresses { + toAddr := sdk.MustAccAddressFromBech32(toAddrStr) + if err := k.SetOptIn(ctx, toAddr); err != nil { + panic(err) + } + } + + for _, qar := range genesisState.AutoResponses { + toAddr := sdk.MustAccAddressFromBech32(qar.ToAddress) + fromAddr := sdk.MustAccAddressFromBech32(qar.FromAddress) + k.SetAutoResponse(ctx, toAddr, fromAddr, qar.Response) + } + + totalQuarantined := sdk.Coins{} + for _, qf := range genesisState.QuarantinedFunds { + toAddr := sdk.MustAccAddressFromBech32(qf.ToAddress) + qr := quarantine.NewQuarantineRecord(qf.UnacceptedFromAddresses, qf.Coins, qf.Declined) + k.SetQuarantineRecord(ctx, toAddr, qr) + totalQuarantined = totalQuarantined.Add(qf.Coins...) + } + + if !totalQuarantined.IsZero() { + qFundHolderBalance := k.bankKeeper.GetAllBalances(ctx, k.fundsHolder) + if _, hasNeg := qFundHolderBalance.SafeSub(totalQuarantined...); hasNeg { + panic(fmt.Errorf("quarantine fund holder account %q does not have enough funds %q to cover quarantined funds %q", + k.fundsHolder.String(), qFundHolderBalance.String(), totalQuarantined.String())) + } + } +} + +// ExportGenesis reads this keeper's entire state and returns it as a GenesisState. +func (k Keeper) ExportGenesis(ctx sdk.Context) *quarantine.GenesisState { + qAddrs := k.GetAllQuarantinedAccounts(ctx) + autoResps := k.GetAllAutoResponseEntries(ctx) + qFunds := k.GetAllQuarantinedFunds(ctx) + + return quarantine.NewGenesisState(qAddrs, autoResps, qFunds) +} + +// GetAllQuarantinedAccounts gets the bech32 string of every account that have opted into quarantine. +// This is designed for use with ExportGenesis. See also IterateQuarantinedAccounts. +func (k Keeper) GetAllQuarantinedAccounts(ctx sdk.Context) []string { + var rv []string + k.IterateQuarantinedAccounts(ctx, func(toAddr sdk.AccAddress) bool { + rv = append(rv, toAddr.String()) + return false + }) + return rv +} + +// GetAllAutoResponseEntries gets an AutoResponseEntry entry for every quarantine auto-response that has been set. +// This is designed for use with ExportGenesis. See also IterateAutoResponses. +func (k Keeper) GetAllAutoResponseEntries(ctx sdk.Context) []*quarantine.AutoResponseEntry { + var rv []*quarantine.AutoResponseEntry + k.IterateAutoResponses(ctx, nil, func(toAddr, fromAddr sdk.AccAddress, resp quarantine.AutoResponse) bool { + rv = append(rv, quarantine.NewAutoResponseEntry(toAddr, fromAddr, resp)) + return false + }) + return rv +} + +// GetAllQuarantinedFunds gets a QuarantinedFunds entry for each QuarantineRecord. +// This is designed for use with ExportGenesis. See also IterateQuarantineRecords. +func (k Keeper) GetAllQuarantinedFunds(ctx sdk.Context) []*quarantine.QuarantinedFunds { + var rv []*quarantine.QuarantinedFunds + k.IterateQuarantineRecords(ctx, nil, func(toAddr, _ sdk.AccAddress, funds *quarantine.QuarantineRecord) bool { + rv = append(rv, funds.AsQuarantinedFunds(toAddr)) + return false + }) + return rv +} diff --git a/x/quarantine/keeper/grpc_query.go b/x/quarantine/keeper/grpc_query.go new file mode 100644 index 0000000000..c41a7d7020 --- /dev/null +++ b/x/quarantine/keeper/grpc_query.go @@ -0,0 +1,149 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +var _ quarantine.QueryServer = Keeper{} + +func (k Keeper) IsQuarantined(goCtx context.Context, req *quarantine.QueryIsQuarantinedRequest) (*quarantine.QueryIsQuarantinedResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if len(req.ToAddress) == 0 { + return nil, status.Error(codes.InvalidArgument, "to address cannot be empty") + } + + toAddr, err := sdk.AccAddressFromBech32(req.ToAddress) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid to address: %s", err.Error()) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + resp := &quarantine.QueryIsQuarantinedResponse{ + IsQuarantined: k.IsQuarantinedAddr(ctx, toAddr), + } + + return resp, nil +} + +func (k Keeper) QuarantinedFunds(goCtx context.Context, req *quarantine.QueryQuarantinedFundsRequest) (*quarantine.QueryQuarantinedFundsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if len(req.FromAddress) > 0 && len(req.ToAddress) == 0 { + return nil, status.Error(codes.InvalidArgument, "to address cannot be empty when from address is not") + } + + var toAddr, fromAddr sdk.AccAddress + var err error + if len(req.ToAddress) > 0 { + toAddr, err = sdk.AccAddressFromBech32(req.ToAddress) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid to address: %s", err.Error()) + } + } + if len(req.FromAddress) > 0 { + fromAddr, err = sdk.AccAddressFromBech32(req.FromAddress) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid from address: %s", err.Error()) + } + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + resp := &quarantine.QueryQuarantinedFundsResponse{} + + if len(fromAddr) > 0 { + // Not paginating here because it's assumed that there are few results. + // Also, there's no way to use query.FilteredPaginate to iterate over just these specific entries. + // So it'd be doing a lot of extra unneeded work. + qRecords := k.GetQuarantineRecords(ctx, toAddr, fromAddr) + for _, qr := range qRecords { + qf := qr.AsQuarantinedFunds(toAddr) + resp.QuarantinedFunds = append(resp.QuarantinedFunds, qf) + } + } else { + store, pre := k.getQuarantineRecordPrefixStore(ctx, toAddr) + resp.Pagination, err = query.FilteredPaginate( + store, req.Pagination, + func(key, value []byte, accumulate bool) (bool, error) { + var qr *quarantine.QuarantineRecord + + qr, err = k.bzToQuarantineRecord(value) + if err != nil { + return false, err + } + if qr.Declined { + return false, nil + } + if accumulate { + kToAddr, _ := quarantine.ParseRecordKey(quarantine.MakeKey(pre, key)) + qf := qr.AsQuarantinedFunds(kToAddr) + resp.QuarantinedFunds = append(resp.QuarantinedFunds, qf) + } + return true, nil + }, + ) + + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + } + + return resp, nil +} + +func (k Keeper) AutoResponses(goCtx context.Context, req *quarantine.QueryAutoResponsesRequest) (*quarantine.QueryAutoResponsesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + if len(req.ToAddress) == 0 { + return nil, status.Error(codes.InvalidArgument, "to address cannot be empty") + } + + toAddr, err := sdk.AccAddressFromBech32(req.ToAddress) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid to address: %s", err.Error()) + } + + var fromAddr sdk.AccAddress + if len(req.FromAddress) > 0 { + fromAddr, err = sdk.AccAddressFromBech32(req.FromAddress) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid from address: %s", err.Error()) + } + } + + ctx := sdk.UnwrapSDKContext(goCtx) + resp := &quarantine.QueryAutoResponsesResponse{} + + if len(fromAddr) > 0 { + qar := k.GetAutoResponse(ctx, toAddr, fromAddr) + r := quarantine.NewAutoResponseEntry(toAddr, fromAddr, qar) + resp.AutoResponses = append(resp.AutoResponses, r) + } else { + store, pre := k.getAutoResponsesPrefixStore(ctx, toAddr) + resp.Pagination, err = query.Paginate( + store, req.Pagination, + func(key, value []byte) error { + kToAddr, kFromAddr := quarantine.ParseAutoResponseKey(quarantine.MakeKey(pre, key)) + qar := quarantine.ToAutoResponse(value) + r := quarantine.NewAutoResponseEntry(kToAddr, kFromAddr, qar) + resp.AutoResponses = append(resp.AutoResponses, r) + return nil + }, + ) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + } + + return resp, nil +} diff --git a/x/quarantine/keeper/grpc_query_test.go b/x/quarantine/keeper/grpc_query_test.go new file mode 100644 index 0000000000..220cfcdbf0 --- /dev/null +++ b/x/quarantine/keeper/grpc_query_test.go @@ -0,0 +1,553 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/quarantine" + + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +// These tests are initiated by TestKeeperTestSuite in keeper_test.go + +func (s *TestSuite) TestIsQuarantined() { + addrQuarantinedAcc := MakeTestAddr("iq", 0) + addrQuarantinedStr := addrQuarantinedAcc.String() + addrNormalStr := MakeTestAddr("iq", 1).String() + + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, addrQuarantinedAcc), "SetOptIn") + + tests := []struct { + name string + req *quarantine.QueryIsQuarantinedRequest + resp *quarantine.QueryIsQuarantinedResponse + err []string + }{ + { + name: "nil req", + req: nil, + err: []string{"empty request"}, + }, + { + name: "empty to address", + req: &quarantine.QueryIsQuarantinedRequest{ + ToAddress: "", + }, + err: []string{"to address cannot be empty"}, + }, + { + name: "bad to address", + req: &quarantine.QueryIsQuarantinedRequest{ + ToAddress: "yupitisbad", + }, + err: []string{"invalid to address", "decoding bech32 failed"}, + }, + { + name: "quarantined address", + req: &quarantine.QueryIsQuarantinedRequest{ + ToAddress: addrQuarantinedStr, + }, + resp: &quarantine.QueryIsQuarantinedResponse{ + IsQuarantined: true, + }, + }, + { + name: "normal address", + req: &quarantine.QueryIsQuarantinedRequest{ + ToAddress: addrNormalStr, + }, + resp: &quarantine.QueryIsQuarantinedResponse{ + IsQuarantined: false, + }, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + resp, err := s.keeper.IsQuarantined(s.stdlibCtx, tc.req) + if s.AssertErrorContents(err, tc.err, "IsQuarantined error") { + s.Assert().Equal(tc.resp, resp, "IsQuarantined result") + } + }) + } +} + +func (s *TestSuite) TestQuarantinedFunds() { + makeAddr := func(index uint8) (sdk.AccAddress, string) { + addr := MakeTestAddr("qf", index) + return addr, addr.String() + } + newQF := func(coins string, toAddr string, fromAddrs ...string) *quarantine.QuarantinedFunds { + return &quarantine.QuarantinedFunds{ + ToAddress: toAddr, + UnacceptedFromAddresses: fromAddrs, + Coins: s.cz(coins), + Declined: false, + } + } + qfz := func(qfs ...*quarantine.QuarantinedFunds) []*quarantine.QuarantinedFunds { + return qfs + } + addr0Acc, addr0Str := makeAddr(0) + addr1Acc, addr1Str := makeAddr(1) + _, addr2Str := makeAddr(2) + addr3Acc, addr3Str := makeAddr(3) + addr4Acc, addr4Str := makeAddr(4) + _, addr5Str := makeAddr(5) + + // 0 <- 1 = nothing + qf023 := newQF("3rec", addr0Str, addr2Str, addr3Str) + qf03 := newQF("7rec", addr0Str, addr3Str) + qf23 := newQF("17goldcoin", addr2Str, addr3Str) + // 1 <- anyone = nothing + qf31 := newQF("37goldcoin", addr3Str, addr1Str) + qf32 := newQF("79goldcoin", addr3Str, addr2Str) + qf40 := newQF("163goldcoin", addr4Str, addr0Str) + qf42d := newQF("331goldcoin", addr4Str, addr2Str) + qf42d.Declined = true + qf43 := newQF("673goldcoin", addr4Str, addr3Str) + qf50 := newQF("1361goldcoin", addr5Str, addr0Str) + qf51 := newQF("2729goldcoin", addr5Str, addr1Str) + qf52 := newQF("5471goldcoin", addr5Str, addr2Str) + qf53 := newQF("10949goldcoin", addr5Str, addr3Str) + qf54 := newQF("21911goldcoin", addr5Str, addr4Str) + qf513d := newQF("43853goldcoin", addr5Str, addr1Str, addr3Str) + qf513d.Declined = true + qf501234 := newQF("43853goldcoin", addr5Str, addr0Str, addr1Str, addr2Str, addr3Str, addr4Str) + allQuarantinedFunds := qfz( + qf023, qf03, + qf23, + qf31, qf32, + qf40, qf42d, qf43, + qf50, qf51, qf52, qf53, qf54, qf513d, qf501234, + ) + + for i, qf := range allQuarantinedFunds { + toAddr, taerr := sdk.AccAddressFromBech32(qf.ToAddress) + s.Require().NoError(taerr, "AccAddressFromBech32 allQuarantinedFunds[%d].ToAddress", i) + var qr *quarantine.QuarantineRecord + testFuncAsQR := func() { + qr = quarantine.NewQuarantineRecord(qf.UnacceptedFromAddresses, qf.Coins, qf.Declined) + } + s.Require().NotPanics(testFuncAsQR, "NewQuarantineRecord allQuarantinedFunds[%d]", i) + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, qr) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord allQuarantinedFunds[%d]", i) + } + + tests := []struct { + name string + req *quarantine.QueryQuarantinedFundsRequest + resp *quarantine.QueryQuarantinedFundsResponse + err []string + }{ + { + name: "nil req", + req: nil, + err: []string{"empty request"}, + }, + { + name: "from without to", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: "", + FromAddress: addr0Str, + }, + err: []string{"to address cannot be empty when from address is not"}, + }, + { + name: "bad to address", + req: &quarantine.QueryQuarantinedFundsRequest{ToAddress: "baaaaaaaaad1sheep"}, + err: []string{"invalid to address", "decoding bech32 failed"}, + }, + { + name: "bad from address", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr0Str, + FromAddress: "still1badsheep", + }, + err: []string{"invalid from address", "decoding bech32 failed"}, + }, + { + name: "to and from has no entries", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr0Str, + FromAddress: addr1Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: nil, + Pagination: nil, + }, + }, + { + name: "to and from has one entry", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr0Str, + FromAddress: addr2Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf023), + Pagination: nil, + }, + }, + { + name: "to and from has two entries", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr0Str, + FromAddress: addr3Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf03, qf023), + Pagination: nil, + }, + }, + { + name: "only to has no entries", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr1Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: nil, + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 0, + }, + }, + }, + { + name: "only to has one entry", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr2Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf23), + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 1, + }, + }, + }, + { + name: "only to has two entries", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr3Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf31, qf32), + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 2, + }, + }, + }, + { + name: "only to does not include declined funds", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr4Str, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf40, qf43), + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 2, + }, + }, + }, + { + name: "only to with page req", + req: &quarantine.QueryQuarantinedFundsRequest{ + ToAddress: addr5Str, + Pagination: &query.PageRequest{ + Key: address.MustLengthPrefix(addr1Acc), + Offset: 0, + Limit: 2, + CountTotal: false, + Reverse: false, + }, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf51, qf52), + Pagination: &query.PageResponse{ + NextKey: address.MustLengthPrefix(addr3Acc), + Total: 0, + }, + }, + }, + { + name: "get all", + req: &quarantine.QueryQuarantinedFundsRequest{}, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz( + qf03, qf023, + qf23, + qf31, qf32, + qf40, qf43, + qf50, qf51, qf52, qf53, qf54, qf501234, + ), + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 13, + }, + }, + }, + { + name: "get all with page req", + req: &quarantine.QueryQuarantinedFundsRequest{ + Pagination: &query.PageRequest{ + Key: nil, + Offset: 3, + Limit: 3, + CountTotal: true, + Reverse: false, + }, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf31, qf32, qf40), + Pagination: &query.PageResponse{ + NextKey: quarantine.CreateRecordKey(addr4Acc, addr3Acc)[1:], + Total: 13, + }, + }, + }, + { + name: "get all with page rev", + req: &quarantine.QueryQuarantinedFundsRequest{ + Pagination: &query.PageRequest{ + Key: nil, + Offset: 4, + Limit: 3, + CountTotal: true, + Reverse: true, + }, + }, + resp: &quarantine.QueryQuarantinedFundsResponse{ + QuarantinedFunds: qfz(qf51, qf50, qf43), + Pagination: &query.PageResponse{ + NextKey: quarantine.CreateRecordKey(addr4Acc, addr0Acc)[1:], + Total: 13, + }, + }, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + resp, err := s.keeper.QuarantinedFunds(s.stdlibCtx, tc.req) + if s.AssertErrorContents(err, tc.err, "QuarantinedFunds error") { + s.Assert().Equal(tc.resp, resp, "QuarantinedFunds response") + } + }) + } +} + +func (s *TestSuite) TestAutoResponses() { + makeAddr := func(index uint8) (sdk.AccAddress, string) { + addr := MakeTestAddr("ar", index) + return addr, addr.String() + } + newARE := func(toAddr, fromAddr string, resp quarantine.AutoResponse) *quarantine.AutoResponseEntry { + return &quarantine.AutoResponseEntry{ + ToAddress: toAddr, + FromAddress: fromAddr, + Response: resp, + } + } + addr0Acc, addr0Str := makeAddr(0) + addr1Acc, addr1Str := makeAddr(1) + addr2Acc, addr2Str := makeAddr(2) + addr3Acc, addr3Str := makeAddr(3) + addr4Acc, _ := makeAddr(4) + addr5Acc, addr5Str := makeAddr(5) + addr6Acc, addr6Str := makeAddr(6) + + // Setup: + // 0 <- 1 accept, 2 decline, 3 unspecified + // 2 <- 3 accept + // 3 <- 2 decline + // 6 <- 0 decline, 1 accept, 2 decline, 3 accept, 4 unspecified, 5 accept + s.keeper.SetAutoResponse(s.sdkCtx, addr0Acc, addr1Acc, quarantine.AUTO_RESPONSE_ACCEPT) + s.keeper.SetAutoResponse(s.sdkCtx, addr0Acc, addr2Acc, quarantine.AUTO_RESPONSE_DECLINE) + s.keeper.SetAutoResponse(s.sdkCtx, addr0Acc, addr3Acc, quarantine.AUTO_RESPONSE_UNSPECIFIED) + s.keeper.SetAutoResponse(s.sdkCtx, addr2Acc, addr3Acc, quarantine.AUTO_RESPONSE_ACCEPT) + s.keeper.SetAutoResponse(s.sdkCtx, addr3Acc, addr2Acc, quarantine.AUTO_RESPONSE_DECLINE) + s.keeper.SetAutoResponse(s.sdkCtx, addr6Acc, addr0Acc, quarantine.AUTO_RESPONSE_DECLINE) + s.keeper.SetAutoResponse(s.sdkCtx, addr6Acc, addr1Acc, quarantine.AUTO_RESPONSE_ACCEPT) + s.keeper.SetAutoResponse(s.sdkCtx, addr6Acc, addr2Acc, quarantine.AUTO_RESPONSE_DECLINE) + s.keeper.SetAutoResponse(s.sdkCtx, addr6Acc, addr3Acc, quarantine.AUTO_RESPONSE_ACCEPT) + s.keeper.SetAutoResponse(s.sdkCtx, addr6Acc, addr4Acc, quarantine.AUTO_RESPONSE_UNSPECIFIED) + s.keeper.SetAutoResponse(s.sdkCtx, addr6Acc, addr5Acc, quarantine.AUTO_RESPONSE_ACCEPT) + + tests := []struct { + name string + req *quarantine.QueryAutoResponsesRequest + resp *quarantine.QueryAutoResponsesResponse + err []string + }{ + { + name: "no req", + req: nil, + err: []string{"empty request"}, + }, + { + name: "no to address", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: "", + FromAddress: addr1Str, + }, + err: []string{"to address cannot be empty"}, + }, + { + name: "bad to address", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: "not1goodone", + FromAddress: addr1Str, + }, + err: []string{"invalid to address", "decoding bech32 failed"}, + }, + { + name: "bad from address", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: addr0Str, + FromAddress: "also1badone", + }, + err: []string{"invalid from address", "decoding bech32 failed"}, + }, + { + name: "to and from auto-accept", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: addr0Str, + FromAddress: addr1Str, + }, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0Str, addr1Str, quarantine.AUTO_RESPONSE_ACCEPT), + }, + Pagination: nil, + }, + }, + { + name: "to and from auto-decline", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: addr0Str, + FromAddress: addr2Str, + }, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0Str, addr2Str, quarantine.AUTO_RESPONSE_DECLINE), + }, + Pagination: nil, + }, + }, + { + name: "to and from unspecified", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: addr0Str, + FromAddress: addr3Str, + }, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0Str, addr3Str, quarantine.AUTO_RESPONSE_UNSPECIFIED), + }, + Pagination: nil, + }, + }, + { + name: "to and same from", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: addr0Str, + FromAddress: addr0Str, + }, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0Str, addr0Str, quarantine.AUTO_RESPONSE_ACCEPT), + }, + Pagination: nil, + }, + }, + { + name: "only to with no entries", + req: &quarantine.QueryAutoResponsesRequest{ToAddress: addr1Str}, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: nil, + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 0, + }, + }, + }, + { + name: "only to with one entry accept", + req: &quarantine.QueryAutoResponsesRequest{ToAddress: addr2Str}, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr2Str, addr3Str, quarantine.AUTO_RESPONSE_ACCEPT), + }, + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 1, + }, + }, + }, + { + name: "only to with one entry decline", + req: &quarantine.QueryAutoResponsesRequest{ToAddress: addr3Str}, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr3Str, addr2Str, quarantine.AUTO_RESPONSE_DECLINE), + }, + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 1, + }, + }, + }, + { + name: "only to with two entries", // 0 = 1 2 (accept/decline) + req: &quarantine.QueryAutoResponsesRequest{ToAddress: addr0Str}, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr0Str, addr1Str, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr0Str, addr2Str, quarantine.AUTO_RESPONSE_DECLINE), + }, + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 2, + }, + }, + }, + { + name: "only to with page req", + req: &quarantine.QueryAutoResponsesRequest{ + ToAddress: addr6Str, + Pagination: &query.PageRequest{ + Key: nil, + Offset: 2, + Limit: 4, + CountTotal: true, + Reverse: false, + }, + }, + resp: &quarantine.QueryAutoResponsesResponse{ + AutoResponses: []*quarantine.AutoResponseEntry{ + newARE(addr6Str, addr2Str, quarantine.AUTO_RESPONSE_DECLINE), + newARE(addr6Str, addr3Str, quarantine.AUTO_RESPONSE_ACCEPT), + newARE(addr6Str, addr5Str, quarantine.AUTO_RESPONSE_ACCEPT), + }, + Pagination: &query.PageResponse{ + NextKey: nil, + Total: 5, + }, + }, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + resp, err := s.keeper.AutoResponses(s.stdlibCtx, tc.req) + if s.AssertErrorContents(err, tc.err, "AutoResponses error") { + s.Assert().Equal(tc.resp, resp, "AutoResponses response") + } + }) + } +} diff --git a/x/quarantine/keeper/invariants.go b/x/quarantine/keeper/invariants.go new file mode 100644 index 0000000000..8866b4cf49 --- /dev/null +++ b/x/quarantine/keeper/invariants.go @@ -0,0 +1,72 @@ +package keeper + +import ( + "fmt" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +const balanceInvariant = "Funds-Holder-Balance" + +// RegisterInvariants registers all quarantine invariants. +func RegisterInvariants(ir sdk.InvariantRegistry, keeper Keeper) { + ir.RegisterRoute(quarantine.ModuleName, balanceInvariant, FundsHolderBalanceInvariant(keeper)) +} + +// FundsHolderBalanceInvariant checks that the funds-holder account has enough funds to cover all quarantined funds. +func FundsHolderBalanceInvariant(keeper Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + msg, broken := fundsHolderBalanceInvariantHelper(ctx, keeper) + return sdk.FormatInvariant(quarantine.ModuleName, balanceInvariant, msg), broken + } +} + +func fundsHolderBalanceInvariantHelper(ctx sdk.Context, keeper Keeper) (string, bool) { + totalQuarantined := sdk.Coins{} + accumulator := func(_, _ sdk.AccAddress, record *quarantine.QuarantineRecord) bool { + totalQuarantined = totalQuarantined.Add(record.Coins...) + return false + } + keeper.IterateQuarantineRecords(ctx, nil, accumulator) + + if totalQuarantined.IsZero() { + return "total funds quarantined is zero", false + } + + holder := keeper.GetFundsHolder() + fundsHolderBalance := keeper.bankKeeper.GetAllBalances(ctx, holder) + + problems := make([]string, 0, len(totalQuarantined)) + for _, needed := range totalQuarantined { + have, holding := fundsHolderBalance.Find(needed.Denom) + switch { + case !have: + problems = append(problems, fmt.Sprintf("zero is less than %s", needed)) + case holding.IsLT(needed): + problems = append(problems, fmt.Sprintf("%s is less than %s", holding, needed)) + } + } + + broken := len(problems) > 0 + msg := fmt.Sprintf("quarantine funds holder account %s balance ", holder) + if broken { + msg += "insufficient" + } else { + msg += "sufficient" + } + + if fundsHolderBalance.IsZero() { + msg += ", have: zero balance" + } else { + msg += fmt.Sprintf(", have: %s", fundsHolderBalance) + } + msg += fmt.Sprintf(", need: %s", totalQuarantined) + + if broken { + msg += fmt.Sprintf(", %s: insufficient funds", strings.Join(problems, ", ")) + } + + return msg, broken +} diff --git a/x/quarantine/keeper/invariants_test.go b/x/quarantine/keeper/invariants_test.go new file mode 100644 index 0000000000..0f8d165681 --- /dev/null +++ b/x/quarantine/keeper/invariants_test.go @@ -0,0 +1,192 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" + "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +// These tests are initiated by TestKeeperTestSuite in keeper_test.go + +func (s *TestSuite) TestFundsHolderBalanceInvariantHelper() { + bk := NewMockBankKeeper() + qk := s.keeper.WithBankKeeper(bk) + + s.Run("no quarantined funds no funds in holding account", func() { + zqk := qk.WithFundsHolder(testutil.MakeTestAddr("fh", 0)) + msg, broken := keeper.FundsHolderBalanceInvariantHelper(s.sdkCtx, zqk) + s.Assert().False(broken, "fundsHolderBalanceInvariantHelper broken") + s.Assert().Equal("total funds quarantined is zero", msg, "fundsHolderBalanceInvariantHelper message") + }) + + dummyAddr0 := testutil.MakeTestAddr("dumfhbi", 0) + dummyAddr1 := testutil.MakeTestAddr("dumfhbi", 1) + dummyAddr2 := testutil.MakeTestAddr("dumfhbi", 2) + dummyAddr3 := testutil.MakeTestAddr("dumfhbi", 3) + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("4acoin"), dummyAddr0, dummyAddr1), "AddQuarantinedCoins 4acoin") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("1acoin,9bcoin"), dummyAddr0, dummyAddr2), "AddQuarantinedCoins 1acoin,9bcoin") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("2acoin,2bcoin,2ccoin"), dummyAddr0, dummyAddr3), "AddQuarantinedCoins 2acoin,2bcoin,2ccoin") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("3acoin,11ccoin"), dummyAddr1, dummyAddr2), "AddQuarantinedCoins 3acoin,11ccoin") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("5bcoin"), dummyAddr1, dummyAddr3), "AddQuarantinedCoins 5bcoin") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("4bcoin,7ccoin"), dummyAddr2, dummyAddr3), "AddQuarantinedCoins 4bcoin,7ccoin") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, s.cz("10ccoin"), dummyAddr3, dummyAddr2, dummyAddr1, dummyAddr0), "AddQuarantinedCoins 10ccoin") + // Quarantine records total: 10acoin,20bcoin,30ccoin + + makeFundedAddr := func(base string, coins sdk.Coins) sdk.AccAddress { + addr := testutil.MakeTestAddr(base, 0) + bk.AllBalances[string(addr)] = coins + return addr + } + makeSufExpMsg := func(addr sdk.AccAddress) string { + return "quarantine funds holder account " + addr.String() + " balance sufficient" + + ", have: " + bk.AllBalances[string(addr)].String() + + ", need: 10acoin,20bcoin,30ccoin" + } + makeInsufExpMsg := func(addr sdk.AccAddress, problems string) string { + return "quarantine funds holder account " + addr.String() + " balance insufficient" + + ", have: " + bk.AllBalances[string(addr)].String() + + ", need: 10acoin,20bcoin,30ccoin" + + ", " + problems + + ": insufficient funds" + } + + exact := makeFundedAddr("exact", s.cz("10acoin,20bcoin,30ccoin")) + plenty := makeFundedAddr("plenty", s.cz("100acoin,200bcoin,300ccoin,400dcoin,500ecoin,600fcoin")) + shorta := makeFundedAddr("ashort", s.cz("9acoin,20bcoin,30ccoin")) + shortb := makeFundedAddr("bshort", s.cz("10acoin,19bcoin,30ccoin")) + shortc := makeFundedAddr("cshort", s.cz("10acoin,20bcoin,29ccoin")) + shortab := makeFundedAddr("abshort", s.cz("9acoin,19bcoin,30ccoin")) + shortac := makeFundedAddr("acshort", s.cz("9acoin,20bcoin,29ccoin")) + shortbc := makeFundedAddr("bcshort", s.cz("10acoin,19bcoin,29ccoin")) + shortabc := makeFundedAddr("abcshort", s.cz("9acoin,19bcoin,29ccoin")) + noa := makeFundedAddr("ano", s.cz("20bcoin,30ccoin")) + nob := makeFundedAddr("bno", s.cz("10acoin,30ccoin")) + noc := makeFundedAddr("cno", s.cz("10acoin,20bcoin")) + noab := makeFundedAddr("abno", s.cz("30ccoin")) + noac := makeFundedAddr("acno", s.cz("20bcoin")) + nobc := makeFundedAddr("bcno", s.cz("10acoin")) + noabc := makeFundedAddr("abcno", s.cz("40dcoin,50ecoin,60fcoin")) + zero := makeFundedAddr("zero", sdk.Coins{}) + + tests := []struct { + name string + keeper keeper.Keeper + expMsg string + expBroken bool + }{ + { + name: "exactly funded", + keeper: qk.WithFundsHolder(exact), + expMsg: makeSufExpMsg(exact), + expBroken: false, + }, + { + name: "overly funded", + keeper: qk.WithFundsHolder(plenty), + expMsg: makeSufExpMsg(plenty), + expBroken: false, + }, + { + name: "short a", + keeper: qk.WithFundsHolder(shorta), + expMsg: makeInsufExpMsg(shorta, "9acoin is less than 10acoin"), + expBroken: true, + }, + { + name: "short b", + keeper: qk.WithFundsHolder(shortb), + expMsg: makeInsufExpMsg(shortb, "19bcoin is less than 20bcoin"), + expBroken: true, + }, + { + name: "short c", + keeper: qk.WithFundsHolder(shortc), + expMsg: makeInsufExpMsg(shortc, "29ccoin is less than 30ccoin"), + expBroken: true, + }, + { + name: "short a b", + keeper: qk.WithFundsHolder(shortab), + expMsg: makeInsufExpMsg(shortab, "9acoin is less than 10acoin, 19bcoin is less than 20bcoin"), + expBroken: true, + }, + { + name: "short a c", + keeper: qk.WithFundsHolder(shortac), + expMsg: makeInsufExpMsg(shortac, "9acoin is less than 10acoin, 29ccoin is less than 30ccoin"), + expBroken: true, + }, + { + name: "short b c", + keeper: qk.WithFundsHolder(shortbc), + expMsg: makeInsufExpMsg(shortbc, "19bcoin is less than 20bcoin, 29ccoin is less than 30ccoin"), + expBroken: true, + }, + { + name: "short a b c", + keeper: qk.WithFundsHolder(shortabc), + expMsg: makeInsufExpMsg(shortabc, "9acoin is less than 10acoin, 19bcoin is less than 20bcoin, 29ccoin is less than 30ccoin"), + expBroken: true, + }, + { + name: "no a", + keeper: qk.WithFundsHolder(noa), + expMsg: makeInsufExpMsg(noa, "zero is less than 10acoin"), + expBroken: true, + }, + { + name: "no b", + keeper: qk.WithFundsHolder(nob), + expMsg: makeInsufExpMsg(nob, "zero is less than 20bcoin"), + expBroken: true, + }, + { + name: "no c", + keeper: qk.WithFundsHolder(noc), + expMsg: makeInsufExpMsg(noc, "zero is less than 30ccoin"), + expBroken: true, + }, + { + name: "no a b", + keeper: qk.WithFundsHolder(noab), + expMsg: makeInsufExpMsg(noab, "zero is less than 10acoin, zero is less than 20bcoin"), + expBroken: true, + }, + { + name: "no a c", + keeper: qk.WithFundsHolder(noac), + expMsg: makeInsufExpMsg(noac, "zero is less than 10acoin, zero is less than 30ccoin"), + expBroken: true, + }, + { + name: "no b c", + keeper: qk.WithFundsHolder(nobc), + expMsg: makeInsufExpMsg(nobc, "zero is less than 20bcoin, zero is less than 30ccoin"), + expBroken: true, + }, + { + name: "no a b c", + keeper: qk.WithFundsHolder(noabc), + expMsg: makeInsufExpMsg(noabc, "zero is less than 10acoin, zero is less than 20bcoin, zero is less than 30ccoin"), + expBroken: true, + }, + { + name: "zero", + keeper: qk.WithFundsHolder(zero), + expMsg: "quarantine funds holder account " + zero.String() + " balance insufficient" + + ", have: zero balance" + + ", need: 10acoin,20bcoin,30ccoin" + + ", zero is less than 10acoin, zero is less than 20bcoin, zero is less than 30ccoin" + + ": insufficient funds", + expBroken: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + msg, broken := keeper.FundsHolderBalanceInvariantHelper(s.sdkCtx, tc.keeper) + s.Assert().Equal(tc.expBroken, broken, "fundsHolderBalanceInvariantHelper broken") + s.Assert().Equal(tc.expMsg, msg, "fundsHolderBalanceInvariantHelper message") + }) + } +} diff --git a/x/quarantine/keeper/keeper.go b/x/quarantine/keeper/keeper.go new file mode 100644 index 0000000000..c7a0f78617 --- /dev/null +++ b/x/quarantine/keeper/keeper.go @@ -0,0 +1,422 @@ +package keeper + +import ( + "fmt" + "strings" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +type Keeper struct { + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + + bankKeeper quarantine.BankKeeper + + fundsHolder sdk.AccAddress +} + +func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey, bankKeeper quarantine.BankKeeper, fundsHolder sdk.AccAddress) Keeper { + if len(fundsHolder) == 0 { + fundsHolder = authtypes.NewModuleAddress(quarantine.ModuleName) + } + rv := Keeper{ + cdc: cdc, + storeKey: storeKey, + bankKeeper: bankKeeper, + fundsHolder: fundsHolder, + } + bankKeeper.AppendSendRestriction(rv.SendRestrictionFn) + return rv +} + +// GetFundsHolder returns the account address that holds quarantined funds. +func (k Keeper) GetFundsHolder() sdk.AccAddress { + return k.fundsHolder +} + +// SetOptIn records that an address has opted into quarantine. +func (k Keeper) SetOptIn(ctx sdk.Context, toAddr sdk.AccAddress) error { + key := quarantine.CreateOptInKey(toAddr) + store := ctx.KVStore(k.storeKey) + store.Set(key, []byte{0x00}) + return ctx.EventManager().EmitTypedEvent(&quarantine.EventOptIn{ToAddress: toAddr.String()}) +} + +// SetOptOut removes an address' quarantine opt-in record. +func (k Keeper) SetOptOut(ctx sdk.Context, toAddr sdk.AccAddress) error { + key := quarantine.CreateOptInKey(toAddr) + store := ctx.KVStore(k.storeKey) + store.Delete(key) + return ctx.EventManager().EmitTypedEvent(&quarantine.EventOptOut{ToAddress: toAddr.String()}) +} + +// IsQuarantinedAddr returns true if the given address has opted into quarantine. +func (k Keeper) IsQuarantinedAddr(ctx sdk.Context, toAddr sdk.AccAddress) bool { + key := quarantine.CreateOptInKey(toAddr) + store := ctx.KVStore(k.storeKey) + return store.Has(key) +} + +// getQuarantinedAccountsPrefixStore returns a kv store prefixed for quarantine opt-in entries, and the prefix bytes. +func (k Keeper) getQuarantinedAccountsPrefixStore(ctx sdk.Context) (sdk.KVStore, []byte) { + return prefix.NewStore(ctx.KVStore(k.storeKey), quarantine.OptInPrefix), quarantine.OptInPrefix +} + +// IterateQuarantinedAccounts iterates over all quarantine account addresses. +// The callback function should accept the to address (that has quarantine enabled). +// It should return whether to stop iteration early. I.e. false will allow iteration to continue, true will stop iteration. +func (k Keeper) IterateQuarantinedAccounts(ctx sdk.Context, cb func(toAddr sdk.AccAddress) (stop bool)) { + store, pre := k.getQuarantinedAccountsPrefixStore(ctx) + iter := store.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + addr := quarantine.ParseOptInKey(quarantine.MakeKey(pre, iter.Key())) + if cb(addr) { + break + } + } +} + +// SetAutoResponse sets the auto response of sends to toAddr from fromAddr. +// If the response is AUTO_RESPONSE_UNSPECIFIED, the auto-response record is deleted, +// otherwise it is created/updated with the given setting. +func (k Keeper) SetAutoResponse(ctx sdk.Context, toAddr, fromAddr sdk.AccAddress, response quarantine.AutoResponse) { + key := quarantine.CreateAutoResponseKey(toAddr, fromAddr) + val := quarantine.ToAutoB(response) + store := ctx.KVStore(k.storeKey) + if val == quarantine.NoAutoB { + store.Delete(key) + } else { + store.Set(key, []byte{val}) + } +} + +// GetAutoResponse returns the quarantine auto-response for the given to/from addresses. +func (k Keeper) GetAutoResponse(ctx sdk.Context, toAddr, fromAddr sdk.AccAddress) quarantine.AutoResponse { + if toAddr.Equals(fromAddr) { + return quarantine.AUTO_RESPONSE_ACCEPT + } + key := quarantine.CreateAutoResponseKey(toAddr, fromAddr) + store := ctx.KVStore(k.storeKey) + bz := store.Get(key) + return quarantine.ToAutoResponse(bz) +} + +// IsAutoAccept returns true if the to address has enabled auto-accept for ALL the from address. +func (k Keeper) IsAutoAccept(ctx sdk.Context, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) bool { + for _, fromAddr := range fromAddrs { + if !k.GetAutoResponse(ctx, toAddr, fromAddr).IsAccept() { + return false + } + } + return true +} + +// IsAutoDecline returns true if the to address has enabled auto-decline for ANY of the from address. +func (k Keeper) IsAutoDecline(ctx sdk.Context, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) bool { + for _, fromAddr := range fromAddrs { + if k.GetAutoResponse(ctx, toAddr, fromAddr).IsDecline() { + return true + } + } + return false +} + +// getAutoResponsesPrefixStore returns a kv store prefixed for quarantine auto-responses and the prefix used. +// If a toAddr is provided, the store is prefixed for just the given address. +// If toAddr is empty, it will be prefixed for all quarantine auto-responses. +func (k Keeper) getAutoResponsesPrefixStore(ctx sdk.Context, toAddr sdk.AccAddress) (sdk.KVStore, []byte) { + pre := quarantine.AutoResponsePrefix + if len(toAddr) > 0 { + pre = quarantine.CreateAutoResponseToAddrPrefix(toAddr) + } + return prefix.NewStore(ctx.KVStore(k.storeKey), pre), pre +} + +// IterateAutoResponses iterates over the auto-responses for a given recipient address, +// or if no address is provided, iterates over all auto-response entries. +// The callback function should accept a to address, from address, and auto-response setting (in that order). +// It should return whether to stop iteration early. I.e. false will allow iteration to continue, true will stop iteration. +func (k Keeper) IterateAutoResponses(ctx sdk.Context, toAddr sdk.AccAddress, cb func(toAddr, fromAddr sdk.AccAddress, response quarantine.AutoResponse) (stop bool)) { + store, pre := k.getAutoResponsesPrefixStore(ctx, toAddr) + iter := store.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + kToAddr, kFromAddr := quarantine.ParseAutoResponseKey(quarantine.MakeKey(pre, iter.Key())) + val := quarantine.ToAutoResponse(iter.Value()) + if cb(kToAddr, kFromAddr, val) { + break + } + } +} + +// SetQuarantineRecord sets a quarantine record. +// Panics if the record is nil. +// If the record is fully accepted, it is deleted. +// Otherwise, it is saved. +func (k Keeper) SetQuarantineRecord(ctx sdk.Context, toAddr sdk.AccAddress, record *quarantine.QuarantineRecord) { + if record == nil { + panic("record cannot be nil") + } + fromAddrs := record.GetAllFromAddrs() + key := quarantine.CreateRecordKey(toAddr, fromAddrs...) + store := ctx.KVStore(k.storeKey) + + if record.IsFullyAccepted() { + store.Delete(key) + if len(fromAddrs) > 1 { + _, suffix := quarantine.ParseRecordIndexKey(key) + k.deleteQuarantineRecordSuffixIndexes(store, toAddr, fromAddrs, suffix) + } + } else { + val := k.cdc.MustMarshal(record) + store.Set(key, val) + if len(fromAddrs) > 1 { + _, suffix := quarantine.ParseRecordIndexKey(key) + k.addQuarantineRecordSuffixIndexes(store, toAddr, fromAddrs, suffix) + } + } +} + +// bzToQuarantineRecord converts the given byte slice into a QuarantineRecord or returns an error. +// If the byte slice is nil or empty, a default QuarantineRecord is returned with zero coins. +func (k Keeper) bzToQuarantineRecord(bz []byte) (*quarantine.QuarantineRecord, error) { + qf := quarantine.QuarantineRecord{ + Coins: sdk.Coins{}, + } + if len(bz) > 0 { + err := k.cdc.Unmarshal(bz, &qf) + if err != nil { + return &qf, err + } + } + return &qf, nil +} + +// mustBzToQuarantineRecord returns bzToQuarantineRecord but panics on error. +func (k Keeper) mustBzToQuarantineRecord(bz []byte) *quarantine.QuarantineRecord { + qf, err := k.bzToQuarantineRecord(bz) + if err != nil { + panic(err) + } + return qf +} + +// GetQuarantineRecord gets the single quarantine record to toAddr from all the fromAddrs. +// If the record doesn't exist, nil is returned. +// +// If you want all records from any of the fromAddrs, use GetQuarantineRecords. +func (k Keeper) GetQuarantineRecord(ctx sdk.Context, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) *quarantine.QuarantineRecord { + store := ctx.KVStore(k.storeKey) + key := quarantine.CreateRecordKey(toAddr, fromAddrs...) + if store.Has(key) { + bz := store.Get(key) + qr := k.mustBzToQuarantineRecord(bz) + return qr + } + return nil +} + +// GetQuarantineRecords gets all the quarantine records to toAddr that involved any of the fromAddrs. +// +// If you want a single record from all the fromAddrs, use GetQuarantineRecord. +func (k Keeper) GetQuarantineRecords(ctx sdk.Context, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) []*quarantine.QuarantineRecord { + store := ctx.KVStore(k.storeKey) + allSuffixes := k.getQuarantineRecordSuffixes(store, toAddr, fromAddrs) + var rv []*quarantine.QuarantineRecord + for _, suffix := range allSuffixes { + key := quarantine.CreateRecordKey(toAddr, suffix) + if store.Has(key) { + bz := store.Get(key) + rv = append(rv, k.mustBzToQuarantineRecord(bz)) + } + } + return rv +} + +// AddQuarantinedCoins records that some new funds have been quarantined. +func (k Keeper) AddQuarantinedCoins(ctx sdk.Context, coins sdk.Coins, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) error { + qr := k.GetQuarantineRecord(ctx, toAddr, fromAddrs...) + if qr != nil { + qr.AddCoins(coins...) + } else { + qr = &quarantine.QuarantineRecord{ + Coins: coins, + } + for _, fromAddr := range fromAddrs { + if k.IsAutoAccept(ctx, toAddr, fromAddr) { + qr.AcceptedFromAddresses = append(qr.AcceptedFromAddresses, fromAddr) + } else { + qr.UnacceptedFromAddresses = append(qr.UnacceptedFromAddresses, fromAddr) + } + } + } + if qr.IsFullyAccepted() { + fromAddrStrs := make([]string, len(fromAddrs)) + for i, addr := range fromAddrs { + fromAddrStrs[i] = addr.String() + } + return fmt.Errorf("cannot add quarantined funds %q to %s from %s: already fully accepted", + coins.String(), toAddr.String(), strings.Join(fromAddrStrs, ", ")) + } + // Regardless of if its new or existing, set declined based on current auto-decline info. + qr.Declined = k.IsAutoDecline(ctx, toAddr, fromAddrs...) + k.SetQuarantineRecord(ctx, toAddr, qr) + return ctx.EventManager().EmitTypedEvent(&quarantine.EventFundsQuarantined{ + ToAddress: toAddr.String(), + Coins: coins, + }) +} + +// AcceptQuarantinedFunds looks up all quarantined funds to toAddr from any of the fromAddrs. +// It marks and saves each as accepted and, if fully accepted, releases (sends) the funds to toAddr. +// Returns total funds released and possibly an error. +func (k Keeper) AcceptQuarantinedFunds(ctx sdk.Context, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) (sdk.Coins, error) { + fundsReleased := sdk.Coins{} + for _, record := range k.GetQuarantineRecords(ctx, toAddr, fromAddrs...) { + if record.AcceptFrom(fromAddrs) { + if record.IsFullyAccepted() { + err := k.bankKeeper.SendCoins(quarantine.WithBypass(ctx), k.fundsHolder, toAddr, record.Coins) + if err != nil { + return nil, err + } + fundsReleased = fundsReleased.Add(record.Coins...) + + err = ctx.EventManager().EmitTypedEvent(&quarantine.EventFundsReleased{ + ToAddress: toAddr.String(), + Coins: record.Coins, + }) + if err != nil { + return nil, err + } + } else { + // update declined to false unless one of the unaccepted from addresses is set to auto-decline. + record.Declined = k.IsAutoDecline(ctx, toAddr, record.UnacceptedFromAddresses...) + } + k.SetQuarantineRecord(ctx, toAddr, record) + } + } + + return fundsReleased, nil +} + +// DeclineQuarantinedFunds marks as declined, all quarantined funds to toAddr where any fromAddr is a sender. +func (k Keeper) DeclineQuarantinedFunds(ctx sdk.Context, toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) { + for _, record := range k.GetQuarantineRecords(ctx, toAddr, fromAddrs...) { + if record.DeclineFrom(fromAddrs) { + k.SetQuarantineRecord(ctx, toAddr, record) + } + } +} + +// getQuarantineRecordPrefixStore returns a kv store prefixed for quarantine records and the prefix used. +// If a toAddr is provided, the store is prefixed for just the given address. +// If toAddr is empty, it will be prefixed for all quarantine records. +func (k Keeper) getQuarantineRecordPrefixStore(ctx sdk.Context, toAddr sdk.AccAddress) (sdk.KVStore, []byte) { + pre := quarantine.RecordPrefix + if len(toAddr) > 0 { + pre = quarantine.CreateRecordToAddrPrefix(toAddr) + } + return prefix.NewStore(ctx.KVStore(k.storeKey), pre), pre +} + +// IterateQuarantineRecords iterates over the quarantine records for a given recipient address, +// or if no address is provided, iterates over all quarantine records. +// The callback function should accept a to address, record suffix, and QuarantineRecord (in that order). +// It should return whether to stop iteration early. I.e. false will allow iteration to continue, true will stop iteration. +func (k Keeper) IterateQuarantineRecords(ctx sdk.Context, toAddr sdk.AccAddress, cb func(toAddr, recordSuffix sdk.AccAddress, record *quarantine.QuarantineRecord) (stop bool)) { + store, pre := k.getQuarantineRecordPrefixStore(ctx, toAddr) + iter := store.Iterator(nil, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + kToAddr, kRecordSuffix := quarantine.ParseRecordKey(quarantine.MakeKey(pre, iter.Key())) + qf := k.mustBzToQuarantineRecord(iter.Value()) + + if cb(kToAddr, kRecordSuffix, qf) { + break + } + } +} + +// setQuarantineRecordSuffixIndex writes the provided suffix index. +// If it is nil or there are no record suffixes, the entry is instead deleted. +func (k Keeper) setQuarantineRecordSuffixIndex(store sdk.KVStore, key []byte, value *quarantine.QuarantineRecordSuffixIndex) { + if value == nil || len(value.RecordSuffixes) == 0 { + store.Delete(key) + } else { + val := k.cdc.MustMarshal(value) + store.Set(key, val) + } +} + +// bzToQuarantineRecordSuffixIndex converts the given byte slice into a QuarantineRecordSuffixIndex or returns an error. +// If the byte slice is nil or empty, a default QuarantineRecordSuffixIndex is returned with no suffixes. +func (k Keeper) bzToQuarantineRecordSuffixIndex(bz []byte) (*quarantine.QuarantineRecordSuffixIndex, error) { + var si quarantine.QuarantineRecordSuffixIndex + if len(bz) > 0 { + err := k.cdc.Unmarshal(bz, &si) + if err != nil { + return &si, err + } + } + return &si, nil +} + +// mustBzToQuarantineRecordSuffixIndex returns bzToQuarantineRecordSuffixIndex but panics on error. +func (k Keeper) mustBzToQuarantineRecordSuffixIndex(bz []byte) *quarantine.QuarantineRecordSuffixIndex { + si, err := k.bzToQuarantineRecordSuffixIndex(bz) + if err != nil { + panic(err) + } + return si +} + +// getQuarantineRecordSuffixIndex gets a quarantine record suffix entry and it's key. +func (k Keeper) getQuarantineRecordSuffixIndex(store sdk.KVStore, toAddr, fromAddr sdk.AccAddress) (*quarantine.QuarantineRecordSuffixIndex, []byte) { + key := quarantine.CreateRecordIndexKey(toAddr, fromAddr) + bz := store.Get(key) + rv := k.mustBzToQuarantineRecordSuffixIndex(bz) + return rv, key +} + +// getQuarantineRecordSuffixes gets a sorted list of known record suffixes of quarantine records to toAddr +// from any of the fromAddrs. The list will not contain duplicates, but may contain suffixes that don't point to records. +func (k Keeper) getQuarantineRecordSuffixes(store sdk.KVStore, toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress) [][]byte { + rv := &quarantine.QuarantineRecordSuffixIndex{} + for _, fromAddr := range fromAddrs { + suffixes, _ := k.getQuarantineRecordSuffixIndex(store, toAddr, fromAddr) + rv.AddSuffixes(suffixes.RecordSuffixes...) + rv.AddSuffixes(fromAddr) + } + rv.Simplify() + return rv.RecordSuffixes +} + +// addQuarantineRecordSuffixIndexes adds the provided suffix to all to/from suffix index entries. +func (k Keeper) addQuarantineRecordSuffixIndexes(store sdk.KVStore, toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress, suffix []byte) { + for _, fromAddr := range fromAddrs { + ind, key := k.getQuarantineRecordSuffixIndex(store, toAddr, fromAddr) + ind.AddSuffixes(suffix) + ind.Simplify(fromAddr) + k.setQuarantineRecordSuffixIndex(store, key, ind) + } +} + +// deleteQuarantineRecordSuffixIndexes removes the provided suffix from all to/from suffix index entries and either saves +// the updated list or deletes it if it's now empty. +func (k Keeper) deleteQuarantineRecordSuffixIndexes(store sdk.KVStore, toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress, suffix []byte) { + for _, fromAddr := range fromAddrs { + ind, key := k.getQuarantineRecordSuffixIndex(store, toAddr, fromAddr) + ind.Simplify(fromAddr, suffix) + k.setQuarantineRecordSuffixIndex(store, key, ind) + } +} diff --git a/x/quarantine/keeper/keeper_test.go b/x/quarantine/keeper/keeper_test.go new file mode 100644 index 0000000000..5e45e83bef --- /dev/null +++ b/x/quarantine/keeper/keeper_test.go @@ -0,0 +1,3787 @@ +package keeper_test + +import ( + "bytes" + "context" + "fmt" + "sort" + "testing" + "time" + + "github.com/stretchr/testify/require" + + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" + + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +// updateQR updates the AccAddresses using the provided addrs. +// Any AccAddress that is 1 byte long and can be an index in addrs, +// is replaced by the addrs entry using that byte as the index. +// E.g. if UnacceptedFromAddresses is []sdk.AccAddress{{1}}, then it will be replaced with addrs[1]. +func updateQR(addrs []sdk.AccAddress, record *quarantine.QuarantineRecord) { + if record != nil { + for i, addr := range record.UnacceptedFromAddresses { + if len(addr) == 1 && int(addr[0]) < len(addrs) { + record.UnacceptedFromAddresses[i] = addrs[addr[0]] + } + } + for i, addr := range record.AcceptedFromAddresses { + if len(addr) == 1 && int(addr[0]) < len(addrs) { + record.AcceptedFromAddresses[i] = addrs[addr[0]] + } + } + } +} + +// qrsi is just a shorter way to create a *quarantine.QuarantineRecordSuffixIndex +func qrsi(suffixes ...[]byte) *quarantine.QuarantineRecordSuffixIndex { + rv := &quarantine.QuarantineRecordSuffixIndex{} + if len(suffixes) > 0 { + rv.RecordSuffixes = suffixes + } + return rv +} + +// qrsis is just a shorter way to create []*quarantine.QuarantineRecordSuffixIndex +// Combine with qrsi for true power. +func qrsis(vals ...*quarantine.QuarantineRecordSuffixIndex) []*quarantine.QuarantineRecordSuffixIndex { + return vals +} + +// accs is just a shorter way to create an []sdk.AccAddress +func accs(accz ...sdk.AccAddress) []sdk.AccAddress { + return accz +} + +type TestSuite struct { + suite.Suite + + app *simapp.SimApp + sdkCtx sdk.Context + stdlibCtx context.Context + keeper keeper.Keeper + bankKeeper bankkeeper.Keeper + + blockTime time.Time + addr1 sdk.AccAddress + addr2 sdk.AccAddress + addr3 sdk.AccAddress + addr4 sdk.AccAddress + addr5 sdk.AccAddress +} + +func (s *TestSuite) SetupTest() { + s.blockTime = tmtime.Now() + s.app = simapp.Setup(s.T(), false) + s.sdkCtx = s.app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeader(tmproto.Header{Time: s.blockTime}) + s.stdlibCtx = sdk.WrapSDKContext(s.sdkCtx) + s.keeper = s.app.QuarantineKeeper + s.bankKeeper = s.app.BankKeeper + + addrs := simapp.AddTestAddrsIncremental(s.app, s.sdkCtx, 5, sdk.NewInt(1_000_000_000)) + s.addr1 = addrs[0] + s.addr2 = addrs[1] + s.addr3 = addrs[2] + s.addr4 = addrs[3] + s.addr5 = addrs[4] +} + +func (s *TestSuite) cz(coins string) sdk.Coins { + s.T().Helper() + rv, err := sdk.ParseCoinsNormalized(coins) + s.Require().NoError(err, "ParseCoinsNormalized(%q)", coins) + return rv +} + +func (s *TestSuite) AssertErrorContents(theError error, contains []string, msgAndArgs ...interface{}) bool { + s.T().Helper() + return AssertErrorContents(s.T(), theError, contains, msgAndArgs...) +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(TestSuite)) +} + +func (s *TestSuite) TestGetFundsHolder() { + s.Run("initial value", func() { + expected := authtypes.NewModuleAddress(quarantine.ModuleName) + + actual := s.keeper.GetFundsHolder() + s.Assert().Equal(expected, actual, "funds holder") + }) + + s.Run("set to nil", func() { + k := s.keeper.WithFundsHolder(nil) + + actual := k.GetFundsHolder() + s.Assert().Nil(actual, "funds holder") + }) + + s.Run("set to something else", func() { + k := s.keeper.WithFundsHolder(s.addr1) + + actual := k.GetFundsHolder() + s.Assert().Equal(s.addr1, actual, "funds holder") + }) +} + +func (s *TestSuite) TestQuarantineOptInOut() { + s.Run("is quarantined before opting in", func() { + actual := s.keeper.IsQuarantinedAddr(s.sdkCtx, s.addr2) + s.Assert().False(actual, "IsQuarantinedAddr addr2") + }) + + s.Run("opt in and check", func() { + err := s.keeper.SetOptIn(s.sdkCtx, s.addr2) + s.Require().NoError(err, "SetOptIn addr2") + actual := s.keeper.IsQuarantinedAddr(s.sdkCtx, s.addr2) + s.Assert().True(actual, "IsQuarantinedAddr addr2") + }) + + s.Run("opt in again and check", func() { + err := s.keeper.SetOptIn(s.sdkCtx, s.addr2) + s.Require().NoError(err, "SetOptIn addr2") + actual := s.keeper.IsQuarantinedAddr(s.sdkCtx, s.addr2) + s.Assert().True(actual, "IsQuarantinedAddr addr2") + }) + + s.Run("opt out and check", func() { + err := s.keeper.SetOptOut(s.sdkCtx, s.addr2) + s.Require().NoError(err, "SetOptOut addr2") + actual := s.keeper.IsQuarantinedAddr(s.sdkCtx, s.addr2) + s.Assert().False(actual, "IsQuarantinedAddr addr2") + }) + + s.Run("opt out again and check", func() { + err := s.keeper.SetOptOut(s.sdkCtx, s.addr2) + s.Require().NoError(err, "SetOptOut addr2") + actual := s.keeper.IsQuarantinedAddr(s.sdkCtx, s.addr2) + s.Assert().False(actual, "IsQuarantinedAddr addr2") + }) + + s.Run("opt in event", func() { + ctx := s.sdkCtx.WithEventManager(sdk.NewEventManager()) + err := s.keeper.SetOptIn(ctx, s.addr3) + s.Require().NoError(err, "SetOptIn addr3") + + expected := sdk.Events{ + { + Type: "cosmos.quarantine.v1beta1.EventOptIn", + Attributes: []abci.EventAttribute{ + { + Key: []byte("to_address"), + Value: []byte(fmt.Sprintf(`"%s"`, s.addr3.String())), + }, + }, + }, + } + actual := ctx.EventManager().Events() + s.Assert().Equal(expected, actual, "emitted events") + }) + + s.Run("opt out event", func() { + ctx := s.sdkCtx.WithEventManager(sdk.NewEventManager()) + err := s.keeper.SetOptOut(ctx, s.addr3) + s.Require().NoError(err, "SetOptOut addr3") + + expected := sdk.Events{ + { + Type: "cosmos.quarantine.v1beta1.EventOptOut", + Attributes: []abci.EventAttribute{ + { + Key: []byte("to_address"), + Value: []byte(fmt.Sprintf(`"%s"`, s.addr3.String())), + }, + }, + }, + } + actual := ctx.EventManager().Events() + s.Assert().Equal(expected, actual, "emitted events") + }) +} + +func (s *TestSuite) TestQuarantinedAccountsIterateAndGetAll() { + // Opt in all of them except addr4. + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr1), "SetOptIn addr1") + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr2), "SetOptIn addr2") + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr3), "SetOptIn addr3") + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr5), "SetOptIn addr5") + + // Now opt out addr2. + s.Require().NoError(s.keeper.SetOptOut(s.sdkCtx, s.addr2), "SetOptOut addr2") + + allAddrs := accs(s.addr1, s.addr3, s.addr5) + sort.Slice(allAddrs, func(i, j int) bool { + return bytes.Compare(allAddrs[i], allAddrs[j]) < 0 + }) + + s.Run("IterateQuarantinedAccounts", func() { + expected := allAddrs + addrs := make([]sdk.AccAddress, 0, len(expected)) + callback := func(toAddr sdk.AccAddress) bool { + addrs = append(addrs, toAddr) + return false + } + + testFunc := func() { + s.keeper.IterateQuarantinedAccounts(s.sdkCtx, callback) + } + s.Require().NotPanics(testFunc, "IterateQuarantinedAccounts") + s.Assert().Equal(expected, addrs, "iterated addrs") + }) + + s.Run("IterateQuarantinedAccounts early stop", func() { + stopLen := 2 + expected := allAddrs[:stopLen] + addrs := make([]sdk.AccAddress, 0, stopLen) + callback := func(toAddr sdk.AccAddress) bool { + addrs = append(addrs, toAddr) + return len(addrs) >= stopLen + } + + testFunc := func() { + s.keeper.IterateQuarantinedAccounts(s.sdkCtx, callback) + } + s.Require().NotPanics(testFunc, "IterateQuarantinedAccounts") + s.Assert().Equal(expected, addrs, "iterated addrs") + }) + + s.Run("GetAllQuarantinedAccounts", func() { + expected := make([]string, len(allAddrs)) + for i, addr := range allAddrs { + expected[i] = addr.String() + } + + var actual []string + testFunc := func() { + actual = s.keeper.GetAllQuarantinedAccounts(s.sdkCtx) + } + s.Require().NotPanics(testFunc, "GetAllQuarantinedAccounts") + s.Assert().Equal(expected, actual, "GetAllQuarantinedAccounts") + }) +} + +func (s *TestSuite) TestAutoResponseGetSet() { + allAddrs := accs(s.addr1, s.addr2, s.addr3, s.addr4, s.addr5) + allResps := []quarantine.AutoResponse{ + quarantine.AUTO_RESPONSE_ACCEPT, + quarantine.AUTO_RESPONSE_DECLINE, + quarantine.AUTO_RESPONSE_UNSPECIFIED, + } + + s.Run("GetAutoResponse on unset addrs", func() { + expected := quarantine.AUTO_RESPONSE_UNSPECIFIED + for i, addrI := range allAddrs { + for j, addrJ := range allAddrs { + if i == j { + continue + } + actual := s.keeper.GetAutoResponse(s.sdkCtx, addrI, addrJ) + s.Assert().Equal(expected, actual, "GetAutoResponse addr%d addr%d", i+1, j+1) + } + } + }) + + s.Run("GetAutoResponse on same addr", func() { + expected := quarantine.AUTO_RESPONSE_ACCEPT + for i, addr := range allAddrs { + actual := s.keeper.GetAutoResponse(s.sdkCtx, addr, addr) + s.Assert().Equal(expected, actual, "GetAutoResponse addr%d addr%d", i+1, i+1) + } + }) + + for _, expected := range allResps { + s.Run(fmt.Sprintf("set %s", expected), func() { + testFunc := func() { + s.keeper.SetAutoResponse(s.sdkCtx, s.addr3, s.addr1, expected) + } + s.Require().NotPanics(testFunc, "SetAutoResponse addr3 addr1 %s", expected) + actual := s.keeper.GetAutoResponse(s.sdkCtx, s.addr3, s.addr1) + s.Assert().Equal(expected, actual, "GetAutoResponse after set %s", expected) + }) + } + + s.Run("IsAutoAccept", func() { + testFunc := func() { + s.keeper.SetAutoResponse(s.sdkCtx, s.addr4, s.addr2, quarantine.AUTO_RESPONSE_ACCEPT) + } + s.Require().NotPanics(testFunc, "SetAutoResponse") + + actual42 := s.keeper.IsAutoAccept(s.sdkCtx, s.addr4, s.addr2) + s.Assert().True(actual42, "IsAutoAccept addr4 addr2") + actual43 := s.keeper.IsAutoAccept(s.sdkCtx, s.addr4, s.addr3) + s.Assert().False(actual43, "IsAutoAccept addr4 addr3") + actual44 := s.keeper.IsAutoAccept(s.sdkCtx, s.addr4, s.addr4) + s.Assert().True(actual44, "IsAutoAccept self") + }) + + s.Run("IsAutoDecline", func() { + testFunc := func() { + s.keeper.SetAutoResponse(s.sdkCtx, s.addr5, s.addr2, quarantine.AUTO_RESPONSE_DECLINE) + } + s.Require().NotPanics(testFunc, "SetAutoResponse") + + actual52 := s.keeper.IsAutoDecline(s.sdkCtx, s.addr5, s.addr2) + s.Assert().True(actual52, "IsAutoDecline addr5 addr2") + actual53 := s.keeper.IsAutoDecline(s.sdkCtx, s.addr5, s.addr3) + s.Assert().False(actual53, "IsAutoDecline addr5 addr3") + actual55 := s.keeper.IsAutoDecline(s.sdkCtx, s.addr5, s.addr5) + s.Assert().False(actual55, "IsAutoDecline self") + }) +} + +func (s *TestSuite) TestAutoResponsesItateAndGetAll() { + setAutoTestFunc := func(addrA, addrB sdk.AccAddress, response quarantine.AutoResponse) func() { + return func() { + s.keeper.SetAutoResponse(s.sdkCtx, addrA, addrB, response) + } + } + // Shorten up the names a bit. + arAccept := quarantine.AUTO_RESPONSE_ACCEPT + arDecline := quarantine.AUTO_RESPONSE_DECLINE + arUnspecified := quarantine.AUTO_RESPONSE_UNSPECIFIED + + // Set up some auto-responses. + // This is purposely done in a random order. + + // Set account 1 to auto-accept from all. + // Set account 2 to auto-accept from all. + // Set 3 to auto-decline from all + // Set 4 to auto-accept from 2 and 3 and auto-decline from 5 + s.Require().NotPanics(setAutoTestFunc(s.addr4, s.addr3, arAccept), "4 <- 3 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr3, s.addr2, arDecline), "3 <- 2 decline") + s.Require().NotPanics(setAutoTestFunc(s.addr2, s.addr5, arAccept), "2 <- 5 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr3, s.addr5, arDecline), "3 <- 5 decline") + s.Require().NotPanics(setAutoTestFunc(s.addr2, s.addr4, arAccept), "2 <- 4 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr2, s.addr1, arAccept), "2 <- 1 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr4, s.addr5, arDecline), "4 <- 5 decline") + s.Require().NotPanics(setAutoTestFunc(s.addr3, s.addr4, arDecline), "3 <- 4 decline") + s.Require().NotPanics(setAutoTestFunc(s.addr3, s.addr1, arDecline), "3 <- 1 decline") + s.Require().NotPanics(setAutoTestFunc(s.addr1, s.addr5, arAccept), "1 <- 5 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr1, s.addr2, arAccept), "1 <- 2 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr1, s.addr4, arAccept), "1 <- 4 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr2, s.addr3, arAccept), "2 <- 3 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr4, s.addr2, arAccept), "4 <- 2 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr1, s.addr3, arAccept), "1 <- 3 accept") + + // Now undo/change a few of those. + // Set 2 to unspecified from 3 and 4 + // Set 3 to unspecified from 5 + // Set 4 to auto-decline from 3 and auto-accept from 5 + s.Require().NotPanics(setAutoTestFunc(s.addr4, s.addr5, arAccept), "4 <- 5 accept") + s.Require().NotPanics(setAutoTestFunc(s.addr2, s.addr3, arUnspecified), "2 <- 3 unspecified") + s.Require().NotPanics(setAutoTestFunc(s.addr3, s.addr5, arUnspecified), "3 <- 5 unspecified") + s.Require().NotPanics(setAutoTestFunc(s.addr4, s.addr3, arDecline), "4 <- 3 decline") + s.Require().NotPanics(setAutoTestFunc(s.addr2, s.addr4, arUnspecified), "2 <- 4 unspecified") + + // Setup result: + // 1 <- 2 = accept 3 <- 1 = decline + // 1 <- 3 = accept 3 <- 2 = decline + // 1 <- 4 = accept 3 <- 4 = decline + // 1 <- 5 = accept 4 <- 2 = accept + // 2 <- 1 = accept 4 <- 3 = decline + // 2 <- 5 = accept 4 <- 5 = accept + + // Let's hope the addresses are actually incremental or else this gets a lot tougher to define. + type callbackArgs struct { + toAddr sdk.AccAddress + fromAddr sdk.AccAddress + response quarantine.AutoResponse + } + + allArgs := []callbackArgs{ + {toAddr: s.addr1, fromAddr: s.addr2, response: arAccept}, + {toAddr: s.addr1, fromAddr: s.addr3, response: arAccept}, + {toAddr: s.addr1, fromAddr: s.addr4, response: arAccept}, + {toAddr: s.addr1, fromAddr: s.addr5, response: arAccept}, + {toAddr: s.addr2, fromAddr: s.addr1, response: arAccept}, + {toAddr: s.addr2, fromAddr: s.addr5, response: arAccept}, + {toAddr: s.addr3, fromAddr: s.addr1, response: arDecline}, + {toAddr: s.addr3, fromAddr: s.addr2, response: arDecline}, + {toAddr: s.addr3, fromAddr: s.addr4, response: arDecline}, + {toAddr: s.addr4, fromAddr: s.addr2, response: arAccept}, + {toAddr: s.addr4, fromAddr: s.addr3, response: arDecline}, + {toAddr: s.addr4, fromAddr: s.addr5, response: arAccept}, + } + + s.Run("IterateAutoResponses all", func() { + expected := allArgs + actualAllArgs := make([]callbackArgs, 0, len(allArgs)) + callback := func(toAddr, fromAddr sdk.AccAddress, response quarantine.AutoResponse) bool { + actualAllArgs = append(actualAllArgs, callbackArgs{toAddr: toAddr, fromAddr: fromAddr, response: response}) + return false + } + testFunc := func() { + s.keeper.IterateAutoResponses(s.sdkCtx, nil, callback) + } + s.Require().NotPanics(testFunc, "IterateAutoResponses") + s.Assert().Equal(expected, actualAllArgs, "iterated args") + }) + + for i, addr := range accs(s.addr1, s.addr2, s.addr3, s.addr4, s.addr5) { + s.Run(fmt.Sprintf("IterateAutoResponses addr%d", i+1), func() { + var expected []callbackArgs + for _, args := range allArgs { + if addr.Equals(args.toAddr) { + expected = append(expected, args) + } + } + var actual []callbackArgs + callback := func(toAddr, fromAddr sdk.AccAddress, response quarantine.AutoResponse) bool { + actual = append(actual, callbackArgs{toAddr: toAddr, fromAddr: fromAddr, response: response}) + return false + } + testFunc := func() { + s.keeper.IterateAutoResponses(s.sdkCtx, addr, callback) + } + s.Require().NotPanics(testFunc, "IterateAutoResponses") + s.Assert().Equal(expected, actual, "iterated args") + }) + } + + s.Run("IterateAutoResponses stop early", func() { + stopLen := 4 + expected := allArgs[:stopLen] + actual := make([]callbackArgs, 0, stopLen) + callback := func(toAddr, fromAddr sdk.AccAddress, response quarantine.AutoResponse) bool { + actual = append(actual, callbackArgs{toAddr: toAddr, fromAddr: fromAddr, response: response}) + return len(actual) >= stopLen + } + testFunc := func() { + s.keeper.IterateAutoResponses(s.sdkCtx, nil, callback) + } + s.Require().NotPanics(testFunc, "IterateAutoResponses") + s.Assert().Equal(expected, actual, "iterated args") + }) + + s.Run("GetAllAutoResponseEntries", func() { + expected := make([]*quarantine.AutoResponseEntry, len(allArgs)) + for i, args := range allArgs { + expected[i] = &quarantine.AutoResponseEntry{ + ToAddress: args.toAddr.String(), + FromAddress: args.fromAddr.String(), + Response: args.response, + } + } + + var actual []*quarantine.AutoResponseEntry + testFunc := func() { + actual = s.keeper.GetAllAutoResponseEntries(s.sdkCtx) + } + s.Require().NotPanics(testFunc, "GetAllAutoResponseEntries") + s.Assert().Equal(expected, actual, "GetAllAutoResponseEntries results") + }) +} + +func (s *TestSuite) TestBzToQuarantineRecord() { + cdc := s.keeper.GetCodec() + + tests := []struct { + name string + bz []byte + expected *quarantine.QuarantineRecord + expErr string + }{ + { + name: "control", + bz: cdc.MustMarshal(&quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr1), + AcceptedFromAddresses: accs(s.addr2), + Coins: s.cz("9000bar,888foo"), + Declined: false, + }), + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr1), + AcceptedFromAddresses: accs(s.addr2), + Coins: s.cz("9000bar,888foo"), + Declined: false, + }, + }, + { + name: "nil bz", + bz: nil, + expected: &quarantine.QuarantineRecord{ + Coins: sdk.Coins{}, + }, + }, + { + name: "empty bz", + bz: nil, + expected: &quarantine.QuarantineRecord{ + Coins: sdk.Coins{}, + }, + }, + { + name: "not a quarantine record", + bz: cdc.MustMarshal(&quarantine.AutoResponseEntry{ + ToAddress: s.addr4.String(), + FromAddress: s.addr3.String(), + Response: quarantine.AUTO_RESPONSE_ACCEPT, + }), + expErr: "proto: wrong wireType = 0 for field Coins", + }, + { + name: "unknown bytes", + bz: []byte{0x75, 110, 0153, 0x6e, 0157, 119, 0156, 0xff, 0142, 0x79, 116, 0x65, 0163}, + expErr: "proto: illegal wireType 7", + }, + { + name: "declined", + bz: cdc.MustMarshal(&quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr1), + AcceptedFromAddresses: accs(s.addr2), + Coins: s.cz("9001bar,889foo"), + Declined: true, + }), + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr1), + AcceptedFromAddresses: accs(s.addr2), + Coins: s.cz("9001bar,889foo"), + Declined: true, + }, + }, + { + name: "no unaccepted", + bz: cdc.MustMarshal(&quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + AcceptedFromAddresses: accs(s.addr2, s.addr1, s.addr3), + Coins: s.cz("9002bar,890foo"), + Declined: false, + }), + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: accs(s.addr2, s.addr1, s.addr3), + Coins: s.cz("9002bar,890foo"), + Declined: false, + }, + }, + { + name: "no accepted", + bz: cdc.MustMarshal(&quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr4, s.addr2, s.addr5), + AcceptedFromAddresses: []sdk.AccAddress{}, + Coins: s.cz("9003bar,891foo"), + Declined: false, + }), + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr4, s.addr2, s.addr5), + AcceptedFromAddresses: nil, + Coins: s.cz("9003bar,891foo"), + Declined: false, + }, + }, + { + name: "no coins", + bz: cdc.MustMarshal(&quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr1), + AcceptedFromAddresses: accs(s.addr2), + Coins: nil, + Declined: false, + }), + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(s.addr1), + AcceptedFromAddresses: accs(s.addr2), + Coins: sdk.Coins{}, + Declined: false, + }, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + var actual *quarantine.QuarantineRecord + var err error + testFunc := func() { + actual, err = s.keeper.BzToQuarantineRecord(tc.bz) + } + s.Require().NotPanics(testFunc, "bzToQuarantineRecord") + if len(tc.expErr) > 0 { + s.Require().EqualError(err, tc.expErr, "bzToQuarantineRecord error: %v", actual) + } else { + s.Require().NoError(err, "bzToQuarantineRecord error") + s.Assert().Equal(tc.expected, actual, "bzToQuarantineRecord record") + } + }) + + s.Run("must "+tc.name, func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.MustBzToQuarantineRecord(tc.bz) + } + if len(tc.expErr) > 0 { + s.Require().PanicsWithError(tc.expErr, testFunc, "mustBzToQuarantineRecord: %v", actual) + } else { + s.Require().NotPanics(testFunc, "mustBzToQuarantineRecord") + s.Assert().Equal(tc.expected, actual, "mustBzToQuarantineRecord record") + } + }) + } +} + +func (s *TestSuite) TestQuarantineRecordGetSet() { + s.Run("get does not exist", func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, s.addr1, s.addr2) + } + s.Require().NotPanics(testFunc, "GetQuarantineRecord") + s.Assert().Nil(actual, "GetQuarantineRecord") + }) + + s.Run("get multiple froms does not exist", func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, s.addr1, s.addr2, s.addr3, s.addr5) + } + s.Require().NotPanics(testFunc, "GetQuarantineRecord") + s.Assert().Nil(actual, "GetQuarantineRecord") + }) + + s.Run("get no froms", func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, s.addr5) + } + s.Assert().Panics(testFunc, "GetQuarantineRecord") + s.Assert().Nil(actual, "GetQuarantineRecord") + }) + + s.Run("set get one unaccepted no accepted", func() { + toAddr := MakeTestAddr("sgouna", 0) + uFromAddr := MakeTestAddr("sgouna", 1) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(uFromAddr), + AcceptedFromAddresses: nil, + Coins: s.cz("456bar,1233foo"), + Declined: false, + } + expected := MakeCopyOfQuarantineRecord(record) + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + var actual *quarantine.QuarantineRecord + testFuncGet := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, uFromAddr) + } + var actualBackwards *quarantine.QuarantineRecord + testFuncGetBackwards := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, uFromAddr, toAddr) + } + + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + if s.Assert().NotPanics(testFuncGet, "GetQuarantineRecord") { + s.Assert().Equal(expected, actual, "GetQuarantineRecord") + } + if s.Assert().NotPanics(testFuncGetBackwards, "GetQuarantineRecord wrong to/from order") { + s.Assert().Nil(actualBackwards, "GetQuarantineRecord wrong to/from order") + } + }) + + s.Run("set get one unaccepted one accepted", func() { + toAddr := MakeTestAddr("sgouoa", 0) + uFromAddr := MakeTestAddr("sgouoa", 1) + aFromAddr := MakeTestAddr("sgouoa", 2) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(uFromAddr), + AcceptedFromAddresses: accs(aFromAddr), + Coins: sdk.Coins{}, + Declined: false, + } + expected := MakeCopyOfQuarantineRecord(record) + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + var actualUA *quarantine.QuarantineRecord + testFuncGetOrderUA := func() { + actualUA = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, uFromAddr, aFromAddr) + } + var actualAU *quarantine.QuarantineRecord + testFuncGetOrderAU := func() { + actualAU = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, aFromAddr, uFromAddr) + } + + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + if s.Assert().NotPanics(testFuncGetOrderUA, "GetQuarantineRecord order: ua") { + s.Assert().Equal(expected, actualUA, "GetQuarantineRecord order: ua") + } + if s.Assert().NotPanics(testFuncGetOrderAU, "GetQuarantineRecord order: au") { + s.Assert().Equal(expected, actualAU, "GetQuarantineRecord order: au") + } + }) + + s.Run("set get two unaccepted no accepted", func() { + toAddr := MakeTestAddr("sgtuna", 0) + uFromAddr1 := MakeTestAddr("sgtuna", 1) + uFromAddr2 := MakeTestAddr("sgtuna", 2) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(uFromAddr1, uFromAddr2), + AcceptedFromAddresses: nil, + Coins: sdk.Coins{}, + Declined: false, + } + expected := MakeCopyOfQuarantineRecord(record) + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + var actual12 *quarantine.QuarantineRecord + testFuncGet12 := func() { + actual12 = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, uFromAddr1, uFromAddr2) + } + var actual21 *quarantine.QuarantineRecord + testFuncGet21 := func() { + actual21 = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, uFromAddr2, uFromAddr1) + } + var actualJust1 *quarantine.QuarantineRecord + testFuncGetJust1 := func() { + actualJust1 = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, uFromAddr1) + } + var actualJust2 *quarantine.QuarantineRecord + testFuncGetJust2 := func() { + actualJust2 = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, uFromAddr2) + } + + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + if s.Assert().NotPanics(testFuncGet12, "GetQuarantineRecord order: 1 2") { + s.Assert().Equal(expected, actual12, "GetQuarantineRecord result order: 1 2") + } + if s.Assert().NotPanics(testFuncGet21, "GetQuarantineRecord order: 2 1") { + s.Assert().Equal(expected, actual21, "GetQuarantineRecord result order: 2 1") + } + if s.Assert().NotPanics(testFuncGetJust1, "GetQuarantineRecord just 1") { + s.Assert().Nil(actualJust1, "GetQuarantineRecord just 1") + } + if s.Assert().NotPanics(testFuncGetJust2, "GetQuarantineRecord just 2") { + s.Assert().Nil(actualJust2, "GetQuarantineRecord just 2") + } + }) + + s.Run("set get no unaccepted one accepted", func() { + toAddr := MakeTestAddr("sgnuoa", 0) + aFromAddr := MakeTestAddr("sgnuoa", 1) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: accs(aFromAddr), + Coins: sdk.Coins{}, + Declined: false, + } + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + var actual *quarantine.QuarantineRecord + testFuncGet := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, aFromAddr) + } + + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + s.Require().NotPanics(testFuncGet, "GetQuarantineRecord") + s.Assert().Nil(actual, "GetQuarantineRecord") + }) + + s.Run("set get no unaccepted two accepted", func() { + toAddr := MakeTestAddr("sgnuta", 0) + aFromAddr1 := MakeTestAddr("sgnuta", 1) + aFromAddr2 := MakeTestAddr("sgnuta", 2) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: accs(aFromAddr1, aFromAddr2), + Coins: sdk.Coins{}, + Declined: false, + } + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + var actual12 *quarantine.QuarantineRecord + testFuncGet12 := func() { + actual12 = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, aFromAddr1, aFromAddr2) + } + var actual21 *quarantine.QuarantineRecord + testFuncGet21 := func() { + actual21 = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, aFromAddr2, aFromAddr1) + } + + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + if s.Assert().NotPanics(testFuncGet12, "GetQuarantineRecord order: 1 2") { + s.Assert().Nil(actual12, "GetQuarantineRecord order: 1 2") + } + if s.Assert().NotPanics(testFuncGet21, "GetQuarantineRecord order: 2 1") { + s.Assert().Nil(actual21, "GetQuarantineRecord order: 2 1") + } + }) + + s.Run("set get two unaccepted one accepted", func() { + toAddr := MakeTestAddr("sgtuoa", 0) + uFromAddr1 := MakeTestAddr("sgtuoa", 1) + uFromAddr2 := MakeTestAddr("sgtuoa", 2) + aFromAddr := MakeTestAddr("sgtuoa", 3) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(uFromAddr1, uFromAddr2), + AcceptedFromAddresses: accs(aFromAddr), + Coins: sdk.Coins{}, + Declined: false, + } + expected := MakeCopyOfQuarantineRecord(record) + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + + positiveTests := []struct { + name string + fromAddrs []sdk.AccAddress + }{ + {"1 2 a", accs(uFromAddr1, uFromAddr2, aFromAddr)}, + {"1 a 2", accs(uFromAddr1, aFromAddr, uFromAddr2)}, + {"2 1 a", accs(uFromAddr2, uFromAddr1, aFromAddr)}, + {"2 a 1", accs(uFromAddr2, aFromAddr, uFromAddr1)}, + {"a 1 2", accs(aFromAddr, uFromAddr1, uFromAddr2)}, + {"a 2 1", accs(aFromAddr, uFromAddr2, uFromAddr1)}, + } + for _, tc := range positiveTests { + s.Run("GetQuarantineRecord order "+tc.name, func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, tc.fromAddrs...) + } + if s.Assert().NotPanics(testFunc, "GetQuarantineRecord") { + s.Assert().Equal(expected, actual, "GetQuarantineRecord") + } + }) + } + + negativeTests := []struct { + name string + fromAddrs []sdk.AccAddress + }{ + {"1", accs(uFromAddr1)}, + {"2", accs(uFromAddr2)}, + {"a", accs(aFromAddr)}, + {"1 1", accs(uFromAddr1, uFromAddr1)}, + {"1 2", accs(uFromAddr1, uFromAddr2)}, + {"1 a", accs(uFromAddr1, aFromAddr)}, + {"2 1", accs(uFromAddr2, uFromAddr1)}, + {"2 2", accs(uFromAddr2, uFromAddr2)}, + {"2 a", accs(uFromAddr2, aFromAddr)}, + {"a 1", accs(aFromAddr, uFromAddr1)}, + {"a 2", accs(aFromAddr, uFromAddr2)}, + {"a a", accs(aFromAddr, aFromAddr)}, + {"1 1 2", accs(uFromAddr1, uFromAddr1, uFromAddr2)}, + {"2 2 a", accs(uFromAddr2, uFromAddr2, aFromAddr)}, + {"1 2 a 1", accs(uFromAddr1, uFromAddr2, aFromAddr, uFromAddr1)}, + {"1 2 2 a", accs(uFromAddr1, uFromAddr2, uFromAddr2, aFromAddr)}, + {"a 1 2 a", accs(aFromAddr, uFromAddr1, uFromAddr2, aFromAddr)}, + } + for _, tc := range negativeTests { + s.Run("GetQuarantineRecord order "+tc.name, func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, tc.fromAddrs...) + } + if s.Assert().NotPanics(testFunc, "GetQuarantineRecord") { + s.Assert().Nil(actual, "GetQuarantineRecord") + } + }) + } + }) + + s.Run("set get one unaccepted two accepted", func() { + toAddr := MakeTestAddr("sgouta", 0) + uFromAddr := MakeTestAddr("sgouta", 1) + aFromAddr1 := MakeTestAddr("sgouta", 2) + aFromAddr2 := MakeTestAddr("sgouta", 3) + record := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(uFromAddr), + AcceptedFromAddresses: accs(aFromAddr1, aFromAddr2), + Coins: sdk.Coins{}, + Declined: false, + } + expected := MakeCopyOfQuarantineRecord(record) + + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + + positiveTests := []struct { + name string + fromAddrs []sdk.AccAddress + }{ + {"1 2 u", accs(aFromAddr1, aFromAddr2, uFromAddr)}, + {"1 u 2", accs(aFromAddr1, uFromAddr, aFromAddr2)}, + {"2 1 u", accs(aFromAddr2, aFromAddr1, uFromAddr)}, + {"2 u 1", accs(aFromAddr2, uFromAddr, aFromAddr1)}, + {"u 1 2", accs(uFromAddr, aFromAddr1, aFromAddr2)}, + {"u 2 1", accs(uFromAddr, aFromAddr2, aFromAddr1)}, + } + for _, tc := range positiveTests { + s.Run("GetQuarantineRecord order "+tc.name, func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, tc.fromAddrs...) + } + if s.Assert().NotPanics(testFunc, "GetQuarantineRecord") { + s.Assert().Equal(expected, actual, "GetQuarantineRecord") + } + }) + } + + negativeTests := []struct { + name string + fromAddrs []sdk.AccAddress + }{ + {"1", accs(aFromAddr1)}, + {"2", accs(aFromAddr2)}, + {"u", accs(uFromAddr)}, + {"1 1", accs(aFromAddr1, aFromAddr1)}, + {"1 2", accs(aFromAddr1, aFromAddr2)}, + {"1 u", accs(aFromAddr1, uFromAddr)}, + {"2 1", accs(aFromAddr2, aFromAddr1)}, + {"2 2", accs(aFromAddr2, aFromAddr2)}, + {"2 u", accs(aFromAddr2, uFromAddr)}, + {"u 1", accs(uFromAddr, aFromAddr1)}, + {"u 2", accs(uFromAddr, aFromAddr2)}, + {"u u", accs(uFromAddr, uFromAddr)}, + {"1 1 2", accs(aFromAddr1, aFromAddr1, aFromAddr2)}, + {"2 2 u", accs(aFromAddr2, aFromAddr2, uFromAddr)}, + {"1 2 u 1", accs(aFromAddr1, aFromAddr2, uFromAddr, aFromAddr1)}, + {"1 2 2 u", accs(aFromAddr1, aFromAddr2, aFromAddr2, uFromAddr)}, + {"u 1 2 u", accs(uFromAddr, aFromAddr1, uFromAddr, uFromAddr)}, + } + for _, tc := range negativeTests { + s.Run("GetQuarantineRecord order "+tc.name, func() { + var actual *quarantine.QuarantineRecord + testFunc := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, tc.fromAddrs...) + } + if s.Assert().NotPanics(testFunc, "GetQuarantineRecord") { + s.Assert().Nil(actual, "GetQuarantineRecord") + } + }) + } + }) +} + +func (s *TestSuite) TestGetQuarantineRecords() { + addr0 := MakeTestAddr("gqr", 0) + addr1 := MakeTestAddr("gqr", 1) + addr2 := MakeTestAddr("gqr", 2) + addr3 := MakeTestAddr("gqr", 3) + + mustCoins := func(amt string) sdk.Coins { + coins, err := sdk.ParseCoinsNormalized(amt) + s.Require().NoError(err, "ParseCoinsNormalized(%q)", amt) + return coins + } + + recordA := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1), + Coins: mustCoins("1acoin"), + Declined: true, + } + recordB := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1), + AcceptedFromAddresses: accs(addr2), + Coins: mustCoins("10bcoin"), + } + recordC := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr2), + Coins: mustCoins("100ccoin"), + } + recordD := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1), + AcceptedFromAddresses: accs(addr0, addr2), + Coins: mustCoins("1000dcoin"), + } + recordE := &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr3), + Coins: mustCoins("100000ecoin"), + } + + testFunc := func(toAddr sdk.AccAddress, record *quarantine.QuarantineRecord) func() { + return func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + } + + s.Require().NotPanics(testFunc(addr0, recordA), "SetQuarantineRecord recordA") + s.Require().NotPanics(testFunc(addr0, recordB), "SetQuarantineRecord recordB") + s.Require().NotPanics(testFunc(addr0, recordC), "SetQuarantineRecord recordC") + s.Require().NotPanics(testFunc(addr0, recordD), "SetQuarantineRecord recordD") + s.Require().NotPanics(testFunc(addr0, recordE), "SetQuarantineRecord recordE") + + // Setup: + // 0 <- 1: 1acoin declined + // 0 <- 1 2: 10bcoin + // 0 <- 2: 100ccoin + // 0 <- 0 1 2: 1000dcoin + // 0 <- 3: 10000ecoin + + qrs := func(qrz ...*quarantine.QuarantineRecord) []*quarantine.QuarantineRecord { + return qrz + } + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddrs []sdk.AccAddress + expected []*quarantine.QuarantineRecord + }{ + { + name: "to 0 from none", + toAddr: addr0, + fromAddrs: accs(), + expected: nil, + }, + { + name: "to 1 from none", + toAddr: addr0, + fromAddrs: accs(), + expected: nil, + }, + { + name: "to 2 from none", + toAddr: addr0, + fromAddrs: accs(), + expected: nil, + }, + { + name: "to 3 from none", + toAddr: addr0, + fromAddrs: accs(), + expected: nil, + }, + { + name: "to 1 from 0", + toAddr: addr1, + fromAddrs: accs(addr0), + expected: nil, + }, + { + name: "to 1 from 1", + toAddr: addr1, + fromAddrs: accs(addr1), + expected: nil, + }, + { + name: "to 1 from 2", + toAddr: addr1, + fromAddrs: accs(addr2), + expected: nil, + }, + { + name: "to 1 from 3", + toAddr: addr1, + fromAddrs: accs(addr3), + expected: nil, + }, + { + name: "to 2 from 0", + toAddr: addr2, + fromAddrs: accs(addr0), + expected: nil, + }, + { + name: "to 2 from 1", + toAddr: addr2, + fromAddrs: accs(addr1), + expected: nil, + }, + { + name: "to 2 from 2", + toAddr: addr2, + fromAddrs: accs(addr2), + expected: nil, + }, + { + name: "to 2 from 3", + toAddr: addr2, + fromAddrs: accs(addr3), + expected: nil, + }, + { + name: "to 3 from 0", + toAddr: addr3, + fromAddrs: accs(addr0), + expected: nil, + }, + { + name: "to 3 from 1", + toAddr: addr3, + fromAddrs: accs(addr1), + expected: nil, + }, + { + name: "to 3 from 2", + toAddr: addr3, + fromAddrs: accs(addr2), + expected: nil, + }, + { + name: "to 3 from 3", + toAddr: addr3, + fromAddrs: accs(addr3), + expected: nil, + }, + { + name: "to 3 from 0 1 2 3", + toAddr: addr3, + fromAddrs: accs(addr0, addr1, addr2, addr3), + expected: nil, + }, + { + name: "to 0 from 0 finds 1: d", + toAddr: addr0, + fromAddrs: accs(addr0), + expected: qrs(recordD), + }, + { + name: "to 0 from 1 finds 3: abd", + toAddr: addr0, + fromAddrs: accs(addr1), + expected: qrs(recordA, recordB, recordD), + }, + { + name: "to 0 from 2 finds 3: bcd", + toAddr: addr0, + fromAddrs: accs(addr2), + expected: qrs(recordB, recordC, recordD), + }, + { + name: "to 0 from 3 finds 1: e", + toAddr: addr0, + fromAddrs: accs(addr3), + expected: qrs(recordE), + }, + { + name: "to 0 from 0 0 finds 1: d", + toAddr: addr0, + fromAddrs: accs(addr0, addr0), + expected: qrs(recordD), + }, + { + name: "to 0 from 0 1 finds 3: abd", + toAddr: addr0, + fromAddrs: accs(addr0, addr1), + expected: qrs(recordA, recordB, recordD), + }, + { + name: "to 0 from 0 2 finds 3: bcd", + toAddr: addr0, + fromAddrs: accs(addr0, addr2), + expected: qrs(recordB, recordC, recordD), + }, + { + name: "to 0 from 0 3 finds 2: de", + toAddr: addr0, + fromAddrs: accs(addr0, addr3), + expected: qrs(recordD, recordE), + }, + { + name: "to 0 from 1 0 finds 3: abd", + toAddr: addr0, + fromAddrs: accs(addr1, addr0), + expected: qrs(recordA, recordB, recordD), + }, + { + name: "to 0 from 1 1 finds 3: abd", + toAddr: addr0, + fromAddrs: accs(addr1, addr1), + expected: qrs(recordA, recordB, recordD), + }, + { + name: "to 0 from 1 2 finds 4: abcd", + toAddr: addr0, + fromAddrs: accs(addr1, addr2), + expected: qrs(recordA, recordB, recordC, recordD), + }, + { + name: "to 0 from 1 3 finds 4: abde", + toAddr: addr0, + fromAddrs: accs(addr1, addr3), + expected: qrs(recordA, recordB, recordD, recordE), + }, + { + name: "to 0 from 2 0 finds 3: bcd", + toAddr: addr0, + fromAddrs: accs(addr2, addr0), + expected: qrs(recordB, recordC, recordD), + }, + { + name: "to 0 from 2 1 finds 4: abcd", + toAddr: addr0, + fromAddrs: accs(addr2, addr1), + expected: qrs(recordA, recordB, recordC, recordD), + }, + { + name: "to 0 from 2 2 finds 3: bcd", + toAddr: addr0, + fromAddrs: accs(addr2, addr2), + expected: qrs(recordB, recordC, recordD), + }, + { + name: "to 0 from 2 3 finds 4: bcde", + toAddr: addr0, + fromAddrs: accs(addr2, addr3), + expected: qrs(recordB, recordC, recordD, recordE), + }, + { + name: "to 0 from 3 0 finds 2: de", + toAddr: addr0, + fromAddrs: accs(addr3, addr0), + expected: qrs(recordD, recordE), + }, + { + name: "to 0 from 3 1 finds 4: abde", + toAddr: addr0, + fromAddrs: accs(addr3, addr1), + expected: qrs(recordA, recordB, recordD, recordE), + }, + { + name: "to 0 from 3 2 finds 4: bcde", + toAddr: addr0, + fromAddrs: accs(addr3, addr2), + expected: qrs(recordB, recordC, recordD, recordE), + }, + { + name: "to 0 from 3 3 finds 1: e", + toAddr: addr0, + fromAddrs: accs(addr3, addr3), + expected: qrs(recordE), + }, + { + name: "to 0 from 0 1 2 finds 4: abcd", + toAddr: addr0, + fromAddrs: accs(addr0, addr1, addr2), + expected: qrs(recordA, recordB, recordC, recordD), + }, + { + name: "to 0 from 0 1 3 finds 4: abde", + toAddr: addr0, + fromAddrs: accs(addr0, addr1, addr3), + expected: qrs(recordA, recordB, recordD, recordE), + }, + { + name: "to 0 from 0 2 3 finds 4: bcde", + toAddr: addr0, + fromAddrs: accs(addr0, addr2, addr3), + expected: qrs(recordB, recordC, recordD, recordE), + }, + { + name: "to 0 from 1 2 3 finds 5: abcde", + toAddr: addr0, + fromAddrs: accs(addr1, addr2, addr3), + expected: qrs(recordA, recordB, recordC, recordD, recordE), + }, + { + name: "to 0 from 0 1 2 3 finds 5: abcde", + toAddr: addr0, + fromAddrs: accs(addr0, addr1, addr2, addr3), + expected: qrs(recordA, recordB, recordC, recordD, recordE), + }, + { + name: "to 0 from 1 3 0 2 finds 5: abcde", + toAddr: addr0, + fromAddrs: accs(addr1, addr3, addr0, addr2), + expected: qrs(recordA, recordB, recordC, recordD, recordE), + }, + { + name: "to 0 from 1 3 1 2 finds 5: abcde", + toAddr: addr0, + fromAddrs: accs(addr1, addr3, addr1, addr2), + expected: qrs(recordA, recordB, recordC, recordD, recordE), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + actual := s.keeper.GetQuarantineRecords(s.sdkCtx, tc.toAddr, tc.fromAddrs...) + s.Assert().ElementsMatch(tc.expected, actual, "GetQuarantineRecords A = expected vs B = actual") + }) + } +} + +func (s *TestSuite) TestAddQuarantinedCoins() { + // Getting a little tricky here because I want different addresses for each test. + // The addrBase is used to generate addrCount addresses. + // Then, the autoAccept, autoDecline, toAddr and fromAddrs are address indexes to use. + // The tricky part is that both the existing and expected Quarantine Records will have their + // AccAddress slices updated before doing anything. For any AccAddress in them that's 1 byte long, and that byte + // is less than addrCount, it's used as an index and the entry is updated to be that address. + tests := []struct { + name string + addrBase string + addrCount uint8 + existing *quarantine.QuarantineRecord + autoAccept []int + autoDecline []int + coins sdk.Coins + toAddr int + fromAddrs []int + expected *quarantine.QuarantineRecord + expErrFmt string + expErrAddrs []int + }{ + { + name: "new record is created", + addrBase: "nr", + addrCount: 2, + coins: s.cz("99bananas"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("99bananas"), + }, + }, + { + name: "new record 2 froms is created", + addrBase: "nr2f", + addrCount: 3, + coins: s.cz("88crazy"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("88crazy"), + }, + }, + { + name: "existing record same denom is updated", + addrBase: "ersd", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("11pants"), + }, + coins: s.cz("200pants"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("211pants"), + }, + }, + { + name: "existing record new denom is updated", + addrBase: "ernd", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("102tower"), + }, + coins: s.cz("5pit"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("5pit,102tower"), + }, + }, + { + name: "existing record 2 froms is updated", + addrBase: "er2f", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("53pcoin"), + }, + coins: s.cz("9000pcoin"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("9053pcoin"), + }, + }, + { + name: "existing record 2 froms other order is updated", + addrBase: "er2foo", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("35pcoin"), + }, + coins: s.cz("800pcoin"), + toAddr: 0, + fromAddrs: []int{2, 1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("835pcoin"), + }, + }, + { + name: "existing record unaccepted now auto-accept is still unaccepted", + addrBase: "eruna", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("543interstellar"), + }, + autoAccept: []int{1}, + coins: s.cz("5012interstellar"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("5555interstellar"), // One more time! + }, + }, + { + name: "new record from is auto-accept nothing stored", + addrBase: "nrfa", + addrCount: 2, + autoAccept: []int{1}, + coins: s.cz("76trombones"), + toAddr: 0, + fromAddrs: []int{1}, + expected: nil, + expErrFmt: `cannot add quarantined funds "76trombones" to %s from %s: already fully accepted`, + expErrAddrs: []int{0, 1}, + }, + { + name: "new record two froms first is auto-accept is marked as such", + addrBase: "nr2fa", + addrCount: 3, + autoAccept: []int{1}, + coins: s.cz("52pinata"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("52pinata"), + }, + }, + { + name: "new record two froms second is auto-accept is marked as such", + addrBase: "nr2sa", + addrCount: 3, + autoAccept: []int{2}, + coins: s.cz("3fiddy"), // Loch Ness Monster, is that you? + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("3fiddy"), + }, + }, + { + name: "new record two froms both auto-accept nothing stored", + addrBase: "nr2ba", + addrCount: 3, + autoAccept: []int{1, 2}, + coins: s.cz("4moo"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: nil, + expErrFmt: `cannot add quarantined funds "4moo" to %s from %s, %s: already fully accepted`, + expErrAddrs: []int{0, 1, 2}, + }, + { + name: "existing record not declined not auto-decline result is not declined", + addrBase: "erndna", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("8nodeca"), + Declined: false, + }, + coins: s.cz("50nodeca"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("58nodeca"), + Declined: false, + }, + }, + { + name: "existing record not declined is auto-decline result is declined", + addrBase: "erndad", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("20deca"), + Declined: false, + }, + autoDecline: []int{1}, + coins: s.cz("406deca"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("426deca"), + Declined: true, + }, + }, + { + name: "existing record declined is auto-declined result is declined", + addrBase: "erdad", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("3000yarp"), + Declined: true, + }, + autoDecline: []int{1}, + coins: s.cz("3yarp"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("3003yarp"), + Declined: true, + }, + }, + { + name: "existing record declined not auto-declined result is not declined", + addrBase: "erdna", + addrCount: 2, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("14dalmatian"), + Declined: true, + }, + autoDecline: nil, + coins: s.cz("87dalmatian"), + toAddr: 0, + fromAddrs: []int{1}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("101dalmatian"), + Declined: false, + }, + }, + { + name: "existing record not declined 2 froms neither are auto-decline result is not declined", + addrBase: "ernd2fna", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("3bill"), + Declined: false, + }, + autoDecline: nil, + coins: s.cz("4bill"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("7bill"), + Declined: false, + }, + }, + { + name: "existing record not declined 2 froms first is auto-decline result is declined", + addrBase: "ernd2ffa", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("20123zela"), + Declined: false, + }, + autoDecline: []int{1}, + coins: s.cz("5000000000zela"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("5000020123zela"), + Declined: true, + }, + }, + { + name: "existing record not declined 2 froms second is auto-decline result is declined", + addrBase: "ernd2fsd", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("456789vids"), + Declined: false, + }, + autoDecline: []int{2}, + coins: s.cz("123000000vids"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("123456789vids"), + Declined: true, + }, + }, + { + name: "existing record not declined 2 froms both are auto-decline result is declined", + addrBase: "ernd2fba", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("5green"), + Declined: false, + }, + autoDecline: []int{1, 2}, + coins: s.cz("333333333333333green"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("333333333333338green"), + Declined: true, + }, + }, + { + name: "existing record declined 2 froms neither are auto-decline result is not declined", + addrBase: "erd2fna", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("4frank"), + Declined: true, + }, + autoDecline: nil, + coins: s.cz("3frank"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("7frank"), + Declined: false, + }, + }, + { + name: "existing record declined 2 froms first is auto-decline result is declined", + addrBase: "erd2ffa", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("10zulu"), + Declined: true, + }, + autoDecline: []int{1}, + coins: s.cz("11zulu"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("21zulu"), + Declined: true, + }, + }, + { + name: "existing record declined 2 froms second is auto-decline result is declined", + addrBase: "erd2fsd", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("11stars"), + Declined: true, + }, + autoDecline: []int{2}, + coins: s.cz("99stars"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("110stars"), + Declined: true, + }, + }, + { + name: "existing record declined 2 froms both are auto-decline result is declined", + addrBase: "erd2fba", + addrCount: 3, + existing: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("44blue"), + Declined: true, + }, + autoDecline: []int{1, 2}, + coins: s.cz("360blue"), + toAddr: 0, + fromAddrs: []int{1, 2}, + expected: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("404blue"), + Declined: true, + }, + }, + } + + seenAddrBases := map[string]bool{} + + for _, tc := range tests { + s.Run(tc.name, func() { + // Make sure the address base isn't used by an earlier test. + s.Require().NotEqual(tc.addrBase, "no AddrBase defined") + s.Require().False(seenAddrBases[tc.addrBase], "an earlier test already used the address base %q", tc.addrBase) + seenAddrBases[tc.addrBase] = true + s.Require().GreaterOrEqual(int(tc.addrCount), 1, "addrCount") + + // Set up all the address stuff. + addrs := make([]sdk.AccAddress, tc.addrCount) + for i := range addrs { + addrs[i] = MakeTestAddr(tc.addrBase, uint8(i)) + } + toAddr := addrs[tc.toAddr] + fromAddrs := make([]sdk.AccAddress, len(tc.fromAddrs)) + for i, fi := range tc.fromAddrs { + fromAddrs[i] = addrs[fi] + } + autoAccept := make([]sdk.AccAddress, len(tc.autoAccept)) + for i, ai := range tc.autoAccept { + autoAccept[i] = addrs[ai] + } + autoDecline := make([]sdk.AccAddress, len(tc.autoDecline)) + for i, ai := range tc.autoDecline { + autoDecline[i] = addrs[ai] + } + updateQR(addrs, tc.existing) + updateQR(addrs, tc.expected) + + expErr := "" + if len(tc.expErrFmt) > 0 { + fmtArgs := make([]any, len(tc.expErrAddrs)) + for i, addrsI := range tc.expErrAddrs { + fmtArgs[i] = addrs[addrsI] + } + expErr = fmt.Sprintf(tc.expErrFmt, fmtArgs...) + } + + // Set the existing value + if tc.existing != nil { + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, tc.existing) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord") + } + + // Set up auto-accept and auto-decline + testFuncAuto := func(fromAddr sdk.AccAddress, response quarantine.AutoResponse) func() { + return func() { + s.keeper.SetAutoResponse(s.sdkCtx, toAddr, fromAddr, response) + } + } + for i, fromAddr := range autoAccept { + s.Require().NotPanics(testFuncAuto(fromAddr, quarantine.AUTO_RESPONSE_ACCEPT), "SetAutoResponse %d accept", i+1) + } + for i, fromAddr := range autoDecline { + s.Require().NotPanics(testFuncAuto(fromAddr, quarantine.AUTO_RESPONSE_DECLINE), "SetAutoResponse %d decline", i+1) + } + + expectedEvents := sdk.Events{} + if len(expErr) == 0 { + // Create events expected to be emitted by AddQuarantinedCoins. + event, err := sdk.TypedEventToEvent(&quarantine.EventFundsQuarantined{ + ToAddress: toAddr.String(), + Coins: tc.coins, + }) + s.Require().NoError(err, "TypedEventToEvent EventFundsQuarantined") + expectedEvents = append(expectedEvents, event) + } + + // Get a context with a fresh event manager and call AddQuarantinedCoins. + // Make sure it doesn't panic and make sure it doesn't return an error. + // Note: As of writing, the only error it could return is from emitting the events, + // and who knows how to actually trigger/test that. + ctx := s.sdkCtx.WithEventManager(sdk.NewEventManager()) + var err error + testFuncAdd := func() { + err = s.keeper.AddQuarantinedCoins(ctx, tc.coins, toAddr, fromAddrs...) + } + s.Require().NotPanics(testFuncAdd, "AddQuarantinedCoins") + if len(expErr) > 0 { + s.Require().EqualError(err, expErr, "AddQuarantinedCoins") + } else { + s.Require().NoError(err, "AddQuarantinedCoins") + } + actualEvents := ctx.EventManager().Events() + s.Assert().Equal(expectedEvents, actualEvents) + + // Now look up the record and make sure it's as expected. + var actual *quarantine.QuarantineRecord + testFuncGet := func() { + actual = s.keeper.GetQuarantineRecord(s.sdkCtx, toAddr, fromAddrs...) + } + s.Require().NotPanics(testFuncGet, "GetQuarantineRecord") + s.Assert().Equal(tc.expected, actual, "resulting quarantine record") + }) + } +} + +func (s *TestSuite) TestAcceptQuarantinedFunds() { + // makeEvent creates a funds-released event. + makeEvent := func(t *testing.T, addr sdk.AccAddress, amt sdk.Coins) sdk.Event { + event, err := sdk.TypedEventToEvent(&quarantine.EventFundsReleased{ + ToAddress: addr.String(), + Coins: amt, + }) + require.NoError(t, err, "TypedEventToEvent EventFundsReleased") + return event + } + + // An event maker knows the coins, and takes in the address to output an + // event with the (presently unknown) ToAddress and the (known) coins. + type eventMaker func(t *testing.T, addr sdk.AccAddress) sdk.Event + + // makes the event maker functions, one for each string provided. + makeEventMakers := func(coins ...string) []eventMaker { + rv := make([]eventMaker, len(coins)) + for i, amtStr := range coins { + // doing this now so that an invalid coin string fails the test before it gets started. + // Really, I didn't want to have to update cz to also take in a *testing.T. + amt := s.cz(amtStr) + rv[i] = func(t *testing.T, addr sdk.AccAddress) sdk.Event { + return makeEvent(t, addr, amt) + } + } + return rv + } + + // Getting a little tricky here because I want different addresses for each test. + // The addrBase is used to generate addrCount addresses. + // Then, addrs[0] becomes the toAddr. The fromAddrs are indexes of the addrs to use. + // The tricky part is that the existing and expected Quarantine Records will have their + // AccAddresses updated before doing anything. For any AccAddress in them that's 1 byte long, and that byte + // is less than addrCount, it's used as an index and the entry is updated to be that address. + // Also, the provided []eventMaker is used to create all expected events receiving the toAddr. + tests := []struct { + name string + addrBase string + addrCount uint8 + records []*quarantine.QuarantineRecord + autoDecline []int + fromAddrs []int + expectedRecords []*quarantine.QuarantineRecord + expectedSent []sdk.Coins + expectedEvents []eventMaker + }{ + { + name: "one from zero records", + addrBase: "ofzr", + addrCount: 2, + fromAddrs: []int{1}, + expectedRecords: nil, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "one from one record fully", + addrBase: "oforf", + addrCount: 2, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("17lemon"), + }, + }, + fromAddrs: []int{1}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("17lemon")}, + expectedEvents: makeEventMakers("17lemon"), + }, + { + name: "one from one record finally fully", + addrBase: "foforf", + addrCount: 4, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}, {3}}, + Coins: s.cz("8878pillow"), + }, + }, + fromAddrs: []int{1}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("8878pillow")}, + expectedEvents: makeEventMakers("8878pillow"), + }, + { + name: "one from one record fully previously declined", + addrBase: "oforfpd", + addrCount: 2, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("5rings,4birds,3hens"), + Declined: true, + }, + }, + fromAddrs: []int{1}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("5rings,4birds,3hens")}, + expectedEvents: makeEventMakers("5rings,4birds,3hens"), + }, + { + name: "one from one record not fully", + addrBase: "ofornf", + addrCount: 3, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("1snow"), + Declined: false, + }, + }, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1snow"), + Declined: false, + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "one from one record not fully previously declined", + addrBase: "ofornfpd", + addrCount: 3, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("55orchid"), + Declined: true, + }, + }, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("55orchid"), + Declined: false, + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "one from one record remaining unaccepted is auto-decline", + addrBase: "oforruad", + addrCount: 3, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("99redballoons"), + Declined: true, + }, + }, + autoDecline: []int{2}, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("99redballoons"), + Declined: true, + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "one from one record accepted was auto-decline", + addrBase: "oforawad", + addrCount: 3, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("7777frog"), + Declined: true, + }, + }, + autoDecline: []int{1}, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("7777frog"), + Declined: false, + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "one from two records neither fully", + addrBase: "oftrnf", + addrCount: 4, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("20533lamp"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("45sun"), + Declined: true, + }, + }, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("20533lamp"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("45sun"), + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "one from two records first fully", + addrBase: "oftrff", + addrCount: 4, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + // key suffix = 0264500F71512C3B111D2D2EAA7322F018DA16B13CBB5D516BD4B51C4F1A94EC + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("43bulb"), + }, + // key suffix = 47F604CA662719863E40CF215D4DE088C22B7FF217236D887A99AF63A8F124E9 + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("5005shade"), + }, + }, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("5005shade"), + }, + }, + expectedSent: []sdk.Coins{s.cz("43bulb")}, + expectedEvents: makeEventMakers("43bulb"), + }, + { + name: "one from two records second fully", + addrBase: "ofttrsf", + addrCount: 4, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + // key suffix = EFC545E02C1785EEAAE9004385C6106E75AC42E8096556376097037A0C122E41 + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("346awning"), + }, + // key suffix = F898B0EAF64B4D67BC2C285E541D381FA422D85B05C69D697C099B1968003955 + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("9444sprout"), + }, + }, + fromAddrs: []int{1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("346awning"), + }, + }, + expectedSent: []sdk.Coins{s.cz("9444sprout")}, + expectedEvents: makeEventMakers("9444sprout"), + }, + { + name: "one from two records both fully", + addrBase: "oftrbf", + addrCount: 4, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("4312stand"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}, {3}}, + Coins: s.cz("9867sit"), + }, + }, + fromAddrs: []int{1}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("4312stand"), s.cz("9867sit")}, + expectedEvents: makeEventMakers("4312stand", "9867sit"), + }, + { + name: "two froms zero records", + addrBase: "tfzr", + addrCount: 3, + fromAddrs: []int{1, 2}, + expectedRecords: nil, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "two froms one record fully", + addrBase: "tforf", + addrCount: 3, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("838hibiscus"), + }, + }, + fromAddrs: []int{1, 2}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("838hibiscus")}, + expectedEvents: makeEventMakers("838hibiscus"), + }, + { + name: "two froms other order one record fully", + addrBase: "tfooorf", + addrCount: 3, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("10downing"), + }, + }, + fromAddrs: []int{2, 1}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("10downing")}, + expectedEvents: makeEventMakers("10downing"), + }, + { + name: "two froms one record not fully", + addrBase: "tfornf", + addrCount: 4, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}, {3}}, + Coins: s.cz("1060waddison"), + }, + }, + fromAddrs: []int{1, 2}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("1060waddison"), + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "two froms other order one record not fully", + addrBase: "tfooornf", + addrCount: 4, + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}, {3}}, + Coins: s.cz("1060waddison"), + }, + }, + fromAddrs: []int{2, 1}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("1060waddison"), + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "two froms two records neither fully", + addrBase: "tftrnf", + addrCount: 5, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + // key suffix = 70705D4547681D550CF0D2A5B0996B6C2B42E181FF3F84A71CF6DAD8527C8C9C + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}, {4}}, + Coins: s.cz("12drummers"), + }, + // key suffix = 83A580037E196C7BB4B36FDB5531BA715DF24F86681A61FE7D72D77BE2ABA4E8 + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}, {3}}, + Coins: s.cz("11pipers"), + }, + }, + fromAddrs: []int{1, 2}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{4}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("12drummers"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("11pipers"), + }, + }, + expectedSent: nil, + expectedEvents: nil, + }, + { + name: "two froms two records first fully", + addrBase: "tftrff", + addrCount: 4, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + // key suffix = 72536EA1F5EB0C1FF2897309892EF28553E7A6C2508AB1751D363B8C3A31A56F + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("8maids,7swans"), + }, + // key suffix = BDA18A04E7AC80DDA290C262CBEF7C2928B95F9DBFE8F392BA82EC0186DBA0CC + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("10lords,9ladies"), + }, + }, + fromAddrs: []int{1, 3}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("10lords,9ladies"), + }, + }, + expectedSent: []sdk.Coins{s.cz("8maids,7swans")}, + expectedEvents: makeEventMakers("8maids,7swans"), + }, + { + name: "two froms two records second fully", + addrBase: "tftrsf", + addrCount: 4, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + // key suffix = 00E641E0BF6DF9F97E61B94BBBA58B78F74198BB72681C9A24C12D2BF1DDC371 + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("6geese"), + }, + // key suffix = D052411A78E6208D482F600692C7382C814C35FB75B49430E5CF895B4FE5EEFF + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("2doves,1peartree"), + }, + }, + fromAddrs: []int{1, 3}, + expectedRecords: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("6geese"), + }, + }, + expectedSent: []sdk.Coins{s.cz("2doves,1peartree")}, + expectedEvents: makeEventMakers("2doves,1peartree"), + }, + { + name: "two froms two records both fully", + addrBase: "tftrbf", + addrCount: 3, + // Note: This assumes AcceptQuarantinedFunds loops through the records ordered by key. + // The ordering defined here should match that to make test maintenance easier. + records: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("3amigos"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("8amigos"), + }, + }, + fromAddrs: []int{1, 2}, + expectedRecords: nil, + expectedSent: []sdk.Coins{s.cz("3amigos"), s.cz("8amigos")}, + expectedEvents: makeEventMakers("3amigos", "8amigos"), + }, + } + + seenAddrBases := map[string]bool{} + + for _, tc := range tests { + s.Run(tc.name, func() { + // Make sure the address base isn't used by an earlier test. + s.Require().NotEqual(tc.addrBase, "", "no AddrBase defined") + s.Require().False(seenAddrBases[tc.addrBase], "an earlier test already used the address base %q", tc.addrBase) + seenAddrBases[tc.addrBase] = true + s.Require().GreaterOrEqual(int(tc.addrCount), 1, "addrCount") + + // Set up all the address stuff. + addrs := make([]sdk.AccAddress, tc.addrCount) + for i := range addrs { + addrs[i] = MakeTestAddr(tc.addrBase, uint8(i)) + } + + toAddr := addrs[0] + fromAddrs := make([]sdk.AccAddress, len(tc.fromAddrs)) + for i, fi := range tc.fromAddrs { + fromAddrs[i] = addrs[fi] + } + + autoDecline := make([]sdk.AccAddress, len(tc.autoDecline)) + for i, addr := range tc.autoDecline { + autoDecline[i] = addrs[addr] + } + + for _, record := range tc.records { + updateQR(addrs, record) + } + + for _, record := range tc.expectedRecords { + updateQR(addrs, record) + } + + var expectedSends []*SentCoins + if len(tc.expectedSent) > 0 { + expectedSends = make([]*SentCoins, len(tc.expectedSent)) + for i, sent := range tc.expectedSent { + expectedSends[i] = &SentCoins{ + FromAddr: s.keeper.GetFundsHolder(), + ToAddr: toAddr, + Amt: sent, + } + } + } + + expectedEvents := make(sdk.Events, len(tc.expectedEvents)) + for i, ev := range tc.expectedEvents { + expectedEvents[i] = ev(s.T(), toAddr) + } + + // Now that we have all the expected stuff defined, let's get things set up. + + // mock the bank keeper and use that, so we don't have to fund stuff, + // and we get a record of the sends made. + bKeeper := NewMockBankKeeper() // bzzzzzzzzzz + qKeeper := s.keeper.WithBankKeeper(bKeeper) + + // Set the existing records + for i, existing := range tc.records { + if existing != nil { + testFuncSet := func() { + qKeeper.SetQuarantineRecord(s.sdkCtx, toAddr, existing) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord[%d]", i) + recordKey := quarantine.CreateRecordKey(toAddr, existing.GetAllFromAddrs()...) + _, suffix := quarantine.ParseRecordIndexKey(recordKey) + s.T().Logf("existing[%d] suffix: %v", i, suffix) + } + } + + // Set existing auto-declines + for i, addr := range autoDecline { + testFuncAuto := func() { + qKeeper.SetAutoResponse(s.sdkCtx, toAddr, addr, quarantine.AUTO_RESPONSE_DECLINE) + } + s.Require().NotPanics(testFuncAuto, "SetAutoResponse[%d]", i) + } + + expectedFundsReleased := sdk.Coins{} + for _, coins := range tc.expectedSent { + expectedFundsReleased = expectedFundsReleased.Add(coins...) + } + + // Setup done. Let's do this. + var err error + var fundsReleased sdk.Coins + ctx := s.sdkCtx.WithEventManager(sdk.NewEventManager()) + testFuncAccept := func() { + fundsReleased, err = qKeeper.AcceptQuarantinedFunds(ctx, toAddr, fromAddrs...) + } + s.Require().NotPanics(testFuncAccept, "AcceptQuarantinedFunds") + s.Require().NoError(err, "AcceptQuarantinedFunds") + s.Assert().Equal(expectedFundsReleased, fundsReleased, "AcceptQuarantinedFunds funds released") + + // And check the expected. + var actualRecords []*quarantine.QuarantineRecord + testFuncGet := func() { + actualRecords = qKeeper.GetQuarantineRecords(s.sdkCtx, toAddr, fromAddrs...) + } + if s.Assert().NotPanics(testFuncGet, "GetQuarantineRecords") { + s.Assert().Equal(tc.expectedRecords, actualRecords, "resulting QuarantineRecords") + } + + actualSends := bKeeper.SentCoins + s.Assert().Equal(expectedSends, actualSends, "sends made") + + actualEvents := ctx.EventManager().Events() + s.Assert().Equal(expectedEvents, actualEvents, "events emitted during accept") + }) + } + + s.Run("send returns an error", func() { + // Setup: There will be 4 records to send, the 3rd will return an error. + // Check that: + // 1. The error is returned by AcceptQuarantinedFunds + // 2. The 1st and 2nd records are removed but the 3rd and 4th remain. + // 3. SendCoins was called for the 1st and 2nd records. + // 4. Events were emitted for the 1st and 2nd records. + + // Setup address stuff. + addrBase := "sre" + s.Require().False(seenAddrBases[addrBase], "an earlier test already used the address base %q", addrBase) + seenAddrBases[addrBase] = true + + toAddr := MakeTestAddr(addrBase, 0) + fromAddr1 := MakeTestAddr(addrBase, 1) + fromAddr2 := MakeTestAddr(addrBase, 2) + fromAddr3 := MakeTestAddr(addrBase, 3) + fromAddr4 := MakeTestAddr(addrBase, 4) + fromAddrs := accs(fromAddr1, fromAddr2, fromAddr3, fromAddr4) + + // Define the existing records and expected stuff. + existingRecords := []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: accs(fromAddr1), + Coins: s.cz("1addra"), + }, + { + UnacceptedFromAddresses: accs(fromAddr2), + Coins: s.cz("2addrb"), + }, + { + UnacceptedFromAddresses: accs(fromAddr3), + Coins: s.cz("3addrc"), + }, + { + UnacceptedFromAddresses: accs(fromAddr4), + Coins: s.cz("4addrd"), + }, + } + + expectedErr := "this is a test error" + + expectedRecords := []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: accs(fromAddr3), + Coins: s.cz("3addrc"), + }, + { + UnacceptedFromAddresses: accs(fromAddr4), + Coins: s.cz("4addrd"), + }, + } + + expectedSends := []*SentCoins{ + { + FromAddr: s.keeper.GetFundsHolder(), + ToAddr: toAddr, + Amt: s.cz("1addra"), + }, + { + FromAddr: s.keeper.GetFundsHolder(), + ToAddr: toAddr, + Amt: s.cz("2addrb"), + }, + } + + // Since an error is being returned, funds released should be nil. + expectedFundsReleased := sdk.Coins(nil) + + expectedEvents := sdk.Events{ + makeEvent(s.T(), toAddr, s.cz("1addra")), + makeEvent(s.T(), toAddr, s.cz("2addrb")), + } + + // mock the bank keeper and set it to return an error on the 3rd send. + bKeeper := NewMockBankKeeper() // bzzzzzzzzzz + bKeeper.QueuedSendCoinsErrors = []error{ + nil, + nil, + fmt.Errorf(expectedErr), + } + qKeeper := s.keeper.WithBankKeeper(bKeeper) + + // Store the existing records. + for i, record := range existingRecords { + testFuncSet := func() { + qKeeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord[%d]", i) + } + + // Do the thing. + var actualErr error + var fundsReleased sdk.Coins + ctx := s.sdkCtx.WithEventManager(sdk.NewEventManager()) + testFuncAccept := func() { + fundsReleased, actualErr = qKeeper.AcceptQuarantinedFunds(ctx, toAddr, fromAddrs...) + } + s.Require().NotPanics(testFuncAccept, "AcceptQuarantinedFunds") + + // Check that: 1. The error is returned by AcceptQuarantinedFunds + s.Assert().EqualError(actualErr, expectedErr, "AcceptQuarantinedFunds error") + + // Check that: 2. The expected funds released was returned. + s.Assert().Equal(expectedFundsReleased, fundsReleased, "AcceptQuarantinedFunds funds released") + + // Check that: 3. The 1st and 2nd records are removed but the 3rd and 4th remain. + var actualRecords []*quarantine.QuarantineRecord + testFuncGet := func() { + actualRecords = qKeeper.GetQuarantineRecords(ctx, toAddr, fromAddrs...) + } + if s.Assert().NotPanics(testFuncGet, "GetQuarantineRecords") { + s.Assert().Equal(expectedRecords, actualRecords) + } + + // Check that: 4. SendCoins was called for the 1st and 2nd records. + actualSends := bKeeper.SentCoins + s.Assert().Equal(expectedSends, actualSends, "sends made") + + // Check that: 5. Events were emitted for the 1st and 2nd records. + actualEvents := ctx.EventManager().Events() + s.Assert().Equal(expectedEvents, actualEvents, "events emitted") + }) +} + +func (s *TestSuite) TestDeclineQuarantinedFunds() { + tests := []struct { + name string + addrBase string + addrCount uint8 + fromAddrs []int + existing []*quarantine.QuarantineRecord + expected []*quarantine.QuarantineRecord + }{ + { + name: "one from zero records", + addrBase: "ofzr", + addrCount: 2, + fromAddrs: []int{1}, + existing: nil, + expected: nil, + }, + { + name: "one from one record", + addrBase: "ofor", + addrCount: 2, + fromAddrs: []int{1}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("13ofor"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("13ofor"), + Declined: true, + }, + }, + }, + { + name: "one from one record previously accepted", + addrBase: "oforpa", + addrCount: 3, + fromAddrs: []int{1}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("8139oforpa"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}, {1}}, + Coins: s.cz("8139oforpa"), + Declined: true, + }, + }, + }, + { + name: "one from two records", + addrBase: "oftr", + addrCount: 4, + fromAddrs: []int{1}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("85oftr"), + Declined: false, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("190oftr"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("85oftr"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {3}}, + Coins: s.cz("190oftr"), + Declined: true, + }, + }, + }, + { + name: "two froms zero records", + addrBase: "tfzr", + addrCount: 3, + fromAddrs: []int{1, 2}, + existing: nil, + expected: nil, + }, + { + name: "two froms one record from first", + addrBase: "tforff", + addrCount: 4, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("321tforff"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}, {1}}, + Coins: s.cz("321tforff"), + Declined: true, + }, + }, + }, + { + name: "two froms one record from second", + addrBase: "tforfs", + addrCount: 4, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("321tforfs"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}, {2}}, + Coins: s.cz("321tforfs"), + Declined: true, + }, + }, + }, + { + name: "two froms one record from both", + addrBase: "tforfb", + addrCount: 4, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}}, + AcceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("4tforfb"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{3}, {1}, {2}}, + AcceptedFromAddresses: nil, + Coins: s.cz("4tforfb"), + Declined: true, + }, + }, + }, + { + name: "two froms two records from first", + addrBase: "tftrff", + addrCount: 5, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{3}}, + Coins: s.cz("13tftrff"), + Declined: false, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {4}}, + Coins: s.cz("14tftrff"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{3}}, + Coins: s.cz("13tftrff"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {4}}, + Coins: s.cz("14tftrff"), + Declined: true, + }, + }, + }, + { + name: "two froms two records from second", + addrBase: "tftrfs", + addrCount: 5, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{3}}, + Coins: s.cz("13tftrfs"), + Declined: false, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}, {4}}, + Coins: s.cz("14tftrfs"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + AcceptedFromAddresses: []sdk.AccAddress{{3}}, + Coins: s.cz("13tftrfs"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}, {4}}, + Coins: s.cz("14tftrfs"), + Declined: true, + }, + }, + }, + { + name: "two froms two records one from each", + addrBase: "tftrofe", + addrCount: 3, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1tftrofe"), + Declined: false, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("2tftrofe"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1tftrofe"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("2tftrofe"), + Declined: true, + }, + }, + }, + { + name: "two froms two records one from one other from both", + addrBase: "tftrofb", + addrCount: 3, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1tftrofb"), + Declined: false, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("12tftrofb"), + Declined: false, + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1tftrofb"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("12tftrofb"), + Declined: true, + }, + }, + }, + { + name: "two froms five records", + // (1st, 2nd, 1st & 2nd, 1st & other, 2nd & other) + addrBase: "tffr", + addrCount: 4, + fromAddrs: []int{1, 2}, + existing: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1tffr"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("2tffr"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("12tffr"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{3}}, + Coins: s.cz("13tffr"), + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}, {3}}, + Coins: s.cz("23tffr"), + }, + }, + expected: []*quarantine.QuarantineRecord{ + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + Coins: s.cz("1tffr"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}}, + Coins: s.cz("2tffr"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}, {2}}, + Coins: s.cz("12tffr"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{1}}, + AcceptedFromAddresses: []sdk.AccAddress{{3}}, + Coins: s.cz("13tffr"), + Declined: true, + }, + { + UnacceptedFromAddresses: []sdk.AccAddress{{2}, {3}}, + Coins: s.cz("23tffr"), + Declined: true, + }, + }, + }, + } + + seenAddrBases := map[string]bool{} + + for _, tc := range tests { + s.Run(tc.name, func() { + // Make sure the address base isn't used by an earlier test. + s.Require().NotEqual(tc.addrBase, "", "no AddrBase defined") + s.Require().False(seenAddrBases[tc.addrBase], "an earlier test already used the address base %q", tc.addrBase) + seenAddrBases[tc.addrBase] = true + s.Require().GreaterOrEqual(int(tc.addrCount), 1, "addrCount") + + // Set up all the address stuff. + addrs := make([]sdk.AccAddress, tc.addrCount) + for i := range addrs { + addrs[i] = MakeTestAddr(tc.addrBase, uint8(i)) + } + + toAddr := addrs[0] + fromAddrs := make([]sdk.AccAddress, len(tc.fromAddrs)) + for i, fi := range tc.fromAddrs { + fromAddrs[i] = addrs[fi] + } + + for _, record := range tc.existing { + updateQR(addrs, record) + } + for _, record := range tc.expected { + updateQR(addrs, record) + } + + // Set the existing records. + for i, record := range tc.existing { + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, toAddr, record) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord[%d]", i) + recordKey := quarantine.CreateRecordKey(toAddr, record.GetAllFromAddrs()...) + _, suffix := quarantine.ParseRecordKey(recordKey) + s.T().Logf("record[%d] suffix: %v", i, suffix) + } + + // Do the thing. + testFuncDecline := func() { + s.keeper.DeclineQuarantinedFunds(s.sdkCtx, toAddr, fromAddrs...) + } + s.Require().NotPanics(testFuncDecline, "DeclineQuarantinedFunds") + + var actual []*quarantine.QuarantineRecord + testFuncGet := func() { + actual = s.keeper.GetQuarantineRecords(s.sdkCtx, toAddr, fromAddrs...) + } + if s.Assert().NotPanics(testFuncGet, "GetQuarantineRecords") { + s.Assert().ElementsMatch(tc.expected, actual, "resulting quarantine records") + } + }) + } +} + +func (s *TestSuite) TestQuarantineRecordsIterateAndGetAll() { + addrBase := "qriga" + addr0 := MakeTestAddr(addrBase, 0) + addr1 := MakeTestAddr(addrBase, 1) + addr2 := MakeTestAddr(addrBase, 2) + addr3 := MakeTestAddr(addrBase, 3) + addr4 := MakeTestAddr(addrBase, 4) + addr5 := MakeTestAddr(addrBase, 5) + addr6 := MakeTestAddr(addrBase, 6) + addr7 := MakeTestAddr(addrBase, 7) + + // Create 7 records + initialRecords := []*struct { + to sdk.AccAddress + record *quarantine.QuarantineRecord + }{ + { + to: addr0, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1), + Coins: s.cz("1boom"), + }, + }, + { + to: addr0, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr2), + Coins: s.cz("5boom"), + }, + }, + { + to: addr3, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1), + Coins: s.cz("23boom"), + Declined: true, + }, + }, + { + to: addr5, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr6), + AcceptedFromAddresses: accs(addr7), + Coins: s.cz("79boom"), + }, + }, + { + to: addr0, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr3), + Coins: s.cz("163boom"), + }, + }, + { + to: addr3, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr4), + Coins: s.cz("331boom"), + }, + }, + { + to: addr0, + record: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr7), + Coins: s.cz("673boom"), + }, + }, + } + + for i, rec := range initialRecords { + testFuncSet := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, rec.to, rec.record) + } + s.Require().NotPanics(testFuncSet, "SetQuarantineRecord[%d]", i) + } + + // Remove the 2nd one by setting it as fully accepted. + secondTo := MakeCopyOfAccAddress(initialRecords[1].to) + secondRec := MakeCopyOfQuarantineRecord(initialRecords[1].record) + secondRec.AcceptFrom(secondRec.UnacceptedFromAddresses) + testFuncUnset := func() { + s.keeper.SetQuarantineRecord(s.sdkCtx, secondTo, secondRec) + } + s.Require().NotPanics(testFuncUnset, "SetQuarantineRecord to remove second") + + // Final setup: + // They should be ordered by key and the keys should start with their indexes. + // [0] 0 <- 1 1boom + // [4] 0 <- 3 163boom + // [6] 0 <- 7 673boom + // [2] 3 <- 1 23boom (declined) + // [5] 3 <- 4 331boom + // [3] 5 <- 6,7 79boom (7 accepted) + + allOrder := []int{0, 4, 6, 2, 5, 3} + + tests := []struct { + name string + toAddr sdk.AccAddress + expectedOrder []int + }{ + { + name: "IterateQuarantineRecords all", + toAddr: nil, + expectedOrder: allOrder, + }, + { + name: "IterateQuarantineRecords addr0", + toAddr: addr0, + expectedOrder: []int{0, 4, 6}, + }, + { + name: "IterateQuarantineRecords addr1", + toAddr: addr1, + expectedOrder: []int{}, + }, + { + name: "IterateQuarantineRecords addr2", + toAddr: addr2, + expectedOrder: []int{}, + }, + { + name: "IterateQuarantineRecords addr3", + toAddr: addr3, + expectedOrder: []int{2, 5}, + }, + { + name: "IterateQuarantineRecords addr4", + toAddr: addr4, + expectedOrder: []int{}, + }, + { + name: "IterateQuarantineRecords addr5", + toAddr: addr5, + expectedOrder: []int{3}, + }, + { + name: "IterateQuarantineRecords addr6", + toAddr: addr6, + expectedOrder: []int{}, + }, + { + name: "IterateQuarantineRecords addr7", + toAddr: addr7, + expectedOrder: []int{}, + }, + } + + // cbArgs are the arguments provided to the callback of IterateQuarantineRecords + type cbArgs struct { + toAddr sdk.AccAddress + suffix sdk.AccAddress + record *quarantine.QuarantineRecord + } + + for _, tc := range tests { + s.Run(tc.name, func() { + expected := make([]*cbArgs, len(tc.expectedOrder)) + for i, iri := range tc.expectedOrder { + tr := initialRecords[iri] + key := quarantine.CreateRecordKey(tr.to, tr.record.GetAllFromAddrs()...) + _, suffix := quarantine.ParseRecordKey(key) + expected[i] = &cbArgs{ + toAddr: MakeCopyOfAccAddress(tr.to), + suffix: MakeCopyOfAccAddress(suffix), + record: MakeCopyOfQuarantineRecord(tr.record), + } + } + + actual := make([]*cbArgs, 0, len(expected)) + callback := func(toAddr, recordSuffix sdk.AccAddress, record *quarantine.QuarantineRecord) bool { + actual = append(actual, &cbArgs{ + toAddr: toAddr, + suffix: recordSuffix, + record: record, + }) + return false + } + testFunc := func() { + s.keeper.IterateQuarantineRecords(s.sdkCtx, tc.toAddr, callback) + } + s.Require().NotPanics(testFunc, "IterateQuarantineRecords") + s.Assert().Equal(expected, actual, "callback args provided to IterateQuarantineRecords") + }) + } + + s.Run("IterateQuarantineRecords stop early", func() { + stopLen := 4 + expected := make([]*cbArgs, stopLen) + for i, iri := range allOrder[:stopLen] { + tr := initialRecords[iri] + key := quarantine.CreateRecordKey(tr.to, tr.record.GetAllFromAddrs()...) + _, suffix := quarantine.ParseRecordKey(key) + expected[i] = &cbArgs{ + toAddr: MakeCopyOfAccAddress(tr.to), + suffix: MakeCopyOfAccAddress(suffix), + record: MakeCopyOfQuarantineRecord(tr.record), + } + } + + actual := make([]*cbArgs, 0, len(expected)) + callback := func(toAddr, recordSuffix sdk.AccAddress, record *quarantine.QuarantineRecord) bool { + actual = append(actual, &cbArgs{ + toAddr: toAddr, + suffix: recordSuffix, + record: record, + }) + return len(actual) >= stopLen + } + testFunc := func() { + s.keeper.IterateQuarantineRecords(s.sdkCtx, nil, callback) + } + s.Require().NotPanics(testFunc, "IterateQuarantineRecords") + s.Assert().Equal(expected, actual, "callback args provided to IterateQuarantineRecords") + }) + + s.Run("GetAllQuarantinedFunds", func() { + expected := make([]*quarantine.QuarantinedFunds, len(allOrder)) + for i, iri := range allOrder { + tr := initialRecords[iri] + expected[i] = tr.record.AsQuarantinedFunds(tr.to) + } + var actual []*quarantine.QuarantinedFunds + testFuncGetAll := func() { + actual = s.keeper.GetAllQuarantinedFunds(s.sdkCtx) + } + s.Require().NotPanics(testFuncGetAll, "GetAllQuarantinedFunds") + s.Assert().Equal(expected, actual, "GetAllQuarantinedFunds results") + }) +} + +func (s *TestSuite) TestBzToQuarantineRecordSuffixIndex() { + cdc := s.keeper.GetCodec() + + tests := []struct { + name string + bz []byte + expected *quarantine.QuarantineRecordSuffixIndex + expErr string + }{ + { + name: "control", + bz: cdc.MustMarshal(&quarantine.QuarantineRecordSuffixIndex{ + RecordSuffixes: [][]byte{{1, 2, 3}, {1, 5, 5}}, + }), + expected: &quarantine.QuarantineRecordSuffixIndex{ + RecordSuffixes: [][]byte{{1, 2, 3}, {1, 5, 5}}, + }, + }, + { + name: "nil bz", + bz: nil, + expected: &quarantine.QuarantineRecordSuffixIndex{ + RecordSuffixes: nil, + }, + }, + { + name: "empty bz", + bz: []byte{}, + expected: &quarantine.QuarantineRecordSuffixIndex{ + RecordSuffixes: nil, + }, + }, + { + name: "unknown bytes", + bz: []byte{0x75, 110, 0153, 0x6e, 0157, 119, 0156, 0xff, 0142, 0x79, 116, 0x65, 0163}, + expErr: "proto: illegal wireType 7", + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + var actual *quarantine.QuarantineRecordSuffixIndex + var err error + testFunc := func() { + actual, err = s.keeper.BzToQuarantineRecordSuffixIndex(tc.bz) + } + s.Require().NotPanics(testFunc, "bzToQuarantineRecordSuffixIndex") + if len(tc.expErr) > 0 { + s.Require().EqualError(err, tc.expErr, "bzToQuarantineRecordSuffixIndex error: %v", actual) + } else { + s.Require().NoError(err, "bzToQuarantineRecordSuffixIndex error") + s.Assert().Equal(tc.expected, actual, "bzToQuarantineRecordSuffixIndex index") + } + }) + + s.Run("must "+tc.name, func() { + var actual *quarantine.QuarantineRecordSuffixIndex + testFunc := func() { + actual = s.keeper.MustBzToQuarantineRecordSuffixIndex(tc.bz) + } + if len(tc.expErr) > 0 { + s.Require().PanicsWithError(tc.expErr, testFunc, "mustBzToQuarantineRecordSuffixIndex: %v", actual) + } else { + s.Require().NotPanics(testFunc, "mustBzToQuarantineRecordSuffixIndex") + s.Assert().Equal(tc.expected, actual, "bzToQuarantineRecordSuffixIndex index") + } + }) + } +} + +func (s *TestSuite) TestSuffixIndexGetSet() { + toAddr := MakeTestAddr("sigs", 0) + fromAddr := MakeTestAddr("sigs", 1) + suffix0 := []byte(MakeTestAddr("sfxsigs", 0)) + suffix1 := []byte(MakeTestAddr("sfxsigs", 1)) + suffix2 := []byte(MakeTestAddr("sfxsigs", 2)) + suffix3 := []byte(MakeTestAddr("sfxsigs", 3)) + suffix4 := []byte(MakeTestAddr("sfxsigs", 4)) + suffix5 := []byte(MakeTestAddr("sfxsigs", 5)) + + s.Run("1 getQuarantineRecordSuffix on unset entry", func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + expectedIndex := &quarantine.QuarantineRecordSuffixIndex{RecordSuffixes: nil} + expectedKey := quarantine.CreateRecordIndexKey(toAddr, fromAddr) + + var actualIndex *quarantine.QuarantineRecordSuffixIndex + var actualKey []byte + testFunc := func() { + actualIndex, actualKey = s.keeper.GetQuarantineRecordSuffixIndex(store, toAddr, fromAddr) + } + s.Require().NotPanics(testFunc, "getQuarantineRecordSuffixIndex") + s.Assert().Equal(expectedIndex, actualIndex, "returned index") + s.Assert().Equal(expectedKey, actualKey, "returned key") + }) + + s.Run("2 setQuarantineRecordSuffixIndex on unset entry", func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + index := &quarantine.QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffix0, suffix1}} + key := quarantine.CreateRecordIndexKey(toAddr, fromAddr) + + testFunc := func() { + s.keeper.SetQuarantineRecordSuffixIndex(store, key, index) + } + s.Require().NotPanics(testFunc, "setQuarantineRecordSuffixIndex") + }) + + s.Run("3 getQuarantineRecordSuffix on previously set entry", func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + expectedIndex := &quarantine.QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffix0, suffix1}} + expectedKey := quarantine.CreateRecordIndexKey(toAddr, fromAddr) + + var actualIndex *quarantine.QuarantineRecordSuffixIndex + var actualKey []byte + testFunc := func() { + actualIndex, actualKey = s.keeper.GetQuarantineRecordSuffixIndex(store, toAddr, fromAddr) + } + s.Require().NotPanics(testFunc, "getQuarantineRecordSuffixIndex") + s.Assert().Equal(expectedIndex, actualIndex, "returned index") + s.Assert().Equal(expectedKey, actualKey, "returned key") + }) + + s.Run("4 set get unordered on previously set entry", func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + expectedIndex := &quarantine.QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffix2, suffix3, suffix1, suffix4, suffix5}} + expectedKey := quarantine.CreateRecordIndexKey(toAddr, fromAddr) + + testFuncSet := func() { + s.keeper.SetQuarantineRecordSuffixIndex(store, expectedKey, expectedIndex) + } + s.Require().NotPanics(testFuncSet, "setQuarantineRecordSuffixIndex") + + var actualIndex *quarantine.QuarantineRecordSuffixIndex + var actualKey []byte + testFuncGet := func() { + actualIndex, actualKey = s.keeper.GetQuarantineRecordSuffixIndex(store, toAddr, fromAddr) + } + s.Require().NotPanics(testFuncGet, "getQuarantineRecordSuffixIndex") + s.Assert().Equal(expectedIndex, actualIndex, "returned index") + s.Assert().Equal(expectedKey, actualKey, "returned key") + }) +} + +func (s *TestSuite) TestAddQuarantineRecordSuffixIndexes() { + toAddr := MakeTestAddr("sad", 0) + fromAddr1 := MakeTestAddr("sad", 1) + fromAddr2 := MakeTestAddr("sad", 2) + fromAddr3 := MakeTestAddr("sad", 3) + suffix0 := []byte(MakeTestAddr("sfxsad", 0)) + suffix1 := []byte(MakeTestAddr("sfxsad", 1)) + suffix2 := []byte(MakeTestAddr("sfxsad", 2)) + suffix3 := []byte(MakeTestAddr("sfxsad", 3)) + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddrs []sdk.AccAddress + suffix []byte + expected *quarantine.QuarantineRecordSuffixIndex + }{ + { + name: "add to one nothing", + toAddr: toAddr, + fromAddrs: accs(fromAddr1), + suffix: suffix0, + expected: qrsi(suffix0), + }, + { + name: "add to two nothings", + toAddr: toAddr, + fromAddrs: accs(fromAddr2, fromAddr3), + suffix: suffix3, + expected: qrsi(suffix3), + }, + { + name: "add to one existing", + toAddr: toAddr, + fromAddrs: accs(fromAddr1), + suffix: suffix1, + expected: qrsi(suffix0, suffix1), + }, + { + name: "add to two existing", + toAddr: toAddr, + fromAddrs: accs(fromAddr2, fromAddr3), + suffix: suffix2, + expected: qrsi(suffix2, suffix3), // Note that this tests ordering too. + }, + { + name: "entry already exists", + toAddr: toAddr, + fromAddrs: accs(fromAddr1), + suffix: suffix0, + expected: qrsi(suffix0, suffix1), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + toAddrOrig := MakeCopyOfAccAddress(tc.toAddr) + fromAddrsOrig := MakeCopyOfAccAddresses(tc.fromAddrs) + suffixOrig := MakeCopyOfByteSlice(tc.suffix) + + testFuncAdd := func() { + s.keeper.AddQuarantineRecordSuffixIndexes(store, tc.toAddr, tc.fromAddrs, tc.suffix) + } + s.Require().NotPanics(testFuncAdd, "addQuarantineRecordSuffixIndexes") + s.Assert().Equal(toAddrOrig, tc.toAddr, "toAddr before and after") + s.Assert().Equal(fromAddrsOrig, tc.fromAddrs, "fromAddrs before and after") + s.Assert().Equal(suffixOrig, tc.suffix, "suffix before and after") + + for i, fromAddr := range fromAddrsOrig { + expected := MakeCopyOfQuarantineRecordSuffixIndex(tc.expected) + var actual *quarantine.QuarantineRecordSuffixIndex + testFuncGet := func() { + actual, _ = s.keeper.GetQuarantineRecordSuffixIndex(store, toAddrOrig, fromAddr) + } + if s.Assert().NotPanics(testFuncGet, "GetQuarantineRecordSuffixIndex[%d]", i) { + s.Assert().Equal(expected, actual, "result of GetQuarantineRecordSuffixIndex[%d]", i) + } + } + }) + } +} + +func (s *TestSuite) TestDeleteQuarantineRecordSuffixIndexes() { + toAddr := MakeTestAddr("sad", 0) + fromAddr1 := MakeTestAddr("sad", 1) + fromAddr2 := MakeTestAddr("sad", 2) + fromAddr3 := MakeTestAddr("sad", 3) + suffix0 := []byte(MakeTestAddr("sfxsad", 0)) + suffix1 := []byte(MakeTestAddr("sfxsad", 1)) + suffix2 := []byte(MakeTestAddr("sfxsad", 2)) + suffix3 := []byte(MakeTestAddr("sfxsad", 3)) + + // Create some existing entries that can then be altered. + existing := []struct { + key []byte + value *quarantine.QuarantineRecordSuffixIndex + }{ + { + key: quarantine.CreateRecordIndexKey(toAddr, fromAddr1), + value: qrsi(suffix0, suffix1, suffix2), + }, + { + key: quarantine.CreateRecordIndexKey(toAddr, fromAddr2), + value: qrsi(suffix2, suffix3), + }, + } + + for i, e := range existing { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + testFuncSet := func() { + s.keeper.SetQuarantineRecordSuffixIndex(store, e.key, e.value) + } + s.Require().NotPanics(testFuncSet, "setQuarantineRecordSuffixIndex[%d] for setup", i) + } + + // Setup: + // All will have the same toAddr. + // <- 1: 0, 1, 2 + // <- 2: 2, 3 + // The above will be altered as the tests progress. + + tests := []struct { + name string + fromAddrs []sdk.AccAddress + suffix []byte + expected []*quarantine.QuarantineRecordSuffixIndex + }{ + { + name: "index does not exist", + fromAddrs: accs(fromAddr3), + suffix: suffix0, + expected: qrsis(qrsi()), + }, + { + name: "index exists without suffix", + fromAddrs: accs(fromAddr1), + suffix: suffix3, + expected: qrsis(qrsi(suffix0, suffix1, suffix2)), + }, + { + name: "index has suffix", + fromAddrs: accs(fromAddr1), + suffix: suffix1, + expected: qrsis(qrsi(suffix0, suffix2)), + }, + { + name: "three froms two have suffix other no index", + fromAddrs: accs(fromAddr1, fromAddr2, fromAddr3), + suffix: suffix2, + expected: qrsis(qrsi(suffix0), qrsi(suffix3), qrsi()), + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + toAddrOrig := MakeCopyOfAccAddress(toAddr) + fromAddrsOrig := MakeCopyOfAccAddresses(tc.fromAddrs) + suffixOrig := MakeCopyOfByteSlice(tc.suffix) + + testFuncDelete := func() { + s.keeper.DeleteQuarantineRecordSuffixIndexes(store, toAddr, tc.fromAddrs, tc.suffix) + } + s.Require().NotPanics(testFuncDelete, "deleteQuarantineRecordSuffixIndexes") + s.Assert().Equal(toAddrOrig, toAddr, "toAddr before and after") + s.Assert().Equal(fromAddrsOrig, tc.fromAddrs, "fromAddrs before and after") + s.Assert().Equal(suffixOrig, tc.suffix, "suffix before and after") + + for i, expected := range tc.expected { + var actual *quarantine.QuarantineRecordSuffixIndex + testFuncGet := func() { + actual, _ = s.keeper.GetQuarantineRecordSuffixIndex(store, toAddrOrig, fromAddrsOrig[i]) + } + if s.Assert().NotPanics(testFuncGet, "GetQuarantineRecordSuffixIndex[%d]", i) { + s.Assert().Equal(expected, actual, "result of GetQuarantineRecordSuffixIndex[%d]", i) + } + } + }) + } + + s.Run("deleting last entry removes it from the store", func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + key := quarantine.CreateRecordIndexKey(toAddr, fromAddr1) + s.Require().True(store.Has(key), "store.Has(key) before the test starts") + + testFuncDelete := func() { + s.keeper.DeleteQuarantineRecordSuffixIndexes(store, toAddr, accs(fromAddr1), suffix0) + } + s.Require().NotPanics(testFuncDelete, "deleteQuarantineRecordSuffixIndexes") + if !s.Assert().False(store.Has(key), "store.Has(key) after last record should have been removed") { + var actual *quarantine.QuarantineRecordSuffixIndex + testFuncGet := func() { + actual, _ = s.keeper.GetQuarantineRecordSuffixIndex(store, toAddr, fromAddr1) + } + if s.Assert().NotPanics(testFuncGet, "getQuarantineRecordSuffixIndex") { + // This should always fail because getQuarantineRecordSuffixIndex never returns nil. + // This is being called only when toe store still has the entry. + // So this is just here so that the value in the store is included in the failure messages. + s.Assert().Nil(actual) + } + } + }) +} + +func (s *TestSuite) TestGetQuarantineRecordSuffixes() { + // The effects of getQuarantineRecordSuffixes are well tested elsewhere. Just doing a big one-off here. + toAddr := MakeTestAddr("gqrs", 0) + fromAddr1 := MakeTestAddr("gqrs", 1) + fromAddr2 := MakeTestAddr("gqrs", 2) + fromAddr3 := MakeTestAddr("gqrs", 3) + fromAddr4 := MakeTestAddr("gqrs", 4) + suffix5 := []byte(MakeTestAddr("sfxgqrs", 5)) + suffix6 := []byte(MakeTestAddr("sfxgqrs", 6)) + suffix7 := []byte(MakeTestAddr("sfxgqrs", 7)) + fromAddr8 := MakeTestAddr("gqrs", 8) + + // sfxs is just a shorter way of creating a [][]byte + sfxs := func(suffixes ...[]byte) [][]byte { + return suffixes + } + + // Setup: + // This may or may not actually make sense, but it's how I'm setting it up. + // {toAddr} <- {fromAddr} = {suffixes} + // 0 <- 1 = 5,6 + // 0 <- 2 = 5,6 + // 0 <- 3 = 5 + // 0 <- 4 = (none) + // 0 <- 8 = 7 + + existing := []struct { + from sdk.AccAddress + suffix []byte + }{ + {from: fromAddr1, suffix: suffix5}, + {from: fromAddr1, suffix: suffix6}, + {from: fromAddr2, suffix: suffix5}, + {from: fromAddr2, suffix: suffix6}, + {from: fromAddr1, suffix: suffix5}, + {from: fromAddr3, suffix: suffix5}, + {from: fromAddr8, suffix: suffix7}, + } + + for i, e := range existing { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + testFuncAdd := func() { + s.keeper.AddQuarantineRecordSuffixIndexes(store, toAddr, accs(e.from), e.suffix) + } + s.Require().NotPanics(testFuncAdd, "addQuarantineRecordSuffixIndexes[%d] for setup", i) + } + + tests := []struct { + name string + fromAddrs []sdk.AccAddress + expected [][]byte + }{ + {name: "nil froms", fromAddrs: nil, expected: nil}, + {name: "empty froms", fromAddrs: []sdk.AccAddress{}, expected: nil}, + {name: "one from with zero suffixes", fromAddrs: accs(fromAddr4), expected: sfxs(fromAddr4)}, + {name: "one from with one shared suffix", fromAddrs: accs(fromAddr3), expected: sfxs(fromAddr3, suffix5)}, + {name: "one from with one lone suffix", fromAddrs: accs(fromAddr8), expected: sfxs(suffix7, fromAddr8)}, + {name: "one from with two suffixes", fromAddrs: accs(fromAddr1), expected: sfxs(fromAddr1, suffix5, suffix6)}, + { + name: "two froms with two overlapping suffixes", + fromAddrs: accs(fromAddr1, fromAddr2), + expected: sfxs(fromAddr1, fromAddr2, suffix5, suffix6)}, + { + name: "two froms with two different suffixes", + fromAddrs: accs(fromAddr8, fromAddr3), + expected: sfxs(fromAddr3, suffix5, suffix7, fromAddr8)}, + { + name: "five froms plus a dupe with 3 suffixes", + fromAddrs: accs(fromAddr4, fromAddr1, fromAddr8, fromAddr2, fromAddr3, fromAddr1), + expected: sfxs(fromAddr1, fromAddr2, fromAddr3, fromAddr4, suffix5, suffix6, suffix7, fromAddr8)}, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + store := s.sdkCtx.KVStore(s.keeper.GetStoreKey()) + toAddrOrig := MakeCopyOfAccAddress(toAddr) + fromAddrsOrig := MakeCopyOfAccAddresses(tc.fromAddrs) + + var actual [][]byte + testFuncGet := func() { + actual = s.keeper.GetQuarantineRecordSuffixes(store, toAddr, tc.fromAddrs) + } + s.Require().NotPanics(testFuncGet, "getQuarantineRecordSuffixes") + s.Assert().Equal(toAddrOrig, toAddr, "toAddr before and after") + s.Assert().Equal(fromAddrsOrig, tc.fromAddrs, "fromAddrs before and after") + s.Assert().Equal(tc.expected, actual, "result of getQuarantineRecordSuffixes") + }) + } +} + +func (s *TestSuite) TestInitAndExportGenesis() { + addr0 := MakeTestAddr("ieg", 0).String() + addr1 := MakeTestAddr("ieg", 1).String() + addr2 := MakeTestAddr("ieg", 2).String() + addr3 := MakeTestAddr("ieg", 3).String() + addr4 := MakeTestAddr("ieg", 4).String() + addr5 := MakeTestAddr("ieg", 5).String() + addr6 := MakeTestAddr("ieg", 6).String() + addr7 := MakeTestAddr("ieg", 7).String() + + genesisState := &quarantine.GenesisState{ + QuarantinedAddresses: []string{addr0, addr2, addr4, addr6, addr7, addr5, addr1, addr3}, + AutoResponses: []*quarantine.AutoResponseEntry{ + { + ToAddress: addr5, + FromAddress: addr4, + Response: quarantine.AUTO_RESPONSE_ACCEPT, + }, + { + ToAddress: addr5, + FromAddress: addr1, + Response: quarantine.AUTO_RESPONSE_ACCEPT, + }, + { + ToAddress: addr5, + FromAddress: addr2, + Response: quarantine.AUTO_RESPONSE_DECLINE, + }, + { + ToAddress: addr2, + FromAddress: addr5, + Response: quarantine.AUTO_RESPONSE_ACCEPT, + }, + { + ToAddress: addr0, + FromAddress: addr7, + Response: quarantine.AUTO_RESPONSE_UNSPECIFIED, + }, + { + ToAddress: addr0, + FromAddress: addr3, + Response: quarantine.AUTO_RESPONSE_DECLINE, + }, + }, + QuarantinedFunds: []*quarantine.QuarantinedFunds{ + { + ToAddress: addr5, + UnacceptedFromAddresses: []string{addr2}, + Coins: s.cz("2dull,5fancy"), + Declined: false, + }, + { + ToAddress: addr0, + UnacceptedFromAddresses: []string{addr1}, + Coins: s.cz("8fancy"), + Declined: false, + }, + { + ToAddress: addr4, + UnacceptedFromAddresses: []string{addr6}, + Coins: s.cz("200000dolla"), + Declined: false, + }, + { + ToAddress: addr0, + UnacceptedFromAddresses: []string{addr1, addr2}, + Coins: s.cz("21fancy"), + Declined: false, + }, + }, + } + + expectedGenesisState := &quarantine.GenesisState{ + QuarantinedAddresses: []string{addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7}, + AutoResponses: []*quarantine.AutoResponseEntry{ + MakeCopyOfAutoResponseEntry(genesisState.AutoResponses[5]), + MakeCopyOfAutoResponseEntry(genesisState.AutoResponses[3]), + MakeCopyOfAutoResponseEntry(genesisState.AutoResponses[1]), + MakeCopyOfAutoResponseEntry(genesisState.AutoResponses[2]), + MakeCopyOfAutoResponseEntry(genesisState.AutoResponses[0]), + }, + QuarantinedFunds: []*quarantine.QuarantinedFunds{ + MakeCopyOfQuarantinedFunds(genesisState.QuarantinedFunds[1]), + MakeCopyOfQuarantinedFunds(genesisState.QuarantinedFunds[3]), + MakeCopyOfQuarantinedFunds(genesisState.QuarantinedFunds[2]), + MakeCopyOfQuarantinedFunds(genesisState.QuarantinedFunds[0]), + }, + } + + s.Run("export while empty", func() { + expected := &quarantine.GenesisState{ + QuarantinedAddresses: nil, + AutoResponses: nil, + QuarantinedFunds: nil, + } + var actual *quarantine.GenesisState + testFuncExport := func() { + actual = s.keeper.ExportGenesis(s.sdkCtx) + } + s.Require().NotPanics(testFuncExport, "ExportGenesis") + s.Assert().Equal(expected, actual, "exported genesis state") + + }) + + s.Run("init not enough funds", func() { + bKeeper := NewMockBankKeeper() + bKeeper.AllBalances[string(s.keeper.GetFundsHolder())] = s.cz("199999dolla,1dull,33fancy") + qKeeper := s.keeper.WithBankKeeper(bKeeper) + expectedErr := fmt.Sprintf("quarantine fund holder account %q does not have enough funds %q to cover quarantined funds %q", + s.keeper.GetFundsHolder().String(), "199999dolla,1dull,33fancy", "200000dolla,2dull,34fancy") + + genStateCopy := MakeCopyOfGenesisState(genesisState) + testFuncInit := func() { + qKeeper.InitGenesis(s.sdkCtx, genStateCopy) + } + s.Require().PanicsWithError(expectedErr, testFuncInit, "InitGenesis") + }) + + s.Run("init with enough funds", func() { + bKeeper := NewMockBankKeeper() + bKeeper.AllBalances[string(s.keeper.GetFundsHolder())] = s.cz("200000dolla,2dull,34fancy") + qKeeper := s.keeper.WithBankKeeper(bKeeper) + + genStateCopy := MakeCopyOfGenesisState(genesisState) + testFuncInit := func() { + qKeeper.InitGenesis(s.sdkCtx, genStateCopy) + } + s.Require().NotPanics(testFuncInit, "InitGenesis") + }) + + s.Run("export after successful init", func() { + var actualGenesisState *quarantine.GenesisState + testFuncExport := func() { + actualGenesisState = s.keeper.ExportGenesis(s.sdkCtx) + } + s.Require().NotPanics(testFuncExport, "ExportGenesis") + s.Assert().Equal(expectedGenesisState, actualGenesisState, "exported genesis state") + }) +} diff --git a/x/quarantine/keeper/mock_bank_keeper_test.go b/x/quarantine/keeper/mock_bank_keeper_test.go new file mode 100644 index 0000000000..d84e2c969b --- /dev/null +++ b/x/quarantine/keeper/mock_bank_keeper_test.go @@ -0,0 +1,68 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +// Define a Mock Bank Keeper that defining of SendCoins errors and +// records calls made to SendCoins (but doesn't do anything else). +// Also have it just do a map lookup for GetAllBalances. + +// SentCoins are the arguments that were provided to SendCoins. +type SentCoins struct { + FromAddr sdk.AccAddress + ToAddr sdk.AccAddress + Amt sdk.Coins +} + +var _ quarantine.BankKeeper = &MockBankKeeper{} + +type MockBankKeeper struct { + // SentCoins are the arguments that were provided to SendCoins, one entry for each call to it. + SentCoins []*SentCoins + // AllBalances are the balances to return from GetAllBalances. + AllBalances map[string]sdk.Coins + // QueuedSendCoinsErrors are any errors queued up to return from SendCoins. + // An entry of nil means no error will be returned. + // If this is empty, no error is returned. + // Entries are removed once they're used. + QueuedSendCoinsErrors []error +} + +func NewMockBankKeeper() *MockBankKeeper { + return &MockBankKeeper{ + SentCoins: nil, + AllBalances: make(map[string]sdk.Coins), + QueuedSendCoinsErrors: nil, + } +} + +func (k *MockBankKeeper) AppendSendRestriction(_ banktypes.SendRestrictionFn) { + // do nothing. +} + +func (k *MockBankKeeper) GetAllBalances(_ sdk.Context, addr sdk.AccAddress) sdk.Coins { + return k.AllBalances[string(addr)] +} + +func (k *MockBankKeeper) SendCoins(_ sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error { + if len(k.QueuedSendCoinsErrors) > 0 { + err := k.QueuedSendCoinsErrors[0] + k.QueuedSendCoinsErrors = k.QueuedSendCoinsErrors[1:] + if err != nil { + return err + } + } + k.SentCoins = append(k.SentCoins, &SentCoins{ + FromAddr: fromAddr, + ToAddr: toAddr, + Amt: amt, + }) + return nil +} + +func (k *MockBankKeeper) SpendableCoins(_ sdk.Context, addr sdk.AccAddress) sdk.Coins { + return k.AllBalances[string(addr)] +} diff --git a/x/quarantine/keeper/msg_server.go b/x/quarantine/keeper/msg_server.go new file mode 100644 index 0000000000..228d793788 --- /dev/null +++ b/x/quarantine/keeper/msg_server.go @@ -0,0 +1,118 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +var _ quarantine.MsgServer = Keeper{} + +func (k Keeper) OptIn(goCtx context.Context, msg *quarantine.MsgOptIn) (*quarantine.MsgOptInResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + toAddr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, err + } + + if err = k.SetOptIn(ctx, toAddr); err != nil { + return nil, err + } + + return &quarantine.MsgOptInResponse{}, nil +} + +func (k Keeper) OptOut(goCtx context.Context, msg *quarantine.MsgOptOut) (*quarantine.MsgOptOutResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + toAddr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, err + } + + if err = k.SetOptOut(ctx, toAddr); err != nil { + return nil, err + } + + return &quarantine.MsgOptOutResponse{}, nil +} + +func (k Keeper) Accept(goCtx context.Context, msg *quarantine.MsgAccept) (*quarantine.MsgAcceptResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + toAddr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %v", err) + } + + fromAddrs := make([]sdk.AccAddress, len(msg.FromAddresses)) + for i, addr := range msg.FromAddresses { + fromAddrs[i], err = sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid from address[%d]: %v", i, err) + } + } + + var fundsReleased sdk.Coins + fundsReleased, err = k.AcceptQuarantinedFunds(ctx, toAddr, fromAddrs...) + if err != nil { + return nil, err + } + + if msg.Permanent { + for _, fromAddr := range fromAddrs { + k.SetAutoResponse(ctx, toAddr, fromAddr, quarantine.AUTO_RESPONSE_ACCEPT) + } + } + + return &quarantine.MsgAcceptResponse{FundsReleased: fundsReleased}, nil +} + +func (k Keeper) Decline(goCtx context.Context, msg *quarantine.MsgDecline) (*quarantine.MsgDeclineResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + toAddr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %v", err) + } + + fromAddrs := make([]sdk.AccAddress, len(msg.FromAddresses)) + for i, addr := range msg.FromAddresses { + fromAddrs[i], err = sdk.AccAddressFromBech32(addr) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid from address[%d]: %v", i, err) + } + } + + k.DeclineQuarantinedFunds(ctx, toAddr, fromAddrs...) + + if msg.Permanent { + for _, fromAddr := range fromAddrs { + k.SetAutoResponse(ctx, toAddr, fromAddr, quarantine.AUTO_RESPONSE_DECLINE) + } + } + + return &quarantine.MsgDeclineResponse{}, nil +} + +func (k Keeper) UpdateAutoResponses(goCtx context.Context, msg *quarantine.MsgUpdateAutoResponses) (*quarantine.MsgUpdateAutoResponsesResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + toAddr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %v", err) + } + + for i, update := range msg.Updates { + fromAddr, err := sdk.AccAddressFromBech32(update.FromAddress) + if err != nil { + return nil, sdkerrors.ErrInvalidAddress.Wrapf("invalid from address[%d]: %v", i, err) + } + k.SetAutoResponse(ctx, toAddr, fromAddr, update.Response) + } + + return &quarantine.MsgUpdateAutoResponsesResponse{}, nil +} diff --git a/x/quarantine/keeper/msg_server_test.go b/x/quarantine/keeper/msg_server_test.go new file mode 100644 index 0000000000..6a6d93d3ff --- /dev/null +++ b/x/quarantine/keeper/msg_server_test.go @@ -0,0 +1,544 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" + + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +// These tests are initiated by TestKeeperTestSuite in keeper_test.go + +func (s *TestSuite) TestOptIn() { + addr0 := MakeTestAddr("optin", 0).String() + + tests := []struct { + name string + msg *quarantine.MsgOptIn + expErr []string + }{ + { + name: "bad address", + msg: &quarantine.MsgOptIn{ToAddress: "badbad"}, + expErr: []string{"decoding bech32 failed"}, + }, + { + name: "okay", + msg: &quarantine.MsgOptIn{ToAddress: addr0}, + }, + { + name: "repeat okay", + msg: &quarantine.MsgOptIn{ToAddress: addr0}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + actResp, actErr := s.keeper.OptIn(s.stdlibCtx, tc.msg) + s.AssertErrorContents(actErr, tc.expErr, "OptIn error") + if len(tc.expErr) == 0 { + s.Assert().NotNil(actResp, "MsgOptInResponse") + addr, err := sdk.AccAddressFromBech32(tc.msg.ToAddress) + if s.Assert().NoError(err, "AccAddressFromBech32 ToAddress") { + isQ := s.keeper.IsQuarantinedAddr(s.sdkCtx, addr) + s.Assert().True(isQ, "IsQuarantinedAddr") + } + } + }) + } +} + +func (s *TestSuite) TestOptOut() { + addr0Acc := MakeTestAddr("optout", 0) + addr0 := addr0Acc.String() + addr1 := MakeTestAddr("oook", 1).String() + + // Setup, opt addr0 in so it can be opted out later. + var err error + testFunc := func() { + err = s.keeper.SetOptIn(s.sdkCtx, addr0Acc) + } + s.Require().NotPanics(testFunc, "SetOptIn") + s.Require().NoError(err, "SetOptIn") + + tests := []struct { + name string + msg *quarantine.MsgOptOut + expErr []string + }{ + { + name: "bad address", + msg: &quarantine.MsgOptOut{ToAddress: "badbad"}, + expErr: []string{"decoding bech32 failed"}, + }, + { + name: "wasnt opted in", + msg: &quarantine.MsgOptOut{ToAddress: addr1}, + }, + { + name: "was opted in", + msg: &quarantine.MsgOptOut{ToAddress: addr0}, + }, + { + name: "again with the one that was opted in", + msg: &quarantine.MsgOptOut{ToAddress: addr0}, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + actResp, actErr := s.keeper.OptOut(s.stdlibCtx, tc.msg) + s.AssertErrorContents(actErr, tc.expErr, "OptOut error") + if len(tc.expErr) == 0 { + s.Assert().NotNil(actResp, "MsgOptOutResponse") + addr, err := sdk.AccAddressFromBech32(tc.msg.ToAddress) + if s.Assert().NoError(err) { + isQ := s.keeper.IsQuarantinedAddr(s.sdkCtx, addr) + s.Assert().False(isQ, "IsQuarantinedAddr") + } + } + }) + } +} + +func (s *TestSuite) TestAccept() { + makeAddr := func(index uint8) (sdk.AccAddress, string) { + addr := MakeTestAddr("accept", index) + return addr, addr.String() + } + makeFREvent := func(addr string, amt sdk.Coins) sdk.Event { + rv, err := sdk.TypedEventToEvent(&quarantine.EventFundsReleased{ + ToAddress: addr, + Coins: amt, + }) + s.Require().NoError(err, "TypedEventToEvent") + return rv + } + addr0Acc, addr0 := makeAddr(0) + addr1Acc, addr1 := makeAddr(1) + addr2Acc, addr2 := makeAddr(2) + + // Set up some quarantined funds to 0 from 1 and to 0 from 2. + amt1 := s.cz("5491book") + amt2 := s.cz("8383tape") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, amt1, addr0Acc, addr1Acc), "AddQuarantinedCoins 0 1") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, amt2, addr0Acc, addr2Acc), "AddQuarantinedCoins 0 2") + + tests := []struct { + name string + msg *quarantine.MsgAccept + expErr []string + expEvents sdk.Events + expSend *SentCoins + expPerm bool + }{ + { + name: "bad to address", + msg: &quarantine.MsgAccept{ToAddress: "stillbad"}, + expErr: []string{"decoding bech32 failed", "invalid to address"}, + }, + { + name: "bad first from", + msg: &quarantine.MsgAccept{ + ToAddress: addr0, + FromAddresses: []string{"notgood"}, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[0]"}, + }, + { + name: "bad second from", + msg: &quarantine.MsgAccept{ + ToAddress: addr0, + FromAddresses: []string{addr1, "notgood", addr2}, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[1]"}, + }, + { + name: "bad third from", + msg: &quarantine.MsgAccept{ + ToAddress: addr0, + FromAddresses: []string{addr1, addr2, "notgood"}, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[2]"}, + }, + { + name: "nothing to accept", + msg: &quarantine.MsgAccept{ + ToAddress: addr2, + FromAddresses: []string{addr0}, + }, + expEvents: sdk.Events{}, + }, + { + name: "nothing to accept but permanent", + msg: &quarantine.MsgAccept{ + ToAddress: addr2, + FromAddresses: []string{addr0}, + Permanent: true, + }, + expEvents: sdk.Events{}, + expPerm: true, + }, + { + name: "funds to accept", + msg: &quarantine.MsgAccept{ + ToAddress: addr0, + FromAddresses: []string{addr1}, + }, + expEvents: sdk.Events{makeFREvent(addr0, amt1)}, + expSend: &SentCoins{ + FromAddr: s.keeper.GetFundsHolder(), + ToAddr: addr0Acc, + Amt: MakeCopyOfCoins(amt1), + }, + }, + { + name: "funds to accept and permanent", + msg: &quarantine.MsgAccept{ + ToAddress: addr0, + FromAddresses: []string{addr2}, + Permanent: true, + }, + expEvents: sdk.Events{makeFREvent(addr0, amt2)}, + expSend: &SentCoins{ + FromAddr: s.keeper.GetFundsHolder(), + ToAddr: addr0Acc, + Amt: MakeCopyOfCoins(amt2), + }, + expPerm: true, + }, + { + name: "nothing to accept now not perm this time", + msg: &quarantine.MsgAccept{ + ToAddress: addr0, + FromAddresses: []string{addr2}, + Permanent: false, + }, + expPerm: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + bKeeper := NewMockBankKeeper() + qKeeper := s.keeper.WithBankKeeper(bKeeper) + em := sdk.NewEventManager() + ctx := sdk.WrapSDKContext(s.sdkCtx.WithEventManager(em)) + actResp, actErr := qKeeper.Accept(ctx, tc.msg) + s.AssertErrorContents(actErr, tc.expErr, "Accept error") + if len(tc.expErr) == 0 { + s.Assert().NotNil(actResp, "MsgAcceptResponse") + } + + if tc.expEvents != nil { + actEvents := em.Events() + s.Assert().Equal(tc.expEvents, actEvents, "emitted events") + } + + var expSends []*SentCoins + if tc.expSend != nil { + expSends = append(expSends, tc.expSend) + } + actSends := bKeeper.SentCoins + s.Assert().Equal(expSends, actSends, "sends made") + + if tc.expPerm { + toAddrAcc, err := sdk.AccAddressFromBech32(tc.msg.ToAddress) + if s.Assert().NoError(err, "toAddr to acc") { + for _, fromAddr := range tc.msg.FromAddresses { + fromAddrAcc, err := sdk.AccAddressFromBech32(fromAddr) + if s.Assert().NoError(err, "fromAddr to acc") { + actPerm := qKeeper.IsAutoAccept(s.sdkCtx, toAddrAcc, fromAddrAcc) + s.Assert().True(actPerm, "IsAutoAccept") + } + } + } + } + }) + } +} + +func (s *TestSuite) TestDecline() { + makeAddr := func(index uint8) (sdk.AccAddress, string) { + addr := MakeTestAddr("decline", index) + return addr, addr.String() + } + addr0Acc, addr0 := makeAddr(0) + addr1Acc, addr1 := makeAddr(1) + addr2Acc, addr2 := makeAddr(2) + + // Set up some quarantined funds to 0 from 1 and to 0 from 2. + amt1 := s.cz("66route") + amt2 := s.cz("55hagar") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, amt1, addr0Acc, addr1Acc), "AddQuarantinedCoins 0 1") + s.Require().NoError(s.keeper.AddQuarantinedCoins(s.sdkCtx, amt2, addr0Acc, addr2Acc), "AddQuarantinedCoins 0 2") + + tests := []struct { + name string + msg *quarantine.MsgDecline + expErr []string + expRec *quarantine.QuarantineRecord + expPerm bool + }{ + { + name: "bad to address", + msg: &quarantine.MsgDecline{ToAddress: "stillbad"}, + expErr: []string{"decoding bech32 failed", "invalid to address"}, + }, + { + name: "bad first from", + msg: &quarantine.MsgDecline{ + ToAddress: addr0, + FromAddresses: []string{"notgood"}, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[0]"}, + }, + { + name: "bad second from", + msg: &quarantine.MsgDecline{ + ToAddress: addr0, + FromAddresses: []string{addr1, "notgood", addr2}, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[1]"}, + }, + { + name: "bad third from", + msg: &quarantine.MsgDecline{ + ToAddress: addr0, + FromAddresses: []string{addr1, addr2, "notgood"}, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[2]"}, + }, + { + name: "nothing to decline", + msg: &quarantine.MsgDecline{ + ToAddress: addr2, + FromAddresses: []string{addr0}, + }, + }, + { + name: "nothing to decline but permanent", + msg: &quarantine.MsgDecline{ + ToAddress: addr2, + FromAddresses: []string{addr0}, + Permanent: true, + }, + expPerm: true, + }, + { + name: "funds to decline", + msg: &quarantine.MsgDecline{ + ToAddress: addr0, + FromAddresses: []string{addr1}, + }, + expRec: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1Acc), + Coins: MakeCopyOfCoins(amt1), + Declined: true, + }, + }, + { + name: "funds to decline and permanent", + msg: &quarantine.MsgDecline{ + ToAddress: addr0, + FromAddresses: []string{addr2}, + Permanent: true, + }, + expRec: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr2Acc), + Coins: MakeCopyOfCoins(amt2), + Declined: true, + }, + expPerm: true, + }, + { + name: "declined funds declined again but with perm", + msg: &quarantine.MsgDecline{ + ToAddress: addr0, + FromAddresses: []string{addr1}, + Permanent: true, + }, + expRec: &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: accs(addr1Acc), + Coins: MakeCopyOfCoins(amt1), + Declined: true, + }, + expPerm: true, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + em := sdk.NewEventManager() + ctx := sdk.WrapSDKContext(s.sdkCtx.WithEventManager(em)) + actResp, actErr := s.keeper.Decline(ctx, tc.msg) + s.AssertErrorContents(actErr, tc.expErr, "Decline error") + if len(tc.expErr) == 0 { + s.Assert().NotNil(actResp, "MsgDeclineResponse") + } + + if tc.expRec != nil { + toAddrAcc, err := sdk.AccAddressFromBech32(tc.msg.ToAddress) + if s.Assert().NoError(err, "AccAddressFromBech32 toAddr") { + actRec := s.keeper.GetQuarantineRecord(s.sdkCtx, toAddrAcc, tc.expRec.GetAllFromAddrs()...) + s.Assert().Equal(tc.expRec, actRec, "resulting record") + } + } + + if tc.expPerm { + toAddrAcc, err := sdk.AccAddressFromBech32(tc.msg.ToAddress) + if s.Assert().NoError(err, "toAddr to acc") { + for _, fromAddr := range tc.msg.FromAddresses { + fromAddrAcc, err := sdk.AccAddressFromBech32(fromAddr) + if s.Assert().NoError(err, "fromAddr to acc") { + actPerm := s.keeper.IsAutoDecline(s.sdkCtx, toAddrAcc, fromAddrAcc) + s.Assert().True(actPerm, "IsAutoDecline") + } + } + } + } + }) + } +} + +func (s *TestSuite) TestUpdateAutoResponses() { + addr0 := MakeTestAddr("uar", 0).String() + addr1 := MakeTestAddr("uar", 1).String() + addr2 := MakeTestAddr("uar", 2).String() + addr3 := MakeTestAddr("uar", 3).String() + addr4 := MakeTestAddr("uar", 4).String() + addr5 := MakeTestAddr("uar", 5).String() + addr6 := MakeTestAddr("uar", 6).String() + + tests := []struct { + name string + msg *quarantine.MsgUpdateAutoResponses + expErr []string + exp []*quarantine.AutoResponseEntry + }{ + { + name: "bad toAddr", + msg: &quarantine.MsgUpdateAutoResponses{ToAddress: "badtoaddr"}, + expErr: []string{"decoding bech32 failed", "invalid to address"}, + }, + { + name: "bad first from", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: "bad0", Response: 0}, + }, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[0]"}, + }, + { + name: "bad second from", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: addr1, Response: 0}, + {FromAddress: "bad1", Response: 0}, + {FromAddress: addr3, Response: 0}, + }, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[1]"}, + }, + { + name: "bad third from", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: addr1, Response: 0}, + {FromAddress: addr2, Response: 0}, + {FromAddress: "bad2", Response: 0}, + }, + }, + expErr: []string{"decoding bech32 failed", "invalid from address[2]"}, + }, + { + name: "single entry accept", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: addr1, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + }, + }, + exp: []*quarantine.AutoResponseEntry{ + {ToAddress: addr0, FromAddress: addr1, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + }, + }, + { + // Note: The next test assumes that this succeeds and is in place (to undo). + name: "single entry decline", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: addr2, Response: quarantine.AUTO_RESPONSE_DECLINE}, + }, + }, + exp: []*quarantine.AutoResponseEntry{ + { + ToAddress: addr0, + FromAddress: addr2, + Response: quarantine.AUTO_RESPONSE_DECLINE, + }, + }, + }, + { + // This assumes a previous test set an auto response to 0 from 2. + name: "single entry unspecified", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: addr2, Response: quarantine.AUTO_RESPONSE_UNSPECIFIED}, + }, + }, + exp: []*quarantine.AutoResponseEntry{ + {ToAddress: addr0, FromAddress: addr2, Response: quarantine.AUTO_RESPONSE_UNSPECIFIED}, + }, + }, + { + name: "multiple entries", + msg: &quarantine.MsgUpdateAutoResponses{ + ToAddress: addr0, + Updates: []*quarantine.AutoResponseUpdate{ + {FromAddress: addr6, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + {FromAddress: addr2, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + {FromAddress: addr4, Response: quarantine.AUTO_RESPONSE_DECLINE}, + {FromAddress: addr1, Response: quarantine.AUTO_RESPONSE_DECLINE}, + {FromAddress: addr5, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + {FromAddress: addr3, Response: quarantine.AUTO_RESPONSE_UNSPECIFIED}, + {FromAddress: addr5, Response: quarantine.AUTO_RESPONSE_UNSPECIFIED}, + }, + }, + exp: []*quarantine.AutoResponseEntry{ + {ToAddress: addr0, FromAddress: addr1, Response: quarantine.AUTO_RESPONSE_DECLINE}, + {ToAddress: addr0, FromAddress: addr2, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + {ToAddress: addr0, FromAddress: addr3, Response: quarantine.AUTO_RESPONSE_UNSPECIFIED}, + {ToAddress: addr0, FromAddress: addr4, Response: quarantine.AUTO_RESPONSE_DECLINE}, + {ToAddress: addr0, FromAddress: addr5, Response: quarantine.AUTO_RESPONSE_UNSPECIFIED}, + {ToAddress: addr0, FromAddress: addr6, Response: quarantine.AUTO_RESPONSE_ACCEPT}, + }, + }, + } + + for _, tc := range tests { + s.Run(tc.name, func() { + actResp, actErr := s.keeper.UpdateAutoResponses(s.stdlibCtx, tc.msg) + s.AssertErrorContents(actErr, tc.expErr, "UpdateAutoResponses error") + if len(tc.expErr) == 0 { + s.Assert().NotNil(actResp, "MsgUpdateAutoResponsesResponse") + } + for i, exp := range tc.exp { + toAddr, err := sdk.AccAddressFromBech32(exp.ToAddress) + if s.Assert().NoError(err, "decoding ToAddress[%d]", i) { + fromAddr, err := sdk.AccAddressFromBech32(exp.FromAddress) + if s.Assert().NoError(err, "decoding FromAddress[%d]", i) { + actResponse := s.keeper.GetAutoResponse(s.sdkCtx, toAddr, fromAddr) + s.Assert().Equal(exp.Response, actResponse, "GetAutoResponse[%d]", i) + } + } + } + }) + } +} diff --git a/x/quarantine/keeper/send_restriction.go b/x/quarantine/keeper/send_restriction.go new file mode 100644 index 0000000000..e5f6bbd5ab --- /dev/null +++ b/x/quarantine/keeper/send_restriction.go @@ -0,0 +1,38 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +var _ banktypes.SendRestrictionFn = Keeper{}.SendRestrictionFn + +func (k Keeper) SendRestrictionFn(ctx sdk.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) (sdk.AccAddress, error) { + // bypass if the context says to. + if quarantine.HasBypass(ctx) { + return toAddr, nil + } + // bypass if the fromAddr is either the toAddr or the funds holder. + fundsHolder := k.GetFundsHolder() + if fromAddr.Equals(toAddr) || fromAddr.Equals(fundsHolder) { + return toAddr, nil + } + // Nothing to do if they're not quarantined or if they are, but have auto-accept enabled for the fromAddr. + if !k.IsQuarantinedAddr(ctx, toAddr) || k.IsAutoAccept(ctx, toAddr, fromAddr) { + return toAddr, nil + } + // Make sure there's a funds holder defined since we need it now. + // This should not be possible since NewKeeper makes sure it always has a value. + // But it would be really bad if it somehow happened. + if fundsHolder.Empty() { + return nil, sdkerrors.ErrUnknownAddress.Wrapf("no quarantine funds holder account defined") + } + // Record the quarantined funds and return the funds holder as the new toAddr. + err := k.AddQuarantinedCoins(ctx, amt, toAddr, fromAddr) + if err != nil { + return nil, err + } + return fundsHolder, nil +} diff --git a/x/quarantine/keeper/send_restriction_test.go b/x/quarantine/keeper/send_restriction_test.go new file mode 100644 index 0000000000..a256fb9204 --- /dev/null +++ b/x/quarantine/keeper/send_restriction_test.go @@ -0,0 +1,289 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/bank/testutil" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" +) + +// These tests are initiated by TestKeeperTestSuite in keeper_test.go + +func (s *TestSuite) TestSendRestrictionFn() { + fundsHolder := s.keeper.GetFundsHolder() + keeperWithoutFundsHolder := s.keeper.WithFundsHolder(nil) + ctxWithBypass := quarantine.WithBypass(s.sdkCtx) + + cz := func(amt string) sdk.Coins { + rv, err := sdk.ParseCoinsNormalized(amt) + if err != nil { + panic(err) + } + return rv + } + + // addr1 opted in: auto-accept from addr2, auto-decline from addr3, unspecified from addr4. + // addr5 NOT opted in, but has the same auto-responses defined as addr1. + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr1), "SetOptIn addr1") + s.keeper.SetAutoResponse(s.sdkCtx, s.addr1, s.addr2, quarantine.AUTO_RESPONSE_ACCEPT) + s.keeper.SetAutoResponse(s.sdkCtx, s.addr1, s.addr3, quarantine.AUTO_RESPONSE_DECLINE) + s.keeper.SetAutoResponse(s.sdkCtx, s.addr1, s.addr4, quarantine.AUTO_RESPONSE_UNSPECIFIED) + s.keeper.SetAutoResponse(s.sdkCtx, s.addr5, s.addr2, quarantine.AUTO_RESPONSE_ACCEPT) + s.keeper.SetAutoResponse(s.sdkCtx, s.addr5, s.addr3, quarantine.AUTO_RESPONSE_DECLINE) + s.keeper.SetAutoResponse(s.sdkCtx, s.addr5, s.addr4, quarantine.AUTO_RESPONSE_UNSPECIFIED) + + tests := []struct { + name string + keeper *keeper.Keeper + ctx *sdk.Context + fromAddr sdk.AccAddress + toAddr sdk.AccAddress + amt sdk.Coins + expErr []string + expQuarantine bool + }{ + { + name: "has bypass", + ctx: &ctxWithBypass, + fromAddr: s.addr4, + toAddr: s.addr1, + amt: cz("10acorns"), + expQuarantine: false, + }, + { + name: "from equals to", + fromAddr: s.addr2, + toAddr: s.addr2, + amt: cz("11bcorns"), + expQuarantine: false, + }, + { + name: "from equals funds holder", + fromAddr: fundsHolder, + toAddr: s.addr2, + amt: cz("12ccorns"), + expQuarantine: false, + }, + { + name: "to equals funds holder", + fromAddr: s.addr5, + toAddr: fundsHolder, + amt: cz("20kcorns"), + expQuarantine: false, + }, + { + name: "to address is not quarantined", + fromAddr: s.addr4, + toAddr: s.addr5, + amt: cz("13dcorns"), + expQuarantine: false, + }, + { + name: "to address is not quarantined but has auto-accept", + fromAddr: s.addr2, + toAddr: s.addr5, + amt: cz("14ecorns"), + expQuarantine: false, + }, + { + name: "to address is not quarantined but has auto-decline", + fromAddr: s.addr3, + toAddr: s.addr5, + amt: cz("15fcorns"), + expQuarantine: false, + }, + { + name: "to address is quarantined with auto-accept", + fromAddr: s.addr2, + toAddr: s.addr1, + amt: cz("16gcorns"), + expQuarantine: false, + }, + { + name: "to address is quarantined with auto-decline", + fromAddr: s.addr3, + toAddr: s.addr1, + amt: cz("17hcorns"), + expQuarantine: true, + }, + { + name: "to address is quarantined with no auto-response", + fromAddr: s.addr4, + toAddr: s.addr1, + amt: cz("18icorns"), + expQuarantine: true, + }, + { + name: "No quarantine funds holder", + keeper: &keeperWithoutFundsHolder, + fromAddr: s.addr4, + toAddr: s.addr1, + amt: cz("19jcorns"), + expErr: []string{"no quarantine funds holder account defined", "unknown address"}, + }, + // AddQuarantinedCoins returns error + // As of writing this, the only reasons AddQuarantinedCoins returns an error is if + // the funds are already fully accepted, or if there's an error emitting an event. + // Neither are possible to trigger from here. + } + + for _, tc := range tests { + s.Run(tc.name, func() { + k := s.keeper + if tc.keeper != nil { + k = *tc.keeper + } + ctx := s.sdkCtx + if tc.ctx != nil { + ctx = *tc.ctx + } + + expNewTo := tc.toAddr + switch { + case len(tc.expErr) != 0: + expNewTo = nil + case tc.expQuarantine: + expNewTo = fundsHolder + } + + newToAddr, err := k.SendRestrictionFn(ctx, tc.fromAddr, tc.toAddr, tc.amt) + s.AssertErrorContents(err, tc.expErr, "SendRestrictionFn error") + s.Assert().Equal(expNewTo, newToAddr, "SendRestrictionFn returned address") + + if tc.expQuarantine { + qReq := s.keeper.GetQuarantineRecord(s.sdkCtx, tc.toAddr, tc.fromAddr) + if s.Assert().NotNil(qReq, "GetQuarantineRecord") { + qFunds := qReq.Coins + s.Assert().Equal(tc.amt, qFunds, "amount quarantined") + // Clear the record just in case a later tests uses the same addresses. + qReq.AcceptedFromAddresses = append(qReq.AcceptedFromAddresses, qReq.UnacceptedFromAddresses...) + qReq.UnacceptedFromAddresses = nil + s.keeper.SetQuarantineRecord(s.sdkCtx, tc.toAddr, qReq) + } + } + }) + } +} + +func (s *TestSuite) TestBankSendCoinsUsesSendRestrictionFn() { + // This specifically does NOT mock the bank keeper because it's testing + // that the bank keeper is applying this module's send restriction. + + denom := "greatcoin" + cz := func(amt int64) sdk.Coins { + return sdk.NewCoins(sdk.NewInt64Coin(denom, amt)) + } + + // Set up addr1 to be quarantined. + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr1), "SetOptIn addr1") + // Give addr2 some funds and send them to addr1. + s.Require().NoError(testutil.FundAccount(s.app.BankKeeper, s.sdkCtx, s.addr2, cz(888)), "FundAccount addr2 888%s", denom) + + // Do a Send from addr2 to addr1 + s.Require().NoError(s.app.BankKeeper.SendCoins(s.sdkCtx, s.addr2, s.addr1, cz(88)), "SendCoins 88%s from addr2 to addr1", denom) + + s.Run("funds do not go into addr1's account", func() { + addr1Bal := s.app.BankKeeper.GetBalance(s.sdkCtx, s.addr1, denom) + s.Assert().Equal("0"+denom, addr1Bal.String(), "addr1's balances") + }) + + s.Run("funds came out of addr2's account", func() { + addr2Bal := s.app.BankKeeper.GetBalance(s.sdkCtx, s.addr2, denom) + s.Assert().Equal("800"+denom, addr2Bal.String(), "addr2's balances") + }) + + s.Run("the funds holder account has them", func() { + fundsHolderBal := s.app.BankKeeper.GetBalance(s.sdkCtx, s.keeper.GetFundsHolder(), denom) + s.Assert().Equal("88"+denom, fundsHolderBal.String(), "quarantine funds holder balance") + }) + + s.Run("there's a record of the quarantined funds", func() { + qReq := s.keeper.GetQuarantineRecord(s.sdkCtx, s.addr1, s.addr2) + if s.Assert().NotNil(qReq, "GetQuarantineRecord to addr1 from addr2") { + qCoins := qReq.Coins + s.Assert().Equal("88"+denom, qCoins.String(), "amount quarantined") + expFroms := []sdk.AccAddress{s.addr2} + froms := qReq.UnacceptedFromAddresses + s.Assert().Equal(expFroms, froms, "UnacceptedFromAddresses") + } + }) +} + +func (s *TestSuite) TestBankInputOutputCoinsUsesSendRestrictionFn() { + // This specifically does NOT mock the bank keeper because it's testing + // that the bank keeper is applying this module's send restriction. + + denom := "greatercoin" + cz := func(amt int64) sdk.Coins { + return sdk.Coins{sdk.NewInt64Coin(denom, amt)} + } + + // Set up addr1 and addr3 to be quarantined. + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr1), "SetOptIn addr1") + s.Require().NoError(s.keeper.SetOptIn(s.sdkCtx, s.addr3), "SetOptIn addr3") + // Set up addr2 and addr4 to not be quarantined. + s.Require().NoError(s.keeper.SetOptOut(s.sdkCtx, s.addr2), "SetOptOut addr2") + s.Require().NoError(s.keeper.SetOptOut(s.sdkCtx, s.addr4), "SetOptOut addr4") + // Give addr5 some funds. + s.Require().NoError(testutil.FundAccount(s.app.BankKeeper, s.sdkCtx, s.addr5, cz(888)), "FundAccount addr5 888%s", denom) + + // Do an InputOutputCoins from 5 to 1, 2, 3, and 4. + inputs := []banktypes.Input{{Address: s.addr5.String(), Coins: cz(322)}} + outputs := []banktypes.Output{ + {Address: s.addr1.String(), Coins: cz(33)}, + {Address: s.addr2.String(), Coins: cz(55)}, + {Address: s.addr3.String(), Coins: cz(89)}, + {Address: s.addr4.String(), Coins: cz(145)}, + } + s.Require().NoError(s.app.BankKeeper.InputOutputCoins(s.sdkCtx, inputs, outputs), "InputOutputCoins") + + expBalances := []struct { + name string + addr sdk.AccAddress + exp sdk.Coins + }{ + {name: "quarantined addr1 did not get funds", addr: s.addr1, exp: cz(0)}, + {name: "non-quarantined addr2 received their funds", addr: s.addr2, exp: cz(55)}, + {name: "quarantined addr3 did not get funds", addr: s.addr3, exp: cz(0)}, + {name: "non-quarantined addr4 received their funds", addr: s.addr4, exp: cz(145)}, + {name: "all funds were removed from input", addr: s.addr5, exp: cz(566)}, + {name: "the funds holder account has all quarantined funds", addr: s.keeper.GetFundsHolder(), exp: cz(122)}, + } + + for _, bal := range expBalances { + s.Run(bal.name, func() { + actual := s.app.BankKeeper.GetBalance(s.sdkCtx, bal.addr, denom) + s.Assert().Equal(bal.exp.String(), actual.String(), "GetBalance") + }) + } + + expQRecs := []struct { + name string + toAddr sdk.AccAddress + fromAddr sdk.AccAddress + exp sdk.Coins + }{ + {name: "quarantined addr1 has a record of quarantined funds", toAddr: s.addr1, fromAddr: s.addr5, exp: cz(33)}, + {name: "non-quarantined addr2 does not have a quarantined funds record", toAddr: s.addr2, fromAddr: s.addr5, exp: nil}, + {name: "quarantined addr3 has a record of quarantined funds", toAddr: s.addr3, fromAddr: s.addr5, exp: cz(89)}, + {name: "non-quarantined addr4 does not have a quarantined funds record", toAddr: s.addr4, fromAddr: s.addr5, exp: nil}, + } + + for _, tc := range expQRecs { + s.Run(tc.name, func() { + qReq := s.keeper.GetQuarantineRecord(s.sdkCtx, tc.toAddr, tc.fromAddr) + if tc.exp != nil { + if s.Assert().NotNil(qReq, "GetQuarantineRecord") { + qCoins := qReq.Coins + s.Assert().Equal(tc.exp.String(), qCoins.String(), "amount quarantined") + expFroms := []sdk.AccAddress{s.addr5} + froms := qReq.UnacceptedFromAddresses + s.Assert().Equal(expFroms, froms, "UnacceptedFromAddresses") + } + } else { + s.Assert().Nil(qReq, "GetQuarantineRecord") + } + }) + } +} diff --git a/x/quarantine/keys.go b/x/quarantine/keys.go new file mode 100644 index 0000000000..c22418cf39 --- /dev/null +++ b/x/quarantine/keys.go @@ -0,0 +1,181 @@ +package quarantine + +import ( + "bytes" + "crypto/sha256" + "sort" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const ( + // ModuleName is the name of the module + ModuleName = "quarantine" + + // StoreKey is the store key string for gov + StoreKey = ModuleName +) + +var ( + // OptInPrefix is the prefix for the quarantine account opt-in flags. + OptInPrefix = []byte{0x00} + + // AutoResponsePrefix is the prefix for quarantine auto-response settings. + AutoResponsePrefix = []byte{0x01} + + // RecordPrefix is the prefix for keys with the records of quarantined funds. + RecordPrefix = []byte{0x02} + + // RecordIndexPrefix is the prefix for the index of record suffixes. + RecordIndexPrefix = []byte{0x03} +) + +// MakeKey concatenates the two byte slices into a new byte slice. +func MakeKey(part1, part2 []byte) []byte { + rv := make([]byte, len(part1)+len(part2)) + copy(rv, part1) + copy(rv[len(part1):], part2) + return rv +} + +// CreateOptInKey creates the key for a quarantine opt-in record. +func CreateOptInKey(toAddr sdk.AccAddress) []byte { + toAddrBz := address.MustLengthPrefix(toAddr) + return MakeKey(OptInPrefix, toAddrBz) +} + +// ParseOptInKey extracts the account address from the provided quarantine opt-in key. +func ParseOptInKey(key []byte) (toAddr sdk.AccAddress) { + // key is of format: + // 0x00 + toAddrLen, toAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, 1, 1) + toAddr, _ = sdk.ParseLengthPrefixedBytes(key, toAddrLenEndIndex+1, int(toAddrLen[0])) + + return toAddr +} + +// CreateAutoResponseToAddrPrefix creates a prefix for the quarantine auto-responses for a receiving address. +func CreateAutoResponseToAddrPrefix(toAddr sdk.AccAddress) []byte { + toAddrBz := address.MustLengthPrefix(toAddr) + return MakeKey(AutoResponsePrefix, toAddrBz) +} + +// CreateAutoResponseKey creates the key for a quarantine auto-response. +func CreateAutoResponseKey(toAddr, fromAddr sdk.AccAddress) []byte { + toAddrPreBz := CreateAutoResponseToAddrPrefix(toAddr) + fromAddrBz := address.MustLengthPrefix(fromAddr) + return MakeKey(toAddrPreBz, fromAddrBz) +} + +// ParseAutoResponseKey extracts the to address and from address from the provided quarantine auto-response key. +func ParseAutoResponseKey(key []byte) (toAddr, fromAddr sdk.AccAddress) { + // key is of format: + // 0x01 + var toAddrEndIndex int + toAddrLen, toAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, 1, 1) + toAddr, toAddrEndIndex = sdk.ParseLengthPrefixedBytes(key, toAddrLenEndIndex+1, int(toAddrLen[0])) + + fromAddrLen, fromAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, toAddrEndIndex+1, 1) + fromAddr, _ = sdk.ParseLengthPrefixedBytes(key, fromAddrLenEndIndex+1, int(fromAddrLen[0])) + + return toAddr, fromAddr +} + +// CreateRecordToAddrPrefix creates a prefix for the quarantine funds for a receiving address. +func CreateRecordToAddrPrefix(toAddr sdk.AccAddress) []byte { + toAddrBz := address.MustLengthPrefix(toAddr) + return MakeKey(RecordPrefix, toAddrBz) +} + +// CreateRecordKey creates the key for a quarantine record. +// +// If there is only one fromAddr, it is used as the record suffix. +// If there are more than one, a hash of them is used as the suffix. +// +// Panics if no fromAddrs are provided. +func CreateRecordKey(toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) []byte { + // This is designed such that a known record suffix can be provided + // as a single "from address" to create the key with that suffix. + toAddrPreBz := CreateRecordToAddrPrefix(toAddr) + recordId := address.MustLengthPrefix(createRecordSuffix(fromAddrs)) + return MakeKey(toAddrPreBz, recordId) +} + +// createRecordSuffix creates a single "address" to use for the provided from addresses. +// This is not to be confused with CreateRecordKey which creates the full key for a quarantine record. +// This only creates a portion of the key. +// +// If one fromAddr is provided, it's what's returned. +// If more than one is provided, they are sorted, combined, and hashed. +// +// Panics if none are provided. +func createRecordSuffix(fromAddrs []sdk.AccAddress) []byte { + // This is designed such that a known record suffix can be provided + // as a single "from address" to create the key with that suffix. + switch len(fromAddrs) { + case 0: + panic(sdkerrors.ErrLogic.Wrap("at least one fromAddr is required")) + case 1: + if len(fromAddrs[0]) > 32 { + return fromAddrs[0][:32] + } + return fromAddrs[0] + default: + // The same n addresses needs to always create the same result. + // And we don't want to change the input slice. + addrs := make([]sdk.AccAddress, len(fromAddrs)) + copy(addrs, fromAddrs) + sort.Slice(addrs, func(i, j int) bool { + return bytes.Compare(addrs[i], addrs[j]) < 0 + }) + var toHash []byte + for _, addr := range addrs { + toHash = append(toHash, addr...) + } + hash := sha256.Sum256(toHash) + return hash[0:] + } +} + +// ParseRecordKey extracts the to address and record suffix from the provided quarantine funds key. +func ParseRecordKey(key []byte) (toAddr, recordSuffix sdk.AccAddress) { + // key is of format: + // 0x02 + var toAddrEndIndex int + toAddrLen, toAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, 1, 1) + toAddr, toAddrEndIndex = sdk.ParseLengthPrefixedBytes(key, toAddrLenEndIndex+1, int(toAddrLen[0])) + + recordSuffixLen, recordSuffixLenEndIndex := sdk.ParseLengthPrefixedBytes(key, toAddrEndIndex+1, 1) + recordSuffix, _ = sdk.ParseLengthPrefixedBytes(key, recordSuffixLenEndIndex+1, int(recordSuffixLen[0])) + + return toAddr, recordSuffix +} + +// CreateRecordIndexToAddrPrefix creates a prefix for the quarantine record index entries for a receiving address. +func CreateRecordIndexToAddrPrefix(toAddr sdk.AccAddress) []byte { + toAddrBz := address.MustLengthPrefix(toAddr) + return MakeKey(RecordIndexPrefix, toAddrBz) +} + +// CreateRecordIndexKey creates the key for the quarantine record suffix index. +func CreateRecordIndexKey(toAddr, fromAddr sdk.AccAddress) []byte { + toAddrPreBz := CreateRecordIndexToAddrPrefix(toAddr) + recordId := address.MustLengthPrefix(fromAddr) + return MakeKey(toAddrPreBz, recordId) +} + +// ParseRecordIndexKey extracts the to address and from address from the provided quarantine record index key. +func ParseRecordIndexKey(key []byte) (toAddr, fromAddr sdk.AccAddress) { + // key is of format: + // 0x03 + var toAddrEndIndex int + toAddrLen, toAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, 1, 1) + toAddr, toAddrEndIndex = sdk.ParseLengthPrefixedBytes(key, toAddrLenEndIndex+1, int(toAddrLen[0])) + + fromAddrLen, fromAddrLenEndIndex := sdk.ParseLengthPrefixedBytes(key, toAddrEndIndex+1, 1) + fromAddr, _ = sdk.ParseLengthPrefixedBytes(key, fromAddrLenEndIndex+1, int(fromAddrLen[0])) + + return toAddr, fromAddr +} diff --git a/x/quarantine/keys_test.go b/x/quarantine/keys_test.go new file mode 100644 index 0000000000..4d6a91aa37 --- /dev/null +++ b/x/quarantine/keys_test.go @@ -0,0 +1,1134 @@ +package quarantine_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + "github.com/stretchr/testify/assert" + + . "github.com/cosmos/cosmos-sdk/x/quarantine" + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +func TestPrefixValues(t *testing.T) { + prefixes := []struct { + name string + prefix []byte + expected []byte + }{ + {name: "OptInPrefix", prefix: OptInPrefix, expected: []byte{0x00}}, + {name: "AutoResponsePrefix", prefix: AutoResponsePrefix, expected: []byte{0x01}}, + {name: "RecordPrefix", prefix: RecordPrefix, expected: []byte{0x02}}, + {name: "RecordIndexPrefix", prefix: RecordIndexPrefix, expected: []byte{0x03}}, + } + + for _, p := range prefixes { + t.Run(fmt.Sprintf("%s expected value", p.name), func(t *testing.T) { + assert.Equal(t, p.prefix, p.expected, p.name) + }) + } + + for i := 0; i < len(prefixes)-1; i++ { + for j := i + 1; j < len(prefixes); j++ { + t.Run(fmt.Sprintf("%s is different from %s", prefixes[i].name, prefixes[j].name), func(t *testing.T) { + assert.NotEqual(t, prefixes[i].prefix, prefixes[j].prefix, "expected: %s, actual: %s", prefixes[i].name, prefixes[j].name) + }) + } + } +} + +func TestMakeKey(t *testing.T) { + tests := []struct { + name string + part1 []byte + part2 []byte + exp []byte + }{ + { + name: "nil + nil", + part1: nil, + part2: nil, + exp: []byte{}, + }, + { + name: "nil + empty", + part1: nil, + part2: []byte{}, + exp: []byte{}, + }, + { + name: "empty + nil", + part1: []byte{}, + part2: nil, + exp: []byte{}, + }, + { + name: "empty + empty", + part1: []byte{}, + part2: []byte{}, + exp: []byte{}, + }, + { + name: "nil + one", + part1: nil, + part2: []byte{0x70}, + exp: []byte{0x70}, + }, + { + name: "empty + one", + part1: []byte{}, + part2: []byte{0x70}, + exp: []byte{0x70}, + }, + { + name: "one + one", + part1: []byte{0x69}, + part2: []byte{0x70}, + exp: []byte{0x69, 0x70}, + }, + + { + name: "nil + five", + part1: nil, + part2: []byte{0x70, 0x70, 0x70, 0x70, 0x70}, + exp: []byte{0x70, 0x70, 0x70, 0x70, 0x70}, + }, + { + name: "empty + five", + part1: []byte{}, + part2: []byte{0x70, 0x70, 0x70, 0x70, 0x70}, + exp: []byte{0x70, 0x70, 0x70, 0x70, 0x70}, + }, + { + name: "one + five", + part1: []byte{0x69}, + part2: []byte{0x70, 0x70, 0x70, 0x70, 0x70}, + exp: []byte{0x69, 0x70, 0x70, 0x70, 0x70, 0x70}, + }, + { + name: "six + five", + part1: []byte{0x68, 0x68, 0x68, 0x68, 0x68, 0x68}, + part2: []byte{0x70, 0x70, 0x70, 0x70, 0x70}, + exp: []byte{0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x70, 0x70, 0x70, 0x70, 0x70}, + }, + { + name: "six + one", + part1: []byte{0x68, 0x68, 0x68, 0x68, 0x68, 0x68}, + part2: []byte{0x70}, + exp: []byte{0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x70}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + origPart1 := MakeCopyOfByteSlice(tc.part1) + origPart2 := MakeCopyOfByteSlice(tc.part2) + actual := MakeKey(tc.part1, tc.part2) + actualCopy := MakeCopyOfByteSlice(actual) + assert.Equal(t, tc.exp, actual, "MakeKey result") + assert.Equal(t, origPart1, tc.part1, "part1 before and after MakeKey") + assert.Equal(t, origPart2, tc.part2, "part2 before and after MakeKey") + if len(tc.part1) > 0 { + // Make sure the result doesn't change if part1 is later changed. + for i := range tc.part1 { + tc.part1[i]++ + } + assert.Equal(t, actualCopy, actual, "MakeKey result after changing each byte of part1 slice") + for i := range tc.part1 { + tc.part1[i]-- + } + } + if len(tc.part2) > 0 { + // Make sure the result doesn't change if part2 is later changed. + for i := range tc.part2 { + tc.part2[i]++ + } + assert.Equal(t, actualCopy, actual, "MakeKey result after changing each byte of part2 slice") + for i := range tc.part2 { + tc.part2[i]-- + } + } + if len(actual) > 0 { + // Make sure the parts don't change if the result is later changed. + for i := range actual { + actual[i]++ + } + assert.Equal(t, origPart1, tc.part1, "part1 after changing each byte of result slice") + assert.Equal(t, origPart2, tc.part2, "part2 after changing each byte of result slice") + for i := range actual { + actual[i]-- + } + } + }) + } +} + +func TestCreateOptInKey(t *testing.T) { + expectedPrefix := OptInPrefix + testAddr0 := MakeTestAddr("coik", 0) + testAddr1 := MakeTestAddr("coik", 1) + badAddr := MakeBadAddr("coik", 2) + + t.Run("starts with OptInPrefix", func(t *testing.T) { + key := CreateOptInKey(testAddr0) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(addrBz []byte) []byte { + rv := make([]byte, 0, len(expectedPrefix)+1+len(addrBz)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(addrBz))) + rv = append(rv, addrBz...) + return rv + } + tests := []struct { + name string + toAddr sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0", + toAddr: testAddr0, + expected: makeExpected(testAddr0), + }, + { + name: "addr 0", + toAddr: testAddr1, + expected: makeExpected(testAddr1), + }, + { + name: "nil", + toAddr: nil, + expected: expectedPrefix, + }, + { + name: "too long", + toAddr: badAddr, + expected: nil, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateOptInKey(tc.toAddr) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateOptInKey") { + assert.Equal(t, tc.expected, actual, "CreateOptInKey result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateOptInKey") + } + }) + } +} + +func TestParseOptInKey(t *testing.T) { + testAddr0 := MakeTestAddr("poik", 0) + testAddr1 := MakeTestAddr("poik", 1) + testAddr2 := MakeTestAddr("poik", 2) + longAddr := MakeLongAddr("poik", 3) + + makeKey := func(pre []byte, addrLen int, addrBz []byte) []byte { + rv := make([]byte, 0, len(pre)+1+len(addrBz)) + rv = append(rv, pre...) + rv = append(rv, byte(addrLen)) + rv = append(rv, addrBz...) + return rv + } + tests := []struct { + name string + key []byte + expected sdk.AccAddress + expPanic string + }{ + { + name: "addr 0", + key: makeKey(OptInPrefix, len(testAddr0), testAddr0), + expected: testAddr0, + }, + { + name: "addr 1", + key: makeKey(OptInPrefix, len(testAddr1), testAddr1), + expected: testAddr1, + }, + { + name: "addr 2", + key: makeKey(OptInPrefix, len(testAddr2), testAddr2), + expected: testAddr2, + }, + { + name: "longer addr", + key: makeKey(OptInPrefix, len(longAddr), longAddr), + expected: longAddr, + }, + { + name: "too short", + key: makeKey(OptInPrefix, len(testAddr0)+1, testAddr0), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", len(testAddr0)+1+2, len(testAddr0)+2), + }, + { + name: "from CreateOptInKey addr 0", + key: CreateOptInKey(testAddr0), + expected: testAddr0, + }, + { + name: "from CreateOptInKey addr 1", + key: CreateOptInKey(testAddr1), + expected: testAddr1, + }, + { + name: "from CreateOptInKey addr 2", + key: CreateOptInKey(testAddr2), + expected: testAddr2, + }, + { + name: "from CreateOptInKey longAddr", + key: CreateOptInKey(longAddr), + expected: longAddr, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual sdk.AccAddress + testFunc := func() { + actual = ParseOptInKey(tc.key) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "ParseOptInKey") { + assert.Equal(t, tc.expected, actual, "ParseOptInKey result") + } + } else { + assert.PanicsWithValue(t, tc.expPanic, testFunc, "ParseOptInKey") + } + }) + } +} + +func TestCreateAutoResponseToAddrPrefix(t *testing.T) { + expectedPrefix := AutoResponsePrefix + testAddr0 := MakeTestAddr("cartap", 0) + testAddr1 := MakeTestAddr("cartap", 1) + badAddr := MakeBadAddr("cartap", 2) + + t.Run("starts with AutoResponsePrefix", func(t *testing.T) { + key := CreateAutoResponseToAddrPrefix(testAddr0) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(addrBz []byte) []byte { + rv := make([]byte, 0, len(expectedPrefix)+1+len(addrBz)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(addrBz))) + rv = append(rv, addrBz...) + return rv + } + + tests := []struct { + name string + toAddr sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0", + toAddr: testAddr0, + expected: makeExpected(testAddr0), + }, + { + name: "addr 1", + toAddr: testAddr1, + expected: makeExpected(testAddr1), + }, + { + name: "nil", + toAddr: nil, + expected: expectedPrefix, + }, + { + name: "too long", + toAddr: badAddr, + expected: nil, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateAutoResponseToAddrPrefix(tc.toAddr) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateAutoResponseToAddrPrefix") { + assert.Equal(t, tc.expected, actual, "CreateAutoResponseToAddrPrefix result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateAutoResponseToAddrPrefix") + } + }) + } +} + +func TestCreateAutoResponseKey(t *testing.T) { + expectedPrefix := AutoResponsePrefix + testAddr0 := MakeTestAddr("cark", 0) + testAddr1 := MakeTestAddr("cark", 1) + badAddr := MakeBadAddr("cark", 2) + longAddr := MakeLongAddr("cark", 3) + + t.Run("starts with AutoResponsePrefix", func(t *testing.T) { + key := CreateAutoResponseKey(testAddr0, testAddr1) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(toAddrBz, fromAddrBz []byte) []byte { + rv := make([]byte, 0, len(expectedPrefix)+1+len(toAddrBz)+1+len(fromAddrBz)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(toAddrBz))) + rv = append(rv, toAddrBz...) + rv = append(rv, byte(len(fromAddrBz))) + rv = append(rv, fromAddrBz...) + return rv + } + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddr sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0 addr 1", + toAddr: testAddr0, + fromAddr: testAddr1, + expected: makeExpected(testAddr0, testAddr1), + }, + { + name: "addr 1 long addr", + toAddr: testAddr1, + fromAddr: longAddr, + expected: makeExpected(testAddr1, longAddr), + }, + { + name: "long addr addr 0", + toAddr: longAddr, + fromAddr: testAddr0, + expected: makeExpected(longAddr, testAddr0), + }, + { + name: "long addr long addr", + toAddr: longAddr, + fromAddr: longAddr, + expected: makeExpected(longAddr, longAddr), + }, + { + name: "bad toAddr", + toAddr: badAddr, + fromAddr: testAddr0, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + { + name: "bad fromAddr", + toAddr: testAddr0, + fromAddr: badAddr, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateAutoResponseKey(tc.toAddr, tc.fromAddr) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateAutoResponseKey") { + assert.Equal(t, tc.expected, actual, "CreateAutoResponseKey result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateAutoResponseKey") + } + }) + } +} + +func TestParseAutoResponseKey(t *testing.T) { + testAddr0 := MakeTestAddr("park", 0) + testAddr1 := MakeTestAddr("park", 1) + longAddr := MakeLongAddr("park", 2) + + makeKey := func(pre []byte, toAddrLen int, toAddrBz []byte, fromAddrLen int, fromAddrBz []byte) []byte { + rv := make([]byte, 0, len(pre)+1+len(toAddrBz)+1+len(fromAddrBz)) + rv = append(rv, pre...) + rv = append(rv, byte(toAddrLen)) + rv = append(rv, toAddrBz...) + rv = append(rv, byte(fromAddrLen)) + rv = append(rv, fromAddrBz...) + return rv + } + + tests := []struct { + name string + key []byte + expToAddr sdk.AccAddress + expFromAddr sdk.AccAddress + expPanic string + }{ + { + name: "addr 0 addr 1", + key: CreateAutoResponseKey(testAddr0, testAddr1), + expToAddr: testAddr0, + expFromAddr: testAddr1, + }, + { + name: "addr 1 addr 0", + key: CreateAutoResponseKey(testAddr1, testAddr0), + expToAddr: testAddr1, + expFromAddr: testAddr0, + }, + { + name: "long addr addr 1", + key: CreateAutoResponseKey(longAddr, testAddr1), + expToAddr: longAddr, + expFromAddr: testAddr1, + }, + { + name: "addr 0 long addr", + key: CreateAutoResponseKey(testAddr0, longAddr), + expToAddr: testAddr0, + expFromAddr: longAddr, + }, + { + name: "bad toAddr len", + key: makeKey(AutoResponsePrefix, 200, testAddr0, 20, testAddr1), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", 202, 43), + }, + { + name: "bad fromAddr len", + key: makeKey(AutoResponsePrefix, len(testAddr1), testAddr1, len(testAddr0)+1, testAddr0), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", 44, 43), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actualToAddr, actualFromAddr sdk.AccAddress + testFunc := func() { + actualToAddr, actualFromAddr = ParseAutoResponseKey(tc.key) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "ParseAutoResponseKey") { + assert.Equal(t, tc.expToAddr, actualToAddr, "ParseAutoResponseKey toAddr") + assert.Equal(t, tc.expFromAddr, actualFromAddr, "ParseAutoResponseKey fromAddr") + } + } else { + assert.PanicsWithValue(t, tc.expPanic, testFunc, "ParseAutoResponseKey") + } + }) + } +} + +func TestCreateRecordToAddrPrefix(t *testing.T) { + expectedPrefix := RecordPrefix + testAddr0 := MakeTestAddr("crtap", 0) + testAddr1 := MakeTestAddr("crtap", 1) + badAddr := MakeBadAddr("crtap", 2) + + t.Run("starts with RecordPrefix", func(t *testing.T) { + key := CreateRecordToAddrPrefix(testAddr0) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(addrBz []byte) []byte { + rv := make([]byte, 0, len(expectedPrefix)+1+len(addrBz)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(addrBz))) + rv = append(rv, addrBz...) + return rv + } + + tests := []struct { + name string + toAddr sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0", + toAddr: testAddr0, + expected: makeExpected(testAddr0), + }, + { + name: "addr 1", + toAddr: testAddr1, + expected: makeExpected(testAddr1), + }, + { + name: "nil", + toAddr: nil, + expected: expectedPrefix, + }, + { + name: "too long", + toAddr: badAddr, + expected: nil, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateRecordToAddrPrefix(tc.toAddr) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateRecordToAddrPrefix") { + assert.Equal(t, tc.expected, actual, "CreateRecordToAddrPrefix result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateRecordToAddrPrefix") + } + }) + } +} + +func TestCreateRecordKey(t *testing.T) { + expectedPrefix := RecordPrefix + testAddr0 := MakeTestAddr("crk", 0) + testAddr1 := MakeTestAddr("crk", 1) + testAddr2 := MakeTestAddr("crk", 2) + testAddr3 := MakeTestAddr("crk", 3) + badAddr := MakeBadAddr("crk", 4) + longAddr := MakeLongAddr("crk", 5) + + t.Run("starts with RecordPrefix", func(t *testing.T) { + key := CreateRecordKey(testAddr0, testAddr1) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(toAddrBz []byte, fromAddrs ...sdk.AccAddress) []byte { + recordId := CreateRecordSuffix(fromAddrs) + rv := make([]byte, 0, len(expectedPrefix)+1+len(toAddrBz)+1+len(recordId)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(toAddrBz))) + rv = append(rv, toAddrBz...) + rv = append(rv, byte(len(recordId))) + rv = append(rv, recordId...) + return rv + } + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddrs []sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0 addr 1", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{testAddr1}, + expected: makeExpected(testAddr0, testAddr1), + }, + { + name: "addr 1 long addr", + toAddr: testAddr1, + fromAddrs: []sdk.AccAddress{longAddr}, + expected: makeExpected(testAddr1, longAddr), + }, + { + name: "long addr addr 0", + toAddr: longAddr, + fromAddrs: []sdk.AccAddress{testAddr0}, + expected: makeExpected(longAddr, testAddr0), + }, + { + name: "long addr long addr", + toAddr: longAddr, + fromAddrs: []sdk.AccAddress{longAddr}, + expected: makeExpected(longAddr, longAddr), + }, + { + name: "to addr 3 from addrs 0 1 2 and long", + toAddr: testAddr3, + fromAddrs: []sdk.AccAddress{testAddr0, testAddr1, testAddr2, longAddr}, + expected: makeExpected(testAddr3, testAddr0, testAddr1, testAddr2, longAddr), + }, + { + name: "to addr 2 from addrs 1 0 diff order", + toAddr: testAddr2, + fromAddrs: []sdk.AccAddress{testAddr1, testAddr0}, + expected: makeExpected(testAddr2, testAddr0, testAddr1), + }, + { + name: "bad toAddr panics", + toAddr: badAddr, + fromAddrs: []sdk.AccAddress{testAddr0}, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + { + name: "bad fromAddr ok", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{badAddr}, + expected: makeExpected(testAddr0, badAddr), + }, + { + name: "no fromAddrs panics", + toAddr: testAddr2, + fromAddrs: []sdk.AccAddress{}, + expPanic: "at least one fromAddr is required: internal logic error", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateRecordKey(tc.toAddr, tc.fromAddrs...) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateRecordKey") { + assert.Equal(t, tc.expected, actual, "CreateRecordKey result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateRecordKey") + } + }) + } +} + +func TestCreateRecordSuffix(t *testing.T) { + testAddr0 := MakeTestAddr("crs", 0) + testAddr1 := MakeTestAddr("crs", 1) + testAddr2 := MakeTestAddr("crs", 2) + testAddrs := []sdk.AccAddress{testAddr0, testAddr1, testAddr2} + badAddr := MakeBadAddr("crs", 3) + + t.Run("panics if no addrs", func(t *testing.T) { + assert.PanicsWithError(t, "at least one fromAddr is required: internal logic error", + func() { CreateRecordSuffix([]sdk.AccAddress{}) }, + "createRecordSuffix([]sdk.AccAddress{})", + ) + }) + + t.Run("panics with nil addrs", func(t *testing.T) { + assert.PanicsWithError(t, "at least one fromAddr is required: internal logic error", + func() { CreateRecordSuffix(nil) }, + "createRecordSuffix(nil)", + ) + }) + + createRecordSuffixAndAssertInputUnchanged := func(t *testing.T, input []sdk.AccAddress, msg string, args ...interface{}) []byte { + t.Helper() + msgAndArgs := []interface{}{msg + " input before and after"} + msgAndArgs = append(msgAndArgs, args...) + var orig []sdk.AccAddress + if input != nil { + orig = make([]sdk.AccAddress, len(input)) + for i, addr := range input { + orig[i] = make(sdk.AccAddress, len(addr)) + copy(orig[i], addr) + } + } + actual := CreateRecordSuffix(input) + assert.Equal(t, orig, input, msgAndArgs...) + return actual + } + + t.Run("single addrs are unchanged", func(t *testing.T) { + for i, addr := range testAddrs { + expected := make([]byte, len(addr)) + copy(expected, addr) + + actual := createRecordSuffixAndAssertInputUnchanged(t, []sdk.AccAddress{addr}, "addr %d", i) + assert.Equal(t, expected, actual, "addr %d", i) + } + }) + + t.Run("long addr is truncated", func(t *testing.T) { + expected := make([]byte, 32) + copy(expected, badAddr[:32]) + + actual := createRecordSuffixAndAssertInputUnchanged(t, []sdk.AccAddress{badAddr}, "bad addr") + assert.Equal(t, expected, actual, "bad addr as suffix") + }) + + t.Run("two addrs order does not matter", func(t *testing.T) { + input1 := []sdk.AccAddress{testAddr0, testAddr1} + input2 := []sdk.AccAddress{testAddr1, testAddr0} + expected := createRecordSuffixAndAssertInputUnchanged(t, input1, "addrs 0 then 1") + actual := createRecordSuffixAndAssertInputUnchanged(t, input2, "addrs 1 then 0") + assert.Equal(t, expected, actual, "addrs 0 then 1, vs 1 then 0") + }) + + t.Run("three addrs order does not matter", func(t *testing.T) { + inputTestAddrsIndexes := [][]int{ + {0, 1, 2}, + {0, 2, 1}, + {1, 0, 2}, + {1, 2, 0}, + {2, 0, 1}, + {2, 1, 0}, + } + inputs := make([][]sdk.AccAddress, len(inputTestAddrsIndexes)) + outputs := make([][]byte, len(inputTestAddrsIndexes)) + for i, taIndexes := range inputTestAddrsIndexes { + inputs[i] = make([]sdk.AccAddress, len(taIndexes)) + for j, ind := range taIndexes { + inputs[i][j] = testAddrs[ind] + } + outputs[i] = createRecordSuffixAndAssertInputUnchanged(t, inputs[i], "addrs %v", taIndexes) + } + for i := 0; i < len(outputs)-1; i++ { + for j := i + 1; j < len(outputs); j++ { + assert.Equal(t, outputs[i], outputs[j], "test addrs %v vs %v", inputTestAddrsIndexes[i], inputTestAddrsIndexes[j]) + } + } + }) + + t.Run("two addrs different alone vs together", func(t *testing.T) { + input1 := []sdk.AccAddress{testAddr1} + input2 := []sdk.AccAddress{testAddr2} + inputBoth := []sdk.AccAddress{testAddr1, testAddr2} + actual1 := createRecordSuffixAndAssertInputUnchanged(t, input1, "addr 1") + actual2 := createRecordSuffixAndAssertInputUnchanged(t, input2, "addr 2") + actualBoth := createRecordSuffixAndAssertInputUnchanged(t, inputBoth, "both") + + assert.NotEqual(t, actual1, actual2, "addr 1 vs addr 2") + assert.NotEqual(t, actual1, actualBoth, "addr 1 vs both") + assert.NotEqual(t, actual2, actualBoth, "addr 2 vs both") + assert.NotContains(t, actualBoth, actual1, "both vs addr 1") + assert.NotContains(t, actualBoth, actual2, "both vs addr 2") + }) +} + +func TestParseRecordKey(t *testing.T) { + testAddr0 := MakeTestAddr("prk", 0) + testAddr1 := MakeTestAddr("prk", 1) + testAddr2 := MakeTestAddr("prk", 2) + longAddr := MakeLongAddr("prk", 3) + + makeKey := func(pre []byte, toAddrLen int, toAddrBz []byte, fromAddrLen int, fromAddrBz []byte) []byte { + rv := make([]byte, 0, len(pre)+1+len(toAddrBz)+1+len(fromAddrBz)) + rv = append(rv, pre...) + rv = append(rv, byte(toAddrLen)) + rv = append(rv, toAddrBz...) + rv = append(rv, byte(fromAddrLen)) + rv = append(rv, fromAddrBz...) + return rv + } + + tests := []struct { + name string + key []byte + expToAddr sdk.AccAddress + expFromAddr sdk.AccAddress + expPanic string + }{ + { + name: "addr 0 addr 1", + key: CreateRecordKey(testAddr0, testAddr1), + expToAddr: testAddr0, + expFromAddr: testAddr1, + }, + { + name: "addr 1 addr 0", + key: CreateRecordKey(testAddr1, testAddr0), + expToAddr: testAddr1, + expFromAddr: testAddr0, + }, + { + name: "long addr addr 1", + key: CreateRecordKey(longAddr, testAddr1), + expToAddr: longAddr, + expFromAddr: testAddr1, + }, + { + name: "addr 0 long addr", + key: CreateRecordKey(testAddr0, longAddr), + expToAddr: testAddr0, + expFromAddr: longAddr, + }, + { + name: "multiple from addrs", + key: CreateRecordKey(testAddr0, testAddr1, testAddr2), + expToAddr: testAddr0, + expFromAddr: CreateRecordSuffix([]sdk.AccAddress{testAddr1, testAddr2}), + }, + { + name: "multiple from addrs diff order", + key: CreateRecordKey(testAddr0, testAddr2, testAddr1), + expToAddr: testAddr0, + expFromAddr: CreateRecordSuffix([]sdk.AccAddress{testAddr1, testAddr2}), + }, + { + name: "bad toAddr len", + key: makeKey(RecordPrefix, 200, testAddr0, 20, testAddr1), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", 202, 43), + }, + { + name: "bad fromAddr len", + key: makeKey(RecordPrefix, len(testAddr1), testAddr1, len(testAddr0)+1, testAddr0), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", 44, 43), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actualToAddr, actualFromAddr sdk.AccAddress + testFunc := func() { + actualToAddr, actualFromAddr = ParseRecordKey(tc.key) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "ParseRecordKey") { + assert.Equal(t, tc.expToAddr, actualToAddr, "ParseRecordKey toAddr") + assert.Equal(t, tc.expFromAddr, actualFromAddr, "ParseRecordKey fromAddr") + } + } else { + assert.PanicsWithValue(t, tc.expPanic, testFunc, "ParseRecordKey") + } + }) + } +} + +func TestCreateRecordIndexToAddrPrefix(t *testing.T) { + expectedPrefix := RecordIndexPrefix + testAddr0 := MakeTestAddr("critap", 0) + testAddr1 := MakeTestAddr("critap", 1) + badAddr := MakeBadAddr("critap", 2) + + t.Run("starts with RecordIndexPrefix", func(t *testing.T) { + key := CreateRecordIndexToAddrPrefix(testAddr0) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(addrBz []byte) []byte { + rv := make([]byte, 0, len(expectedPrefix)+1+len(addrBz)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(addrBz))) + rv = append(rv, addrBz...) + return rv + } + + tests := []struct { + name string + toAddr sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0", + toAddr: testAddr0, + expected: makeExpected(testAddr0), + }, + { + name: "addr 1", + toAddr: testAddr1, + expected: makeExpected(testAddr1), + }, + { + name: "nil", + toAddr: nil, + expected: expectedPrefix, + }, + { + name: "too long", + toAddr: badAddr, + expected: nil, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateRecordIndexToAddrPrefix(tc.toAddr) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateRecordIndexToAddrPrefix") { + assert.Equal(t, tc.expected, actual, "CreateRecordIndexToAddrPrefix result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateRecordIndexToAddrPrefix") + } + }) + } +} + +func TestCreateRecordIndexKey(t *testing.T) { + expectedPrefix := RecordIndexPrefix + testAddr0 := MakeTestAddr("crik", 0) + testAddr1 := MakeTestAddr("crik", 1) + badAddr := MakeBadAddr("crik", 2) + longAddr := MakeLongAddr("crik", 3) + + t.Run("starts with RecordIndexPrefix", func(t *testing.T) { + key := CreateRecordIndexKey(testAddr0, testAddr1) + actual := key[:len(expectedPrefix)] + assert.Equal(t, expectedPrefix, actual, "key prefix") + }) + + makeExpected := func(toAddrBz, fromAddrBz []byte) []byte { + rv := make([]byte, 0, len(expectedPrefix)+1+len(toAddrBz)+1+len(fromAddrBz)) + rv = append(rv, expectedPrefix...) + rv = append(rv, byte(len(toAddrBz))) + rv = append(rv, toAddrBz...) + rv = append(rv, byte(len(fromAddrBz))) + rv = append(rv, fromAddrBz...) + return rv + } + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddr sdk.AccAddress + expected []byte + expPanic string + }{ + { + name: "addr 0 addr 1", + toAddr: testAddr0, + fromAddr: testAddr1, + expected: makeExpected(testAddr0, testAddr1), + }, + { + name: "addr 1 long addr", + toAddr: testAddr1, + fromAddr: longAddr, + expected: makeExpected(testAddr1, longAddr), + }, + { + name: "long addr addr 0", + toAddr: longAddr, + fromAddr: testAddr0, + expected: makeExpected(longAddr, testAddr0), + }, + { + name: "long addr long addr", + toAddr: longAddr, + fromAddr: longAddr, + expected: makeExpected(longAddr, longAddr), + }, + { + name: "bad toAddr", + toAddr: badAddr, + fromAddr: testAddr0, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + { + name: "bad fromAddr", + toAddr: testAddr0, + fromAddr: badAddr, + expPanic: fmt.Sprintf("address length should be max %d bytes, got %d: unknown address", address.MaxAddrLen, len(badAddr)), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual []byte + testFunc := func() { + actual = CreateRecordIndexKey(tc.toAddr, tc.fromAddr) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "CreateRecordIndexKey") { + assert.Equal(t, tc.expected, actual, "CreateRecordIndexKey result") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "CreateRecordIndexKey") + } + }) + } +} + +func TestParseRecordIndexKey(t *testing.T) { + testAddr0 := MakeTestAddr("prik", 0) + testAddr1 := MakeTestAddr("prik", 1) + longAddr := MakeLongAddr("prik", 2) + + makeKey := func(pre []byte, toAddrLen int, toAddrBz []byte, fromAddrLen int, fromAddrBz []byte) []byte { + rv := make([]byte, 0, len(pre)+1+len(toAddrBz)+1+len(fromAddrBz)) + rv = append(rv, pre...) + rv = append(rv, byte(toAddrLen)) + rv = append(rv, toAddrBz...) + rv = append(rv, byte(fromAddrLen)) + rv = append(rv, fromAddrBz...) + return rv + } + + tests := []struct { + name string + key []byte + expToAddr sdk.AccAddress + expFromAddr sdk.AccAddress + expPanic string + }{ + { + name: "addr 0 addr 1", + key: CreateRecordIndexKey(testAddr0, testAddr1), + expToAddr: testAddr0, + expFromAddr: testAddr1, + }, + { + name: "addr 1 addr 0", + key: CreateRecordIndexKey(testAddr1, testAddr0), + expToAddr: testAddr1, + expFromAddr: testAddr0, + }, + { + name: "long addr addr 1", + key: CreateRecordIndexKey(longAddr, testAddr1), + expToAddr: longAddr, + expFromAddr: testAddr1, + }, + { + name: "addr 0 long addr", + key: CreateRecordIndexKey(testAddr0, longAddr), + expToAddr: testAddr0, + expFromAddr: longAddr, + }, + { + name: "bad toAddr len", + key: makeKey(RecordIndexPrefix, 200, testAddr0, 20, testAddr1), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", 202, 43), + }, + { + name: "bad fromAddr len", + key: makeKey(RecordIndexPrefix, len(testAddr1), testAddr1, len(testAddr0)+1, testAddr0), + expPanic: fmt.Sprintf("expected key of length at least %d, got %d", 44, 43), + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actualToAddr, actualFromAddr sdk.AccAddress + testFunc := func() { + actualToAddr, actualFromAddr = ParseRecordIndexKey(tc.key) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "ParseRecordIndexKey") { + assert.Equal(t, tc.expToAddr, actualToAddr, "ParseRecordIndexKey toAddr") + assert.Equal(t, tc.expFromAddr, actualFromAddr, "ParseRecordIndexKey fromAddr") + } + } else { + assert.PanicsWithValue(t, tc.expPanic, testFunc, "ParseRecordIndexKey") + } + }) + } +} diff --git a/x/quarantine/module/module.go b/x/quarantine/module/module.go new file mode 100644 index 0000000000..3d7e9c257e --- /dev/null +++ b/x/quarantine/module/module.go @@ -0,0 +1,176 @@ +package module + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + sdkclient "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/client/cli" + "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" + "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" + abci "github.com/tendermint/tendermint/abci/types" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} +) + +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper + accKeeper quarantine.AccountKeeper + bankKeeper quarantine.BankKeeper + registry cdctypes.InterfaceRegistry +} + +func NewAppModule(cdc codec.Codec, quarantineKeeper keeper.Keeper, accKeeper quarantine.AccountKeeper, bankKeeper quarantine.BankKeeper, registry cdctypes.InterfaceRegistry) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{cdc: cdc}, + keeper: quarantineKeeper, + accKeeper: accKeeper, + bankKeeper: bankKeeper, + registry: registry, + } +} + +type AppModuleBasic struct { + cdc codec.Codec +} + +func (AppModuleBasic) Name() string { + return quarantine.ModuleName +} + +// DefaultGenesis returns default genesis state as raw bytes for the quarantine module. +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(quarantine.DefaultGenesisState()) +} + +// ValidateGenesis performs genesis state validation for the quarantine module. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ sdkclient.TxEncodingConfig, bz json.RawMessage) error { + var data quarantine.GenesisState + if err := cdc.UnmarshalJSON(bz, &data); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", quarantine.ModuleName, err) + } + return data.Validate() +} + +// GetQueryCmd returns the cli query commands for the quarantine module +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.QueryCmd() +} + +// GetTxCmd returns the transaction commands for the quarantine module +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.TxCmd() +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the quarantine module. +func (a AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx sdkclient.Context, mux *runtime.ServeMux) { + if err := quarantine.RegisterQueryHandlerClient(context.Background(), mux, quarantine.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// RegisterInterfaces registers the quarantine module's interface types +func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + quarantine.RegisterInterfaces(registry) +} + +// RegisterLegacyAminoCodec registers the quarantine module's types for the given codec. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + quarantine.RegisterLegacyAminoCodec(cdc) +} + +// Name returns the quarantine module's name. +func (AppModule) Name() string { + return quarantine.ModuleName +} + +// RegisterInvariants does nothing, there are no invariants to enforce for the quarantine module. +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + keeper.RegisterInvariants(ir, am.keeper) +} + +// Deprecated: Route returns the message routing key for the quarantine module, empty. +func (am AppModule) Route() sdk.Route { + return sdk.Route{} +} + +// Deprecated: QuerierRoute returns the route we respond to for abci queries, "". +func (AppModule) QuerierRoute() string { return "" } + +// Deprecated: LegacyQuerierHandler returns the quarantine module sdk.Querier (nil). +func (am AppModule) LegacyQuerierHandler(_ *codec.LegacyAmino) sdk.Querier { + return nil +} + +// InitGenesis performs genesis initialization for the quarantine module. It returns +// no validator updates. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate { + var genesisState quarantine.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) + am.keeper.InitGenesis(ctx, &genesisState) + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the exported genesis state as raw bytes for the quarantine module. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(gs) +} + +// RegisterServices registers a gRPC query service to respond to the quarantine-specific gRPC queries. +func (am AppModule) RegisterServices(cfg module.Configurator) { + quarantine.RegisterMsgServer(cfg.MsgServer(), am.keeper) + quarantine.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// ____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the quarantine module. +func (am AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState, am.keeper.GetFundsHolder()) +} + +// ProposalContents returns all the quarantine content functions used to +// simulate governance proposals. +func (am AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized quarantine param changes for the simulator. +func (AppModule) RandomizedParams(_ *rand.Rand) []simtypes.ParamChange { + return nil +} + +// RegisterStoreDecoder registers a decoder for quarantine module's types +func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[quarantine.StoreKey] = simulation.NewDecodeStore(am.cdc) +} + +// WeightedOperations returns the all the quarantine module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accKeeper, am.bankKeeper, am.keeper, am.cdc, + ) +} diff --git a/x/quarantine/msgs.go b/x/quarantine/msgs.go new file mode 100644 index 0000000000..c0403118d8 --- /dev/null +++ b/x/quarantine/msgs.go @@ -0,0 +1,152 @@ +package quarantine + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + qerrors "github.com/cosmos/cosmos-sdk/x/quarantine/errors" +) + +var _ sdk.Msg = &MsgOptIn{} + +// NewMsgOptIn creates a new msg to opt in to account quarantine. +func NewMsgOptIn(toAddr sdk.AccAddress) *MsgOptIn { + return &MsgOptIn{ + ToAddress: toAddr.String(), + } +} + +// ValidateBasic does simple stateless validation of this Msg. +func (msg MsgOptIn) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + return nil +} + +// GetSigners returns the addresses of required signers of this Msg. +func (msg MsgOptIn) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.ToAddress) + return []sdk.AccAddress{addr} +} + +var _ sdk.Msg = &MsgOptOut{} + +// NewMsgOptOut creates a new msg to opt out of account quarantine. +func NewMsgOptOut(toAddr sdk.AccAddress) *MsgOptOut { + return &MsgOptOut{ + ToAddress: toAddr.String(), + } +} + +// ValidateBasic does simple stateless validation of this Msg. +func (msg MsgOptOut) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + return nil +} + +// GetSigners returns the addresses of required signers of this Msg. +func (msg MsgOptOut) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.ToAddress) + return []sdk.AccAddress{addr} +} + +var _ sdk.Msg = &MsgAccept{} + +// NewMsgAccept creates a new msg to accept quarantined funds. +func NewMsgAccept(toAddr sdk.AccAddress, fromAddrsStrs []string, permanent bool) *MsgAccept { + return &MsgAccept{ + ToAddress: toAddr.String(), + FromAddresses: fromAddrsStrs, + Permanent: permanent, + } +} + +// ValidateBasic does simple stateless validation of this Msg. +func (msg MsgAccept) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + if len(msg.FromAddresses) == 0 { + return sdkerrors.ErrUnknownAddress.Wrap("at least one from address is required") + } + for i, addr := range msg.FromAddresses { + if _, err := sdk.AccAddressFromBech32(addr); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address[%d]: %s", i, err) + } + } + return nil +} + +// GetSigners returns the addresses of required signers of this Msg. +func (msg MsgAccept) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.ToAddress) + return []sdk.AccAddress{addr} +} + +var _ sdk.Msg = &MsgDecline{} + +// NewMsgDecline creates a new msg to decline quarantined funds. +func NewMsgDecline(toAddr sdk.AccAddress, fromAddrsStrs []string, permanent bool) *MsgDecline { + return &MsgDecline{ + ToAddress: toAddr.String(), + FromAddresses: fromAddrsStrs, + Permanent: permanent, + } +} + +// ValidateBasic does simple stateless validation of this Msg. +func (msg MsgDecline) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + if len(msg.FromAddresses) == 0 { + return sdkerrors.ErrUnknownAddress.Wrap("at least one from address is required") + } + for i, addr := range msg.FromAddresses { + if _, err := sdk.AccAddressFromBech32(addr); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address[%d]: %s", i, err) + } + } + return nil +} + +// GetSigners returns the addresses of required signers of this Msg. +func (msg MsgDecline) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.ToAddress) + return []sdk.AccAddress{addr} +} + +var _ sdk.Msg = &MsgUpdateAutoResponses{} + +// NewMsgUpdateAutoResponses creates a new msg to update quarantined auto-responses. +func NewMsgUpdateAutoResponses(toAddr sdk.AccAddress, updates []*AutoResponseUpdate) *MsgUpdateAutoResponses { + return &MsgUpdateAutoResponses{ + ToAddress: toAddr.String(), + Updates: updates, + } +} + +// ValidateBasic does simple stateless validation of this Msg. +func (msg MsgUpdateAutoResponses) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %s", err) + } + if len(msg.Updates) == 0 { + return qerrors.ErrInvalidValue.Wrap("no updates") + } + for i, update := range msg.Updates { + if err := update.Validate(); err != nil { + return errors.Wrapf(err, "invalid update %d", i+1) + } + } + return nil +} + +// GetSigners returns the addresses of required signers of this Msg. +func (msg MsgUpdateAutoResponses) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.ToAddress) + return []sdk.AccAddress{addr} +} diff --git a/x/quarantine/msgs_test.go b/x/quarantine/msgs_test.go new file mode 100644 index 0000000000..2d3b4ef449 --- /dev/null +++ b/x/quarantine/msgs_test.go @@ -0,0 +1,1102 @@ +package quarantine_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + + . "github.com/cosmos/cosmos-sdk/x/quarantine" + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +func TestNewMsgOptIn(t *testing.T) { + testAddr0 := MakeTestAddr("nmoi", 0) + testAddr1 := MakeTestAddr("nmoi", 1) + + tests := []struct { + name string + toAddr sdk.AccAddress + expected *MsgOptIn + }{ + { + name: "addr 0", + toAddr: testAddr0, + expected: &MsgOptIn{ToAddress: testAddr0.String()}, + }, + { + name: "addr 1", + toAddr: testAddr1, + expected: &MsgOptIn{ToAddress: testAddr1.String()}, + }, + { + name: "nil", + toAddr: nil, + expected: &MsgOptIn{ToAddress: ""}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewMsgOptIn(tc.toAddr) + assert.Equal(t, tc.expected, actual, "NewMsgOptIn") + }) + } +} + +func TestMsgOptIn_ValidateBasic(t *testing.T) { + addr := MakeTestAddr("moivb", 0).String() + + tests := []struct { + name string + addr string + expectedInErr []string + }{ + { + name: "addr", + addr: addr, + expectedInErr: nil, + }, + { + name: "bad", + addr: "not an actual address", + expectedInErr: []string{"invalid to address"}, + }, + { + name: "empty", + addr: "", + expectedInErr: []string{"invalid to address"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgOptIn{ToAddress: tc.addr} + msg := MsgOptIn{ToAddress: tc.addr} + err := msg.ValidateBasic() + AssertErrorContents(t, err, tc.expectedInErr, "ValidateBasic") + assert.Equal(t, msgOrig, msg, "MsgOptIn before and after") + }) + } +} + +func TestMsgOptIn_GetSigners(t *testing.T) { + addr := MakeTestAddr("moigs", 0) + + tests := []struct { + name string + addr string + expected []sdk.AccAddress + }{ + { + name: "addr", + addr: addr.String(), + expected: []sdk.AccAddress{addr}, + }, + { + name: "bad", + addr: "not an actual address", + expected: []sdk.AccAddress{nil}, + }, + { + name: "empty", + addr: "", + expected: []sdk.AccAddress{{}}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgOptIn{ToAddress: tc.addr} + msg := MsgOptIn{ToAddress: tc.addr} + actual := msg.GetSigners() + assert.Equal(t, tc.expected, actual, "GetSigners") + assert.Equal(t, msgOrig, msg, "MsgOptIn before and after") + }) + } +} + +func TestNewMsgOptOut(t *testing.T) { + testAddr0 := MakeTestAddr("nmoo", 0) + testAddr1 := MakeTestAddr("nmoo", 1) + + tests := []struct { + name string + toAddr sdk.AccAddress + expected *MsgOptOut + }{ + { + name: "addr 0", + toAddr: testAddr0, + expected: &MsgOptOut{ToAddress: testAddr0.String()}, + }, + { + name: "addr 1", + toAddr: testAddr1, + expected: &MsgOptOut{ToAddress: testAddr1.String()}, + }, + { + name: "nil", + toAddr: nil, + expected: &MsgOptOut{ToAddress: ""}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewMsgOptOut(tc.toAddr) + assert.Equal(t, tc.expected, actual, "NewMsgOptOut") + }) + } +} + +func TestMsgOptOut_ValidateBasic(t *testing.T) { + addr := MakeTestAddr("moovb", 0).String() + + tests := []struct { + name string + addr string + expectedInErr []string + }{ + { + name: "addr", + addr: addr, + expectedInErr: nil, + }, + { + name: "bad", + addr: "not an actual address", + expectedInErr: []string{"invalid to address"}, + }, + { + name: "empty", + addr: "", + expectedInErr: []string{"invalid to address"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgOptOut{ToAddress: tc.addr} + msg := MsgOptOut{ToAddress: tc.addr} + err := msg.ValidateBasic() + AssertErrorContents(t, err, tc.expectedInErr, "ValidateBasic") + assert.Equal(t, msgOrig, msg, "MsgOptOut before and after") + }) + } +} + +func TestMsgOptOut_GetSigners(t *testing.T) { + addr := MakeTestAddr("moogs", 0) + + tests := []struct { + name string + addr string + expected []sdk.AccAddress + }{ + { + name: "addr", + addr: addr.String(), + expected: []sdk.AccAddress{addr}, + }, + { + name: "bad", + addr: "not an actual address", + expected: []sdk.AccAddress{nil}, + }, + { + name: "empty", + addr: "", + expected: []sdk.AccAddress{{}}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgOptOut{ToAddress: tc.addr} + msg := MsgOptOut{ToAddress: tc.addr} + actual := msg.GetSigners() + assert.Equal(t, tc.expected, actual, "GetSigners") + assert.Equal(t, msgOrig, msg, "MsgOptOut before and after") + }) + } +} + +func TestNewMsgAccept(t *testing.T) { + testAddr0 := MakeTestAddr("nma", 0) + testAddr1 := MakeTestAddr("nma", 1) + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddrs []string + permanent bool + expected *MsgAccept + }{ + { + name: "control", + toAddr: testAddr0, + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: &MsgAccept{ + ToAddress: testAddr0.String(), + FromAddresses: []string{testAddr1.String()}, + Permanent: false, + }, + }, + { + name: "nil toAddr", + toAddr: nil, + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: &MsgAccept{ + ToAddress: "", + FromAddresses: []string{testAddr1.String()}, + Permanent: false, + }, + }, + { + name: "nil fromAddrsStrs", + toAddr: testAddr1, + fromAddrs: nil, + permanent: false, + expected: &MsgAccept{ + ToAddress: testAddr1.String(), + FromAddresses: nil, + Permanent: false, + }, + }, + { + name: "empty fromAddrsStrs", + toAddr: testAddr1, + fromAddrs: []string{}, + permanent: false, + expected: &MsgAccept{ + ToAddress: testAddr1.String(), + FromAddresses: []string{}, + Permanent: false, + }, + }, + { + name: "three bad fromAddrsStrs", + toAddr: testAddr1, + fromAddrs: []string{"one", "two", "three"}, + permanent: false, + expected: &MsgAccept{ + ToAddress: testAddr1.String(), + FromAddresses: []string{"one", "two", "three"}, + Permanent: false, + }, + }, + { + name: "permanent", + toAddr: testAddr1, + fromAddrs: []string{testAddr0.String()}, + permanent: true, + expected: &MsgAccept{ + ToAddress: testAddr1.String(), + FromAddresses: []string{testAddr0.String()}, + Permanent: true, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewMsgAccept(tc.toAddr, tc.fromAddrs, tc.permanent) + assert.Equal(t, tc.expected, actual, "NewMsgAccept") + }) + } +} + +func TestMsgAccept_ValidateBasic(t *testing.T) { + testAddr0 := MakeTestAddr("mavb", 0).String() + testAddr1 := MakeTestAddr("mavb", 1).String() + testAddr2 := MakeTestAddr("mavb", 2).String() + + tests := []struct { + name string + toAddr string + fromAddrs []string + permanent bool + expectedInErr []string + }{ + { + name: "control", + toAddr: testAddr0, + fromAddrs: []string{testAddr1}, + permanent: false, + expectedInErr: nil, + }, + { + name: "permanent", + toAddr: testAddr0, + fromAddrs: []string{testAddr1}, + permanent: true, + expectedInErr: nil, + }, + { + name: "empty to address", + toAddr: "", + fromAddrs: []string{testAddr1}, + permanent: false, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "bad to address", + toAddr: "this address isn't", + fromAddrs: []string{testAddr0}, + permanent: false, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "nil from addresses", + toAddr: testAddr1, + fromAddrs: nil, + permanent: false, + expectedInErr: []string{"at least one from address is required", "unknown address"}, + }, + { + name: "empty from addresses", + toAddr: testAddr1, + fromAddrs: []string{}, + permanent: false, + expectedInErr: []string{"at least one from address is required", "unknown address"}, + }, + { + name: "bad from address", + toAddr: testAddr0, + fromAddrs: []string{"this one is a tunic"}, + permanent: false, + expectedInErr: []string{"invalid from address[0]"}, + }, + { + name: "bad third from address", + toAddr: testAddr0, + fromAddrs: []string{testAddr1, testAddr2, "Michael Jackson (he's bad)"}, + permanent: false, + expectedInErr: []string{"invalid from address[2]"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgAccept{ + ToAddress: tc.toAddr, + FromAddresses: MakeCopyOfStringSlice(tc.fromAddrs), + Permanent: tc.permanent, + } + msg := MsgAccept{ + ToAddress: tc.toAddr, + FromAddresses: tc.fromAddrs, + Permanent: tc.permanent, + } + err := msg.ValidateBasic() + AssertErrorContents(t, err, tc.expectedInErr, "ValidateBasic") + assert.Equal(t, msgOrig, msg, "MsgAccept before and after") + }) + } +} + +func TestMsgAccept_GetSigners(t *testing.T) { + testAddr0 := MakeTestAddr("mags", 0) + testAddr1 := MakeTestAddr("mags", 1) + testAddr2 := MakeTestAddr("mags", 2) + + tests := []struct { + name string + toAddr string + fromAddrs []string + permanent bool + expected []sdk.AccAddress + }{ + { + name: "control", + toAddr: testAddr0.String(), + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: []sdk.AccAddress{testAddr0}, + }, + { + name: "permanent", + toAddr: testAddr0.String(), + fromAddrs: []string{testAddr1.String()}, + permanent: true, + expected: []sdk.AccAddress{testAddr0}, + }, + { + name: "empty to address", + toAddr: "", + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: []sdk.AccAddress{{}}, + }, + { + name: "bad to address", + toAddr: "this address isn't", + fromAddrs: []string{testAddr0.String()}, + permanent: false, + expected: []sdk.AccAddress{nil}, + }, + { + name: "empty from addresses", + toAddr: testAddr1.String(), + fromAddrs: []string{}, + permanent: false, + expected: []sdk.AccAddress{testAddr1}, + }, + { + name: "two from addresses", + toAddr: testAddr2.String(), + fromAddrs: []string{testAddr0.String(), testAddr1.String()}, + permanent: false, + expected: []sdk.AccAddress{testAddr2}, + }, + { + name: "bad from address", + toAddr: testAddr0.String(), + fromAddrs: []string{"this one is a tunic"}, + permanent: false, + expected: []sdk.AccAddress{testAddr0}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgAccept{ + ToAddress: tc.toAddr, + FromAddresses: MakeCopyOfStringSlice(tc.fromAddrs), + Permanent: tc.permanent, + } + msg := MsgAccept{ + ToAddress: tc.toAddr, + FromAddresses: tc.fromAddrs, + Permanent: tc.permanent, + } + actual := msg.GetSigners() + assert.Equal(t, tc.expected, actual, "GetSigners") + assert.Equal(t, msgOrig, msg, "MsgAccept before and after") + }) + } +} + +func TestNewMsgDecline(t *testing.T) { + testAddr0 := MakeTestAddr("nmd", 0) + testAddr1 := MakeTestAddr("nmd", 1) + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddrs []string + permanent bool + expected *MsgDecline + }{ + { + name: "control", + toAddr: testAddr0, + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: &MsgDecline{ + ToAddress: testAddr0.String(), + FromAddresses: []string{testAddr1.String()}, + Permanent: false, + }, + }, + { + name: "nil toAddr", + toAddr: nil, + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: &MsgDecline{ + ToAddress: "", + FromAddresses: []string{testAddr1.String()}, + Permanent: false, + }, + }, + { + name: "nil fromAddrsStrs", + toAddr: testAddr1, + fromAddrs: nil, + permanent: false, + expected: &MsgDecline{ + ToAddress: testAddr1.String(), + FromAddresses: nil, + Permanent: false, + }, + }, + { + name: "empty fromAddrsStrs", + toAddr: testAddr1, + fromAddrs: []string{}, + permanent: false, + expected: &MsgDecline{ + ToAddress: testAddr1.String(), + FromAddresses: []string{}, + Permanent: false, + }, + }, + { + name: "three bad fromAddrsStrs", + toAddr: testAddr1, + fromAddrs: []string{"one", "two", "three"}, + permanent: false, + expected: &MsgDecline{ + ToAddress: testAddr1.String(), + FromAddresses: []string{"one", "two", "three"}, + Permanent: false, + }, + }, + { + name: "permanent", + toAddr: testAddr1, + fromAddrs: []string{testAddr0.String()}, + permanent: true, + expected: &MsgDecline{ + ToAddress: testAddr1.String(), + FromAddresses: []string{testAddr0.String()}, + Permanent: true, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewMsgDecline(tc.toAddr, tc.fromAddrs, tc.permanent) + assert.Equal(t, tc.expected, actual, "NewMsgDecline") + }) + } +} + +func TestMsgDecline_ValidateBasic(t *testing.T) { + testAddr0 := MakeTestAddr("mdvb", 0).String() + testAddr1 := MakeTestAddr("mdvb", 1).String() + testAddr2 := MakeTestAddr("mdvb", 2).String() + + tests := []struct { + name string + toAddr string + fromAddrs []string + permanent bool + expectedInErr []string + }{ + { + name: "control", + toAddr: testAddr0, + fromAddrs: []string{testAddr1}, + permanent: false, + expectedInErr: nil, + }, + { + name: "permanent", + toAddr: testAddr0, + fromAddrs: []string{testAddr1}, + permanent: true, + expectedInErr: nil, + }, + { + name: "empty to address", + toAddr: "", + fromAddrs: []string{testAddr1}, + permanent: false, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "bad to address", + toAddr: "this address isn't", + fromAddrs: []string{testAddr0}, + permanent: false, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "nil from addresses", + toAddr: testAddr1, + fromAddrs: nil, + permanent: false, + expectedInErr: []string{"at least one from address is required", "unknown address"}, + }, + { + name: "empty from addresses", + toAddr: testAddr1, + fromAddrs: []string{}, + permanent: false, + expectedInErr: []string{"at least one from address is required", "unknown address"}, + }, + { + name: "bad from address", + toAddr: testAddr0, + fromAddrs: []string{"this one is a tunic"}, + permanent: false, + expectedInErr: []string{"invalid from address[0]"}, + }, + { + name: "bad third from address", + toAddr: testAddr0, + fromAddrs: []string{testAddr1, testAddr2, "Michael Jackson (he's bad)"}, + permanent: false, + expectedInErr: []string{"invalid from address[2]"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgDecline{ + ToAddress: tc.toAddr, + FromAddresses: MakeCopyOfStringSlice(tc.fromAddrs), + Permanent: tc.permanent, + } + msg := MsgDecline{ + ToAddress: tc.toAddr, + FromAddresses: tc.fromAddrs, + Permanent: tc.permanent, + } + err := msg.ValidateBasic() + AssertErrorContents(t, err, tc.expectedInErr, "ValidateBasic") + assert.Equal(t, msgOrig, msg, "MsgDecline before and after") + }) + } +} + +func TestMsgDecline_GetSigners(t *testing.T) { + testAddr0 := MakeTestAddr("mdgs", 0) + testAddr1 := MakeTestAddr("mdgs", 1) + testAddr2 := MakeTestAddr("mdgs", 2) + + tests := []struct { + name string + toAddr string + fromAddrs []string + permanent bool + expected []sdk.AccAddress + }{ + { + name: "control", + toAddr: testAddr0.String(), + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: []sdk.AccAddress{testAddr0}, + }, + { + name: "permanent", + toAddr: testAddr0.String(), + fromAddrs: []string{testAddr1.String()}, + permanent: true, + expected: []sdk.AccAddress{testAddr0}, + }, + { + name: "empty to address", + toAddr: "", + fromAddrs: []string{testAddr1.String()}, + permanent: false, + expected: []sdk.AccAddress{{}}, + }, + { + name: "bad to address", + toAddr: "this address isn't", + fromAddrs: []string{testAddr0.String()}, + permanent: false, + expected: []sdk.AccAddress{nil}, + }, + { + name: "empty from addresses", + toAddr: testAddr1.String(), + fromAddrs: []string{}, + permanent: false, + expected: []sdk.AccAddress{testAddr1}, + }, + { + name: "two from addresses", + toAddr: testAddr2.String(), + fromAddrs: []string{testAddr0.String(), testAddr1.String()}, + permanent: false, + expected: []sdk.AccAddress{testAddr2}, + }, + { + name: "bad from address", + toAddr: testAddr0.String(), + fromAddrs: []string{"this one is a tunic"}, + permanent: false, + expected: []sdk.AccAddress{testAddr0}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msgOrig := MsgDecline{ + ToAddress: tc.toAddr, + FromAddresses: MakeCopyOfStringSlice(tc.fromAddrs), + Permanent: tc.permanent, + } + msg := MsgDecline{ + ToAddress: tc.toAddr, + FromAddresses: tc.fromAddrs, + Permanent: tc.permanent, + } + actual := msg.GetSigners() + assert.Equal(t, tc.expected, actual, "GetSigners") + assert.Equal(t, msgOrig, msg, "MsgDecline before and after") + }) + } +} + +func TestNewMsgUpdateAutoResponses(t *testing.T) { + testAddr0 := MakeTestAddr("nmuar", 0) + testAddr1 := MakeTestAddr("nmuar", 1) + testAddr2 := MakeTestAddr("nmuar", 2) + testAddr3 := MakeTestAddr("nmuar", 3) + testAddr4 := MakeTestAddr("nmuar", 4) + testAddr5 := MakeTestAddr("nmuar", 5) + + tests := []struct { + name string + toAddr sdk.AccAddress + updates []*AutoResponseUpdate + expected *MsgUpdateAutoResponses + }{ + { + name: "empty updates", + toAddr: testAddr0, + updates: []*AutoResponseUpdate{}, + expected: &MsgUpdateAutoResponses{ + ToAddress: testAddr0.String(), + Updates: []*AutoResponseUpdate{}, + }, + }, + { + name: "one update no to addr", + toAddr: nil, + updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_ACCEPT}}, + expected: &MsgUpdateAutoResponses{ + ToAddress: "", + Updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_ACCEPT}}, + }, + }, + { + name: "one update accept", + toAddr: testAddr1, + updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_ACCEPT}}, + expected: &MsgUpdateAutoResponses{ + ToAddress: testAddr1.String(), + Updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_ACCEPT}}, + }, + }, + { + name: "one update decline", + toAddr: testAddr2, + updates: []*AutoResponseUpdate{{FromAddress: testAddr1.String(), Response: AUTO_RESPONSE_DECLINE}}, + expected: &MsgUpdateAutoResponses{ + ToAddress: testAddr2.String(), + Updates: []*AutoResponseUpdate{{FromAddress: testAddr1.String(), Response: AUTO_RESPONSE_DECLINE}}, + }, + }, + { + name: "one update unspecified", + toAddr: testAddr0, + updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_UNSPECIFIED}}, + expected: &MsgUpdateAutoResponses{ + ToAddress: testAddr0.String(), + Updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_UNSPECIFIED}}, + }, + }, + { + name: "one update unspecified", + toAddr: testAddr0, + updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_UNSPECIFIED}}, + expected: &MsgUpdateAutoResponses{ + ToAddress: testAddr0.String(), + Updates: []*AutoResponseUpdate{{FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_UNSPECIFIED}}, + }, + }, + { + name: "five updates", + toAddr: testAddr0, + updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1.String(), Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_DECLINE}, + {FromAddress: testAddr3.String(), Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr4.String(), Response: AUTO_RESPONSE_UNSPECIFIED}, + {FromAddress: testAddr5.String(), Response: AUTO_RESPONSE_ACCEPT}, + }, + expected: &MsgUpdateAutoResponses{ + ToAddress: testAddr0.String(), + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1.String(), Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_DECLINE}, + {FromAddress: testAddr3.String(), Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr4.String(), Response: AUTO_RESPONSE_UNSPECIFIED}, + {FromAddress: testAddr5.String(), Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewMsgUpdateAutoResponses(tc.toAddr, tc.updates) + assert.Equal(t, tc.expected, actual, "NewMsgUpdateAutoResponses") + }) + } +} + +func TestMsgUpdateAutoResponses_ValidateBasic(t *testing.T) { + testAddr0 := MakeTestAddr("muarvb", 0).String() + testAddr1 := MakeTestAddr("muarvb", 1).String() + testAddr2 := MakeTestAddr("muarvb", 2).String() + testAddr3 := MakeTestAddr("muarvb", 3).String() + testAddr4 := MakeTestAddr("muarvb", 4).String() + testAddr5 := MakeTestAddr("muarvb", 5).String() + + tests := []struct { + name string + orig MsgUpdateAutoResponses + expectedInErr []string + }{ + { + name: "control accept", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: nil, + }, + { + name: "control decline", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr2, Response: AUTO_RESPONSE_DECLINE}, + }, + }, + expectedInErr: nil, + }, + { + name: "control unspecified", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr3, Response: AUTO_RESPONSE_UNSPECIFIED}, + }, + }, + expectedInErr: nil, + }, + { + name: "bad to address", + orig: MsgUpdateAutoResponses{ + ToAddress: "not really that bad", + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "empty to address", + orig: MsgUpdateAutoResponses{ + ToAddress: "", + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "nil updates", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: nil, + }, + expectedInErr: []string{"invalid value", "no updates"}, + }, + { + name: "empty updates", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{}, + }, + expectedInErr: []string{"invalid value", "no updates"}, + }, + { + name: "one update bad from address", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: "Okay, I'm bad again.", Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid update 1", "invalid from address"}, + }, + { + name: "one update empty from address", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: "", Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid update 1", "invalid from address"}, + }, + { + name: "one update negative resp", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: -1}, + }, + }, + expectedInErr: []string{"invalid update 1", "unknown auto-response value: -1"}, + }, + { + name: "one update resp too large", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr2, Response: 900}, + }, + }, + expectedInErr: []string{"invalid update 1", "unknown auto-response value: 900"}, + }, + { + name: "five updates third bad from address", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr2, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: "still not good", Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr4, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr5, Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid update 3", "invalid from address"}, + }, + { + name: "five updates fourth empty from address", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr2, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr3, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: "", Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr5, Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid update 4", "invalid from address"}, + }, + { + name: "five updates first negative resp", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: -88}, + {FromAddress: testAddr2, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr3, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr4, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr5, Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expectedInErr: []string{"invalid update 1", "unknown auto-response value: -88"}, + }, + { + name: "five update last resp too large", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0, + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr2, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr3, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr4, Response: AUTO_RESPONSE_ACCEPT}, + {FromAddress: testAddr5, Response: 55}, + }, + }, + expectedInErr: []string{"invalid update 5", "unknown auto-response value: 55"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msg := MsgUpdateAutoResponses{ + ToAddress: tc.orig.ToAddress, + Updates: nil, + } + if tc.orig.Updates != nil { + msg.Updates = []*AutoResponseUpdate{} + for _, update := range tc.orig.Updates { + msg.Updates = append(msg.Updates, &AutoResponseUpdate{ + FromAddress: update.FromAddress, + Response: update.Response, + }) + } + } + err := msg.ValidateBasic() + AssertErrorContents(t, err, tc.expectedInErr, "ValidateBasic") + assert.Equal(t, tc.orig, msg, "MsgUpdateAutoResponses before and after") + }) + } +} + +func TestMsgUpdateAutoResponses_GetSigners(t *testing.T) { + testAddr0 := MakeTestAddr("muargs", 0) + testAddr1 := MakeTestAddr("muargs", 1) + testAddr2 := MakeTestAddr("muargs", 2) + + tests := []struct { + name string + orig MsgUpdateAutoResponses + expected []sdk.AccAddress + }{ + { + name: "control", + orig: MsgUpdateAutoResponses{ + ToAddress: testAddr0.String(), + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1.String(), Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expected: []sdk.AccAddress{testAddr0}, + }, + { + name: "bad addr", + orig: MsgUpdateAutoResponses{ + ToAddress: "bad bad bad", + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr2.String(), Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expected: []sdk.AccAddress{nil}, + }, + { + name: "empty addr", + orig: MsgUpdateAutoResponses{ + ToAddress: "", + Updates: []*AutoResponseUpdate{ + {FromAddress: testAddr1.String(), Response: AUTO_RESPONSE_ACCEPT}, + }, + }, + expected: []sdk.AccAddress{{}}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + msg := MsgUpdateAutoResponses{ + ToAddress: tc.orig.ToAddress, + Updates: nil, + } + if tc.orig.Updates != nil { + msg.Updates = []*AutoResponseUpdate{} + for _, update := range tc.orig.Updates { + msg.Updates = append(msg.Updates, &AutoResponseUpdate{ + FromAddress: update.FromAddress, + Response: update.Response, + }) + } + } + actual := msg.GetSigners() + assert.Equal(t, tc.expected, actual, "GetSigners") + assert.Equal(t, tc.orig, msg, "MsgUpdateAutoResponses before and after") + }) + } +} diff --git a/x/quarantine/quarantine.go b/x/quarantine/quarantine.go new file mode 100644 index 0000000000..ae85fc8510 --- /dev/null +++ b/x/quarantine/quarantine.go @@ -0,0 +1,326 @@ +package quarantine + +import ( + "bytes" + "sort" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/quarantine/errors" +) + +// containsAddress returns true if the addrToFind is an entry in the addrs. +func containsAddress(addrs []sdk.AccAddress, addrToFind sdk.AccAddress) bool { + for _, addr := range addrs { + if addrToFind.Equals(addr) { + return true + } + } + return false +} + +// findAddresses searches allAddrs for each of the addrsToFind. +// It returns two slices. The first is each of the addrsToFind that were in allAddrs. +// The second is each of the allAddrs that were not in addrsToFind. +// Each entry in allAddrs will either end up in the first or second return slice. +func findAddresses(allAddrs []sdk.AccAddress, addrsToFind []sdk.AccAddress) (found []sdk.AccAddress, leftover []sdk.AccAddress) { + found = make([]sdk.AccAddress, 0, len(addrsToFind)) + leftover = make([]sdk.AccAddress, 0, len(allAddrs)) + for _, existing := range allAddrs { + if containsAddress(addrsToFind, existing) { + found = append(found, existing) + } else { + leftover = append(leftover, existing) + } + } + if len(found) == 0 { + found = nil + } + if len(leftover) == 0 { + leftover = nil + } + return found, leftover +} + +// containsSuffix returns true if the suffixToFind is in the suffixes. +func containsSuffix(suffixes [][]byte, suffixToFind []byte) bool { + for _, suffix := range suffixes { + if bytes.Equal(suffixToFind, suffix) { + return true + } + } + return false +} + +// NewQuarantinedFunds creates a new quarantined funds object. +func NewQuarantinedFunds(toAddr sdk.AccAddress, fromAddrs []sdk.AccAddress, coins sdk.Coins, declined bool) *QuarantinedFunds { + rv := &QuarantinedFunds{ + ToAddress: toAddr.String(), + UnacceptedFromAddresses: make([]string, len(fromAddrs)), + Coins: coins, + Declined: declined, + } + for i, addr := range fromAddrs { + rv.UnacceptedFromAddresses[i] = addr.String() + } + return rv +} + +// Validate does simple stateless validation of these quarantined funds. +func (f QuarantinedFunds) Validate() error { + if _, err := sdk.AccAddressFromBech32(f.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %v", err) + } + if len(f.UnacceptedFromAddresses) == 0 { + return errors.ErrInvalidValue.Wrap("at least one unaccepted from address is required") + } + seen := make(map[string]struct{}) + for i, addr := range f.UnacceptedFromAddresses { + if _, err := sdk.AccAddressFromBech32(addr); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid unaccepted from address[%d]: %v", i, err) + } + if _, found := seen[addr]; found { + return errors.ErrInvalidValue.Wrapf("duplicate unaccepted from address: %q", addr) + } + seen[addr] = struct{}{} + } + if err := f.Coins.Validate(); err != nil { + return err + } + return nil +} + +// NewAutoResponseEntry creates a new quarantined auto-response entry. +func NewAutoResponseEntry(toAddr, fromAddr sdk.AccAddress, response AutoResponse) *AutoResponseEntry { + return &AutoResponseEntry{ + ToAddress: toAddr.String(), + FromAddress: fromAddr.String(), + Response: response, + } +} + +// Validate does simple stateless validation of these quarantined funds. +func (e AutoResponseEntry) Validate() error { + if _, err := sdk.AccAddressFromBech32(e.ToAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %v", err) + } + if _, err := sdk.AccAddressFromBech32(e.FromAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %v", err) + } + if !e.Response.IsValid() { + return errors.ErrInvalidValue.Wrapf("unknown auto-response value: %d", e.Response) + } + return nil +} + +// Validate does simple stateless validation of this update. +func (u AutoResponseUpdate) Validate() error { + if _, err := sdk.AccAddressFromBech32(u.FromAddress); err != nil { + return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %s", err) + } + if !u.Response.IsValid() { + return errors.ErrInvalidValue.Wrapf("unknown auto-response value: %d", u.Response) + } + return nil +} + +const ( + // NoAutoB is a byte with value 0 (corresponding to AUTO_RESPONSE_UNSPECIFIED). + NoAutoB = byte(0x00) + // AutoAcceptB is a byte with value 1 (corresponding to AUTO_RESPONSE_ACCEPT). + AutoAcceptB = byte(0x01) + // AutoDeclineB is a byte with value 2 (corresponding to AUTO_RESPONSE_DECLINE). + AutoDeclineB = byte(0x02) +) + +// ToAutoB converts a AutoResponse into the byte that will represent it. +func ToAutoB(r AutoResponse) byte { + switch r { + case AUTO_RESPONSE_ACCEPT: + return AutoAcceptB + case AUTO_RESPONSE_DECLINE: + return AutoDeclineB + default: + return NoAutoB + } +} + +// ToAutoResponse returns the AutoResponse represented by the provided byte slice. +func ToAutoResponse(bz []byte) AutoResponse { + if len(bz) == 1 { + switch bz[0] { + case AutoAcceptB: + return AUTO_RESPONSE_ACCEPT + case AutoDeclineB: + return AUTO_RESPONSE_DECLINE + } + } + return AUTO_RESPONSE_UNSPECIFIED +} + +// IsValid returns true if this is a known response value +func (r AutoResponse) IsValid() bool { + _, found := AutoResponse_name[int32(r)] + return found +} + +// IsAccept returns true if this is an auto-accept response. +func (r AutoResponse) IsAccept() bool { + return r == AUTO_RESPONSE_ACCEPT +} + +// IsDecline returns true if this is an auto-decline response. +func (r AutoResponse) IsDecline() bool { + return r == AUTO_RESPONSE_DECLINE +} + +// NewQuarantineRecord creates a new quarantine record object. +func NewQuarantineRecord(unacceptedFromAddrs []string, coins sdk.Coins, declined bool) *QuarantineRecord { + rv := &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coins, + Declined: declined, + } + if len(unacceptedFromAddrs) > 0 { + rv.UnacceptedFromAddresses = make([]sdk.AccAddress, len(unacceptedFromAddrs)) + for i, addr := range unacceptedFromAddrs { + rv.UnacceptedFromAddresses[i] = sdk.MustAccAddressFromBech32(addr) + } + } + return rv +} + +// Validate does simple stateless validation of these quarantined funds. +func (r QuarantineRecord) Validate() error { + if len(r.UnacceptedFromAddresses) == 0 { + return errors.ErrInvalidValue.Wrap("at least one unaccepted from address is required") + } + return r.Coins.Validate() +} + +// AddCoins adds coins to this. +func (r *QuarantineRecord) AddCoins(coins ...sdk.Coin) { + r.Coins = r.Coins.Add(coins...) +} + +// IsFullyAccepted returns true if this record has been accepted for all from addresses involved. +func (r QuarantineRecord) IsFullyAccepted() bool { + return len(r.UnacceptedFromAddresses) == 0 +} + +// AcceptFrom moves the provided addrs from the unaccepted slice to the accepted slice. +// If none of the provided addrs are in this record's unaccepted slice, this does nothing. +// Returns true if anything in this record changed. +func (r *QuarantineRecord) AcceptFrom(addrs []sdk.AccAddress) bool { + nowAccepted, leftovers := findAddresses(r.UnacceptedFromAddresses, addrs) + if len(nowAccepted) == 0 { + return false + } + r.AcceptedFromAddresses = append(r.AcceptedFromAddresses, nowAccepted...) + if len(leftovers) > 0 { + r.UnacceptedFromAddresses = leftovers + } else { + r.UnacceptedFromAddresses = nil + } + return true +} + +// DeclineFrom marks this as declined and moves any of the provided addrs from accepted to unaccepted. +// If none of the provided addrs are in this record's accepted slice, accepted and unaccepted are left unchanged, +// but the record is still marked as declined. +// Returns true if anything in this record changed. +func (r *QuarantineRecord) DeclineFrom(addrs []sdk.AccAddress) bool { + rv := false + if !r.Declined { + r.Declined = true + rv = true + } + backToUnaccepted, leftovers := findAddresses(r.AcceptedFromAddresses, addrs) + if len(backToUnaccepted) > 0 { + rv = true + r.UnacceptedFromAddresses = append(r.UnacceptedFromAddresses, backToUnaccepted...) + if len(leftovers) > 0 { + r.AcceptedFromAddresses = leftovers + } else { + r.AcceptedFromAddresses = nil + } + } + return rv +} + +func (r *QuarantineRecord) GetAllFromAddrs() []sdk.AccAddress { + rv := make([]sdk.AccAddress, len(r.UnacceptedFromAddresses)+len(r.AcceptedFromAddresses)) + copy(rv, r.UnacceptedFromAddresses) + copy(rv[len(r.UnacceptedFromAddresses):], r.AcceptedFromAddresses) + return rv +} + +// AsQuarantinedFunds creates a new QuarantinedFunds using fields in this and the provided addresses. +func (r QuarantineRecord) AsQuarantinedFunds(toAddr sdk.AccAddress) *QuarantinedFunds { + return NewQuarantinedFunds(toAddr, r.UnacceptedFromAddresses, r.Coins, r.Declined) +} + +// AddSuffixes adds the provided suffixes to this. +// No attempt is made to deduplicate entries. After using this, you should use Simplify before trying to save it. +func (s *QuarantineRecordSuffixIndex) AddSuffixes(suffixes ...[]byte) { + s.RecordSuffixes = append(s.RecordSuffixes, suffixes...) +} + +// Simplify updates the suffixes in this so that they are ordered and there aren't any duplicates. +func (s *QuarantineRecordSuffixIndex) Simplify(toRemove ...[]byte) { + switch len(s.RecordSuffixes) { + case 0: + // do nothing for now. + case 1: + if containsSuffix(toRemove, s.RecordSuffixes[0]) { + s.RecordSuffixes = nil + } + default: + // Sort the suffixes first, so that deduplication is simpler. + sort.Slice(s.RecordSuffixes, func(i, j int) bool { + return bytes.Compare(s.RecordSuffixes[i], s.RecordSuffixes[j]) < 0 + }) + // Do as little work as possible for deduplication. + // It's assumed that the slice has few duplicates, if any. + // This is a little extra complex so that the slice isn't just + // copied every time there aren't any duplicates. + + // func for testing whether an entry is worth keeping. + isKeeper := func(cur, other []byte) bool { + return !containsSuffix(toRemove, cur) && !bytes.Equal(cur, other) + } + + // First, get rid of any non-keepers at the front of the slice since that can be done in-place. + for len(s.RecordSuffixes) > 0 && !isKeeper(s.RecordSuffixes[0], nil) { + s.RecordSuffixes = s.RecordSuffixes[1:] + } + + // Then, look through the rest of the slice looking for one to remove. + // If one is found, note it and stop. + firstRem := -1 + for i := 1; i < len(s.RecordSuffixes); i++ { + if !isKeeper(s.RecordSuffixes[i], s.RecordSuffixes[i-1]) { + firstRem = i + break + } + } + // If we found one to remove, we'll then create the new slice that doesn't have + // the unwanted entries. + if firstRem != -1 { + suffixes := make([][]byte, firstRem, len(s.RecordSuffixes)-1) + copy(suffixes, s.RecordSuffixes[:firstRem]) + for i := firstRem + 1; i < len(s.RecordSuffixes); i++ { + if isKeeper(s.RecordSuffixes[i], s.RecordSuffixes[i-1]) { + suffixes = append(suffixes, s.RecordSuffixes[i]) + } + } + s.RecordSuffixes = suffixes + } + } + + // If there's nothing left, make sure it's nil. + if len(s.RecordSuffixes) == 0 { + s.RecordSuffixes = nil + } +} diff --git a/x/quarantine/quarantine.pb.go b/x/quarantine/quarantine.pb.go new file mode 100644 index 0000000000..2b78c26f3d --- /dev/null +++ b/x/quarantine/quarantine.pb.go @@ -0,0 +1,1525 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/quarantine/v1beta1/quarantine.proto + +package quarantine + +import ( + 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/gogo/protobuf/gogoproto" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// AutoResponse enumerates the quarantine auto-response options. +type AutoResponse int32 + +const ( + // AUTO_RESPONSE_UNSPECIFIED defines that an automatic response has not been specified. + // This means that no automatic action should be taken, i.e. this auto-response is off, + // and default quarantine behavior is used. + AUTO_RESPONSE_UNSPECIFIED AutoResponse = 0 + // AUTO_RESPONSE_ACCEPT defines that sends should be automatically accepted, bypassing quarantine. + AUTO_RESPONSE_ACCEPT AutoResponse = 1 + // AUTO_RESPONSE_DECLINE defines that sends should be automatically declined. + AUTO_RESPONSE_DECLINE AutoResponse = 2 +) + +var AutoResponse_name = map[int32]string{ + 0: "AUTO_RESPONSE_UNSPECIFIED", + 1: "AUTO_RESPONSE_ACCEPT", + 2: "AUTO_RESPONSE_DECLINE", +} + +var AutoResponse_value = map[string]int32{ + "AUTO_RESPONSE_UNSPECIFIED": 0, + "AUTO_RESPONSE_ACCEPT": 1, + "AUTO_RESPONSE_DECLINE": 2, +} + +func (x AutoResponse) String() string { + return proto.EnumName(AutoResponse_name, int32(x)) +} + +func (AutoResponse) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_0b055d4922680476, []int{0} +} + +// QuarantinedFunds defines structure that represents coins that have been quarantined. +type QuarantinedFunds struct { + // to_address is the intended recipient of the coins that have been quarantined. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // unaccepted_from_addresses are the senders that have not been part of an accept yet for these coins. + UnacceptedFromAddresses []string `protobuf:"bytes,2,rep,name=unaccepted_from_addresses,json=unacceptedFromAddresses,proto3" json:"unaccepted_from_addresses,omitempty"` + // coins is the amount currently in quarantined for the two addresses. + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` + // declined is true if these funds were previously declined. + Declined bool `protobuf:"varint,4,opt,name=declined,proto3" json:"declined,omitempty"` +} + +func (m *QuarantinedFunds) Reset() { *m = QuarantinedFunds{} } +func (m *QuarantinedFunds) String() string { return proto.CompactTextString(m) } +func (*QuarantinedFunds) ProtoMessage() {} +func (*QuarantinedFunds) Descriptor() ([]byte, []int) { + return fileDescriptor_0b055d4922680476, []int{0} +} +func (m *QuarantinedFunds) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuarantinedFunds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuarantinedFunds.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 *QuarantinedFunds) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuarantinedFunds.Merge(m, src) +} +func (m *QuarantinedFunds) XXX_Size() int { + return m.Size() +} +func (m *QuarantinedFunds) XXX_DiscardUnknown() { + xxx_messageInfo_QuarantinedFunds.DiscardUnknown(m) +} + +var xxx_messageInfo_QuarantinedFunds proto.InternalMessageInfo + +func (m *QuarantinedFunds) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *QuarantinedFunds) GetUnacceptedFromAddresses() []string { + if m != nil { + return m.UnacceptedFromAddresses + } + return nil +} + +func (m *QuarantinedFunds) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +func (m *QuarantinedFunds) GetDeclined() bool { + if m != nil { + return m.Declined + } + return false +} + +// AutoResponseEntry defines the auto response to one address from another. +type AutoResponseEntry struct { + // to_address is the receiving address. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // from_address is the sending address. + FromAddress string `protobuf:"bytes,2,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // response is the auto-response setting for these two addresses. + Response AutoResponse `protobuf:"varint,3,opt,name=response,proto3,enum=cosmos.quarantine.v1beta1.AutoResponse" json:"response,omitempty"` +} + +func (m *AutoResponseEntry) Reset() { *m = AutoResponseEntry{} } +func (m *AutoResponseEntry) String() string { return proto.CompactTextString(m) } +func (*AutoResponseEntry) ProtoMessage() {} +func (*AutoResponseEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_0b055d4922680476, []int{1} +} +func (m *AutoResponseEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AutoResponseEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AutoResponseEntry.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 *AutoResponseEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_AutoResponseEntry.Merge(m, src) +} +func (m *AutoResponseEntry) XXX_Size() int { + return m.Size() +} +func (m *AutoResponseEntry) XXX_DiscardUnknown() { + xxx_messageInfo_AutoResponseEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_AutoResponseEntry proto.InternalMessageInfo + +func (m *AutoResponseEntry) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *AutoResponseEntry) GetFromAddress() string { + if m != nil { + return m.FromAddress + } + return "" +} + +func (m *AutoResponseEntry) GetResponse() AutoResponse { + if m != nil { + return m.Response + } + return AUTO_RESPONSE_UNSPECIFIED +} + +// AutoResponseUpdate defines a quarantine auto response update that should be applied. +type AutoResponseUpdate struct { + // from_address is the address that funds would be coming from. + FromAddress string `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // response is the automatic action to take on funds sent from from_address. + // Provide AUTO_RESPONSE_UNSPECIFIED to turn off an auto-response. + Response AutoResponse `protobuf:"varint,2,opt,name=response,proto3,enum=cosmos.quarantine.v1beta1.AutoResponse" json:"response,omitempty"` +} + +func (m *AutoResponseUpdate) Reset() { *m = AutoResponseUpdate{} } +func (m *AutoResponseUpdate) String() string { return proto.CompactTextString(m) } +func (*AutoResponseUpdate) ProtoMessage() {} +func (*AutoResponseUpdate) Descriptor() ([]byte, []int) { + return fileDescriptor_0b055d4922680476, []int{2} +} +func (m *AutoResponseUpdate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AutoResponseUpdate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AutoResponseUpdate.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 *AutoResponseUpdate) XXX_Merge(src proto.Message) { + xxx_messageInfo_AutoResponseUpdate.Merge(m, src) +} +func (m *AutoResponseUpdate) XXX_Size() int { + return m.Size() +} +func (m *AutoResponseUpdate) XXX_DiscardUnknown() { + xxx_messageInfo_AutoResponseUpdate.DiscardUnknown(m) +} + +var xxx_messageInfo_AutoResponseUpdate proto.InternalMessageInfo + +func (m *AutoResponseUpdate) GetFromAddress() string { + if m != nil { + return m.FromAddress + } + return "" +} + +func (m *AutoResponseUpdate) GetResponse() AutoResponse { + if m != nil { + return m.Response + } + return AUTO_RESPONSE_UNSPECIFIED +} + +// QuarantineRecord defines information regarding quarantined funds that is stored in state. +type QuarantineRecord struct { + // unaccepted_from_addresses are the senders that have not been part of an accept yet for these coins. + UnacceptedFromAddresses []github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,rep,name=unaccepted_from_addresses,json=unacceptedFromAddresses,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"unaccepted_from_addresses,omitempty"` + // accepted_from_addresses are the senders that have already been part of an accept for these coins. + AcceptedFromAddresses []github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,2,rep,name=accepted_from_addresses,json=acceptedFromAddresses,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"accepted_from_addresses,omitempty"` + // coins is the amount that has been quarantined. + Coins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=coins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"coins"` + // declined is whether these funds have been declined. + Declined bool `protobuf:"varint,4,opt,name=declined,proto3" json:"declined,omitempty"` +} + +func (m *QuarantineRecord) Reset() { *m = QuarantineRecord{} } +func (m *QuarantineRecord) String() string { return proto.CompactTextString(m) } +func (*QuarantineRecord) ProtoMessage() {} +func (*QuarantineRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_0b055d4922680476, []int{3} +} +func (m *QuarantineRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuarantineRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuarantineRecord.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 *QuarantineRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuarantineRecord.Merge(m, src) +} +func (m *QuarantineRecord) XXX_Size() int { + return m.Size() +} +func (m *QuarantineRecord) XXX_DiscardUnknown() { + xxx_messageInfo_QuarantineRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_QuarantineRecord proto.InternalMessageInfo + +func (m *QuarantineRecord) GetUnacceptedFromAddresses() []github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.UnacceptedFromAddresses + } + return nil +} + +func (m *QuarantineRecord) GetAcceptedFromAddresses() []github_com_cosmos_cosmos_sdk_types.AccAddress { + if m != nil { + return m.AcceptedFromAddresses + } + return nil +} + +func (m *QuarantineRecord) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.Coins + } + return nil +} + +func (m *QuarantineRecord) GetDeclined() bool { + if m != nil { + return m.Declined + } + return false +} + +// QuarantineRecordSuffixIndex defines a list of record suffixes that can be stored in state and used as an index. +type QuarantineRecordSuffixIndex struct { + RecordSuffixes [][]byte `protobuf:"bytes,1,rep,name=record_suffixes,json=recordSuffixes,proto3" json:"record_suffixes,omitempty"` +} + +func (m *QuarantineRecordSuffixIndex) Reset() { *m = QuarantineRecordSuffixIndex{} } +func (m *QuarantineRecordSuffixIndex) String() string { return proto.CompactTextString(m) } +func (*QuarantineRecordSuffixIndex) ProtoMessage() {} +func (*QuarantineRecordSuffixIndex) Descriptor() ([]byte, []int) { + return fileDescriptor_0b055d4922680476, []int{4} +} +func (m *QuarantineRecordSuffixIndex) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuarantineRecordSuffixIndex) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuarantineRecordSuffixIndex.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 *QuarantineRecordSuffixIndex) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuarantineRecordSuffixIndex.Merge(m, src) +} +func (m *QuarantineRecordSuffixIndex) XXX_Size() int { + return m.Size() +} +func (m *QuarantineRecordSuffixIndex) XXX_DiscardUnknown() { + xxx_messageInfo_QuarantineRecordSuffixIndex.DiscardUnknown(m) +} + +var xxx_messageInfo_QuarantineRecordSuffixIndex proto.InternalMessageInfo + +func (m *QuarantineRecordSuffixIndex) GetRecordSuffixes() [][]byte { + if m != nil { + return m.RecordSuffixes + } + return nil +} + +func init() { + proto.RegisterEnum("cosmos.quarantine.v1beta1.AutoResponse", AutoResponse_name, AutoResponse_value) + proto.RegisterType((*QuarantinedFunds)(nil), "cosmos.quarantine.v1beta1.QuarantinedFunds") + proto.RegisterType((*AutoResponseEntry)(nil), "cosmos.quarantine.v1beta1.AutoResponseEntry") + proto.RegisterType((*AutoResponseUpdate)(nil), "cosmos.quarantine.v1beta1.AutoResponseUpdate") + proto.RegisterType((*QuarantineRecord)(nil), "cosmos.quarantine.v1beta1.QuarantineRecord") + proto.RegisterType((*QuarantineRecordSuffixIndex)(nil), "cosmos.quarantine.v1beta1.QuarantineRecordSuffixIndex") +} + +func init() { + proto.RegisterFile("cosmos/quarantine/v1beta1/quarantine.proto", fileDescriptor_0b055d4922680476) +} + +var fileDescriptor_0b055d4922680476 = []byte{ + // 562 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0x41, 0x8f, 0xd2, 0x40, + 0x18, 0xed, 0xc0, 0x6a, 0x76, 0x67, 0x37, 0x2b, 0x4e, 0xd8, 0x6c, 0xc1, 0x58, 0x1a, 0x2e, 0x5b, + 0x37, 0xa1, 0xc8, 0x7a, 0xf0, 0xe0, 0xa9, 0x74, 0x4b, 0x42, 0x62, 0x58, 0x2c, 0x70, 0xf1, 0xd2, + 0x94, 0x76, 0x60, 0x1b, 0xa5, 0x83, 0x33, 0x53, 0xc3, 0xfe, 0x03, 0x8f, 0x9e, 0x3c, 0x9b, 0x78, + 0xf3, 0xec, 0x8f, 0xd8, 0x93, 0xd9, 0x78, 0xf2, 0xb4, 0x1a, 0x38, 0xfa, 0x0f, 0x3c, 0x19, 0xe8, + 0x00, 0x45, 0xb3, 0x68, 0x38, 0x79, 0x82, 0xf9, 0xde, 0xbc, 0x37, 0xaf, 0x6f, 0x5e, 0x06, 0x1e, + 0x7b, 0x84, 0x0d, 0x08, 0x2b, 0xbf, 0x8a, 0x5c, 0xea, 0x86, 0x3c, 0x08, 0x71, 0xf9, 0x75, 0xa5, + 0x8b, 0xb9, 0x5b, 0x49, 0x8c, 0xf4, 0x21, 0x25, 0x9c, 0xa0, 0x5c, 0xbc, 0x57, 0x4f, 0x00, 0x62, + 0x6f, 0x5e, 0x11, 0x32, 0x5d, 0x97, 0x2d, 0x05, 0x3c, 0x12, 0x84, 0x31, 0x35, 0x2f, 0xa8, 0xce, + 0x6c, 0x55, 0x16, 0x3a, 0x31, 0x94, 0xed, 0x93, 0x3e, 0x89, 0xe7, 0xd3, 0x7f, 0xf1, 0xb4, 0xf8, + 0x3e, 0x05, 0x33, 0xcf, 0x16, 0xe7, 0xf8, 0xb5, 0x28, 0xf4, 0x19, 0x7a, 0x0c, 0x21, 0x27, 0x8e, + 0xeb, 0xfb, 0x14, 0x33, 0x26, 0x03, 0x15, 0x68, 0x3b, 0x55, 0xf9, 0xcb, 0xa7, 0x52, 0x56, 0x08, + 0x1a, 0x31, 0xd2, 0xe2, 0x34, 0x08, 0xfb, 0xf6, 0x0e, 0x27, 0x62, 0x80, 0xda, 0x30, 0x17, 0x85, + 0xae, 0xe7, 0xe1, 0x21, 0xc7, 0xbe, 0xd3, 0xa3, 0x64, 0x30, 0x57, 0xc1, 0x4c, 0x4e, 0xa9, 0xe9, + 0xb5, 0x3a, 0x87, 0x4b, 0x6a, 0x8d, 0x92, 0x81, 0x31, 0x27, 0x22, 0x17, 0xde, 0x9a, 0x7e, 0x22, + 0x93, 0xd3, 0x6a, 0x5a, 0xdb, 0x3d, 0xc9, 0xe9, 0x82, 0x3e, 0x0d, 0x61, 0x9e, 0x8c, 0x6e, 0x92, + 0x20, 0xac, 0x3e, 0xbc, 0xbc, 0x2e, 0x48, 0x1f, 0xbf, 0x15, 0xb4, 0x7e, 0xc0, 0xcf, 0xa3, 0xae, + 0xee, 0x91, 0x81, 0x08, 0x41, 0xfc, 0x94, 0x98, 0xff, 0xa2, 0xcc, 0x2f, 0x86, 0x98, 0xcd, 0x08, + 0xcc, 0x8e, 0x95, 0x51, 0x1e, 0x6e, 0xfb, 0xd8, 0x7b, 0x39, 0x8d, 0x40, 0xde, 0x52, 0x81, 0xb6, + 0x6d, 0x2f, 0xd6, 0xc5, 0xcf, 0x00, 0xde, 0x35, 0x22, 0x4e, 0x6c, 0xcc, 0x86, 0x24, 0x64, 0xd8, + 0x0a, 0x39, 0xbd, 0xd8, 0x3c, 0xa3, 0x27, 0x70, 0x2f, 0x19, 0x8c, 0x9c, 0xfa, 0x0b, 0x75, 0xb7, + 0xb7, 0x0c, 0x03, 0x99, 0x70, 0x9b, 0x0a, 0x1b, 0x72, 0x5a, 0x05, 0xda, 0xfe, 0xc9, 0x91, 0x7e, + 0x63, 0x5b, 0xf4, 0xa4, 0x6b, 0x7b, 0x41, 0x2c, 0xbe, 0x03, 0x10, 0x25, 0xa1, 0xce, 0xd0, 0x77, + 0x39, 0xfe, 0xc3, 0x18, 0xd8, 0xd4, 0x58, 0x6a, 0x53, 0x63, 0x3f, 0x56, 0xca, 0x68, 0x63, 0x8f, + 0x50, 0x1f, 0x0d, 0xd6, 0x75, 0x0a, 0xa8, 0x69, 0x6d, 0xaf, 0x5a, 0xf9, 0x79, 0x5d, 0x28, 0xfd, + 0xc3, 0x95, 0x1b, 0x9e, 0x27, 0xfc, 0xde, 0x5c, 0xb6, 0x00, 0x1e, 0xae, 0x2b, 0xf0, 0x46, 0x87, + 0x1d, 0xfc, 0x97, 0xbd, 0xae, 0xc1, 0x7b, 0xbf, 0x87, 0xdd, 0x8a, 0x7a, 0xbd, 0x60, 0x54, 0x0f, + 0x7d, 0x3c, 0x42, 0x47, 0xf0, 0x0e, 0x9d, 0x0d, 0x1d, 0x36, 0x9b, 0xce, 0xd3, 0xb6, 0xf7, 0x69, + 0x62, 0x2f, 0x66, 0xc7, 0xe7, 0x70, 0x2f, 0x79, 0x9f, 0xe8, 0x3e, 0xcc, 0x19, 0x9d, 0xf6, 0x99, + 0x63, 0x5b, 0xad, 0xe6, 0x59, 0xa3, 0x65, 0x39, 0x9d, 0x46, 0xab, 0x69, 0x99, 0xf5, 0x5a, 0xdd, + 0x3a, 0xcd, 0x48, 0x48, 0x86, 0xd9, 0x55, 0xd8, 0x30, 0x4d, 0xab, 0xd9, 0xce, 0x00, 0x94, 0x83, + 0x07, 0xab, 0xc8, 0xa9, 0x65, 0x3e, 0xad, 0x37, 0xac, 0x4c, 0x2a, 0xbf, 0xf5, 0xe6, 0x83, 0x22, + 0x55, 0xcd, 0xcb, 0xb1, 0x02, 0xae, 0xc6, 0x0a, 0xf8, 0x3e, 0x56, 0xc0, 0xdb, 0x89, 0x22, 0x5d, + 0x4d, 0x14, 0xe9, 0xeb, 0x44, 0x91, 0x9e, 0x3f, 0x58, 0x1b, 0xcc, 0x28, 0xf1, 0xc6, 0x76, 0x6f, + 0xcf, 0x1e, 0xbe, 0x47, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x97, 0x30, 0xea, 0x7d, 0x92, 0x05, + 0x00, 0x00, +} + +func (m *QuarantinedFunds) 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 *QuarantinedFunds) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuarantinedFunds) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Declined { + i-- + if m.Declined { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuarantine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.UnacceptedFromAddresses) > 0 { + for iNdEx := len(m.UnacceptedFromAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.UnacceptedFromAddresses[iNdEx]) + copy(dAtA[i:], m.UnacceptedFromAddresses[iNdEx]) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.UnacceptedFromAddresses[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AutoResponseEntry) 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 *AutoResponseEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AutoResponseEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Response != 0 { + i = encodeVarintQuarantine(dAtA, i, uint64(m.Response)) + i-- + dAtA[i] = 0x18 + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *AutoResponseUpdate) 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 *AutoResponseUpdate) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AutoResponseUpdate) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Response != 0 { + i = encodeVarintQuarantine(dAtA, i, uint64(m.Response)) + i-- + dAtA[i] = 0x10 + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QuarantineRecord) 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 *QuarantineRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuarantineRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Declined { + i-- + if m.Declined { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.Coins) > 0 { + for iNdEx := len(m.Coins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Coins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuarantine(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.AcceptedFromAddresses) > 0 { + for iNdEx := len(m.AcceptedFromAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AcceptedFromAddresses[iNdEx]) + copy(dAtA[i:], m.AcceptedFromAddresses[iNdEx]) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.AcceptedFromAddresses[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.UnacceptedFromAddresses) > 0 { + for iNdEx := len(m.UnacceptedFromAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.UnacceptedFromAddresses[iNdEx]) + copy(dAtA[i:], m.UnacceptedFromAddresses[iNdEx]) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.UnacceptedFromAddresses[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *QuarantineRecordSuffixIndex) 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 *QuarantineRecordSuffixIndex) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuarantineRecordSuffixIndex) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.RecordSuffixes) > 0 { + for iNdEx := len(m.RecordSuffixes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.RecordSuffixes[iNdEx]) + copy(dAtA[i:], m.RecordSuffixes[iNdEx]) + i = encodeVarintQuarantine(dAtA, i, uint64(len(m.RecordSuffixes[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuarantine(dAtA []byte, offset int, v uint64) int { + offset -= sovQuarantine(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QuarantinedFunds) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovQuarantine(uint64(l)) + } + if len(m.UnacceptedFromAddresses) > 0 { + for _, s := range m.UnacceptedFromAddresses { + l = len(s) + n += 1 + l + sovQuarantine(uint64(l)) + } + } + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovQuarantine(uint64(l)) + } + } + if m.Declined { + n += 2 + } + return n +} + +func (m *AutoResponseEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovQuarantine(uint64(l)) + } + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovQuarantine(uint64(l)) + } + if m.Response != 0 { + n += 1 + sovQuarantine(uint64(m.Response)) + } + return n +} + +func (m *AutoResponseUpdate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovQuarantine(uint64(l)) + } + if m.Response != 0 { + n += 1 + sovQuarantine(uint64(m.Response)) + } + return n +} + +func (m *QuarantineRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.UnacceptedFromAddresses) > 0 { + for _, b := range m.UnacceptedFromAddresses { + l = len(b) + n += 1 + l + sovQuarantine(uint64(l)) + } + } + if len(m.AcceptedFromAddresses) > 0 { + for _, b := range m.AcceptedFromAddresses { + l = len(b) + n += 1 + l + sovQuarantine(uint64(l)) + } + } + if len(m.Coins) > 0 { + for _, e := range m.Coins { + l = e.Size() + n += 1 + l + sovQuarantine(uint64(l)) + } + } + if m.Declined { + n += 2 + } + return n +} + +func (m *QuarantineRecordSuffixIndex) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.RecordSuffixes) > 0 { + for _, b := range m.RecordSuffixes { + l = len(b) + n += 1 + l + sovQuarantine(uint64(l)) + } + } + return n +} + +func sovQuarantine(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuarantine(x uint64) (n int) { + return sovQuarantine(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QuarantinedFunds) 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 ErrIntOverflowQuarantine + } + 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: QuarantinedFunds: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuarantinedFunds: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + 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 ErrInvalidLengthQuarantine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnacceptedFromAddresses", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + 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 ErrInvalidLengthQuarantine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UnacceptedFromAddresses = append(m.UnacceptedFromAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuarantine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Declined", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Declined = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuarantine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuarantine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AutoResponseEntry) 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 ErrIntOverflowQuarantine + } + 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: AutoResponseEntry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AutoResponseEntry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + 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 ErrInvalidLengthQuarantine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + 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 ErrInvalidLengthQuarantine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Response", wireType) + } + m.Response = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Response |= AutoResponse(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuarantine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuarantine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AutoResponseUpdate) 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 ErrIntOverflowQuarantine + } + 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: AutoResponseUpdate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AutoResponseUpdate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + 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 ErrInvalidLengthQuarantine + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Response", wireType) + } + m.Response = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Response |= AutoResponse(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuarantine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuarantine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuarantineRecord) 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 ErrIntOverflowQuarantine + } + 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: QuarantineRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuarantineRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field UnacceptedFromAddresses", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuarantine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.UnacceptedFromAddresses = append(m.UnacceptedFromAddresses, make([]byte, postIndex-iNdEx)) + copy(m.UnacceptedFromAddresses[len(m.UnacceptedFromAddresses)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AcceptedFromAddresses", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuarantine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AcceptedFromAddresses = append(m.AcceptedFromAddresses, make([]byte, postIndex-iNdEx)) + copy(m.AcceptedFromAddresses[len(m.AcceptedFromAddresses)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Coins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuarantine + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Coins = append(m.Coins, types.Coin{}) + if err := m.Coins[len(m.Coins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Declined", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Declined = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuarantine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuarantine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuarantineRecordSuffixIndex) 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 ErrIntOverflowQuarantine + } + 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: QuarantineRecordSuffixIndex: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuarantineRecordSuffixIndex: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RecordSuffixes", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuarantine + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthQuarantine + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthQuarantine + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RecordSuffixes = append(m.RecordSuffixes, make([]byte, postIndex-iNdEx)) + copy(m.RecordSuffixes[len(m.RecordSuffixes)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuarantine(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuarantine + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuarantine(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, ErrIntOverflowQuarantine + } + 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, ErrIntOverflowQuarantine + } + 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, ErrIntOverflowQuarantine + } + 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, ErrInvalidLengthQuarantine + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuarantine + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuarantine + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuarantine = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuarantine = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuarantine = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/quarantine/quarantine_test.go b/x/quarantine/quarantine_test.go new file mode 100644 index 0000000000..4c8764d8d5 --- /dev/null +++ b/x/quarantine/quarantine_test.go @@ -0,0 +1,4164 @@ +package quarantine_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/assert" + + . "github.com/cosmos/cosmos-sdk/x/quarantine" + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +type coinMaker func() sdk.Coins + +var ( + coinMakerOK coinMaker = func() sdk.Coins { return sdk.NewCoins(sdk.NewInt64Coin("okcoin", 100)) } + coinMakerMulti coinMaker = func() sdk.Coins { + return sdk.NewCoins(sdk.NewInt64Coin("multicoina", 33), sdk.NewInt64Coin("multicoinb", 67)) + } + coinMakerEmpty coinMaker = func() sdk.Coins { return sdk.Coins{} } + coinMakerNil coinMaker = func() sdk.Coins { return nil } + coinMakerBad coinMaker = func() sdk.Coins { return sdk.Coins{sdk.Coin{Denom: "badcoin", Amount: sdk.NewInt(-1)}} } +) + +func TestContainsAddress(t *testing.T) { + // Technically, if containsAddress breaks, a lot of other tests should also break, + // but I figure it's better safe than sorry. + addrShort0 := MakeTestAddr("cs", 0) + addrShort1 := MakeTestAddr("cs", 1) + addrLong2 := MakeLongAddr("cs", 2) + addrLong3 := MakeLongAddr("cs", 3) + addrEmpty := make(sdk.AccAddress, 0) + addrShort0Almost := MakeCopyOfAccAddress(addrShort0) + addrShort0Almost[len(addrShort0Almost)-1]++ + addr2Almost := MakeCopyOfAccAddress(addrLong2) + addr2Almost[len(addr2Almost)-1]++ + + tests := []struct { + name string + addrs []sdk.AccAddress + addrToFind sdk.AccAddress + expected bool + }{ + { + name: "nil | nil", + addrs: nil, + addrToFind: nil, + expected: false, + }, + { + name: "nil | empty addr", + addrs: nil, + addrToFind: addrEmpty, + expected: false, + }, + { + name: "nil | short", + addrs: nil, + addrToFind: addrShort0, + expected: false, + }, + { + name: "nil | long", + addrs: nil, + addrToFind: addrLong2, + expected: false, + }, + { + name: "empty addr | empty addr", + addrs: []sdk.AccAddress{addrEmpty}, + addrToFind: addrEmpty, + expected: true, + }, + { + name: "empty | nil", + addrs: []sdk.AccAddress{}, + addrToFind: nil, + expected: false, + }, + { + name: "empty | empty addr", + addrs: []sdk.AccAddress{}, + addrToFind: addrEmpty, + expected: false, + }, + { + name: "empty | short", + addrs: []sdk.AccAddress{}, + addrToFind: addrShort0, + expected: false, + }, + { + name: "empty | long", + addrs: []sdk.AccAddress{}, + addrToFind: addrLong2, + expected: false, + }, + { + name: "short0 | nil", + addrs: []sdk.AccAddress{addrShort0}, + addrToFind: nil, + expected: false, + }, + { + name: "short0 | empty addr", + addrs: []sdk.AccAddress{addrShort0}, + addrToFind: addrEmpty, + expected: false, + }, + { + name: "short0 | short0", + addrs: []sdk.AccAddress{addrShort0}, + addrToFind: addrShort0, + expected: true, + }, + { + name: "short0 | short0 almost", + addrs: []sdk.AccAddress{addrShort0}, + addrToFind: addrShort0Almost, + expected: false, + }, + { + name: "short0 | short1", + addrs: []sdk.AccAddress{addrShort0}, + addrToFind: addrShort1, + expected: false, + }, + { + name: "short0 | long", + addrs: []sdk.AccAddress{addrShort0}, + addrToFind: addrLong2, + expected: false, + }, + { + name: "long2 | nil", + addrs: []sdk.AccAddress{addrLong2}, + addrToFind: nil, + expected: false, + }, + { + name: "long2 | empty addr", + addrs: []sdk.AccAddress{addrLong2}, + addrToFind: addrEmpty, + expected: false, + }, + { + name: "long2 | long2", + addrs: []sdk.AccAddress{addrLong2}, + addrToFind: addrLong2, + expected: true, + }, + { + name: "long2 | long2 almost", + addrs: []sdk.AccAddress{addrLong2}, + addrToFind: addr2Almost, + expected: false, + }, + { + name: "long2 | long3", + addrs: []sdk.AccAddress{addrLong2}, + addrToFind: addrLong3, + expected: false, + }, + { + name: "long2 | short", + addrs: []sdk.AccAddress{addrLong2}, + addrToFind: addrShort0, + expected: false, + }, + { + name: "short0 long3 short1 long2 | empty", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addrEmpty, + expected: false, + }, + { + name: "short0 long3 short1 long2 | short0", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addrShort0, + expected: true, + }, + { + name: "short0 long3 short1 long2 | short1", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addrShort1, + expected: true, + }, + { + name: "short0 long3 short1 long2 | long2", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addrLong2, + expected: true, + }, + { + name: "short0 long3 short1 long2 | long3", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addrLong3, + expected: true, + }, + { + name: "short0 long3 short1 long2 | short0 almost", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addrShort0Almost, + expected: false, + }, + { + name: "short0 long3 short1 long2 | long2 almost", + addrs: []sdk.AccAddress{addrShort0, addrLong3, addrShort1, addrLong2}, + addrToFind: addr2Almost, + expected: false, + }, + { + name: "long3 empty long3 | short1", + addrs: []sdk.AccAddress{addrLong3, addrEmpty, addrLong3}, + addrToFind: addrShort1, + expected: false, + }, + { + name: "long3 empty long3 | long2", + addrs: []sdk.AccAddress{addrLong3, addrEmpty, addrLong3}, + addrToFind: addrLong2, + expected: false, + }, + { + name: "long3 empty long3 | long3", + addrs: []sdk.AccAddress{addrLong3, addrEmpty, addrLong3}, + addrToFind: addrLong3, + expected: true, + }, + { + name: "long3 empty long3 | empty", + addrs: []sdk.AccAddress{addrLong3, addrEmpty, addrLong3}, + addrToFind: addrEmpty, + expected: true, + }, + { + name: "long3 empty long3 | nil", + addrs: []sdk.AccAddress{addrLong3, addrEmpty, addrLong3}, + addrToFind: nil, + expected: true, + }, + { + name: "short0 almost short0 almost long2 almost | short0", + addrs: []sdk.AccAddress{addrShort0Almost, addrShort0Almost, addr2Almost}, + addrToFind: addrShort0, + expected: false, + }, + { + name: "short0 almost short0 almost long2 almost | short0 almost", + addrs: []sdk.AccAddress{addrShort0Almost, addrShort0Almost, addr2Almost}, + addrToFind: addrShort0Almost, + expected: true, + }, + { + name: "short0 almost short0 almost long2 almost | long2", + addrs: []sdk.AccAddress{addrShort0Almost, addrShort0Almost, addr2Almost}, + addrToFind: addrLong2, + expected: false, + }, + { + name: "short0 almost short0 almost long2 almost | long2 almost", + addrs: []sdk.AccAddress{addrShort0Almost, addrShort0Almost, addr2Almost}, + addrToFind: addr2Almost, + expected: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + origSuffixes := MakeCopyOfAccAddresses(tc.addrs) + origSuffixToFind := MakeCopyOfAccAddress(tc.addrToFind) + + actual := ContainsAddress(tc.addrs, tc.addrToFind) + assert.Equal(t, tc.expected, actual, "containsSuffix result") + assert.Equal(t, origSuffixes, tc.addrs, "addrs before and after containsSuffix") + assert.Equal(t, origSuffixToFind, tc.addrToFind, "addrToFind before and after containsSuffix") + }) + } +} + +func TestFindAddresses(t *testing.T) { + addr0 := MakeTestAddr("fa", 0) + addr1 := MakeTestAddr("fa", 1) + addr2 := MakeTestAddr("fa", 2) + addr3 := MakeTestAddr("fa", 3) + addr4 := MakeTestAddr("fa", 4) + addr5 := MakeTestAddr("fa", 5) + + tests := []struct { + name string + allAddrs []sdk.AccAddress + addrsToFind []sdk.AccAddress + found []sdk.AccAddress + leftover []sdk.AccAddress + }{ + { + name: "nil nil", + allAddrs: nil, + addrsToFind: nil, + found: nil, + leftover: nil, + }, + { + name: "nil empty", + allAddrs: nil, + addrsToFind: []sdk.AccAddress{}, + found: nil, + leftover: nil, + }, + { + name: "empty nil", + allAddrs: []sdk.AccAddress{}, + addrsToFind: nil, + found: nil, + leftover: nil, + }, + { + name: "empty empty", + allAddrs: []sdk.AccAddress{}, + addrsToFind: []sdk.AccAddress{}, + found: nil, + leftover: nil, + }, + { + name: "two nil", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: nil, + found: nil, + leftover: []sdk.AccAddress{addr0, addr1}, + }, + { + name: "two empty", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{}, + found: nil, + leftover: []sdk.AccAddress{addr0, addr1}, + }, + { + name: "two first", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr0}, + found: []sdk.AccAddress{addr0}, + leftover: []sdk.AccAddress{addr1}, + }, + { + name: "two second", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr1}, + found: []sdk.AccAddress{addr1}, + leftover: []sdk.AccAddress{addr0}, + }, + { + name: "two other", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr2}, + found: nil, + leftover: []sdk.AccAddress{addr0, addr1}, + }, + { + name: "two first second", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr0, addr1}, + found: []sdk.AccAddress{addr0, addr1}, + leftover: nil, + }, + { + name: "two second first", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr1, addr0}, + found: []sdk.AccAddress{addr0, addr1}, + leftover: nil, + }, + { + name: "two first second first", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr0, addr1, addr0}, + found: []sdk.AccAddress{addr0, addr1}, + leftover: nil, + }, + { + name: "two first first", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr0, addr0}, + found: []sdk.AccAddress{addr0}, + leftover: []sdk.AccAddress{addr1}, + }, + { + name: "two second second", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr1, addr1}, + found: []sdk.AccAddress{addr1}, + leftover: []sdk.AccAddress{addr0}, + }, + { + name: "two first other", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr0, addr2}, + found: []sdk.AccAddress{addr0}, + leftover: []sdk.AccAddress{addr1}, + }, + { + name: "two second other", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr1, addr2}, + found: []sdk.AccAddress{addr1}, + leftover: []sdk.AccAddress{addr0}, + }, + { + name: "two other first", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr2, addr0}, + found: []sdk.AccAddress{addr0}, + leftover: []sdk.AccAddress{addr1}, + }, + { + name: "two other second", + allAddrs: []sdk.AccAddress{addr0, addr1}, + addrsToFind: []sdk.AccAddress{addr2, addr1}, + found: []sdk.AccAddress{addr1}, + leftover: []sdk.AccAddress{addr0}, + }, + { + name: "four other third other", + allAddrs: []sdk.AccAddress{addr0, addr1, addr2, addr3}, + addrsToFind: []sdk.AccAddress{addr4, addr2, addr5}, + found: []sdk.AccAddress{addr2}, + leftover: []sdk.AccAddress{addr0, addr1, addr3}, + }, + { + name: "dups in allAddrs", + allAddrs: []sdk.AccAddress{addr0, addr1, addr0, addr1, addr2}, + addrsToFind: []sdk.AccAddress{addr0, addr1}, + found: []sdk.AccAddress{addr0, addr1, addr0, addr1}, + leftover: []sdk.AccAddress{addr2}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + allAddrsOrig := MakeCopyOfAccAddresses(tc.allAddrs) + addrsToFindOrig := MakeCopyOfAccAddresses(tc.addrsToFind) + found, leftover := FindAddresses(tc.allAddrs, tc.addrsToFind) + assert.Equal(t, tc.found, found, "found") + assert.Equal(t, tc.leftover, leftover, "leftover") + assert.Equal(t, allAddrsOrig, tc.allAddrs, "allAddrs before and after findAddresses") + assert.Equal(t, addrsToFindOrig, tc.addrsToFind, "addrsToFindOrig before and after findAddresses") + }) + } +} + +func TestContainsSuffix(t *testing.T) { + // Technically, if containsSuffix breaks, a lot of other tests should also break, + // but I figure it's better safe than sorry. + suffixShort0 := []byte(MakeTestAddr("cs", 0)) + suffixShort1 := []byte(MakeTestAddr("cs", 1)) + suffixLong2 := []byte(MakeLongAddr("cs", 2)) + suffixLong3 := []byte(MakeLongAddr("cs", 3)) + suffixEmpty := make([]byte, 0) + suffixShort0Almost := MakeCopyOfByteSlice(suffixShort0) + suffixShort0Almost[len(suffixShort0Almost)-1]++ + suffixLong2Almost := MakeCopyOfByteSlice(suffixLong2) + suffixLong2Almost[len(suffixLong2Almost)-1]++ + + tests := []struct { + name string + suffixes [][]byte + suffixToFind []byte + expected bool + }{ + { + name: "nil | nil", + suffixes: nil, + suffixToFind: nil, + expected: false, + }, + { + name: "nil | empty suffix", + suffixes: nil, + suffixToFind: suffixEmpty, + expected: false, + }, + { + name: "nil | short", + suffixes: nil, + suffixToFind: suffixShort0, + expected: false, + }, + { + name: "nil | long", + suffixes: nil, + suffixToFind: suffixLong2, + expected: false, + }, + { + name: "empty suffix | empty suffix", + suffixes: [][]byte{suffixEmpty}, + suffixToFind: suffixEmpty, + expected: true, + }, + { + name: "empty | nil", + suffixes: [][]byte{}, + suffixToFind: nil, + expected: false, + }, + { + name: "empty | empty suffix", + suffixes: [][]byte{}, + suffixToFind: suffixEmpty, + expected: false, + }, + { + name: "empty | short", + suffixes: [][]byte{}, + suffixToFind: suffixShort0, + expected: false, + }, + { + name: "empty | long", + suffixes: [][]byte{}, + suffixToFind: suffixLong2, + expected: false, + }, + { + name: "short0 | nil", + suffixes: [][]byte{suffixShort0}, + suffixToFind: nil, + expected: false, + }, + { + name: "short0 | empty suffix", + suffixes: [][]byte{suffixShort0}, + suffixToFind: suffixEmpty, + expected: false, + }, + { + name: "short0 | short0", + suffixes: [][]byte{suffixShort0}, + suffixToFind: suffixShort0, + expected: true, + }, + { + name: "short0 | short0 almost", + suffixes: [][]byte{suffixShort0}, + suffixToFind: suffixShort0Almost, + expected: false, + }, + { + name: "short0 | short1", + suffixes: [][]byte{suffixShort0}, + suffixToFind: suffixShort1, + expected: false, + }, + { + name: "short0 | long", + suffixes: [][]byte{suffixShort0}, + suffixToFind: suffixLong2, + expected: false, + }, + { + name: "long2 | nil", + suffixes: [][]byte{suffixLong2}, + suffixToFind: nil, + expected: false, + }, + { + name: "long2 | empty suffix", + suffixes: [][]byte{suffixLong2}, + suffixToFind: suffixEmpty, + expected: false, + }, + { + name: "long2 | long2", + suffixes: [][]byte{suffixLong2}, + suffixToFind: suffixLong2, + expected: true, + }, + { + name: "long2 | long2 almost", + suffixes: [][]byte{suffixLong2}, + suffixToFind: suffixLong2Almost, + expected: false, + }, + { + name: "long2 | long3", + suffixes: [][]byte{suffixLong2}, + suffixToFind: suffixLong3, + expected: false, + }, + { + name: "long2 | short", + suffixes: [][]byte{suffixLong2}, + suffixToFind: suffixShort0, + expected: false, + }, + { + name: "short0 long3 short1 long2 | empty", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixEmpty, + expected: false, + }, + { + name: "short0 long3 short1 long2 | short0", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixShort0, + expected: true, + }, + { + name: "short0 long3 short1 long2 | short1", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixShort1, + expected: true, + }, + { + name: "short0 long3 short1 long2 | long2", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixLong2, + expected: true, + }, + { + name: "short0 long3 short1 long2 | long3", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixLong3, + expected: true, + }, + { + name: "short0 long3 short1 long2 | short0 almost", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixShort0Almost, + expected: false, + }, + { + name: "short0 long3 short1 long2 | long2 almost", + suffixes: [][]byte{suffixShort0, suffixLong3, suffixShort1, suffixLong2}, + suffixToFind: suffixLong2Almost, + expected: false, + }, + { + name: "long3 empty long3 | short1", + suffixes: [][]byte{suffixLong3, suffixEmpty, suffixLong3}, + suffixToFind: suffixShort1, + expected: false, + }, + { + name: "long3 empty long3 | long2", + suffixes: [][]byte{suffixLong3, suffixEmpty, suffixLong3}, + suffixToFind: suffixLong2, + expected: false, + }, + { + name: "long3 empty long3 | long3", + suffixes: [][]byte{suffixLong3, suffixEmpty, suffixLong3}, + suffixToFind: suffixLong3, + expected: true, + }, + { + name: "long3 empty long3 | empty", + suffixes: [][]byte{suffixLong3, suffixEmpty, suffixLong3}, + suffixToFind: suffixEmpty, + expected: true, + }, + { + name: "long3 empty long3 | nil", + suffixes: [][]byte{suffixLong3, suffixEmpty, suffixLong3}, + suffixToFind: nil, + expected: true, + }, + { + name: "short0 almost short0 almost long2 almost | short0", + suffixes: [][]byte{suffixShort0Almost, suffixShort0Almost, suffixLong2Almost}, + suffixToFind: suffixShort0, + expected: false, + }, + { + name: "short0 almost short0 almost long2 almost | short0 almost", + suffixes: [][]byte{suffixShort0Almost, suffixShort0Almost, suffixLong2Almost}, + suffixToFind: suffixShort0Almost, + expected: true, + }, + { + name: "short0 almost short0 almost long2 almost | long2", + suffixes: [][]byte{suffixShort0Almost, suffixShort0Almost, suffixLong2Almost}, + suffixToFind: suffixLong2, + expected: false, + }, + { + name: "short0 almost short0 almost long2 almost | long2 almost", + suffixes: [][]byte{suffixShort0Almost, suffixShort0Almost, suffixLong2Almost}, + suffixToFind: suffixLong2Almost, + expected: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + origSuffixes := MakeCopyOfByteSliceSlice(tc.suffixes) + origSuffixToFind := MakeCopyOfByteSlice(tc.suffixToFind) + + actual := ContainsSuffix(tc.suffixes, tc.suffixToFind) + assert.Equal(t, tc.expected, actual, "containsSuffix result") + assert.Equal(t, origSuffixes, tc.suffixes, "suffixes before and after containsSuffix") + assert.Equal(t, origSuffixToFind, tc.suffixToFind, "suffixToFind before and after containsSuffix") + }) + } +} + +func TestNewQuarantinedFunds(t *testing.T) { + testAddr0 := MakeTestAddr("nqf", 0) + testAddr1 := MakeTestAddr("nqf", 1) + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddrs []sdk.AccAddress + Coins sdk.Coins + declined bool + expected *QuarantinedFunds + }{ + { + name: "control", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{testAddr1}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 88)), + declined: false, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 88)), + Declined: false, + }, + }, + { + name: "declined true", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{testAddr1}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 87)), + declined: true, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 87)), + Declined: true, + }, + }, + { + name: "nil toAddr", + toAddr: nil, + fromAddrs: []sdk.AccAddress{testAddr1}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 86)), + declined: false, + expected: &QuarantinedFunds{ + ToAddress: "", + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 86)), + Declined: false, + }, + }, + { + name: "nil fromAddrs", + toAddr: testAddr0, + fromAddrs: nil, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 85)), + declined: false, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 85)), + Declined: false, + }, + }, + { + name: "empty fromAddrs", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 85)), + declined: false, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{}, + Coins: sdk.NewCoins(sdk.NewInt64Coin("rando", 85)), + Declined: false, + }, + }, + { + name: "empty coins", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{testAddr1}, + Coins: sdk.Coins{}, + declined: false, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: sdk.Coins{}, + Declined: false, + }, + }, + { + name: "nil coins", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{testAddr1}, + Coins: nil, + declined: false, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: nil, + Declined: false, + }, + }, + { + name: "invalid coins", + toAddr: testAddr0, + fromAddrs: []sdk.AccAddress{testAddr1}, + Coins: sdk.Coins{sdk.Coin{Denom: "bad", Amount: sdk.NewInt(-1)}}, + declined: false, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: sdk.Coins{sdk.Coin{Denom: "bad", Amount: sdk.NewInt(-1)}}, + Declined: false, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewQuarantinedFunds(tc.toAddr, tc.fromAddrs, tc.Coins, tc.declined) + assert.Equal(t, tc.expected, actual, "NewQuarantinedFunds") + }) + } +} + +func TestQuarantinedFunds_Validate(t *testing.T) { + testAddr0 := MakeTestAddr("qfv", 0).String() + testAddr1 := MakeTestAddr("qfv", 1).String() + testAddr2 := MakeTestAddr("qfv", 2).String() + + tests := []struct { + name string + qf *QuarantinedFunds + expectedInErr []string + }{ + { + name: "control", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "declined true", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + expectedInErr: nil, + }, + { + name: "bad to address", + qf: &QuarantinedFunds{ + ToAddress: "notgonnawork", + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "empty to address", + qf: &QuarantinedFunds{ + ToAddress: "", + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "bad from address", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{"alsonotgood"}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"invalid unaccepted from address[0]"}, + }, + { + name: "empty from address", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{""}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"invalid unaccepted from address[0]"}, + }, + { + name: "nil from addresses", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"at least one unaccepted from address is required", "invalid value"}, + }, + { + name: "empty from addresses", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"at least one unaccepted from address is required", "invalid value"}, + }, + { + name: "two from addresses both good", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1, testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "two same from addresses", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr2, testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"duplicate unaccepted from address", testAddr2}, + }, + { + name: "three from addresses same first last", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1, testAddr2, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"duplicate unaccepted from address", testAddr1}, + }, + { + name: "two from addresses first bad", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{"this is not an address", testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"invalid unaccepted from address[0]"}, + }, + { + name: "two from addresses last bad", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1, "this is also bad"}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"invalid unaccepted from address[1]"}, + }, + { + name: "empty coins", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerEmpty(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "nil coins", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerNil(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "bad coins", + qf: &QuarantinedFunds{ + ToAddress: testAddr0, + UnacceptedFromAddresses: []string{testAddr1}, + Coins: coinMakerBad(), + Declined: false, + }, + expectedInErr: []string{coinMakerBad().String(), "amount is not positive"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + qfOrig := MakeCopyOfQuarantinedFunds(tc.qf) + err := tc.qf.Validate() + AssertErrorContents(t, err, tc.expectedInErr, "Validate") + assert.Equal(t, qfOrig, tc.qf, "QuarantinedFunds before and after") + }) + } +} + +func TestNewAutoResponseEntry(t *testing.T) { + testAddr0 := MakeTestAddr("nare", 0) + testAddr1 := MakeTestAddr("nare", 1) + + tests := []struct { + name string + toAddr sdk.AccAddress + fromAddr sdk.AccAddress + resp AutoResponse + expected *AutoResponseEntry + }{ + { + name: "accept", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_ACCEPT, + expected: &AutoResponseEntry{ + ToAddress: testAddr0.String(), + FromAddress: testAddr1.String(), + Response: AUTO_RESPONSE_ACCEPT, + }, + }, + { + name: "decline", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_DECLINE, + expected: &AutoResponseEntry{ + ToAddress: testAddr0.String(), + FromAddress: testAddr1.String(), + Response: AUTO_RESPONSE_DECLINE, + }, + }, + { + name: "unspecified", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_UNSPECIFIED, + expected: &AutoResponseEntry{ + ToAddress: testAddr0.String(), + FromAddress: testAddr1.String(), + Response: AUTO_RESPONSE_UNSPECIFIED, + }, + }, + { + name: "nil to address", + toAddr: nil, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_ACCEPT, + expected: &AutoResponseEntry{ + ToAddress: "", + FromAddress: testAddr1.String(), + Response: AUTO_RESPONSE_ACCEPT, + }, + }, + { + name: "nil from address", + toAddr: testAddr0, + fromAddr: nil, + resp: AUTO_RESPONSE_DECLINE, + expected: &AutoResponseEntry{ + ToAddress: testAddr0.String(), + FromAddress: "", + Response: AUTO_RESPONSE_DECLINE, + }, + }, + { + name: "weird response", + toAddr: testAddr1, + fromAddr: testAddr0, + resp: -3, + expected: &AutoResponseEntry{ + ToAddress: testAddr1.String(), + FromAddress: testAddr0.String(), + Response: -3, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := NewAutoResponseEntry(tc.toAddr, tc.fromAddr, tc.resp) + assert.Equal(t, tc.expected, actual, "NewAutoResponseEntry") + }) + } +} + +func TestAutoResponseEntry_Validate(t *testing.T) { + testAddr0 := MakeTestAddr("arev", 0).String() + testAddr1 := MakeTestAddr("arev", 1).String() + + tests := []struct { + name string + toAddr string + fromAddr string + resp AutoResponse + qf QuarantinedFunds + expectedInErr []string + }{ + { + name: "accept", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_ACCEPT, + expectedInErr: nil, + }, + { + name: "decline", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_DECLINE, + expectedInErr: nil, + }, + { + name: "unspecified", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: AUTO_RESPONSE_UNSPECIFIED, + expectedInErr: nil, + }, + { + name: "bad to address", + toAddr: "notgonnawork", + fromAddr: testAddr1, + resp: AUTO_RESPONSE_ACCEPT, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "empty to address", + toAddr: "", + fromAddr: testAddr1, + resp: AUTO_RESPONSE_DECLINE, + expectedInErr: []string{"invalid to address"}, + }, + { + name: "bad from address", + toAddr: testAddr0, + fromAddr: "alsonotgood", + resp: AUTO_RESPONSE_UNSPECIFIED, + expectedInErr: []string{"invalid from address"}, + }, + { + name: "empty from address", + toAddr: testAddr0, + fromAddr: "", + resp: AUTO_RESPONSE_ACCEPT, + expectedInErr: []string{"invalid from address"}, + }, + { + name: "negative response", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: -1, + expectedInErr: []string{"unknown auto-response value", "-1"}, + }, + { + name: "response too large", + toAddr: testAddr0, + fromAddr: testAddr1, + resp: 3, + expectedInErr: []string{"unknown auto-response value", "3"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + entryOrig := AutoResponseEntry{ + ToAddress: tc.toAddr, + FromAddress: tc.fromAddr, + Response: tc.resp, + } + entry := AutoResponseEntry{ + ToAddress: tc.toAddr, + FromAddress: tc.fromAddr, + Response: tc.resp, + } + err := entry.Validate() + AssertErrorContents(t, err, tc.expectedInErr, "Validate") + assert.Equal(t, entryOrig, entry, "AutoResponseEntry before and after") + }) + } +} + +func TestAutoResponseUpdate_Validate(t *testing.T) { + testAddr0 := MakeTestAddr("arev", 0).String() + testAddr1 := MakeTestAddr("arev", 1).String() + + tests := []struct { + name string + fromAddr string + resp AutoResponse + qf QuarantinedFunds + expectedInErr []string + }{ + { + name: "accept", + fromAddr: testAddr0, + resp: AUTO_RESPONSE_ACCEPT, + expectedInErr: nil, + }, + { + name: "decline", + fromAddr: testAddr1, + resp: AUTO_RESPONSE_DECLINE, + expectedInErr: nil, + }, + { + name: "unspecified", + fromAddr: testAddr0, + resp: AUTO_RESPONSE_UNSPECIFIED, + expectedInErr: nil, + }, + { + name: "bad from address", + fromAddr: "yupnotgood", + resp: AUTO_RESPONSE_UNSPECIFIED, + expectedInErr: []string{"invalid from address"}, + }, + { + name: "empty from address", + fromAddr: "", + resp: AUTO_RESPONSE_ACCEPT, + expectedInErr: []string{"invalid from address"}, + }, + { + name: "negative response", + fromAddr: testAddr1, + resp: -1, + expectedInErr: []string{"unknown auto-response value", "-1"}, + }, + { + name: "response too large", + fromAddr: testAddr0, + resp: 3, + expectedInErr: []string{"unknown auto-response value", "3"}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + updateOrig := AutoResponseUpdate{ + FromAddress: tc.fromAddr, + Response: tc.resp, + } + update := AutoResponseUpdate{ + FromAddress: tc.fromAddr, + Response: tc.resp, + } + err := update.Validate() + AssertErrorContents(t, err, tc.expectedInErr, "Validate") + assert.Equal(t, updateOrig, update, "AutoResponseUpdate before and after") + }) + } +} + +func TestAutoBValues(t *testing.T) { + // If these were the same, it'd be bad. + assert.NotEqual(t, NoAutoB, AutoAcceptB, "NoAutoB vs AutoAcceptB") + assert.NotEqual(t, NoAutoB, AutoDeclineB, "NoAutoB vs AutoDeclineB") + assert.NotEqual(t, AutoAcceptB, AutoDeclineB, "AutoAcceptB vs AutoDeclineB") +} + +func TestToAutoB(t *testing.T) { + tests := []struct { + name string + r AutoResponse + expected byte + }{ + { + name: "accept", + r: AUTO_RESPONSE_ACCEPT, + expected: AutoAcceptB, + }, + { + name: "decline", + r: AUTO_RESPONSE_DECLINE, + expected: AutoDeclineB, + }, + { + name: "unspecified", + r: AUTO_RESPONSE_UNSPECIFIED, + expected: NoAutoB, + }, + { + name: "negative", + r: -1, + expected: NoAutoB, + }, + { + name: "too large", + r: 3, + expected: NoAutoB, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := ToAutoB(tc.r) + assert.Equal(t, tc.expected, actual, "ToAutoB(%s)", tc.r) + }) + } +} + +func TestAutoResponseValues(t *testing.T) { + // If these were the same, it'd be bad. + assert.NotEqual(t, AUTO_RESPONSE_UNSPECIFIED, AUTO_RESPONSE_ACCEPT, "AUTO_RESPONSE_UNSPECIFIED vs AUTO_RESPONSE_ACCEPT") + assert.NotEqual(t, AUTO_RESPONSE_UNSPECIFIED, AUTO_RESPONSE_DECLINE, "AUTO_RESPONSE_UNSPECIFIED vs AUTO_RESPONSE_DECLINE") + assert.NotEqual(t, AUTO_RESPONSE_ACCEPT, AUTO_RESPONSE_DECLINE, "AUTO_RESPONSE_ACCEPT vs AUTO_RESPONSE_DECLINE") +} + +func TestToAutoResponse(t *testing.T) { + tests := []struct { + name string + bz []byte + expected AutoResponse + }{ + { + name: "AutoAcceptB", + bz: []byte{AutoAcceptB}, + expected: AUTO_RESPONSE_ACCEPT, + }, + { + name: "AutoDeclineB", + bz: []byte{AutoDeclineB}, + expected: AUTO_RESPONSE_DECLINE, + }, + { + name: "NoAutoB", + bz: []byte{NoAutoB}, + expected: AUTO_RESPONSE_UNSPECIFIED, + }, + { + name: "something else", + bz: []byte{0x7d}, + expected: AUTO_RESPONSE_UNSPECIFIED, + }, + { + name: "nil", + bz: nil, + expected: AUTO_RESPONSE_UNSPECIFIED, + }, + { + name: "empty", + bz: []byte{}, + expected: AUTO_RESPONSE_UNSPECIFIED, + }, + { + name: "too long", + bz: []byte{AutoAcceptB, AutoAcceptB}, + expected: AUTO_RESPONSE_UNSPECIFIED, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := ToAutoResponse(tc.bz) + assert.Equal(t, tc.expected, actual, "ToAutoResponse(%v)", tc.bz) + }) + } +} + +func TestAutoResponse_IsValid(t *testing.T) { + tests := []struct { + name string + r AutoResponse + expected bool + }{ + { + name: "accept", + r: AUTO_RESPONSE_ACCEPT, + expected: true, + }, + { + name: "decline", + r: AUTO_RESPONSE_DECLINE, + expected: true, + }, + { + name: "unspecified", + r: AUTO_RESPONSE_UNSPECIFIED, + expected: true, + }, + { + name: "negative", + r: -1, + expected: false, + }, + { + name: "too large", + r: 3, + expected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + r := tc.r + actual := r.IsValid() + assert.Equal(t, tc.expected, actual, "%s.IsValid", tc.r) + assert.Equal(t, tc.r, r, "AutoResponse before and after") + }) + } +} + +func TestAutoResponse_IsAccept(t *testing.T) { + tests := []struct { + name string + r AutoResponse + expected bool + }{ + { + name: "accept", + r: AUTO_RESPONSE_ACCEPT, + expected: true, + }, + { + name: "decline", + r: AUTO_RESPONSE_DECLINE, + expected: false, + }, + { + name: "unspecified", + r: AUTO_RESPONSE_UNSPECIFIED, + expected: false, + }, + { + name: "negative", + r: -1, + expected: false, + }, + { + name: "too large", + r: 3, + expected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + r := tc.r + actual := r.IsAccept() + assert.Equal(t, tc.expected, actual, "%s.IsAccept", tc.r) + assert.Equal(t, tc.r, r, "AutoResponse before and after") + }) + } +} + +func TestAutoResponse_IsDecline(t *testing.T) { + tests := []struct { + name string + r AutoResponse + expected bool + }{ + { + name: "accept", + r: AUTO_RESPONSE_ACCEPT, + expected: false, + }, + { + name: "decline", + r: AUTO_RESPONSE_DECLINE, + expected: true, + }, + { + name: "unspecified", + r: AUTO_RESPONSE_UNSPECIFIED, + expected: false, + }, + { + name: "negative", + r: -1, + expected: false, + }, + { + name: "too large", + r: 3, + expected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + r := tc.r + actual := r.IsDecline() + assert.Equal(t, tc.expected, actual, "%s.IsDecline", tc.r) + assert.Equal(t, tc.r, r, "AutoResponse before and after") + }) + } +} + +func TestNewQuarantineRecord(t *testing.T) { + testAddr0 := MakeTestAddr("nqr", 0) + testAddr1 := MakeTestAddr("nqr", 1) + + tests := []struct { + name string + uaFromAddrs []string + coins sdk.Coins + declined bool + expected *QuarantineRecord + expPanic string + }{ + { + name: "control", + uaFromAddrs: []string{testAddr0.String()}, + coins: coinMakerOK(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "declined", + uaFromAddrs: []string{testAddr0.String()}, + coins: coinMakerOK(), + declined: true, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "multi coins", + uaFromAddrs: []string{testAddr0.String()}, + coins: coinMakerMulti(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerMulti(), + Declined: false, + }, + }, + { + name: "empty coins", + uaFromAddrs: []string{testAddr0.String()}, + coins: coinMakerEmpty(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerEmpty(), + Declined: false, + }, + }, + { + name: "nil coins", + uaFromAddrs: []string{testAddr0.String()}, + coins: coinMakerNil(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerNil(), + Declined: false, + }, + }, + { + name: "bad coins", + uaFromAddrs: []string{testAddr0.String()}, + coins: coinMakerBad(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerBad(), + Declined: false, + }, + }, + { + name: "bad unaccepted addr panics", + uaFromAddrs: []string{"I'm a bad address"}, + coins: coinMakerOK(), + declined: false, + expPanic: "decoding bech32 failed: string not all lowercase or all uppercase", + }, + { + name: "empty unaccepted addr string panics", + uaFromAddrs: []string{""}, + coins: coinMakerOK(), + declined: false, + expPanic: "empty address string is not allowed", + }, + { + name: "bad second unaccepted addr panics", + uaFromAddrs: []string{testAddr0.String(), "I'm a bad address"}, + coins: coinMakerOK(), + declined: false, + expPanic: "decoding bech32 failed: string not all lowercase or all uppercase", + }, + { + name: "two unaccepted addresses", + uaFromAddrs: []string{testAddr0.String(), testAddr1.String()}, + coins: coinMakerOK(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "empty unaccepted addresses", + uaFromAddrs: []string{}, + coins: coinMakerOK(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "nil unaccepted addresses", + uaFromAddrs: nil, + coins: coinMakerOK(), + declined: false, + expected: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual *QuarantineRecord + testFunc := func() { + actual = NewQuarantineRecord(tc.uaFromAddrs, tc.coins, tc.declined) + } + if len(tc.expPanic) == 0 { + if assert.NotPanics(t, testFunc, "NewQuarantineRecord") { + assert.Equal(t, tc.expected, actual, "NewQuarantineRecord") + } + } else { + assert.PanicsWithError(t, tc.expPanic, testFunc, "NewQuarantineRecord") + } + }) + } +} + +func TestQuarantineRecord_Validate(t *testing.T) { + testAddr0 := MakeTestAddr("qrv", 0) + testAddr1 := MakeTestAddr("qrv", 1) + testAddr2 := MakeTestAddr("qrv", 2) + + tests := []struct { + name string + qr *QuarantineRecord + expectedInErr []string + }{ + { + name: "control", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "declined", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + expectedInErr: nil, + }, + { + name: "no accepted addresses is ok", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "nil accepted addresses is ok", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "multi coins", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerMulti(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "empty coins", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerEmpty(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "nil coins", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerNil(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "bad coins", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerBad(), + Declined: false, + }, + expectedInErr: []string{coinMakerBad().String(), "amount is not positive"}, + }, + { + name: "nil unaccepted addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"at least one unaccepted from address is required"}, + }, + { + name: "empty unaccepted addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: []string{"at least one unaccepted from address is required"}, + }, + { + name: "two unaccepted addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + { + name: "three unaccepted addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1, testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expectedInErr: nil, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + qrOrig := MakeCopyOfQuarantineRecord(tc.qr) + err := tc.qr.Validate() + AssertErrorContents(t, err, tc.expectedInErr, "Validate") + assert.Equal(t, qrOrig, tc.qr, "QuarantineRecord before and after") + }) + } +} + +func TestQuarantineRecord_AddCoins(t *testing.T) { + testAddr0 := MakeTestAddr("qrac", 0) + testAddr1 := MakeTestAddr("qrac", 1) + testAddr2 := MakeTestAddr("qrac", 2) + testAddr3 := MakeTestAddr("qrac", 3) + + keyEmpty := "empty" + keyNil := "nil" + key0Acorn := "0acorn" + key50Acorn := "50acorn" + key32Almond := "32almond" + key8acorn9Almond := "8acorn,9almond" + coinMakerMap := map[string]coinMaker{ + keyEmpty: coinMakerEmpty, + keyNil: coinMakerNil, + key0Acorn: func() sdk.Coins { return sdk.Coins{sdk.NewInt64Coin("acorn", 0)} }, + key50Acorn: func() sdk.Coins { return sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)) }, + key32Almond: func() sdk.Coins { return sdk.NewCoins(sdk.NewInt64Coin("almond", 32)) }, + key8acorn9Almond: func() sdk.Coins { return sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)) }, + } + + tests := []struct { + qrCoinKey string + addCoinKey string + expected sdk.Coins + }{ + // empty + { + qrCoinKey: keyEmpty, + addCoinKey: keyEmpty, + expected: nil, + }, + { + qrCoinKey: keyEmpty, + addCoinKey: keyNil, + expected: nil, + }, + { + qrCoinKey: keyEmpty, + addCoinKey: key0Acorn, + expected: nil, + }, + { + qrCoinKey: keyEmpty, + addCoinKey: key50Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)), + }, + { + qrCoinKey: keyEmpty, + addCoinKey: key32Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: keyEmpty, + addCoinKey: key8acorn9Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)), + }, + + // nil + { + qrCoinKey: keyNil, + addCoinKey: keyEmpty, + expected: nil, + }, + { + qrCoinKey: keyNil, + addCoinKey: keyNil, + expected: nil, + }, + { + qrCoinKey: keyNil, + addCoinKey: key0Acorn, + expected: nil, + }, + { + qrCoinKey: keyNil, + addCoinKey: key50Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)), + }, + { + qrCoinKey: keyNil, + addCoinKey: key32Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: keyNil, + addCoinKey: key8acorn9Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)), + }, + + // 0acorn + { + qrCoinKey: key0Acorn, + addCoinKey: keyEmpty, + expected: nil, + }, + { + qrCoinKey: key0Acorn, + addCoinKey: keyNil, + expected: nil, + }, + { + qrCoinKey: key0Acorn, + addCoinKey: key0Acorn, + expected: nil, + }, + { + qrCoinKey: key0Acorn, + addCoinKey: key50Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)), + }, + { + qrCoinKey: key0Acorn, + addCoinKey: key32Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: key0Acorn, + addCoinKey: key8acorn9Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)), + }, + + // 50acorn + { + qrCoinKey: key50Acorn, + addCoinKey: keyEmpty, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)), + }, + { + qrCoinKey: key50Acorn, + addCoinKey: keyNil, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)), + }, + { + qrCoinKey: key50Acorn, + addCoinKey: key0Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50)), + }, + { + qrCoinKey: key50Acorn, + addCoinKey: key50Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 100)), + }, + { + qrCoinKey: key50Acorn, + addCoinKey: key32Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50), sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: key50Acorn, + addCoinKey: key8acorn9Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 58), sdk.NewInt64Coin("almond", 9)), + }, + + // 32almond + { + qrCoinKey: key32Almond, + addCoinKey: keyEmpty, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: key32Almond, + addCoinKey: keyNil, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: key32Almond, + addCoinKey: key0Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: key32Almond, + addCoinKey: key50Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 50), sdk.NewInt64Coin("almond", 32)), + }, + { + qrCoinKey: key32Almond, + addCoinKey: key32Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("almond", 64)), + }, + { + qrCoinKey: key32Almond, + addCoinKey: key8acorn9Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 41)), + }, + + // 8acorn,9almond + { + qrCoinKey: key8acorn9Almond, + addCoinKey: keyEmpty, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)), + }, + { + qrCoinKey: key8acorn9Almond, + addCoinKey: keyNil, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)), + }, + { + qrCoinKey: key8acorn9Almond, + addCoinKey: key0Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 9)), + }, + { + qrCoinKey: key8acorn9Almond, + addCoinKey: key50Acorn, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 58), sdk.NewInt64Coin("almond", 9)), + }, + { + qrCoinKey: key8acorn9Almond, + addCoinKey: key32Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 8), sdk.NewInt64Coin("almond", 41)), + }, + { + qrCoinKey: key8acorn9Almond, + addCoinKey: key8acorn9Almond, + expected: sdk.NewCoins(sdk.NewInt64Coin("acorn", 16), sdk.NewInt64Coin("almond", 18)), + }, + } + + addressCombos := []struct { + name string + unaccepted []sdk.AccAddress + accepted []sdk.AccAddress + }{ + { + name: "no addresses", + unaccepted: nil, + accepted: nil, + }, + { + name: "one unaccepted", + unaccepted: []sdk.AccAddress{testAddr0}, + accepted: nil, + }, + { + name: "two unaccepted", + unaccepted: []sdk.AccAddress{testAddr0, testAddr1}, + accepted: nil, + }, + { + name: "one accepted", + unaccepted: nil, + accepted: []sdk.AccAddress{testAddr2}, + }, + { + name: "two accepted", + unaccepted: nil, + accepted: []sdk.AccAddress{testAddr2, testAddr3}, + }, + { + name: "one unaccepted one accepted", + unaccepted: []sdk.AccAddress{testAddr0}, + accepted: []sdk.AccAddress{testAddr2}, + }, + { + name: "two unaccepted one accepted", + unaccepted: []sdk.AccAddress{testAddr0, testAddr1}, + accepted: []sdk.AccAddress{testAddr2}, + }, + { + name: "one unaccepted two accepted", + unaccepted: []sdk.AccAddress{testAddr0}, + accepted: []sdk.AccAddress{testAddr2, testAddr3}, + }, + { + name: "two unaccepted two accepted", + unaccepted: []sdk.AccAddress{testAddr0, testAddr1}, + accepted: []sdk.AccAddress{testAddr2, testAddr3}, + }, + } + + for _, tc := range tests { + for _, ac := range addressCombos { + for _, declined := range []bool{false, true} { + name := fmt.Sprintf("%s+%s=%q %t %s", tc.qrCoinKey, tc.addCoinKey, tc.expected.String(), declined, ac.name) + t.Run(name, func(t *testing.T) { + expected := QuarantineRecord{ + UnacceptedFromAddresses: MakeCopyOfAccAddresses(ac.unaccepted), + AcceptedFromAddresses: MakeCopyOfAccAddresses(ac.accepted), + Coins: tc.expected, + Declined: declined, + } + qr := QuarantineRecord{ + UnacceptedFromAddresses: ac.unaccepted, + AcceptedFromAddresses: ac.accepted, + Coins: coinMakerMap[tc.qrCoinKey](), + Declined: declined, + } + addCoinsOrig := coinMakerMap[tc.addCoinKey]() + addCoins := coinMakerMap[tc.addCoinKey]() + qr.AddCoins(addCoins...) + assert.Equal(t, expected, qr, "QuarantineRecord after AddCoins") + assert.Equal(t, addCoinsOrig, addCoins, "Coins before and after") + }) + } + } + } +} + +func TestQuarantineRecord_IsFullyAccepted(t *testing.T) { + testAddr0 := MakeTestAddr("qrifa", 0) + testAddr1 := MakeTestAddr("qrifa", 1) + + tests := []struct { + name string + qr *QuarantineRecord + expected bool + }{ + { + name: "no addresses at all", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + expected: true, + }, + { + name: "one unaccepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + expected: false, + }, + { + name: "one accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expected: true, + }, + { + name: "declined one accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + expected: true, + }, + { + name: "one accepted one unaccepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expected: false, + }, + { + name: "two unaccepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + expected: false, + }, + { + name: "two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + expected: true, + }, + { + name: "declined two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + expected: true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + orig := MakeCopyOfQuarantineRecord(tc.qr) + actual := tc.qr.IsFullyAccepted() + assert.Equal(t, tc.expected, actual, "IsFullyAccepted: %v", tc.qr) + assert.Equal(t, orig, tc.qr, "QuarantineRecord before and after") + }) + } +} + +func TestQuarantineRecord_AcceptFrom(t *testing.T) { + testAddr0 := MakeTestAddr("qraf", 0) + testAddr1 := MakeTestAddr("qraf", 1) + testAddr2 := MakeTestAddr("qraf", 2) + testAddr3 := MakeTestAddr("qraf", 3) + testAddr4 := MakeTestAddr("qraf", 4) + + tests := []struct { + name string + qr *QuarantineRecord + addrs []sdk.AccAddress + exp bool + expQr *QuarantineRecord + }{ + { + name: "control", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "nil addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: nil, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "empty addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{}, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "one addrs only in accepted already", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr1}, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "record has nil addresses", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "one address in both", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted two other provided", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr2, testAddr3}, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted both provided", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr1}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted both provided opposite order", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr1, testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted first provided first with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr3, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted first provided second with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr3, testAddr0, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted first provided third with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr4, testAddr3, testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two same unaccepted provided once", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted second provided first with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr1, testAddr3, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted second provided second with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr3, testAddr1, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two unaccepted second provided third with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr4, testAddr3, testAddr1}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "one unaccepted provided thrice", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr4}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr0, testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr4, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + origInput := MakeCopyOfAccAddresses(tc.addrs) + actual := tc.qr.AcceptFrom(tc.addrs) + assert.Equal(t, tc.exp, actual, "AcceptFrom return value") + assert.Equal(t, tc.expQr, tc.qr, "QuarantineRecord after AcceptFrom") + assert.Equal(t, origInput, tc.addrs, "input address slice before and after AcceptFrom") + }) + } +} + +func TestQuarantineRecord_DeclineFrom(t *testing.T) { + testAddr0 := MakeTestAddr("qrdf", 0) + testAddr1 := MakeTestAddr("qrdf", 1) + testAddr2 := MakeTestAddr("qrdf", 2) + testAddr3 := MakeTestAddr("qrdf", 3) + testAddr4 := MakeTestAddr("qrdf", 4) + + tests := []struct { + name string + qr *QuarantineRecord + addrs []sdk.AccAddress + exp bool + expQr *QuarantineRecord + }{ + { + name: "control", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "nil addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: nil, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "nil addrs already declined", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + addrs: nil, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "empty addrs", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "one addrs only in unaccepted already", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "one addrs only in unaccepted already and already declined", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: false, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "record has nil addresses", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "one address in both", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted two other provided", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr2, testAddr3}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted both provided", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr1}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted both provided previously declined", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr1}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted both provided opposite order", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr1, testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted first provided first with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr3, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted first provided second with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr3, testAddr0, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted first provided third with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + addrs: []sdk.AccAddress{testAddr4, testAddr3, testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two same accepted provided once", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr0, testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted second provided first with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr1, testAddr3, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted second provided second with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr3, testAddr1, testAddr4}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "two accepted second provided third with 2 others", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr4, testAddr3, testAddr1}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "one accepted provided thrice", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr4}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + Coins: coinMakerOK(), + Declined: false, + }, + addrs: []sdk.AccAddress{testAddr0, testAddr0, testAddr0}, + exp: true, + expQr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr4, testAddr0}, + AcceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: true, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + origInput := MakeCopyOfAccAddresses(tc.addrs) + actual := tc.qr.DeclineFrom(tc.addrs) + assert.Equal(t, tc.exp, actual, "DeclineFrom return value") + assert.Equal(t, tc.expQr, tc.qr, "QuarantineRecord after DeclineFrom") + assert.Equal(t, origInput, tc.addrs, "input address slice before and after DeclineFrom") + }) + } + +} + +func TestQuarantineRecord_GetAllFromAddrs(t *testing.T) { + testAddr0 := MakeTestAddr("qrgafa", 0) + testAddr1 := MakeTestAddr("qrgafa", 1) + testAddr2 := MakeTestAddr("qrgafa", 2) + testAddr3 := MakeTestAddr("qrgafa", 3) + testAddr4 := MakeTestAddr("qrgafa", 4) + + tests := []struct { + name string + qr *QuarantineRecord + exp []sdk.AccAddress + }{ + { + name: "nil unaccepted nil accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: nil, + }, + exp: []sdk.AccAddress{}, + }, + { + name: "nil unaccepted empty accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{}, + }, + exp: []sdk.AccAddress{}, + }, + { + name: "empty unaccepted nil accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + AcceptedFromAddresses: nil, + }, + exp: []sdk.AccAddress{}, + }, + { + name: "empty unaccepted empty accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + AcceptedFromAddresses: []sdk.AccAddress{}, + }, + exp: []sdk.AccAddress{}, + }, + { + name: "one unaccepted nil accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: nil, + }, + exp: []sdk.AccAddress{testAddr0}, + }, + { + name: "two unaccepted nil accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: nil, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1}, + }, + { + name: "one unaccepted empty accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{}, + }, + exp: []sdk.AccAddress{testAddr0}, + }, + { + name: "two unaccepted empty accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1}, + }, + { + name: "nil unaccepted one accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + }, + exp: []sdk.AccAddress{testAddr0}, + }, + { + name: "nil unaccepted two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1}, + }, + { + name: "empty unaccepted one accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0}, + }, + exp: []sdk.AccAddress{testAddr0}, + }, + { + name: "empty unaccepted two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1}, + }, + { + name: "one unaccepted one accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1}, + }, + { + name: "two unaccepted one accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1, testAddr2}, + }, + { + name: "one unaccepted two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1, testAddr2}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr1, testAddr2}, + }, + { + name: "two unaccepted two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr4, testAddr3}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1, testAddr2}, + }, + exp: []sdk.AccAddress{testAddr4, testAddr3, testAddr1, testAddr2}, + }, + { + name: "three unaccepted two accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr3, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr4}, + }, + exp: []sdk.AccAddress{testAddr2, testAddr3, testAddr1, testAddr0, testAddr4}, + }, + { + name: "two unaccepted three accepted", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr0, testAddr4}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr2, testAddr3, testAddr1}, + }, + exp: []sdk.AccAddress{testAddr0, testAddr4, testAddr2, testAddr3, testAddr1}, + }, + { + name: "same address in both twice", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1, testAddr1}, + AcceptedFromAddresses: []sdk.AccAddress{testAddr1, testAddr1}, + }, + exp: []sdk.AccAddress{testAddr1, testAddr1, testAddr1, testAddr1}, + }, + } + + // These shouldn't affect tests at all, but it's better to have + // them set just in case, for some reason, they do. + // But I didn't want to worry about them when defining the tests, + // so I'm doing it here instead. + for i, tc := range tests { + if i%2 == 0 { + tc.qr.Coins = coinMakerOK() + tc.qr.Declined = true + } else { + tc.qr.Coins = coinMakerMulti() + tc.qr.Declined = false + } + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + orig := MakeCopyOfQuarantineRecord(tc.qr) + actual := tc.qr.GetAllFromAddrs() + assert.Equal(t, tc.exp, actual, "GetAllFromAddrs result") + assert.Equal(t, orig, tc.qr, "QuarantineRecord before and after") + }) + } +} + +func TestQuarantineRecord_AsQuarantinedFunds(t *testing.T) { + testAddr0 := MakeTestAddr("qrasqf", 0) + testAddr1 := MakeTestAddr("qrasqf", 1) + testAddr2 := MakeTestAddr("qrasqf", 2) + + tests := []struct { + name string + qr *QuarantineRecord + toAddr sdk.AccAddress + expected *QuarantinedFunds + }{ + { + name: "control", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "declined", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: true, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: coinMakerOK(), + Declined: true, + }, + }, + { + name: "bad coins", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerBad(), + Declined: false, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: coinMakerBad(), + Declined: false, + }, + }, + { + name: "empty coins", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerEmpty(), + Declined: false, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: coinMakerEmpty(), + Declined: false, + }, + }, + { + name: "no to address", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1}, + Coins: coinMakerOK(), + Declined: false, + }, + toAddr: nil, + expected: &QuarantinedFunds{ + ToAddress: "", + UnacceptedFromAddresses: []string{testAddr1.String()}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "nil from addresses", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: nil, + Coins: coinMakerOK(), + Declined: false, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "empty from addresses", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{}, + Coins: coinMakerOK(), + Declined: false, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + { + name: "two from addresses", + qr: &QuarantineRecord{ + UnacceptedFromAddresses: []sdk.AccAddress{testAddr1, testAddr2}, + Coins: coinMakerOK(), + Declined: false, + }, + toAddr: testAddr0, + expected: &QuarantinedFunds{ + ToAddress: testAddr0.String(), + UnacceptedFromAddresses: []string{testAddr1.String(), testAddr2.String()}, + Coins: coinMakerOK(), + Declined: false, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + qrOrig := MakeCopyOfQuarantineRecord(tc.qr) + actual := tc.qr.AsQuarantinedFunds(tc.toAddr) + assert.Equal(t, tc.expected, actual, "resulting QuarantinedFunds") + assert.Equal(t, qrOrig, tc.qr, "QuarantineRecord before and after") + }) + } +} + +func TestQuarantineRecordSuffixIndex_AddSuffixes(t *testing.T) { + suffixShort0 := []byte(MakeTestAddr("qrsias", 0)) + suffixShort1 := []byte(MakeTestAddr("qrsias", 1)) + suffixShort2 := []byte(MakeTestAddr("qrsias", 2)) + suffixShort3 := []byte(MakeTestAddr("qrsias", 3)) + suffixLong4 := []byte(MakeLongAddr("qrsias", 4)) + suffixLong5 := []byte(MakeLongAddr("qrsias", 5)) + suffixLong6 := []byte(MakeLongAddr("qrsias", 6)) + suffixLong7 := []byte(MakeLongAddr("qrsias", 7)) + suffixBad8 := []byte(MakeBadAddr("qrsias", 8)) + suffixEmpty := make([]byte, 0) + + tests := []struct { + name string + qrsi *QuarantineRecordSuffixIndex + toAdd [][]byte + exp *QuarantineRecordSuffixIndex + }{ + // nil + ... + { + name: "nil + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1}}, + }, + { + name: "nil + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong5}}, + }, + { + name: "nil + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort3}}, + }, + { + name: "nil + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixLong6}}, + }, + { + name: "nil + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong7, suffixShort3}}, + }, + { + name: "nil + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong7, suffixLong6}}, + }, + + // empty + ... + { + name: "empty + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + }, + { + name: "empty + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + }, + { + name: "empty + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1}}, + }, + { + name: "empty + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong5}}, + }, + { + name: "empty + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort3}}, + }, + { + name: "empty + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixLong6}}, + }, + { + name: "empty + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong7, suffixShort3}}, + }, + { + name: "empty + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong7, suffixLong6}}, + }, + + // short + ... + { + name: "short + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong5}}, + }, + { + name: "short + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2, suffixShort3}}, + }, + { + name: "short + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2, suffixLong6}}, + }, + { + name: "short + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong7, suffixShort3}}, + }, + { + name: "short + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong7, suffixLong6}}, + }, + + // long + ... + { + name: "long + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort1}}, + }, + { + name: "long + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + }, + { + name: "long + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort2, suffixShort3}}, + }, + { + name: "long + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort2, suffixLong6}}, + }, + { + name: "long + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong7, suffixShort3}}, + }, + { + name: "long + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong7, suffixLong6}}, + }, + + // short short + ... + { + name: "short short + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short short + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short short + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2, suffixShort1}}, + }, + { + name: "short short + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1, suffixLong5}}, + }, + { + name: "short short + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toAdd: [][]byte{suffixShort1, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2, suffixShort1, suffixShort3}}, + }, + { + name: "short short + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toAdd: [][]byte{suffixShort1, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2, suffixShort1, suffixLong6}}, + }, + { + name: "short short + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1, suffixLong7, suffixShort3}}, + }, + { + name: "short short + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1, suffixLong7, suffixLong6}}, + }, + + // short long + ... + { + name: "short long + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + }, + { + name: "short long + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + }, + { + name: "short long + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4, suffixShort1}}, + }, + { + name: "short long + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4, suffixLong5}}, + }, + { + name: "short long + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4, suffixShort2, suffixShort3}}, + }, + { + name: "short long + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4, suffixShort2, suffixLong6}}, + }, + { + name: "short long + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4, suffixLong7, suffixShort3}}, + }, + { + name: "short long + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong4, suffixLong7, suffixLong6}}, + }, + + // long short + ... + { + name: "long short + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + }, + { + name: "long short + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + }, + { + name: "long short + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0, suffixShort1}}, + }, + { + name: "long short + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0, suffixLong5}}, + }, + { + name: "long short + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0, suffixShort2, suffixShort3}}, + }, + { + name: "long short + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0, suffixShort2, suffixLong6}}, + }, + { + name: "long short + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0, suffixLong7, suffixShort3}}, + }, + { + name: "long short + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixShort0, suffixLong7, suffixLong6}}, + }, + + // long long + ... + { + name: "long long + nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + }, + { + name: "long long + empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + }, + { + name: "long long + short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5, suffixShort1}}, + }, + { + name: "long long + long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong6}}, + toAdd: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong6, suffixLong5}}, + }, + { + name: "long long + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5, suffixShort2, suffixShort3}}, + }, + { + name: "long long + short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5, suffixShort2, suffixLong6}}, + }, + { + name: "long long + long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5, suffixLong7, suffixShort3}}, + }, + { + name: "long long + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5}}, + toAdd: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4, suffixLong5, suffixLong7, suffixLong6}}, + }, + + // other ... + { + name: "short long + bad", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong7}}, + toAdd: [][]byte{suffixBad8}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong7, suffixBad8}}, + }, + { + name: "long short + empty suffix", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong5, suffixShort0}}, + toAdd: [][]byte{suffixEmpty}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong5, suffixShort0, suffixEmpty}}, + }, + { + name: "bad + short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixBad8}}, + toAdd: [][]byte{suffixShort3, suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixBad8, suffixShort3, suffixShort1}}, + }, + { + name: "empty suffix + long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixEmpty}}, + toAdd: [][]byte{suffixLong7, suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixEmpty, suffixLong7, suffixLong4}}, + }, + { + name: "short + same short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toAdd: [][]byte{suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort0}}, + }, + { + name: "short long + same short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong4}}, + toAdd: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong4, suffixShort1}}, + }, + { + name: "short long + same long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong4}}, + toAdd: [][]byte{suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong4, suffixLong4}}, + }, + { + name: "long short + same short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong6, suffixShort2}}, + toAdd: [][]byte{suffixShort2}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong6, suffixShort2, suffixShort2}}, + }, + { + name: "long short + same long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong6, suffixShort2}}, + toAdd: [][]byte{suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong6, suffixShort2, suffixLong6}}, + }, + { + name: "shmorgishborg", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{ + suffixShort1, suffixShort3, suffixLong6, suffixBad8, suffixLong7, + suffixLong4, suffixShort0, suffixLong5, suffixEmpty, suffixShort2, + }}, + toAdd: [][]byte{ + suffixShort0, suffixBad8, suffixShort1, suffixShort1, suffixLong5, + suffixEmpty, suffixLong4, suffixLong6, suffixShort0, suffixLong7, + }, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{ + suffixShort1, suffixShort3, suffixLong6, suffixBad8, suffixLong7, + suffixLong4, suffixShort0, suffixLong5, suffixEmpty, suffixShort2, + suffixShort0, suffixBad8, suffixShort1, suffixShort1, suffixLong5, + suffixEmpty, suffixLong4, suffixLong6, suffixShort0, suffixLong7, + }}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tc.qrsi.AddSuffixes(tc.toAdd...) + assert.Equal(t, tc.exp, tc.qrsi, "QuarantineRecordSuffixIndex after AddSuffixes") + }) + } +} + +func TestQuarantineRecordSuffixIndex_Simplify(t *testing.T) { + suffixShort0 := []byte(MakeTestAddr("qrsis", 0)) + suffixShort1 := []byte(MakeTestAddr("qrsis", 1)) + suffixShort2 := []byte(MakeTestAddr("qrsis", 2)) + suffixShort3 := []byte(MakeTestAddr("qrsis", 3)) + suffixLong4 := []byte(MakeLongAddr("qrsis", 4)) + suffixLong5 := []byte(MakeLongAddr("qrsis", 5)) + suffixLong6 := []byte(MakeLongAddr("qrsis", 6)) + suffixLong7 := []byte(MakeLongAddr("qrsis", 7)) + suffixBad8 := []byte(MakeBadAddr("qrsis", 8)) + suffixEmpty := make([]byte, 0) + + tests := []struct { + name string + qrsi *QuarantineRecordSuffixIndex + toRemove [][]byte + exp *QuarantineRecordSuffixIndex + }{ + // nil - ... + { + name: "nil - nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "nil - long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + toRemove: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + + // empty - ... + { + name: "empty - nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty - long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{}}, + toRemove: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + + // short - ... + { + name: "short - nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - same short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "short - long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - other short other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - same short other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort0, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "short - other short same short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort2, suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "short - same short same short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort0, suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "short - short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short - long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + toRemove: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + + // long - ... + { + name: "long - nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - other long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - same long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "long - short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - short other long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixShort2, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - short same long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixShort2, suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "long - other long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - same long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong4, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "long - other long other long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + }, + { + name: "long - other long same long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong7, suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "long - same long other long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong4, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "long - same long same long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong4}}, + toRemove: [][]byte{suffixLong4, suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + + // short short - ... + { + name: "short short - nil", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toRemove: nil, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short short - empty", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toRemove: [][]byte{}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short short - other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toRemove: [][]byte{suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + }, + { + name: "short short - same first short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toRemove: [][]byte{suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2}}, + }, + { + name: "short short - same second short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toRemove: [][]byte{suffixShort2}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short short - long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toRemove: [][]byte{suffixLong5}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short short - other short other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort1, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + }, + { + name: "short short - first short other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort2, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short short - second short other short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort0, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2}}, + }, + { + name: "short short - other short first short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort1, suffixShort2}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0}}, + }, + { + name: "short short - other short second short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort1, suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2}}, + }, + { + name: "short short - first short second short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort2, suffixShort0}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "short short - second short first short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort2, suffixShort0}}, + toRemove: [][]byte{suffixShort0, suffixShort2}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "short short - short long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + toRemove: [][]byte{suffixShort1, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort2}}, + }, + { + name: "short short - long short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toRemove: [][]byte{suffixLong7, suffixShort3}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + { + name: "short short - long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + toRemove: [][]byte{suffixLong7, suffixLong6}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixShort1}}, + }, + + // other ... + { + name: "short long - bad", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong7}}, + toRemove: [][]byte{suffixBad8}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort1, suffixLong7}}, + }, + { + name: "long short - empty suffix", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixLong5, suffixShort0}}, + toRemove: [][]byte{suffixEmpty}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixShort0, suffixLong5}}, + }, + { + name: "bad - short short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixBad8}}, + toRemove: [][]byte{suffixShort3, suffixShort1}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixBad8}}, + }, + { + name: "bad - short bad long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixBad8}}, + toRemove: [][]byte{suffixShort3, suffixBad8, suffixLong7}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "empty suffix - long long", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixEmpty}}, + toRemove: [][]byte{suffixLong7, suffixLong4}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixEmpty}}, + }, + { + name: "empty suffix - long empty suffix short", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{suffixEmpty}}, + toRemove: [][]byte{suffixLong7, suffixEmpty, suffixShort2}, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: nil}, + }, + { + name: "shmorgishborg", + qrsi: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{ + suffixShort1, suffixShort3, suffixLong6, suffixBad8, suffixLong7, + suffixLong4, suffixShort0, suffixLong5, suffixEmpty, suffixShort2, + }}, + toRemove: [][]byte{ + suffixShort0, suffixBad8, suffixShort1, suffixShort1, suffixLong4, + suffixEmpty, suffixLong4, suffixLong6, suffixShort0, suffixLong7, + }, + exp: &QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{ + suffixShort2, suffixShort3, suffixLong5, + }}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if tc.toRemove == nil { + tc.qrsi.Simplify() + } else { + tc.qrsi.Simplify(tc.toRemove...) + } + assert.Equal(t, tc.exp, tc.qrsi, "QuarantineRecordSuffixIndex after Simplify") + }) + } +} diff --git a/x/quarantine/query.pb.go b/x/quarantine/query.pb.go new file mode 100644 index 0000000000..f53a45b414 --- /dev/null +++ b/x/quarantine/query.pb.go @@ -0,0 +1,1756 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/quarantine/v1beta1/query.proto + +package quarantine + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + query "github.com/cosmos/cosmos-sdk/types/query" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryIsQuarantinedRequest defines the RPC request for checking if an account has opted into quarantine. +type QueryIsQuarantinedRequest struct { + // to_address is the address to check. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` +} + +func (m *QueryIsQuarantinedRequest) Reset() { *m = QueryIsQuarantinedRequest{} } +func (m *QueryIsQuarantinedRequest) String() string { return proto.CompactTextString(m) } +func (*QueryIsQuarantinedRequest) ProtoMessage() {} +func (*QueryIsQuarantinedRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6e6232ebe830d056, []int{0} +} +func (m *QueryIsQuarantinedRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIsQuarantinedRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIsQuarantinedRequest.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 *QueryIsQuarantinedRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIsQuarantinedRequest.Merge(m, src) +} +func (m *QueryIsQuarantinedRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryIsQuarantinedRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIsQuarantinedRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIsQuarantinedRequest proto.InternalMessageInfo + +func (m *QueryIsQuarantinedRequest) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +// QueryIsQuarantinedResponse defines the RPC response of an IsQuarantined query. +type QueryIsQuarantinedResponse struct { + // is_quarantined is true if the to_address has opted into quarantine. + IsQuarantined bool `protobuf:"varint,1,opt,name=is_quarantined,json=isQuarantined,proto3" json:"is_quarantined,omitempty"` +} + +func (m *QueryIsQuarantinedResponse) Reset() { *m = QueryIsQuarantinedResponse{} } +func (m *QueryIsQuarantinedResponse) String() string { return proto.CompactTextString(m) } +func (*QueryIsQuarantinedResponse) ProtoMessage() {} +func (*QueryIsQuarantinedResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6e6232ebe830d056, []int{1} +} +func (m *QueryIsQuarantinedResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryIsQuarantinedResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryIsQuarantinedResponse.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 *QueryIsQuarantinedResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryIsQuarantinedResponse.Merge(m, src) +} +func (m *QueryIsQuarantinedResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryIsQuarantinedResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryIsQuarantinedResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryIsQuarantinedResponse proto.InternalMessageInfo + +func (m *QueryIsQuarantinedResponse) GetIsQuarantined() bool { + if m != nil { + return m.IsQuarantined + } + return false +} + +// QueryQuarantinedFundsRequest defines the RPC request for looking up quarantined funds. +type QueryQuarantinedFundsRequest struct { + // to_address is the intended recipient of the coins that have been quarantined. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // from_address is the sender of the coins. If provided, a to_address must also be provided. + FromAddress string `protobuf:"bytes,2,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // pagination defines optional pagination parameters for the request. + Pagination *query.PageRequest `protobuf:"bytes,99,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryQuarantinedFundsRequest) Reset() { *m = QueryQuarantinedFundsRequest{} } +func (m *QueryQuarantinedFundsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryQuarantinedFundsRequest) ProtoMessage() {} +func (*QueryQuarantinedFundsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6e6232ebe830d056, []int{2} +} +func (m *QueryQuarantinedFundsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryQuarantinedFundsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryQuarantinedFundsRequest.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 *QueryQuarantinedFundsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryQuarantinedFundsRequest.Merge(m, src) +} +func (m *QueryQuarantinedFundsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryQuarantinedFundsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryQuarantinedFundsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryQuarantinedFundsRequest proto.InternalMessageInfo + +func (m *QueryQuarantinedFundsRequest) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *QueryQuarantinedFundsRequest) GetFromAddress() string { + if m != nil { + return m.FromAddress + } + return "" +} + +func (m *QueryQuarantinedFundsRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryQuarantinedFundsResponse defines the RPC response of a QuarantinedFunds query. +type QueryQuarantinedFundsResponse struct { + // quarantinedFunds is info about coins sitting in quarantine. + QuarantinedFunds []*QuarantinedFunds `protobuf:"bytes,1,rep,name=quarantinedFunds,proto3" json:"quarantinedFunds,omitempty"` + // pagination defines the pagination parameters of the response. + Pagination *query.PageResponse `protobuf:"bytes,99,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryQuarantinedFundsResponse) Reset() { *m = QueryQuarantinedFundsResponse{} } +func (m *QueryQuarantinedFundsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryQuarantinedFundsResponse) ProtoMessage() {} +func (*QueryQuarantinedFundsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6e6232ebe830d056, []int{3} +} +func (m *QueryQuarantinedFundsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryQuarantinedFundsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryQuarantinedFundsResponse.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 *QueryQuarantinedFundsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryQuarantinedFundsResponse.Merge(m, src) +} +func (m *QueryQuarantinedFundsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryQuarantinedFundsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryQuarantinedFundsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryQuarantinedFundsResponse proto.InternalMessageInfo + +func (m *QueryQuarantinedFundsResponse) GetQuarantinedFunds() []*QuarantinedFunds { + if m != nil { + return m.QuarantinedFunds + } + return nil +} + +func (m *QueryQuarantinedFundsResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryAutoResponsesRequest defines the RPC request for getting auto-response settings for an address. +type QueryAutoResponsesRequest struct { + // to_address is the quarantined account to get info on. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // from_address is an optional sender address to limit results. + FromAddress string `protobuf:"bytes,2,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` + // pagination defines optional pagination parameters for the request. + Pagination *query.PageRequest `protobuf:"bytes,99,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAutoResponsesRequest) Reset() { *m = QueryAutoResponsesRequest{} } +func (m *QueryAutoResponsesRequest) String() string { return proto.CompactTextString(m) } +func (*QueryAutoResponsesRequest) ProtoMessage() {} +func (*QueryAutoResponsesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_6e6232ebe830d056, []int{4} +} +func (m *QueryAutoResponsesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAutoResponsesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAutoResponsesRequest.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 *QueryAutoResponsesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAutoResponsesRequest.Merge(m, src) +} +func (m *QueryAutoResponsesRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryAutoResponsesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAutoResponsesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAutoResponsesRequest proto.InternalMessageInfo + +func (m *QueryAutoResponsesRequest) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *QueryAutoResponsesRequest) GetFromAddress() string { + if m != nil { + return m.FromAddress + } + return "" +} + +func (m *QueryAutoResponsesRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryAutoResponsesResponse defines the RPC response of a AutoResponses query. +type QueryAutoResponsesResponse struct { + // auto_responses are the auto-response entries from the provided query. + AutoResponses []*AutoResponseEntry `protobuf:"bytes,1,rep,name=auto_responses,json=autoResponses,proto3" json:"auto_responses,omitempty"` + // pagination defines the pagination parameters of the response. + Pagination *query.PageResponse `protobuf:"bytes,99,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryAutoResponsesResponse) Reset() { *m = QueryAutoResponsesResponse{} } +func (m *QueryAutoResponsesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAutoResponsesResponse) ProtoMessage() {} +func (*QueryAutoResponsesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_6e6232ebe830d056, []int{5} +} +func (m *QueryAutoResponsesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAutoResponsesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAutoResponsesResponse.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 *QueryAutoResponsesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAutoResponsesResponse.Merge(m, src) +} +func (m *QueryAutoResponsesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAutoResponsesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAutoResponsesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAutoResponsesResponse proto.InternalMessageInfo + +func (m *QueryAutoResponsesResponse) GetAutoResponses() []*AutoResponseEntry { + if m != nil { + return m.AutoResponses + } + return nil +} + +func (m *QueryAutoResponsesResponse) GetPagination() *query.PageResponse { + if m != nil { + return m.Pagination + } + return nil +} + +func init() { + proto.RegisterType((*QueryIsQuarantinedRequest)(nil), "cosmos.quarantine.v1beta1.QueryIsQuarantinedRequest") + proto.RegisterType((*QueryIsQuarantinedResponse)(nil), "cosmos.quarantine.v1beta1.QueryIsQuarantinedResponse") + proto.RegisterType((*QueryQuarantinedFundsRequest)(nil), "cosmos.quarantine.v1beta1.QueryQuarantinedFundsRequest") + proto.RegisterType((*QueryQuarantinedFundsResponse)(nil), "cosmos.quarantine.v1beta1.QueryQuarantinedFundsResponse") + proto.RegisterType((*QueryAutoResponsesRequest)(nil), "cosmos.quarantine.v1beta1.QueryAutoResponsesRequest") + proto.RegisterType((*QueryAutoResponsesResponse)(nil), "cosmos.quarantine.v1beta1.QueryAutoResponsesResponse") +} + +func init() { + proto.RegisterFile("cosmos/quarantine/v1beta1/query.proto", fileDescriptor_6e6232ebe830d056) +} + +var fileDescriptor_6e6232ebe830d056 = []byte{ + // 605 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0x4f, 0x6b, 0x13, 0x41, + 0x1c, 0xed, 0x44, 0x2a, 0x76, 0x62, 0x4a, 0x19, 0x3c, 0xa4, 0xa1, 0x2e, 0x61, 0xa1, 0x1a, 0xb5, + 0x99, 0xb1, 0xf1, 0x4f, 0x85, 0xaa, 0xd0, 0x16, 0x2b, 0xde, 0x6c, 0x2a, 0x08, 0xb9, 0x84, 0x49, + 0x76, 0xba, 0x2e, 0x9a, 0x99, 0x64, 0x67, 0xb6, 0x58, 0x4a, 0x2f, 0x7e, 0x02, 0xa1, 0x37, 0x8f, + 0x7e, 0x86, 0x9e, 0xbc, 0x79, 0xf3, 0x58, 0xf4, 0xa0, 0x82, 0x07, 0x49, 0xfc, 0x02, 0x7e, 0x03, + 0xc9, 0xce, 0x24, 0xd9, 0xa4, 0xd9, 0x2c, 0x41, 0x4f, 0x9e, 0x42, 0xf6, 0xf7, 0xde, 0xfb, 0xfd, + 0xde, 0xbe, 0xdf, 0xcc, 0xc2, 0xe5, 0xba, 0x90, 0x0d, 0x21, 0x49, 0x2b, 0xa0, 0x3e, 0xe5, 0xca, + 0xe3, 0x8c, 0xec, 0xaf, 0xd6, 0x98, 0xa2, 0xab, 0xa4, 0x15, 0x30, 0xff, 0x00, 0x37, 0x7d, 0xa1, + 0x04, 0x5a, 0xd4, 0x30, 0x3c, 0x80, 0x61, 0x03, 0xcb, 0x5d, 0x37, 0x0a, 0x35, 0x2a, 0x99, 0xe6, + 0xf4, 0x15, 0x9a, 0xd4, 0xf5, 0x38, 0x55, 0x9e, 0xe0, 0x5a, 0xa6, 0x8f, 0x1d, 0xdb, 0xad, 0xaf, + 0xac, 0xb1, 0xa6, 0x65, 0x35, 0xfc, 0x47, 0x4c, 0x7f, 0x5d, 0x5a, 0x72, 0x85, 0x70, 0x5f, 0x31, + 0x42, 0x9b, 0x1e, 0xa1, 0x9c, 0x0b, 0x15, 0xf6, 0x30, 0x55, 0xfb, 0x19, 0x5c, 0xdc, 0xe9, 0x8e, + 0xf1, 0x44, 0xee, 0xf4, 0x35, 0x9d, 0x32, 0x6b, 0x05, 0x4c, 0x2a, 0xb4, 0x06, 0xa1, 0x12, 0x55, + 0xea, 0x38, 0x3e, 0x93, 0x32, 0x0b, 0xf2, 0xa0, 0x30, 0xb7, 0x99, 0xfd, 0x7c, 0x52, 0xbc, 0x64, + 0x1a, 0x6c, 0xe8, 0xca, 0xae, 0xf2, 0x3d, 0xee, 0x96, 0xe7, 0x94, 0x30, 0x0f, 0xec, 0x2d, 0x98, + 0x1b, 0xa7, 0x2a, 0x9b, 0x82, 0x4b, 0x86, 0x96, 0xe1, 0xbc, 0x27, 0xab, 0x03, 0x0f, 0x4e, 0x28, + 0x7d, 0xa1, 0x9c, 0xf1, 0xa2, 0x70, 0xfb, 0x07, 0x80, 0x4b, 0xa1, 0x4a, 0xe4, 0xe1, 0x76, 0xc0, + 0x1d, 0xf9, 0xb7, 0xe3, 0xa1, 0x75, 0x78, 0x71, 0xcf, 0x17, 0x8d, 0x3e, 0x35, 0x95, 0x40, 0x4d, + 0x77, 0xd1, 0x3d, 0xf2, 0x36, 0x84, 0x83, 0xa8, 0xb2, 0xf5, 0x3c, 0x28, 0xa4, 0x4b, 0x57, 0xb0, + 0xe1, 0x75, 0x73, 0xc5, 0x7a, 0x17, 0x4c, 0x56, 0xf8, 0x29, 0x75, 0x99, 0x99, 0xb8, 0x1c, 0x61, + 0xda, 0x1f, 0x01, 0xbc, 0x1c, 0x63, 0xcf, 0xbc, 0xa7, 0xe7, 0x70, 0xa1, 0x35, 0x52, 0xcb, 0x82, + 0xfc, 0xb9, 0x42, 0xba, 0x74, 0x03, 0xc7, 0xae, 0x18, 0x3e, 0x23, 0x77, 0x46, 0x04, 0x3d, 0x1e, + 0x63, 0xe1, 0x6a, 0xa2, 0x05, 0x3d, 0xd5, 0x90, 0x87, 0xef, 0xc0, 0xac, 0xcf, 0x46, 0xa0, 0x44, + 0x0f, 0xf1, 0x9f, 0xe4, 0xf3, 0x01, 0x98, 0x25, 0x1e, 0xf1, 0x66, 0xc2, 0xd9, 0x85, 0xf3, 0x34, + 0x50, 0xa2, 0xea, 0xf7, 0x2a, 0x26, 0x9a, 0x95, 0x09, 0xd1, 0x44, 0x95, 0x1e, 0x71, 0xe5, 0x1f, + 0x94, 0x33, 0x34, 0x2a, 0xfe, 0xcf, 0x82, 0x29, 0x7d, 0x9d, 0x85, 0xb3, 0xe1, 0xf0, 0xe8, 0x04, + 0xc0, 0xcc, 0xd0, 0x31, 0x44, 0xb7, 0x27, 0x2e, 0x4f, 0xcc, 0x5d, 0x90, 0xbb, 0x33, 0x25, 0x4b, + 0x0f, 0x65, 0xdf, 0x7d, 0xf3, 0xe5, 0xd7, 0x71, 0xea, 0x26, 0xc2, 0x24, 0xfe, 0x36, 0xa3, 0x75, + 0xe5, 0xed, 0x33, 0x72, 0x38, 0x58, 0x96, 0x23, 0xf4, 0x3e, 0x05, 0x17, 0x46, 0x37, 0x19, 0xad, + 0x25, 0xcd, 0x10, 0x73, 0x53, 0xe4, 0xee, 0x4d, 0x4f, 0x34, 0xf3, 0xbf, 0x03, 0xa1, 0x81, 0x63, + 0x80, 0xf2, 0x13, 0x1c, 0xec, 0x75, 0x39, 0x15, 0x82, 0x8a, 0x49, 0x98, 0x21, 0x93, 0x95, 0x87, + 0xe8, 0xfe, 0x54, 0x04, 0x72, 0x18, 0x3d, 0x16, 0x47, 0xe8, 0x37, 0x80, 0x99, 0xa1, 0xed, 0x4c, + 0xce, 0x76, 0xdc, 0x41, 0x4d, 0xce, 0x76, 0xec, 0x11, 0xb0, 0x65, 0xf8, 0x6a, 0x1a, 0x68, 0x65, + 0x52, 0xb6, 0x81, 0x12, 0xc3, 0xa6, 0x1f, 0xa0, 0xf5, 0x69, 0xf0, 0x23, 0x9e, 0x37, 0xb7, 0x3e, + 0xb5, 0x2d, 0x70, 0xda, 0xb6, 0xc0, 0xcf, 0xb6, 0x05, 0xde, 0x76, 0xac, 0x99, 0xd3, 0x8e, 0x35, + 0xf3, 0xad, 0x63, 0xcd, 0x54, 0xae, 0xb9, 0x9e, 0x7a, 0x11, 0xd4, 0x70, 0x5d, 0x34, 0x7a, 0x0d, + 0xf4, 0x4f, 0x51, 0x3a, 0x2f, 0xc9, 0xeb, 0x48, 0xb7, 0xda, 0xf9, 0xf0, 0xe3, 0x77, 0xeb, 0x4f, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xc3, 0x3c, 0x9b, 0xd1, 0x07, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // IsQuarantined checks if an account has opted into quarantine. + IsQuarantined(ctx context.Context, in *QueryIsQuarantinedRequest, opts ...grpc.CallOption) (*QueryIsQuarantinedResponse, error) + // QuarantinedFunds gets information about funds that have been quarantined. + // + // If both a to_address and from_address are provided, any such quarantined funds will be returned regardless of + // whether they've been declined. If only a to_address is provided, the unaccepted and undeclined funds waiting on a + // response from to_address will be returned. If neither a to_address nor from_address is provided, all non-declined + // quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. + QuarantinedFunds(ctx context.Context, in *QueryQuarantinedFundsRequest, opts ...grpc.CallOption) (*QueryQuarantinedFundsResponse, error) + // AutoResponses gets the auto-response settings for a quarantined account. + // + // The to_address is required. If a from_address is provided only the auto response for that from_address will be + // returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. + AutoResponses(ctx context.Context, in *QueryAutoResponsesRequest, opts ...grpc.CallOption) (*QueryAutoResponsesResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) IsQuarantined(ctx context.Context, in *QueryIsQuarantinedRequest, opts ...grpc.CallOption) (*QueryIsQuarantinedResponse, error) { + out := new(QueryIsQuarantinedResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Query/IsQuarantined", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) QuarantinedFunds(ctx context.Context, in *QueryQuarantinedFundsRequest, opts ...grpc.CallOption) (*QueryQuarantinedFundsResponse, error) { + out := new(QueryQuarantinedFundsResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Query/QuarantinedFunds", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) AutoResponses(ctx context.Context, in *QueryAutoResponsesRequest, opts ...grpc.CallOption) (*QueryAutoResponsesResponse, error) { + out := new(QueryAutoResponsesResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Query/AutoResponses", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // IsQuarantined checks if an account has opted into quarantine. + IsQuarantined(context.Context, *QueryIsQuarantinedRequest) (*QueryIsQuarantinedResponse, error) + // QuarantinedFunds gets information about funds that have been quarantined. + // + // If both a to_address and from_address are provided, any such quarantined funds will be returned regardless of + // whether they've been declined. If only a to_address is provided, the unaccepted and undeclined funds waiting on a + // response from to_address will be returned. If neither a to_address nor from_address is provided, all non-declined + // quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. + QuarantinedFunds(context.Context, *QueryQuarantinedFundsRequest) (*QueryQuarantinedFundsResponse, error) + // AutoResponses gets the auto-response settings for a quarantined account. + // + // The to_address is required. If a from_address is provided only the auto response for that from_address will be + // returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. + AutoResponses(context.Context, *QueryAutoResponsesRequest) (*QueryAutoResponsesResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) IsQuarantined(ctx context.Context, req *QueryIsQuarantinedRequest) (*QueryIsQuarantinedResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method IsQuarantined not implemented") +} +func (*UnimplementedQueryServer) QuarantinedFunds(ctx context.Context, req *QueryQuarantinedFundsRequest) (*QueryQuarantinedFundsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QuarantinedFunds not implemented") +} +func (*UnimplementedQueryServer) AutoResponses(ctx context.Context, req *QueryAutoResponsesRequest) (*QueryAutoResponsesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AutoResponses not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_IsQuarantined_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryIsQuarantinedRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).IsQuarantined(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Query/IsQuarantined", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).IsQuarantined(ctx, req.(*QueryIsQuarantinedRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_QuarantinedFunds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryQuarantinedFundsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QuarantinedFunds(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Query/QuarantinedFunds", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QuarantinedFunds(ctx, req.(*QueryQuarantinedFundsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_AutoResponses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAutoResponsesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AutoResponses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Query/AutoResponses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AutoResponses(ctx, req.(*QueryAutoResponsesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cosmos.quarantine.v1beta1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "IsQuarantined", + Handler: _Query_IsQuarantined_Handler, + }, + { + MethodName: "QuarantinedFunds", + Handler: _Query_QuarantinedFunds_Handler, + }, + { + MethodName: "AutoResponses", + Handler: _Query_AutoResponses_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cosmos/quarantine/v1beta1/query.proto", +} + +func (m *QueryIsQuarantinedRequest) 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 *QueryIsQuarantinedRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIsQuarantinedRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryIsQuarantinedResponse) 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 *QueryIsQuarantinedResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryIsQuarantinedResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IsQuarantined { + i-- + if m.IsQuarantined { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryQuarantinedFundsRequest) 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 *QueryQuarantinedFundsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryQuarantinedFundsRequest) 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] = 0x6 + i-- + dAtA[i] = 0x9a + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryQuarantinedFundsResponse) 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 *QueryQuarantinedFundsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryQuarantinedFundsResponse) 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] = 0x6 + i-- + dAtA[i] = 0x9a + } + if len(m.QuarantinedFunds) > 0 { + for iNdEx := len(m.QuarantinedFunds) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.QuarantinedFunds[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 *QueryAutoResponsesRequest) 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 *QueryAutoResponsesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAutoResponsesRequest) 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] = 0x6 + i-- + dAtA[i] = 0x9a + } + if len(m.FromAddress) > 0 { + i -= len(m.FromAddress) + copy(dAtA[i:], m.FromAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.FromAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryAutoResponsesResponse) 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 *QueryAutoResponsesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAutoResponsesResponse) 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] = 0x6 + i-- + dAtA[i] = 0x9a + } + if len(m.AutoResponses) > 0 { + for iNdEx := len(m.AutoResponses) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.AutoResponses[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryIsQuarantinedRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryIsQuarantinedResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.IsQuarantined { + n += 2 + } + return n +} + +func (m *QueryQuarantinedFundsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 2 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryQuarantinedFundsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.QuarantinedFunds) > 0 { + for _, e := range m.QuarantinedFunds { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 2 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAutoResponsesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.FromAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 2 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryAutoResponsesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.AutoResponses) > 0 { + for _, e := range m.AutoResponses { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 2 + 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 *QueryIsQuarantinedRequest) 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: QueryIsQuarantinedRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIsQuarantinedRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = 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 *QueryIsQuarantinedResponse) 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: QueryIsQuarantinedResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryIsQuarantinedResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsQuarantined", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsQuarantined = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryQuarantinedFundsRequest) 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: QueryQuarantinedFundsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryQuarantinedFundsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", 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.FromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 99: + 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 *QueryQuarantinedFundsResponse) 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: QueryQuarantinedFundsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryQuarantinedFundsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field QuarantinedFunds", 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.QuarantinedFunds = append(m.QuarantinedFunds, &QuarantinedFunds{}) + if err := m.QuarantinedFunds[len(m.QuarantinedFunds)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 99: + 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 *QueryAutoResponsesRequest) 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: QueryAutoResponsesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAutoResponsesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddress", 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.FromAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 99: + 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 *QueryAutoResponsesResponse) 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: QueryAutoResponsesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAutoResponsesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AutoResponses", 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.AutoResponses = append(m.AutoResponses, &AutoResponseEntry{}) + if err := m.AutoResponses[len(m.AutoResponses)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 99: + 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/quarantine/query.pb.gw.go b/x/quarantine/query.pb.gw.go new file mode 100644 index 0000000000..0fbc4c9143 --- /dev/null +++ b/x/quarantine/query.pb.gw.go @@ -0,0 +1,792 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: cosmos/quarantine/v1beta1/query.proto + +/* +Package quarantine is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package quarantine + +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_IsQuarantined_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIsQuarantinedRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_address", err) + } + + msg, err := client.IsQuarantined(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_IsQuarantined_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryIsQuarantinedRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_address", err) + } + + msg, err := server.IsQuarantined(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_QuarantinedFunds_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_QuarantinedFunds_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryQuarantinedFundsRequest + 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_QuarantinedFunds_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QuarantinedFunds(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QuarantinedFunds_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryQuarantinedFundsRequest + 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_QuarantinedFunds_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QuarantinedFunds(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_QuarantinedFunds_1 = &utilities.DoubleArray{Encoding: map[string]int{"to_address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_QuarantinedFunds_1(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryQuarantinedFundsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_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_QuarantinedFunds_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QuarantinedFunds(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QuarantinedFunds_1(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryQuarantinedFundsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_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_QuarantinedFunds_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QuarantinedFunds(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_QuarantinedFunds_2 = &utilities.DoubleArray{Encoding: map[string]int{"to_address": 0, "from_address": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_Query_QuarantinedFunds_2(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryQuarantinedFundsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_address", err) + } + + val, ok = pathParams["from_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "from_address") + } + + protoReq.FromAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "from_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_QuarantinedFunds_2); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QuarantinedFunds(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QuarantinedFunds_2(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryQuarantinedFundsRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_address", err) + } + + val, ok = pathParams["from_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "from_address") + } + + protoReq.FromAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "from_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_QuarantinedFunds_2); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QuarantinedFunds(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_AutoResponses_0 = &utilities.DoubleArray{Encoding: map[string]int{"to_address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_Query_AutoResponses_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAutoResponsesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_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_AutoResponses_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.AutoResponses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AutoResponses_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAutoResponsesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_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_AutoResponses_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.AutoResponses(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_AutoResponses_1 = &utilities.DoubleArray{Encoding: map[string]int{"to_address": 0, "from_address": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_Query_AutoResponses_1(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAutoResponsesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_address", err) + } + + val, ok = pathParams["from_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "from_address") + } + + protoReq.FromAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "from_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_AutoResponses_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.AutoResponses(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AutoResponses_1(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAutoResponsesRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["to_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "to_address") + } + + protoReq.ToAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "to_address", err) + } + + val, ok = pathParams["from_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "from_address") + } + + protoReq.FromAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "from_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_AutoResponses_1); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.AutoResponses(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_IsQuarantined_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_IsQuarantined_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_IsQuarantined_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QuarantinedFunds_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_QuarantinedFunds_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_QuarantinedFunds_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QuarantinedFunds_1, 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_QuarantinedFunds_1(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_QuarantinedFunds_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QuarantinedFunds_2, 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_QuarantinedFunds_2(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_QuarantinedFunds_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AutoResponses_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_AutoResponses_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_AutoResponses_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AutoResponses_1, 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_AutoResponses_1(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_AutoResponses_1(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_IsQuarantined_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_IsQuarantined_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_IsQuarantined_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QuarantinedFunds_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_QuarantinedFunds_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_QuarantinedFunds_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QuarantinedFunds_1, 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_QuarantinedFunds_1(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QuarantinedFunds_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QuarantinedFunds_2, 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_QuarantinedFunds_2(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QuarantinedFunds_2(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AutoResponses_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_AutoResponses_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_AutoResponses_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_AutoResponses_1, 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_AutoResponses_1(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AutoResponses_1(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_IsQuarantined_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "quarantine", "v1beta1", "active", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QuarantinedFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "quarantine", "v1beta1", "funds"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QuarantinedFunds_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "quarantine", "v1beta1", "funds", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QuarantinedFunds_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "quarantine", "v1beta1", "funds", "to_address", "from_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AutoResponses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "quarantine", "v1beta1", "auto", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AutoResponses_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "quarantine", "v1beta1", "auto", "to_address", "from_address"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_IsQuarantined_0 = runtime.ForwardResponseMessage + + forward_Query_QuarantinedFunds_0 = runtime.ForwardResponseMessage + + forward_Query_QuarantinedFunds_1 = runtime.ForwardResponseMessage + + forward_Query_QuarantinedFunds_2 = runtime.ForwardResponseMessage + + forward_Query_AutoResponses_0 = runtime.ForwardResponseMessage + + forward_Query_AutoResponses_1 = runtime.ForwardResponseMessage +) diff --git a/x/quarantine/send_restriction.go b/x/quarantine/send_restriction.go new file mode 100644 index 0000000000..2e4dc484a8 --- /dev/null +++ b/x/quarantine/send_restriction.go @@ -0,0 +1,25 @@ +package quarantine + +import sdk "github.com/cosmos/cosmos-sdk/types" + +var bypassKey = "bypass-quarantine-restriction" + +// WithBypass returns a new context that will cause the quarantine bank send restriction to be skipped. +func WithBypass(ctx sdk.Context) sdk.Context { + return ctx.WithValue(bypassKey, true) +} + +// WithoutBypass returns a new context that will cause the quarantine bank send restriction to not be skipped. +func WithoutBypass(ctx sdk.Context) sdk.Context { + return ctx.WithValue(bypassKey, false) +} + +// HasBypass checks the context to see if the quarantine bank send restriction should be skipped. +func HasBypass(ctx sdk.Context) bool { + bypassValue := ctx.Value(bypassKey) + if bypassValue == nil { + return false + } + bypass, isBool := bypassValue.(bool) + return isBool && bypass +} diff --git a/x/quarantine/send_restriction_test.go b/x/quarantine/send_restriction_test.go new file mode 100644 index 0000000000..4b59267132 --- /dev/null +++ b/x/quarantine/send_restriction_test.go @@ -0,0 +1,77 @@ +package quarantine + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" +) + +func TestSendRestrictionContextFuncs(t *testing.T) { + tests := []struct { + name string + ctx sdk.Context + exp bool + }{ + { + name: "brand new mostly empty context", + ctx: sdk.NewContext(nil, tmproto.Header{}, false, nil), + exp: false, + }, + { + name: "context with bypass", + ctx: WithBypass(sdk.NewContext(nil, tmproto.Header{}, false, nil)), + exp: true, + }, + { + name: "context with bypass on one that originally was without it", + ctx: WithBypass(WithoutBypass(sdk.NewContext(nil, tmproto.Header{}, false, nil))), + exp: true, + }, + { + name: "context with bypass twice", + ctx: WithBypass(WithBypass(sdk.NewContext(nil, tmproto.Header{}, false, nil))), + exp: true, + }, + { + name: "context without bypass", + ctx: WithoutBypass(sdk.NewContext(nil, tmproto.Header{}, false, nil)), + exp: false, + }, + { + name: "context without bypass on one that originally had it", + ctx: WithoutBypass(WithBypass(sdk.NewContext(nil, tmproto.Header{}, false, nil))), + exp: false, + }, + { + name: "context without bypass twice", + ctx: WithoutBypass(WithoutBypass(sdk.NewContext(nil, tmproto.Header{}, false, nil))), + exp: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actual := HasBypass(tc.ctx) + assert.Equal(t, tc.exp, actual, "HasBypass") + }) + } +} + +func TestContextFuncsDoNotModifyProvided(t *testing.T) { + origCtx := sdk.NewContext(nil, tmproto.Header{}, false, nil) + assert.False(t, HasBypass(origCtx), "HasBypass(origCtx)") + afterWith := WithBypass(origCtx) + assert.True(t, HasBypass(afterWith), "HasBypass(afterWith)") + assert.False(t, HasBypass(origCtx), "HasBypass(origCtx) after giving it to WithBypass") + afterWithout := WithoutBypass(afterWith) + assert.False(t, HasBypass(afterWithout), "HasBypass(afterWithout)") + assert.True(t, HasBypass(afterWith), "HasBypass(afterWith) after giving it to WithoutBypass") + assert.False(t, HasBypass(origCtx), "HasBypass(origCtx) after giving afterWith to WithoutBypass") +} + +func TestKeyContainsModuleName(t *testing.T) { + assert.Contains(t, bypassKey, ModuleName, "bypassKey") +} diff --git a/x/quarantine/simulation/decoder.go b/x/quarantine/simulation/decoder.go new file mode 100644 index 0000000000..9b00596af7 --- /dev/null +++ b/x/quarantine/simulation/decoder.go @@ -0,0 +1,41 @@ +package simulation + +import ( + "bytes" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types/kv" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's +// Value to the corresponding group type. +func NewDecodeStore(cdc codec.Codec) func(kvA, kvB kv.Pair) string { + return func(kvA, kvB kv.Pair) string { + switch { + case bytes.HasPrefix(kvA.Key, quarantine.OptInPrefix): + return fmt.Sprintf("%v\n%v", kvA.Value, kvB.Value) + + case bytes.HasPrefix(kvA.Key, quarantine.AutoResponsePrefix): + respA := quarantine.ToAutoResponse(kvA.Value) + respB := quarantine.ToAutoResponse(kvB.Value) + return fmt.Sprintf("%s\n%s", respA.String(), respB.String()) + + case bytes.HasPrefix(kvA.Key, quarantine.RecordPrefix): + var qrA, qrB quarantine.QuarantineRecord + cdc.MustUnmarshal(kvA.Value, &qrA) + cdc.MustUnmarshal(kvB.Value, &qrB) + return fmt.Sprintf("%v\n%v", qrA, qrB) + + case bytes.HasPrefix(kvA.Key, quarantine.RecordIndexPrefix): + var riA, riB quarantine.QuarantineRecordSuffixIndex + cdc.MustUnmarshal(kvA.Value, &riA) + cdc.MustUnmarshal(kvB.Value, &riB) + return fmt.Sprintf("%v\n%v", riA, riB) + + default: + panic(fmt.Sprintf("invalid quarantine key %X", kvA.Key)) + } + } +} diff --git a/x/quarantine/simulation/decoder_test.go b/x/quarantine/simulation/decoder_test.go new file mode 100644 index 0000000000..ee7651982c --- /dev/null +++ b/x/quarantine/simulation/decoder_test.go @@ -0,0 +1,107 @@ +package simulation_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/kv" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" +) + +func TestDecodeStore(t *testing.T) { + cdc := simapp.MakeTestEncodingConfig().Codec + dec := simulation.NewDecodeStore(cdc) + + cz := func(coins string) sdk.Coins { + rv, err := sdk.ParseCoinsNormalized(coins) + require.NoError(t, err, "ParseCoinsNormalized(%q)", coins) + return rv + } + + marshal := func(o codec.ProtoMarshaler, name string) []byte { + rv, err := cdc.Marshal(o) + require.NoError(t, err, "cdc.Marshal(%s)", name) + return rv + } + + addr0 := sdk.AccAddress("addr0_______________") + addr1 := sdk.AccAddress("addr1_______________") + addr2 := sdk.AccAddress("addr2_______________") + addr3 := sdk.AccAddress("addr3_______________") + + autoRespA := quarantine.AUTO_RESPONSE_ACCEPT + autoRespB := quarantine.AUTO_RESPONSE_DECLINE + autoRespABz := []byte{quarantine.ToAutoB(autoRespA)} + autoRespBBz := []byte{quarantine.ToAutoB(autoRespB)} + + recordA := quarantine.NewQuarantineRecord([]string{addr1.String()}, cz("5bananas"), false) + recordB := quarantine.NewQuarantineRecord([]string{addr3.String()}, cz("8sunflowers"), true) + recordABz := marshal(recordA, "recordA") + recordBBz := marshal(recordB, "recordB") + + recordIndexA := &quarantine.QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{[]byte("0123"), []byte("6789")}} + recordIndexB := &quarantine.QuarantineRecordSuffixIndex{RecordSuffixes: [][]byte{[]byte("abcd"), []byte("wxyz")}} + recordIndexABz := marshal(recordIndexA, "recordIndexA") + recordIndexBBz := marshal(recordIndexB, "recordIndexB") + + tests := []struct { + name string + kvA kv.Pair + kvB kv.Pair + exp string + expPanic string + }{ + { + name: "OptIn", + kvA: kv.Pair{Key: quarantine.CreateOptInKey(addr0), Value: []byte{0x00}}, + kvB: kv.Pair{Key: quarantine.CreateOptInKey(addr1), Value: []byte{0x01}}, + exp: "[0]\n[1]", + }, + { + name: "AutoResponse", + kvA: kv.Pair{Key: quarantine.CreateAutoResponseKey(addr0, addr1), Value: autoRespABz}, + kvB: kv.Pair{Key: quarantine.CreateAutoResponseKey(addr2, addr3), Value: autoRespBBz}, + exp: "AUTO_RESPONSE_ACCEPT\nAUTO_RESPONSE_DECLINE", + }, + { + name: "Record", + kvA: kv.Pair{Key: quarantine.CreateRecordKey(addr0, addr1), Value: recordABz}, + kvB: kv.Pair{Key: quarantine.CreateRecordKey(addr2, addr3), Value: recordBBz}, + exp: "{[61646472315F5F5F5F5F5F5F5F5F5F5F5F5F5F5F] [] 5bananas false}\n{[61646472335F5F5F5F5F5F5F5F5F5F5F5F5F5F5F] [] 8sunflowers true}", + }, + { + name: "RecordIndex", + kvA: kv.Pair{Key: quarantine.CreateRecordIndexKey(addr0, addr1), Value: recordIndexABz}, + kvB: kv.Pair{Key: quarantine.CreateRecordIndexKey(addr1, addr2), Value: recordIndexBBz}, + exp: "{[[48 49 50 51] [54 55 56 57]]}\n{[[97 98 99 100] [119 120 121 122]]}", + }, + { + name: "unknown", + kvA: kv.Pair{Key: []byte{0x9a}, Value: []byte{0x9b}}, + kvB: kv.Pair{Key: []byte{0x9c}, Value: []byte{0x9d}}, + expPanic: "invalid quarantine key 9A", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var actual string + testFunc := func() { + actual = dec(tc.kvA, tc.kvB) + } + if len(tc.expPanic) > 0 { + assert.PanicsWithValue(t, tc.expPanic, testFunc, "running decoder") + } else { + if assert.NotPanics(t, testFunc, "running decoder") { + assert.Equal(t, tc.exp, actual, "decoder result") + } + } + }) + } +} diff --git a/x/quarantine/simulation/genesis.go b/x/quarantine/simulation/genesis.go new file mode 100644 index 0000000000..33c052d9e1 --- /dev/null +++ b/x/quarantine/simulation/genesis.go @@ -0,0 +1,252 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +const ( + QuarantineOptIn = "quarantine-opt-in" + QuarantineAutoResp = "quarantine-auto-resp" + QuarantineFunds = "quarantine-funds" +) + +// RandomQuarantinedAddresses randomly selects accounts from the ones provided to be quarantined. +func RandomQuarantinedAddresses(r *rand.Rand, accounts []simtypes.Account) []string { + // Max number of addresses: + // 15% each: 1, 2, 3, 4, 5 + // 5% each: 6, 7, 8, 9, 0 + // Each provided account has a 25% chance to be quarantined. + max := 0 + maxR := r.Intn(20) + switch { + case maxR <= 14: + max = maxR/3 + 1 + case maxR >= 15 && maxR <= 18: + max = maxR - 9 + case maxR == 19: + max = 0 + default: + panic(sdkerrors.ErrLogic.Wrapf("address max count random number case %d not present in switch", maxR)) + } + + if max == 0 { + return nil + } + + rv := make([]string, 0) + for _, acct := range accounts { + if r.Intn(4) == 0 { + rv = append(rv, acct.Address.String()) + } + if len(rv) >= max { + break + } + } + + if len(rv) == 0 { + return nil + } + + return rv +} + +// RandomQuarantineAutoResponses randomly defines some auto-responses for some of the provided addresses (and maybe others). +func RandomQuarantineAutoResponses(r *rand.Rand, quarantinedAddrs []string) []*quarantine.AutoResponseEntry { + addrs := make([]string, 0) + // First, identify the address that will have some auto-responses. + // Each quarantined address has a 50% chance of having entries. + for _, addr := range quarantinedAddrs { + if r.Intn(2) == 0 { + addrs = append(addrs, addr) + } + } + + // Then, maybe add some new ones. 25% each for 0, 1, 2, or 3 more. + for _, acct := range simtypes.RandomAccounts(r, r.Intn(4)) { + addrs = append(addrs, acct.Address.String()) + } + + if len(addrs) == 0 { + return nil + } + + rv := make([]*quarantine.AutoResponseEntry, 0) + // For each address: + // Number of entries: 50% 1, 25% 2, 25% 3 + // For each entry: + // Response: 5% unspecified, 25% decline, 70% accept + // From: 75% a brand-new address, 25% a quarantined address + // Each quarantined address can be used only once for a given toAddr. + // Once all quarantined address (other than the toAddr) get used, only brand-new addresses are used. + for _, toAddr := range addrs { + unusedQAddrs := append(make([]string, 0, len(quarantinedAddrs)), quarantinedAddrs...) + + entryCount := 0 + entryCountR := r.Intn(4) + switch entryCountR { + case 0, 1: + entryCount = 1 + case 2: + entryCount = 2 + case 3: + entryCount = 3 + default: + panic(sdkerrors.ErrLogic.Wrapf("entry count random number case %d not present in switch", entryCountR)) + } + + for i := 0; i < entryCount; i++ { + entry := &quarantine.AutoResponseEntry{ToAddress: toAddr} + + respR := r.Intn(20) + switch respR { + case 0: + entry.Response = quarantine.AUTO_RESPONSE_UNSPECIFIED + case 1, 2, 3, 4, 5: + entry.Response = quarantine.AUTO_RESPONSE_DECLINE + case 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19: + entry.Response = quarantine.AUTO_RESPONSE_ACCEPT + default: + panic(sdkerrors.ErrLogic.Wrapf("response type random number case %d not present in switch", respR)) + } + + fromR := 0 + if len(unusedQAddrs) > 0 { + fromR = r.Intn(4) + } + switch fromR { + case 0, 1, 2: + acct := simtypes.RandomAccounts(r, 1) + entry.FromAddress = acct[0].Address.String() + case 3: + indR := r.Intn(len(unusedQAddrs)) + entry.FromAddress = unusedQAddrs[indR] + unusedQAddrs[indR] = unusedQAddrs[len(unusedQAddrs)-1] + unusedQAddrs = unusedQAddrs[:len(unusedQAddrs)-1] + default: + panic(sdkerrors.ErrLogic.Wrapf("address from random number case %d not present in switch", fromR)) + } + + rv = append(rv, entry) + } + } + + return rv +} + +// RandomQuarantinedFunds randomly generates some quarantined funds for some of the provided addresses. +func RandomQuarantinedFunds(r *rand.Rand, quarantinedAddrs []string) []*quarantine.QuarantinedFunds { + addrs := make([]string, 0) + // Each quarantined address has a 75% chance of having entries. + for _, addr := range quarantinedAddrs { + if r.Intn(4) != 0 { + addrs = append(addrs, addr) + } + } + + if len(addrs) == 0 { + return nil + } + + rv := make([]*quarantine.QuarantinedFunds, 0) + // For each address: + // Number of entries: 50% 1, 25% 2, 25% 3 + // For each entry: + // Number of from addresses: 75% 1, 20% 2, 5% 3 + // Coins: 1 to 1000 (inclusive) of the bond denom. + // Declined: 80% false, 20% true + + for _, toAddr := range addrs { + entryCount := 0 + entryCountR := r.Intn(4) + switch entryCountR { + case 0, 1: + entryCount = 1 + case 2: + entryCount = 2 + case 3: + entryCount = 3 + default: + panic(sdkerrors.ErrLogic.Wrapf("entry count random number case %d not present in switch", entryCountR)) + } + + for i := 0; i < entryCount; i++ { + addrCount := 0 + addrCountR := r.Intn(20) + switch addrCountR { + case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14: + addrCount = 1 + case 15, 16, 17, 18: + addrCount = 2 + case 19: + addrCount = 3 + default: + panic(sdkerrors.ErrLogic.Wrapf("address count random number case %d not present in switch", addrCountR)) + } + + entry := &quarantine.QuarantinedFunds{ + ToAddress: toAddr, + Coins: sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, r.Int63n(1000)+1)), + Declined: r.Intn(5) == 0, + UnacceptedFromAddresses: make([]string, addrCount), + } + + for a, acct := range simtypes.RandomAccounts(r, addrCount) { + entry.UnacceptedFromAddresses[a] = acct.Address.String() + } + + rv = append(rv, entry) + } + } + + return rv +} + +// RandomizedGenState generates a random GenesisState for the quarantine module. +func RandomizedGenState(simState *module.SimulationState, fundsHolder sdk.AccAddress) { + gen := &quarantine.GenesisState{} + + // QuarantinedAddresses + simState.AppParams.GetOrGenerate( + simState.Cdc, QuarantineOptIn, &gen.QuarantinedAddresses, simState.Rand, + func(r *rand.Rand) { gen.QuarantinedAddresses = RandomQuarantinedAddresses(r, simState.Accounts) }, + ) + + // AutoResponses + simState.AppParams.GetOrGenerate( + simState.Cdc, QuarantineAutoResp, &gen.AutoResponses, simState.Rand, + func(r *rand.Rand) { gen.AutoResponses = RandomQuarantineAutoResponses(r, gen.QuarantinedAddresses) }, + ) + + // QuarantinedFunds + simState.AppParams.GetOrGenerate( + simState.Cdc, QuarantineFunds, &gen.QuarantinedFunds, simState.Rand, + func(r *rand.Rand) { gen.QuarantinedFunds = RandomQuarantinedFunds(r, gen.QuarantinedAddresses) }, + ) + + simState.GenState[quarantine.ModuleName] = simState.Cdc.MustMarshalJSON(gen) + + totalQuarantined := sdk.Coins{} + for _, qf := range gen.QuarantinedFunds { + totalQuarantined = totalQuarantined.Add(qf.Coins...) + } + + if !totalQuarantined.IsZero() { + bankGenRaw := simState.GenState[banktypes.ModuleName] + bankGen := banktypes.GenesisState{} + simState.Cdc.MustUnmarshalJSON(bankGenRaw, &bankGen) + bankGen.Balances = append(bankGen.Balances, banktypes.Balance{ + Address: fundsHolder.String(), + Coins: totalQuarantined, + }) + bankGen.Supply = bankGen.Supply.Add(totalQuarantined...) + + simState.GenState[banktypes.ModuleName] = simState.Cdc.MustMarshalJSON(&bankGen) + } +} diff --git a/x/quarantine/simulation/genesis_test.go b/x/quarantine/simulation/genesis_test.go new file mode 100644 index 0000000000..26c934573b --- /dev/null +++ b/x/quarantine/simulation/genesis_test.go @@ -0,0 +1,500 @@ +package simulation_test + +import ( + "encoding/json" + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" +) + +func TestRandomizedGenState(t *testing.T) { + s := rand.NewSource(1) + r := rand.New(s) + + simState := module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: simapp.MakeTestEncodingConfig().Codec, + Rand: r, + NumBonded: 3, + Accounts: simtypes.RandomAccounts(r, 10), + InitialStake: sdkmath.NewInt(1000), + GenState: make(map[string]json.RawMessage), + } + + var err error + bankGenBefore := banktypes.GenesisState{} + simState.GenState[banktypes.ModuleName], err = simState.Cdc.MarshalJSON(&bankGenBefore) + require.NoError(t, err, "MarshalJSON empty bank genesis state") + + fundsHolder := authtypes.NewModuleAddress(quarantine.ModuleName) + + simulation.RandomizedGenState(&simState, fundsHolder) + var gen quarantine.GenesisState + err = simState.Cdc.UnmarshalJSON(simState.GenState[quarantine.ModuleName], &gen) + require.NoError(t, err, "UnmarshalJSON on quarantine genesis state") + + totalQuarantined := sdk.Coins{} + for _, qf := range gen.QuarantinedFunds { + totalQuarantined = totalQuarantined.Add(qf.Coins...) + } + + if !totalQuarantined.IsZero() { + var bankGen banktypes.GenesisState + err = simState.Cdc.UnmarshalJSON(simState.GenState[banktypes.ModuleName], &bankGen) + require.NoError(t, err, "UnmarshalJSON on quarantine bank state") + holder := fundsHolder.String() + holderFound := false + for _, bal := range bankGen.Balances { + if holder == bal.Address { + holderFound = true + assert.Equal(t, totalQuarantined.String(), bal.Coins.String()) + } + } + assert.True(t, holderFound, "no balance entry found for the funds holder") + _, hasNeg := bankGen.Supply.SafeSub(totalQuarantined...) + assert.False(t, hasNeg, "not enough supply %s to cover the total quarantined %s", bankGen.Supply.String(), totalQuarantined.String()) + } +} + +func TestRandomizedGenStateImportExport(t *testing.T) { + cdc := simapp.MakeTestEncodingConfig().Codec + accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 10) + emptyBankGen := banktypes.GenesisState{} + emptyBankGenBz, err := cdc.MarshalJSON(&emptyBankGen) + require.NoError(t, err, "MarshalJSON empty bank genesis state") + fundsHolder := authtypes.NewModuleAddress(quarantine.ModuleName) + + for i := int64(0); i <= 1000; i++ { + passed := t.Run(fmt.Sprintf("seed %d", i), func(t *testing.T) { + simState := module.SimulationState{ + AppParams: make(simtypes.AppParams), + Cdc: cdc, + Rand: rand.New(rand.NewSource(i)), + NumBonded: 3, + Accounts: make([]simtypes.Account, len(accounts)), + InitialStake: sdkmath.NewInt(1000), + GenState: make(map[string]json.RawMessage), + } + copy(simState.Accounts, accounts) + simState.GenState[banktypes.ModuleName] = emptyBankGenBz + + simulation.RandomizedGenState(&simState, fundsHolder) + var randomGenState quarantine.GenesisState + err = simState.Cdc.UnmarshalJSON(simState.GenState[quarantine.ModuleName], &randomGenState) + require.NoError(t, err, "UnmarshalJSON on quarantine genesis state") + + // The unspecified auto-responses don't get written, so we need to remove them to get the expected. + expGenState := MakeCopyOfGenesisState(&randomGenState) + expectedAutoResponses := make([]*quarantine.AutoResponseEntry, 0, len(expGenState.AutoResponses)) + for _, entry := range expGenState.AutoResponses { + if entry.Response != quarantine.AUTO_RESPONSE_UNSPECIFIED { + expectedAutoResponses = append(expectedAutoResponses, entry) + } + } + expGenState.AutoResponses = expectedAutoResponses + + var bankGen banktypes.GenesisState + err = simState.Cdc.UnmarshalJSON(simState.GenState[banktypes.ModuleName], &bankGen) + require.NoError(t, err, "UnmarshalJSON on bank genesis state") + + app := simapp.Setup(t, false) + ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + + testBankInit := func() { + app.BankKeeper.InitGenesis(ctx, &bankGen) + } + require.NotPanics(t, testBankInit, "bank InitGenesis") + + testInit := func() { + app.QuarantineKeeper.InitGenesis(ctx, &randomGenState) + } + require.NotPanics(t, testInit, "quarantine InitGenesis") + + var actualGenState *quarantine.GenesisState + testExport := func() { + actualGenState = app.QuarantineKeeper.ExportGenesis(ctx) + } + require.NotPanics(t, testExport, "ExportGenesis") + + // Note: The contents of the genesis state is not expected to be in the same order after the init/export. + // I could probably go through the trouble of sorting things, but it would either be horribly inefficient or annoyingly complex (probably both). + // Primarily, the genesis state uses bech32 encoding for the addresses, but when exported, the entries are sorted based on their byte values. + // And sorting by bech32 does not equal sorting by byte values. + assert.ElementsMatch(t, expGenState.QuarantinedAddresses, actualGenState.QuarantinedAddresses, "QuarantinedAddresses, A = expected, B = actual") + assert.ElementsMatch(t, expGenState.AutoResponses, actualGenState.AutoResponses, "AutoResponses, A = expected, B = actual") + assert.ElementsMatch(t, expGenState.QuarantinedFunds, actualGenState.QuarantinedFunds, "QuarantinedFunds, A = expected, B = actual") + }) + if !passed { + break + } + } +} + +func TestRandomQuarantinedAddresses(t *testing.T) { + // Once RandomAccounts is called, we can't trust the values returned from r. + // So all we can do here is check the length of the returned list using seed values found through trial and error. + // These will probably be prone to breakage since any change in use of r will alter the outcomes. + // In the event that this test fails, make sure that there was a change that should alter the outcomes. + // If you've verified that use of r has changed, you can look at the logs of the " good seeds" test to get the + // new expected seed values for each entry. + + type testCase struct { + name string + seed int64 + expLen int + } + + tests := []*testCase{ + { + name: "zero", + seed: 103, + expLen: 0, + }, + { + name: "one", + seed: 3, + expLen: 1, + }, + { + name: "two", + seed: 17, + expLen: 2, + }, + { + name: "three", + seed: 2, + expLen: 3, + }, + { + name: "four", + seed: 4, + expLen: 4, + }, + { + name: "five", + seed: 0, + expLen: 5, + }, + { + name: "six", + seed: 15, + expLen: 6, + }, + { + name: "seven", + seed: 31, + expLen: 7, + }, + { + name: "eight", + seed: 45, + expLen: 8, + }, + { + name: "nine", + seed: 238, + expLen: 9, + }, + } + + runTest := func(t *testing.T, tc *testCase) bool { + t.Helper() + rv := true + // Using a separate rand to generate accounts to make it easier to predict the func being tested. + accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(1)), tc.expLen*4) + r := rand.New(rand.NewSource(tc.seed)) + actual := simulation.RandomQuarantinedAddresses(r, accounts) + if assert.Len(t, actual, tc.expLen, "QuarantinedAddresses") { + if tc.expLen == 0 { + rv = assert.Nil(t, actual, "QuarantinedAddresses") && rv + } + } else { + rv = false + } + for i, addr := range actual { + assert.NotEmpty(t, addr, "QuarantinedAddress[%d]", i) + } + return rv + } + + allPassed := true + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + allPassed = runTest(t, tc) && allPassed + }) + } + + if !allPassed { + stillBad := make(map[string]bool) + maxAttempts := 10000 + t.Run("find good seeds", func(t *testing.T) { + for _, tc := range tests { + for i := 0; i < maxAttempts; i++ { + if runTest(t, tc) { + break + } + tc.seed += 1 + } + } + }) + // opening space is on purpose so it gets sorted to the top. + t.Run(" good seeds", func(t *testing.T) { + for _, tc := range tests { + if stillBad[tc.name] { + t.Logf("%q => no passing seed found from %d to %d", tc.name, int(tc.seed)-maxAttempts, tc.seed-1) + } else { + t.Logf("%q => %d", tc.name, tc.seed) + } + } + t.Fail() // Only runs if the whole test fails. Marking this subtest as failed draws attention to it. + }) + } +} + +func TestRandomQuarantineAutoResponses(t *testing.T) { + // Once RandomAccounts is called, we can't trust the values returned from r. + // In here, using seeds found through trial and error, we can check that some + // addrs are kept, others ignored, and some new ones added. + // These will probably be prone to breakage since any change in use of r will alter the outcomes. + // In the event that this test fails, make sure that there was a change that should alter the outcomes. + // If you've verified that use of r has changed, you can look at the logs of the " good seeds" test to get the + // new expected seed values for each entry. + + type testCase struct { + name string + seed int64 + qAddrs []string + expAddrs []string + newAddrs int + } + + tests := []*testCase{ + { + name: "no addrs in no new addrs", + seed: 3, + qAddrs: nil, + expAddrs: nil, + newAddrs: 0, + }, + { + name: "no addrs in one new addr", + seed: 1, + qAddrs: nil, + expAddrs: nil, + newAddrs: 1, + }, + { + name: "one addr in is kept", + seed: 5, + qAddrs: []string{"addr1"}, + expAddrs: []string{"addr1"}, + newAddrs: 0, + }, + { + name: "one addr in is not kept", + seed: 4, + qAddrs: []string{"addr1"}, + expAddrs: nil, + newAddrs: 0, + }, + { + name: "two addrs in first kept new added", + seed: 2, + qAddrs: []string{"addr1", "addr2"}, + expAddrs: []string{"addr1"}, + newAddrs: 1, + }, + } + + runTest := func(t *testing.T, tc *testCase) bool { + t.Helper() + rv := true + r := rand.New(rand.NewSource(tc.seed)) + actual := simulation.RandomQuarantineAutoResponses(r, tc.qAddrs) + addrMap := make(map[string]bool) + for i, entry := range actual { + addrMap[entry.ToAddress] = true + assert.NotEmpty(t, entry.ToAddress, "[%d].ToAddress", i) + assert.NotEmpty(t, entry.FromAddress, "[%d].FromAddress", i) + assert.True(t, entry.Response.IsValid(), "[%d].Response.IsValid(), Response = %s", i, entry.Response) + } + addrs := make([]string, 0, len(addrMap)) + for addr := range addrMap { + addrs = append(addrs, addr) + } + rv = assert.Len(t, addrs, len(tc.expAddrs)+tc.newAddrs, "to addresses") && rv + for _, addr := range tc.expAddrs { + rv = assert.Contains(t, addrs, addr, "to addresses") && rv + } + return rv + } + + allPassed := true + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + allPassed = runTest(t, tc) && allPassed + }) + } + + if !allPassed { + stillBad := make(map[string]bool) + maxAttempts := 10000 + t.Run("find good seeds", func(t *testing.T) { + for _, tc := range tests { + for i := 0; i < maxAttempts; i++ { + if runTest(t, tc) { + break + } + tc.seed += 1 + } + } + }) + // opening space is on purpose so it gets sorted to the top. + t.Run(" good seeds", func(t *testing.T) { + for _, tc := range tests { + if stillBad[tc.name] { + t.Logf("%q => no passing seed found from %d to %d", tc.name, int(tc.seed)-maxAttempts, tc.seed-1) + } else { + t.Logf("%q => %d", tc.name, tc.seed) + } + } + t.Fail() // Only runs if the whole test fails. Marking this subtest as failed draws attention to it. + }) + } +} + +func TestRandomQuarantinedFunds(t *testing.T) { + // Once RandomAccounts is called, we can't trust the values returned from r. + // In here, using seeds found through trial and error, we can check that some + // addrs are kept, others ignored. + // These will probably be prone to breakage since any change in use of r will alter the outcomes. + // In the event that this test fails, make sure that there was a change that should alter the outcomes. + // If you've verified that use of r has changed, you can look at the logs of the " good seeds" test to get the + // new expected seed values for each entry. + + type testCase struct { + name string + seed int64 + qAddrs []string + expAddrs []string + } + + tests := []*testCase{ + { + name: "no addrs in", + seed: 0, + qAddrs: nil, + expAddrs: nil, + }, + { + name: "one addr in is kept", + seed: 0, + qAddrs: []string{"addr1"}, + expAddrs: []string{"addr1"}, + }, + { + name: "one addr in is not kept", + seed: 3, + qAddrs: []string{"addr1"}, + expAddrs: nil, + }, + { + name: "two addrs in none kept", + seed: 8, + qAddrs: []string{"addr1", "addr2"}, + expAddrs: []string{}, + }, + { + name: "two addrs in first kept", + seed: 4, + qAddrs: []string{"addr1", "addr2"}, + expAddrs: []string{"addr1"}, + }, + { + name: "two addrs in second kept", + seed: 3, + qAddrs: []string{"addr1", "addr2"}, + expAddrs: []string{"addr2"}, + }, + { + name: "two addrs in both kept", + seed: 0, + qAddrs: []string{"addr1", "addr2"}, + expAddrs: []string{"addr1", "addr2"}, + }, + } + + runTest := func(t *testing.T, tc *testCase) bool { + t.Helper() + rv := true + r := rand.New(rand.NewSource(tc.seed)) + actual := simulation.RandomQuarantinedFunds(r, tc.qAddrs) + addrMap := make(map[string]bool) + for i, entry := range actual { + addrMap[entry.ToAddress] = true + assert.NotEmpty(t, entry.ToAddress, "[%d].ToAddress", i) + for j, addr := range entry.UnacceptedFromAddresses { + assert.NotEmpty(t, addr, "[%d].UnacceptedFromAddresses[%d]", i, j) + } + assert.NoError(t, entry.Coins.Validate(), "[%d].Coins", i) + } + addrs := make([]string, 0, len(addrMap)) + for addr := range addrMap { + addrs = append(addrs, addr) + } + rv = assert.Len(t, addrs, len(tc.expAddrs), "to addresses") && rv + for _, addr := range tc.expAddrs { + rv = assert.Contains(t, addrs, addr, "to addresses") && rv + } + return rv + } + + allPassed := true + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + allPassed = runTest(t, tc) && allPassed + }) + } + + if !allPassed { + stillBad := make(map[string]bool) + maxAttempts := 10000 + t.Run("find good seeds", func(t *testing.T) { + for _, tc := range tests { + for i := 0; i < maxAttempts; i++ { + if runTest(t, tc) { + break + } + tc.seed += 1 + } + } + }) + // opening space is on purpose so it gets sorted to the top. + t.Run(" good seeds", func(t *testing.T) { + for _, tc := range tests { + if stillBad[tc.name] { + t.Logf("%q => no passing seed found from %d to %d", tc.name, int(tc.seed)-maxAttempts, tc.seed-1) + } else { + t.Logf("%q => %d", tc.name, tc.seed) + } + } + t.Fail() // Only runs if the whole test fails. Marking this subtest as failed draws attention to it. + }) + } +} diff --git a/x/quarantine/simulation/operations.go b/x/quarantine/simulation/operations.go new file mode 100644 index 0000000000..b60deb60fe --- /dev/null +++ b/x/quarantine/simulation/operations.go @@ -0,0 +1,449 @@ +package simulation + +import ( + "bytes" + "math/rand" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Quarantine message types. +var ( + TypeMsgOptIn = sdk.MsgTypeURL(&quarantine.MsgOptIn{}) + TypeMsgOptOut = sdk.MsgTypeURL(&quarantine.MsgOptOut{}) + TypeMsgAccept = sdk.MsgTypeURL(&quarantine.MsgAccept{}) + TypeMsgDecline = sdk.MsgTypeURL(&quarantine.MsgDecline{}) + TypeMsgUpdateAutoResponses = sdk.MsgTypeURL(&quarantine.MsgUpdateAutoResponses{}) +) + +// Simulation operation weights constants. +const ( + OpMsgOptIn = "op_weight_quarantine_msg_opt_in" + OpMsgOptOut = "op_weight_quarantine_msg_opt_out" + OpMsgAccept = "op_weight_quarantine_msg_accept" + OpMsgDecline = "op_weight_quarantine_msg_decline" + OpMsgUpdateAutoResponses = "op_weight_quarantine_msg_update_auto_responses" +) + +// Default weights. +const ( + WeightMsgOptIn = 100 + WeightMsgOptOut = 50 + WeightMsgAccept = 50 + WeightMsgDecline = 20 + WeightMsgUpdateAutoResponses = 50 +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simtypes.AppParams, cdc codec.JSONCodec, + ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker, +) simulation.WeightedOperations { + var ( + weightMsgOptIn int + weightMsgOptOut int + weightMsgAccept int + weightMsgDecline int + weightMsgUpdateAutoResponses int + ) + + appParams.GetOrGenerate(cdc, OpMsgOptIn, &weightMsgOptIn, nil, + func(_ *rand.Rand) { weightMsgOptIn = WeightMsgOptIn }) + appParams.GetOrGenerate(cdc, OpMsgOptOut, &weightMsgOptOut, nil, + func(_ *rand.Rand) { weightMsgOptOut = WeightMsgOptOut }) + appParams.GetOrGenerate(cdc, OpMsgAccept, &weightMsgAccept, nil, + func(_ *rand.Rand) { weightMsgAccept = WeightMsgAccept }) + appParams.GetOrGenerate(cdc, OpMsgDecline, &weightMsgDecline, nil, + func(_ *rand.Rand) { weightMsgDecline = WeightMsgDecline }) + appParams.GetOrGenerate(cdc, OpMsgUpdateAutoResponses, &weightMsgUpdateAutoResponses, nil, + func(_ *rand.Rand) { weightMsgUpdateAutoResponses = WeightMsgUpdateAutoResponses }) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation(weightMsgOptIn, SimulateMsgOptIn(ak, bk)), + simulation.NewWeightedOperation(weightMsgOptOut, SimulateMsgOptOut(ak, bk, k)), + simulation.NewWeightedOperation(weightMsgAccept, SimulateMsgAccept(ak, bk, k)), + simulation.NewWeightedOperation(weightMsgDecline, SimulateMsgDecline(ak, bk, k)), + simulation.NewWeightedOperation(weightMsgUpdateAutoResponses, SimulateMsgUpdateAutoResponses(ak, bk, k)), + } +} + +// SimulateMsgOptIn opts an account into quarantine. +func SimulateMsgOptIn(ak quarantine.AccountKeeper, bk quarantine.BankKeeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + acct, _ := simtypes.RandomAcc(r, accs) + msg := &quarantine.MsgOptIn{ + ToAddress: acct.Address.String(), + } + msgType := TypeMsgOptIn + + spendableCoins := bk.SpendableCoins(ctx, acct.Address) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "fee error"), nil, err + } + + account := ak.GetAccount(ctx, acct.Address) + + encCfg := simappparams.MakeTestEncodingConfig() + tx, err := helpers.GenSignedMockTx( + r, + encCfg.TxConfig, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acct.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to generate mock tx"), nil, err + } + + _, _, err = app.SimDeliver(encCfg.TxConfig.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", codec.NewProtoCodec(encCfg.InterfaceRegistry)), nil, nil + } +} + +// SimulateMsgOptOut opts an account out of quarantine. +func SimulateMsgOptOut(ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + msg := &quarantine.MsgOptOut{} + msgType := TypeMsgOptOut + + // 3 in 4 chance of using a quarantined account. + // 1 in 4 chance of using a random account. + var acct simtypes.Account + if r.Intn(4) != 0 { + addr := randomQuarantinedAccount(ctx, r, k) + if len(addr) == 0 { + return simtypes.NoOpMsg(msgType, msgType, "no addresses opted in yet"), nil, nil + } + acctInd := findAccount(accs, addr) + if acctInd < 0 { + return simtypes.NoOpMsg(msgType, msgType, "account not found for quarantined address"), nil, nil + } + acct = accs[acctInd] + msg.ToAddress = addr.String() + } + + if len(msg.ToAddress) == 0 { + acct, _ = simtypes.RandomAcc(r, accs) + msg.ToAddress = acct.Address.String() + } + + spendableCoins := bk.SpendableCoins(ctx, acct.Address) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "fee error"), nil, err + } + + account := ak.GetAccount(ctx, acct.Address) + + encCfg := simappparams.MakeTestEncodingConfig() + tx, err := helpers.GenSignedMockTx( + r, + encCfg.TxConfig, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acct.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to generate mock tx"), nil, err + } + + _, _, err = app.SimDeliver(encCfg.TxConfig.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", codec.NewProtoCodec(encCfg.InterfaceRegistry)), nil, nil + } +} + +// SimulateMsgAccept accepts quarantined funds. +func SimulateMsgAccept(ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + msg := &quarantine.MsgAccept{} + msgType := TypeMsgAccept + + // 3 in 4 chance of accepting actually quarantined funds (if any exist). + // 1 in 4 chance of the accept being meaningless. + // Then, 1 in 5 chance of it being permanent. + var acct simtypes.Account + if r.Intn(4) != 0 { + funds := randomQuarantinedFunds(ctx, r, k) + if funds == nil { + return simtypes.NoOpMsg(msgType, msgType, "no funds yet quarantined"), nil, nil + } + msg.ToAddress = funds.ToAddress + msg.FromAddresses = funds.UnacceptedFromAddresses + addr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "invalid to address in quarantined funds"), nil, err + } + acctInd := findAccount(accs, addr) + if acctInd < 0 { + return simtypes.NoOpMsg(msgType, msgType, "account not found for to address"), nil, nil + } + acct = accs[acctInd] + } + + if len(msg.ToAddress) == 0 { + acct, _ = simtypes.RandomAcc(r, accs) + fromAcct, _ := simtypes.RandomAcc(r, accs) + msg.ToAddress = acct.Address.String() + msg.FromAddresses = append(msg.FromAddresses, fromAcct.Address.String()) + } + + msg.Permanent = r.Intn(5) == 0 + + spendableCoins := bk.SpendableCoins(ctx, acct.Address) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "fee error"), nil, err + } + + account := ak.GetAccount(ctx, acct.Address) + + encCfg := simappparams.MakeTestEncodingConfig() + tx, err := helpers.GenSignedMockTx( + r, + encCfg.TxConfig, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acct.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to generate mock tx"), nil, err + } + + _, _, err = app.SimDeliver(encCfg.TxConfig.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", codec.NewProtoCodec(encCfg.InterfaceRegistry)), nil, nil + } +} + +// SimulateMsgDecline declines quarantined funds. +func SimulateMsgDecline(ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + msg := &quarantine.MsgDecline{} + msgType := TypeMsgDecline + + // 3 in 4 chance of declining actually quarantined funds (if any exist). + // 1 in 4 chance of the decline being meaningless. + // Then, 1 in 5 chance of it being permanent. + var acct simtypes.Account + if r.Intn(4) != 0 { + funds := randomQuarantinedFunds(ctx, r, k) + if funds == nil { + return simtypes.NoOpMsg(msgType, msgType, "no funds yet quarantined"), nil, nil + } + msg.ToAddress = funds.ToAddress + msg.FromAddresses = funds.UnacceptedFromAddresses + addr, err := sdk.AccAddressFromBech32(msg.ToAddress) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "invalid to address in quarantined funds"), nil, err + } + acctInd := findAccount(accs, addr) + if acctInd < 0 { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "account not found for to address"), nil, nil + } + acct = accs[acctInd] + } + + if len(msg.ToAddress) == 0 { + acct, _ = simtypes.RandomAcc(r, accs) + fromAcct, _ := simtypes.RandomAcc(r, accs) + msg.ToAddress = acct.Address.String() + msg.FromAddresses = append(msg.FromAddresses, fromAcct.Address.String()) + } + + msg.Permanent = r.Intn(5) == 0 + + spendableCoins := bk.SpendableCoins(ctx, acct.Address) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "fee error"), nil, err + } + + account := ak.GetAccount(ctx, acct.Address) + + encCfg := simappparams.MakeTestEncodingConfig() + tx, err := helpers.GenSignedMockTx( + r, + encCfg.TxConfig, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acct.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to generate mock tx"), nil, err + } + + _, _, err = app.SimDeliver(encCfg.TxConfig.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", codec.NewProtoCodec(encCfg.InterfaceRegistry)), nil, nil + } +} + +// SimulateMsgUpdateAutoResponses updates an accounts auto-responses +func SimulateMsgUpdateAutoResponses(ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper) simtypes.Operation { + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, + accs []simtypes.Account, chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + msg := &quarantine.MsgUpdateAutoResponses{} + msgType := TypeMsgUpdateAutoResponses + + // 3 in 4 chance of using a quarantined account. + // 1 to 4 entries. + // Each entry: 75% accept, 25% decline, 5% unspecified. + var acct simtypes.Account + if r.Intn(4) != 0 { + addr := randomQuarantinedAccount(ctx, r, k) + if len(addr) == 0 { + return simtypes.NoOpMsg(msgType, msgType, "no addresses opted in yet"), nil, nil + } + acctInd := findAccount(accs, addr) + if acctInd < 0 { + return simtypes.NoOpMsg(msgType, msgType, "account not found for quarantined address"), nil, nil + } + acct = accs[acctInd] + msg.ToAddress = addr.String() + } + + if len(msg.ToAddress) == 0 { + acct, _ = simtypes.RandomAcc(r, accs) + msg.ToAddress = acct.Address.String() + } + + entryCount := r.Intn(3) + 1 + for len(msg.Updates) < entryCount { + entry := &quarantine.AutoResponseUpdate{} + acct, _ := simtypes.RandomAcc(r, accs) + entry.FromAddress = acct.Address.String() + respR := r.Intn(20) + switch respR { + case 0: + entry.Response = quarantine.AUTO_RESPONSE_UNSPECIFIED + case 1, 2, 3, 4, 5: + entry.Response = quarantine.AUTO_RESPONSE_DECLINE + case 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19: + entry.Response = quarantine.AUTO_RESPONSE_ACCEPT + default: + err := sdkerrors.ErrLogic.Wrapf("response type random number case %d not present in switch", respR) + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, ""), nil, err + } + msg.Updates = append(msg.Updates, entry) + } + + spendableCoins := bk.SpendableCoins(ctx, acct.Address) + fees, err := simtypes.RandomFees(r, ctx, spendableCoins) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "fee error"), nil, err + } + + account := ak.GetAccount(ctx, acct.Address) + + encCfg := simappparams.MakeTestEncodingConfig() + tx, err := helpers.GenSignedMockTx( + r, + encCfg.TxConfig, + []sdk.Msg{msg}, + fees, + helpers.DefaultGenTxGas, + chainID, + []uint64{account.GetAccountNumber()}, + []uint64{account.GetSequence()}, + acct.PrivKey, + ) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to generate mock tx"), nil, err + } + + _, _, err = app.SimDeliver(encCfg.TxConfig.TxEncoder(), tx) + if err != nil { + return simtypes.NoOpMsg(quarantine.ModuleName, msgType, "unable to deliver tx"), nil, err + } + + return simtypes.NewOperationMsg(msg, true, "", codec.NewProtoCodec(encCfg.InterfaceRegistry)), nil, nil + } +} + +func randomQuarantinedAccount(ctx sdk.Context, r *rand.Rand, k keeper.Keeper) sdk.AccAddress { + allQuarantinedAddrs := []*sdk.AccAddress{} + k.IterateQuarantinedAccounts(ctx, func(toAddr sdk.AccAddress) bool { + allQuarantinedAddrs = append(allQuarantinedAddrs, &toAddr) + return false + }) + rv := randomEntry(r, allQuarantinedAddrs) + if rv == nil || len(*rv) == 0 { + return nil + } + return *rv +} + +func randomQuarantinedFunds(ctx sdk.Context, r *rand.Rand, k keeper.Keeper) *quarantine.QuarantinedFunds { + return randomEntry(r, k.GetAllQuarantinedFunds(ctx)) +} + +func randomEntry[V any](r *rand.Rand, addrs []*V) *V { + if len(addrs) == 0 { + return nil + } + return addrs[r.Intn(len(addrs))] +} + +func findAccount(accounts []simtypes.Account, addr sdk.AccAddress) int { + for i := range accounts { + if bytes.Equal(addr, accounts[i].Address) { + return i + } + } + return -1 +} diff --git a/x/quarantine/simulation/operations_test.go b/x/quarantine/simulation/operations_test.go new file mode 100644 index 0000000000..8075825a09 --- /dev/null +++ b/x/quarantine/simulation/operations_test.go @@ -0,0 +1,223 @@ +package simulation_test + +import ( + "math/rand" + "strings" + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/simapp" + sdk "github.com/cosmos/cosmos-sdk/types" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/testutil" + "github.com/cosmos/cosmos-sdk/x/quarantine" + "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" +) + +type SimTestSuite struct { + suite.Suite + + ctx sdk.Context + app *simapp.SimApp +} + +func TestSimTestSuite(t *testing.T) { + suite.Run(t, new(SimTestSuite)) +} + +func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Account { + accounts := simtypes.RandomAccounts(r, n) + + initAmt := sdk.TokensFromConsensusPower(200, sdk.DefaultPowerReduction) + initCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, initAmt)) + + // add coins to the accounts + for _, account := range accounts { + acc := s.app.AccountKeeper.NewAccountWithAddress(s.ctx, account.Address) + s.app.AccountKeeper.SetAccount(s.ctx, acc) + s.Require().NoError(testutil.FundAccount(s.app.BankKeeper, s.ctx, account.Address, initCoins)) + } + + return accounts +} + +func (s *SimTestSuite) SetupTest() { + s.app = simapp.Setup(s.T(), false) + s.ctx = s.app.BaseApp.NewContext(false, tmproto.Header{}) +} + +func (s *SimTestSuite) TestWeightedOperations() { + cdc := s.app.AppCodec() + appParams := make(simtypes.AppParams) + + expected := []struct { + weight int + opsMsgRoute string + opsMsgName string + }{ + {simulation.WeightMsgOptIn, simulation.TypeMsgOptIn, simulation.TypeMsgOptIn}, + {simulation.WeightMsgOptOut, simulation.TypeMsgOptOut, simulation.TypeMsgOptOut}, + {simulation.WeightMsgAccept, simulation.TypeMsgAccept, simulation.TypeMsgAccept}, + {simulation.WeightMsgDecline, simulation.TypeMsgDecline, simulation.TypeMsgDecline}, + {simulation.WeightMsgUpdateAutoResponses, simulation.TypeMsgUpdateAutoResponses, simulation.TypeMsgUpdateAutoResponses}, + } + + weightedOps := simulation.WeightedOperations( + appParams, cdc, + s.app.AccountKeeper, s.app.BankKeeper, s.app.QuarantineKeeper, cdc, + ) + + s.Require().Len(weightedOps, len(expected), "weighted ops") + + r := rand.New(rand.NewSource(1)) + accs := s.getTestingAccounts(r, 10) + + for i, actual := range weightedOps { + exp := expected[i] + parts := strings.Split(exp.opsMsgName, ".") + s.Run(parts[len(parts)-1], func() { + operationMsg, futureOps, err := actual.Op()(r, s.app.BaseApp, s.ctx, accs, "") + s.Assert().NoError(err, "op error") + s.Assert().Equal(exp.weight, actual.Weight(), "op weight") + s.Assert().Equal(exp.opsMsgRoute, operationMsg.Route, "op route") + s.Assert().Equal(exp.opsMsgName, operationMsg.Name, "op name") + s.Assert().Nil(futureOps, "future ops") + }) + } +} + +func (s *SimTestSuite) TestSimulateMsgOptIn() { + r := rand.New(rand.NewSource(1)) + accounts := s.getTestingAccounts(r, 10) + + s.app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: s.app.LastBlockHeight() + 1, + AppHash: s.app.LastCommitID().Hash, + }, + }) + + op := simulation.SimulateMsgOptIn(s.app.AccountKeeper, s.app.BankKeeper) + opMsg, futureOps, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "running SimulateMsgOptIn op") + + var msg quarantine.MsgOptIn + err = s.app.AppCodec().UnmarshalJSON(opMsg.Msg, &msg) + s.Assert().NoError(err, "UnmarshalJSON on opMsg.Msg for MsgOptIn") + s.Assert().True(opMsg.OK, "opMsg.OK") + s.Assert().Len(futureOps, 0) +} + +func (s *SimTestSuite) TestSimulateMsgOptOut() { + r := rand.New(rand.NewSource(1)) + accounts := s.getTestingAccounts(r, 10) + + err := s.app.QuarantineKeeper.SetOptIn(s.ctx, accounts[0].Address) + s.Require().NoError(err, "SetOptIn on accounts[0]") + + s.app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: s.app.LastBlockHeight() + 1, + AppHash: s.app.LastCommitID().Hash, + }, + }) + + op := simulation.SimulateMsgOptOut(s.app.AccountKeeper, s.app.BankKeeper, s.app.QuarantineKeeper) + opMsg, futureOps, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "running SimulateMsgOptIn op") + + var msg quarantine.MsgOptOut + err = s.app.AppCodec().UnmarshalJSON(opMsg.Msg, &msg) + s.Assert().NoError(err, "UnmarshalJSON on opMsg.Msg for MsgOptIn") + s.Assert().True(opMsg.OK, "opMsg.OK") + s.Assert().Len(futureOps, 0) +} + +func (s *SimTestSuite) TestSimulateMsgAccept() { + r := rand.New(rand.NewSource(1)) + accounts := s.getTestingAccounts(r, 10) + + err := s.app.QuarantineKeeper.SetOptIn(s.ctx, accounts[0].Address) + s.Require().NoError(err, "SetOptIn on accounts[0]") + spendableCoins := s.app.BankKeeper.SpendableCoins(s.ctx, accounts[1].Address) + toSend, err := simtypes.RandomFees(r, s.ctx, spendableCoins) + s.Require().NoError(err, "RandomFees(%q)", spendableCoins.String()) + err = s.app.BankKeeper.SendCoins(s.ctx, accounts[1].Address, accounts[0].Address, toSend) + s.Require().NoError(err, "SendCoins") + + s.app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: s.app.LastBlockHeight() + 1, + AppHash: s.app.LastCommitID().Hash, + }, + }) + + op := simulation.SimulateMsgAccept(s.app.AccountKeeper, s.app.BankKeeper, s.app.QuarantineKeeper) + opMsg, futureOps, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "running SimulateMsgOptIn op") + + var msg quarantine.MsgAccept + err = s.app.AppCodec().UnmarshalJSON(opMsg.Msg, &msg) + s.Assert().NoError(err, "UnmarshalJSON on opMsg.Msg for MsgOptIn") + s.Assert().True(opMsg.OK, "opMsg.OK") + s.Assert().Len(futureOps, 0) +} + +func (s *SimTestSuite) TestSimulateMsgDecline() { + r := rand.New(rand.NewSource(1)) + accounts := s.getTestingAccounts(r, 10) + + err := s.app.QuarantineKeeper.SetOptIn(s.ctx, accounts[0].Address) + s.Require().NoError(err, "SetOptIn on accounts[0]") + spendableCoins := s.app.BankKeeper.SpendableCoins(s.ctx, accounts[1].Address) + toSend, err := simtypes.RandomFees(r, s.ctx, spendableCoins) + s.Require().NoError(err, "RandomFees(%q)", spendableCoins.String()) + err = s.app.BankKeeper.SendCoins(s.ctx, accounts[1].Address, accounts[0].Address, toSend) + s.Require().NoError(err, "SendCoins") + + s.app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: s.app.LastBlockHeight() + 1, + AppHash: s.app.LastCommitID().Hash, + }, + }) + + op := simulation.SimulateMsgDecline(s.app.AccountKeeper, s.app.BankKeeper, s.app.QuarantineKeeper) + opMsg, futureOps, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "running SimulateMsgOptIn op") + + var msg quarantine.MsgDecline + err = s.app.AppCodec().UnmarshalJSON(opMsg.Msg, &msg) + s.Assert().NoError(err, "UnmarshalJSON on opMsg.Msg for MsgOptIn") + s.Assert().True(opMsg.OK, "opMsg.OK") + s.Assert().Len(futureOps, 0) +} + +func (s *SimTestSuite) TestSimulateMsgUpdateAutoResponses() { + r := rand.New(rand.NewSource(1)) + accounts := s.getTestingAccounts(r, 10) + + err := s.app.QuarantineKeeper.SetOptIn(s.ctx, accounts[0].Address) + s.Require().NoError(err, "SetOptIn on accounts[0]") + + s.app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: s.app.LastBlockHeight() + 1, + AppHash: s.app.LastCommitID().Hash, + }, + }) + + op := simulation.SimulateMsgUpdateAutoResponses(s.app.AccountKeeper, s.app.BankKeeper, s.app.QuarantineKeeper) + opMsg, futureOps, err := op(r, s.app.BaseApp, s.ctx, accounts, "") + s.Require().NoError(err, "running SimulateMsgOptIn op") + + var msg quarantine.MsgUpdateAutoResponses + err = s.app.AppCodec().UnmarshalJSON(opMsg.Msg, &msg) + s.Assert().NoError(err, "UnmarshalJSON on opMsg.Msg for MsgOptIn") + s.Assert().True(opMsg.OK, "opMsg.OK") + s.Assert().Len(futureOps, 0) + s.Assert().GreaterOrEqual(len(msg.Updates), 1, "number of updates") +} diff --git a/x/quarantine/spec/01_concepts.md b/x/quarantine/spec/01_concepts.md new file mode 100644 index 0000000000..fe7cc03f3a --- /dev/null +++ b/x/quarantine/spec/01_concepts.md @@ -0,0 +1,49 @@ + + +# Concepts + +## Quarantined Account + +A quarantined account is one that has elected to not receive funds transfers until the transfer has been accepted. + +When funds are sent using the `x/bank` module keeper's `SendCoins` or `InputOutputCoins` functions (e.g. from a `Send` or `MultiSend` Tx), +if the receiver is quarantined, the funds are sent to an intermediary quarantined funds holder account and a record of the quarantined funds is made. +Later, the receiver can `Approve` or `Decline` the funds as they see fit. + +## Opt-In + +An account becomes quarantined when the account owner issues an `OptIn` Tx. +An account can later opt out by issuing an `OptOut` Tx. +Opting in or out does not affect any previously quarantined funds. + +## Quarantined Funds + +Quarantined funds can either be accepted or declined (or ignored) by the receiver. + +### Accept Funds + +When a receiver `Accept`s funds, all fully approved quarantined funds from each sender are transferred to the receiver. +Quarantined funds are fully approved when all senders involved in the transfer of those funds have been part of an `Accept` from the receiver. +Funds quarantined for a receiver are aggregated by sender (or set of senders in the case of a `MultiSend`). +That is, if a sender issues two different transfers to a receiver, they are quarantined together and the receiver only needs to issue a single `Accept` for them. + +### Decline Funds + +When a receiver `Decline`s funds, all quarantined funds from each sender are marked as declined. +Declined funds remain held by the quarantined fund holder account and can later be accepted. +Declined funds are not returned by the `QuarantinedFunds` query unless the query params included a specific sender. +The decline indicator is reset to `false` if new funds are quarantined (to the same receiver from the same sender) and auto-decline is not set up. + +## Auto-Responses + +A quarantined account can set up auto-accept from known trusted senders, and auto-decline from known untrusted senders. +An auto-response is unique for a given receiver and sender and only applies in one direction. +That is, the auto-responses that one receiver has defined, do not affect any other accounts. + +If funds are sent to a quarantined account from an auto-accept sender, the transfer occurs as if the receiver weren't quarantined. +When there are multiple senders, the funds are quarantined unless the receiver has auto-accept for **ALL** of the senders. + +If funds are sent to a quarantined account from an auto-decline sender, the funds are quarantined and marked as declined. +When there are multiple senders, the funds are declined if the receiver has auto-decline for **ANY** of the senders. diff --git a/x/quarantine/spec/02_state.md b/x/quarantine/spec/02_state.md new file mode 100644 index 0000000000..312f31d4ec --- /dev/null +++ b/x/quarantine/spec/02_state.md @@ -0,0 +1,60 @@ + + +# State + +The `x/quarantine` module uses key/value pairs to store quarantine-related data in state. + +## Quarantined Accounts + +When an account opts into quarantine, the following record is made: + +``` +0x00 | len([]byte()) | []byte() -> 0x00 +``` + +When an account opts out of quarantine, that record is deleted. + +## Auto-Responses + +Auto-Responses are stored using the following format: + +``` +0x01 | len([]byte()) | []byte() | len([]byte()) | []byte() -> +``` + +`` values: +- `0x01` = `AUTO_RESPONSE_ACCEPT` +- `0x02` = `AUTO_RESPONSE_DECLINE` + +Instead of storing `AUTO_RESPONSE_UNSPECIFIED` the record is deleted. + +## Quarantine Records + +Records of quarantined funds are stored using the following format: + +``` +0x02 | len([]byte()) | []byte() | len([]byte()) | []byte() -> ProtocolBuffer(QuarantineRecord) +``` + +When there is a single sender, the `` is the ``. + +When there are multiple senders, the `` is a function of all sender addresses combined. +Specifically, all involved sender addresses are sorted and concatenated into a single `[]byte`, then provided to a `sha256` checksum generator. + +Once quarantined funds are accepted and released, this record is deleted. + +## Quarantine Records Suffix Index + +When there are multiple senders, an index entry is made for each sender. +These entries use the following format: + +``` +0x03 | len([]byte()) | []byte() | len([]byte()) | []byte() -> ProtocolBuffer(QuarantineRecordSuffixIndex) +``` + +These entries allow multi-sender quarantine records to be located based on a single sender. +They are not needed for single-sender records; as such, they are only made for multi-sender records. + +Once a quarantine record is deleted, its suffix index entries are also deleted. diff --git a/x/quarantine/spec/03_messages.md b/x/quarantine/spec/03_messages.md new file mode 100644 index 0000000000..eeafe060d9 --- /dev/null +++ b/x/quarantine/spec/03_messages.md @@ -0,0 +1,84 @@ + + +# Msg Service + +## Msg/OptIn + +An account can activate quarantine using a `MsgOptIn`. +It contains only the address to quarantine. + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L33-L38 + +It is expected to fail if the `to_address` is invalid. + +## Msg/OptOut + +An account can deactivate quarantine using a `MsgOptOut`. +It contains only the address to unquarantine. + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L43-L48 + +It is expected to fail if the `to_address` is invalid. + +## Msg/Accept + +Quarantined funds can be accepted by the intended receiver using a `MsgAccept`. +It contains a `to_address` (receiver) and one or more `from_addresses` (senders). +It also contains a flag to indicate whether auto-accept should be set up for all provided addresses. + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L53-L67 + +Any quarantined funds for the `to_address` from any `from_address` are accepted (regardless of whether they've been previously declined). + +For quarantined funds from multiple senders (e.g. from a `MultiSend`), all senders must be part of an `Accept` before the funds will be released, +but they don't all have to be part of the same `Accept`. + +If the `permanent` flag is `true`, after accepting all applicable funds, auto-accept is set up to the `to_address` from each of the provided `from_addresses`. + +It is expected to fail if: +- The `to_address` is missing or invalid. +- No `from_addresses` are provided. +- Any `from_addresses` are invalid. + +The response will contain a total of all funds released. + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L69-L74 + +## Msg/Decline + +Quarantined funds can be declined by the intended receiver using a `MsgDecline`. +It contains a `to_address` (receiver) and one or more `from_addresses` (senders). +It also contains a flag to indicate whether auto-decline should be set up for all provided addresses. + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L76-L90 + +Any quarantined funds for the `to_address` from any `from_address` are declined. + +For quarantined funds from multiple senders (e.g. from a `MultiSend`), a decline from any sender involved is sufficient to decline the funds. +Funds that have been declined can always be accepted later. + +If the `permanent` flag is `true`, after declining all applicable funds, auto-decline is set up to the `to_address` from each of the provided `from_addresses`. + +It is expected to fail if: +- The `to_address` is missing or invalid. +- No `from_addresses` are provided. +- Any `from_addresses` are invalid. + +## Msg/UpdateAutoResponses + +Auto-Responses can be defined either through the `permanent` flags with a `MsgAccept` or `MsgDecline`, or using a `MsgUpdateAutoResponses`. +It contains a `to_address` and a list of `updates`. Each `AutoResponseUpdate` contains a `from_address` and the desired `response` for it. + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L95-L104 + +Providing a `response` of `AUTO_RESPONSE_UNSPECIFIED` will cause the applicable entry to be deleted, allowing users to un-set previous auto-responses. + +Updating auto-responses has no effect on existing quarantined funds. + +It is expected to fail if: +- The `to_address` is invalid. +- No `updates` are provided. +- Any `from_address` is missing or invalid. +- Any `response` value is something other than `AUTO_RESPONSE_ACCEPT`, `AUTO_RESPONSE_DECLINE`, or `AUTO_RESPONSE_UNSPECIFIED`. \ No newline at end of file diff --git a/x/quarantine/spec/04_events.md b/x/quarantine/spec/04_events.md new file mode 100644 index 0000000000..58548bdcf0 --- /dev/null +++ b/x/quarantine/spec/04_events.md @@ -0,0 +1,50 @@ + + +# Events + +The `x/quarantine` module emits the following events: + +## EventOptIn + +This event is emitted when an account opts into quarantine. + +`@Type`: `/cosmos.quarantine.v1beta1.EventOptIn` + +| Attribute Key | Attribute Value | +| ------------- |----------------------------------------| +| to_address | {bech32 string of account opting in} | + +## EventOptOut + +This event is emitted when an account opts out of quarantine. + +`@Type`: `/cosmos.quarantine.v1beta1.EventOptOut` + +| Attribute Key | Attribute Value | +|---------------|----------------------------------------| +| to_address | {bech32 string of account opting out} | + +## EventFundsQuarantined + +When funds are quarantined, the `recipient` in events emitted by the `x/bank` module will be the quarantined funds holder account instead of the intended recipient. +The following event is also emitted. + +`@Type`: `/cosmos.quarantine.v1beta1.EventFundsQuarantined` + +| Attribute Key | Attribute Value | +| ------------- |---------------------------------------| +| to_address | {bech32 string of intended recipient} | +| coins | {sdk.Coins of funds quarantined} | + +## EventFundsReleased + +This event is emitted when funds are fully accepted and sent from the quarantine funds holder to the originally intended recipient. + +`@Type`: `/cosmos.quarantine.v1beta1.EventFundsReleased` + +| Attribute Key | Attribute Value | +| ------------- |-------------------------------| +| to_address | {bech32 string of recipient} | +| coins | {sdk.Coins of funds released} | diff --git a/x/quarantine/spec/05_queries.md b/x/quarantine/spec/05_queries.md new file mode 100644 index 0000000000..16cdbdcfae --- /dev/null +++ b/x/quarantine/spec/05_queries.md @@ -0,0 +1,76 @@ + + +# gRPC Queries + +## Query/IsQuarantined + +To find out if an account is quarantined, use `QueryIsQuarantinedRequest`. +The query takes in a `to_address` and outputs `true` if the address is quarantined, or `false` otherwise. + +Request: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L46-L50 + +Response: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L52-L56 + +It is expected to fail if the `to_address` is invalid. + +## Query/QuarantinedFunds + +To get information on quarantined funds, use `QueryQuarantinedFundsRequest`. +This query takes in an optional `to_address` and optional `from_address` and outputs information on quarantined funds. + +Request: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L58-L67 + +Response: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L69-L76 + +QuarantinedFunds: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/quarantine.proto#L10-L21 + +- If neither a `to_address` nor `from_address` are provided, all non-declined quarantined funds for any addresses will be returned. +- If the request contains a `to_address` but no `from_address`, all non-declined quarantined funds for the `to_address` are returned. +- If both a `to_address` and `from_address` are provided, all quarantined funds to the `to_address` involving the `from_address` a returned regardless of whether they've been declined. + +This query is paginated. + +It is expected to fail if: +- A `from_address` is provided without a `to_address`. +- Either the `to_address` or `from_address` is provided but invalid. +- Invalid pagination parameters are provided. + +## Query/AutoResponses + +To see the auto-response settings, use `QueryAutoResponsesRequest`. +This query takes in a `to_address` and optional `from_address` and outputs information about auto-responses. + +Request: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L78-L87 + +Response: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L89-L96 + +AutoResponseEntry: + ++++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/quarantine.proto#L23-L31 + +- If no `from_address` is provided, all auto-response entries for the provided `to_address` are returned. The results will not contain any entries for `AUTO_RESPONSE_UNSPECIFIED`. +- If a `from_address` is provided, the auto-response setting that `to_address` has from `from_address` is returned. This result might be `AUTO_RESPONSE_UNSPECIFIED`. + +This query is paginated. + +It is expected to fail if: +- The `to_address` is empty or invalid. +- A `from_address` is provided and invalid. +- Invalid pagination parameters are provided. + diff --git a/x/quarantine/spec/06_client.md b/x/quarantine/spec/06_client.md new file mode 100644 index 0000000000..49711d06d4 --- /dev/null +++ b/x/quarantine/spec/06_client.md @@ -0,0 +1,222 @@ + + +# Client + +A user can interact with the `x/quarantine` module using `gRPC`, `CLI`, or `REST`. + +## gRPC + +A user can interact with and query the `x/quarantine` module using `gRPC`. + +For details see [Msg Service](03_messages.md) or [gRPC Queries](05_queries.md). + +## CLI + +The `gRPC` transaction and query endpoints are made available through CLI helpers. + +### Transactions + +Each of these commands facilitates generating, signing and sending of a `tx`. +Standard `tx` flags are available unless otherwise noted. + +In these commands, the `` can either be a name from your keyring or your account address. +The `--from` flag is ignored since that is being conveyed using the `` 1st argument to each command. + +#### OptIn + +```shell +$ simd tx quarantine opt-in --help +Activate quarantine for an account. +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). + +Usage: + simd tx quarantine opt-in [] [flags] + +Examples: + +$ simd tx quarantine opt-in cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-in personal +$ simd tx quarantine opt-in --from cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-in --from personal +``` + +#### OptOut + +```shell +$ simd tx quarantine opt-out --help +Deactivate quarantine for an account. +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). + +Usage: + simd tx quarantine opt-out [] [flags] + +Examples: + +$ simd tx quarantine opt-out cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-out personal +$ simd tx quarantine opt-out --from cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-out --from personal +``` + +#### Accept + +```shell +$ ./build/simd tx quarantine accept --help +Accept quarantined funds sent to from . +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). + +Usage: + simd tx quarantine accept [ ...] [flags] + +Examples: + +$ simd tx quarantine accept cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut +$ simd tx quarantine accept personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut +$ simd tx quarantine accept personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut cosmos1phx24ecmuw3s7fmy8c87gh3rdq5lwskqur3t00 +``` + +At least one `` is required, but multiple can be provided. + +A `--permanent` flag is also available with this command: + +```shell + --permanent Also set auto-accept for sends from any of the from_addresses to to_address +``` + +#### Decline + +```shell +$ simd tx quarantine decline --help +Decline quarantined funds sent to from . +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). + +Usage: + simd tx quarantine decline [ ...] [flags] + +Examples: + +$ simd tx quarantine decline cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut +$ simd tx quarantine decline personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut +$ simd tx quarantine decline personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut cosmos1phx24ecmuw3s7fmy8c87gh3rdq5lwskqur3t00 +``` + +At least one `` is required, but multiple can be provided. + +A `--permanent` flag is also available with this command: + +```shell + --permanent Also set auto-decline for sends from any of the from_addresses to to_address +``` + +#### UpdateAutoResponses + +```shell +$ simd tx quarantine update-auto-responses --help +Update auto-responses for transfers to from one or more addresses. +Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). + +The is required. +At least one and must be provided. + +Valid values: + "accept" or "a" - turn on auto-accept for the following (es). + "decline" or "d" - turn on auto-decline for the following (es). + "unspecified", "u", "off", or "o" - turn off auto-responses for the following (es). + +Each value can be repeated as an arg as many times as needed as long as each is followed by at least one . +Each will be assigned the nearest preceding value. + +Usage: + simd tx quarantine update-auto-responses [ ...] [ [ ...] ...] [flags] + +Aliases: + update-auto-responses, auto-responses, uar + +Examples: + +$ simd tx quarantine update-auto-responses cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 accept cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut +$ simd tx quarantine update-auto-responses personal decline cosmos1phx24ecmuw3s7fmy8c87gh3rdq5lwskqur3t00 unspecified cosmos1lfuwk97g6y9du8altct63vwgz5620t929n8g9l +$ simd tx quarantine auto-responses personal accept cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut cosmos1qsjw3kjaf33qk2urxg54lzxkw525ngghzneujh off cosmos1lfuwk97g6y9du8altct63vwgz5620t929n8g9l +``` + +### Queries + +Each of these commands facilitates running a `gRPC` query. +Standard `query` flags are available unless otherwise noted. + +#### IsQuarantined + +```shell +$ simd query quarantine is-quarantined --help +Query whether an account is opted into quarantined. + +Examples: + $ simd query quarantine is-quarantined cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 + $ simd query quarantine is cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut + +Usage: + simd query quarantine is-quarantined [flags] + +Aliases: + is-quarantined, is +``` + +#### QuarantinedFunds + +```shell +simd query quarantine funds --help +Query for quarantined funds. + +If no arguments are provided, all quarantined funds will be returned. +If only a to_address is provided, only undeclined funds quarantined for that address are returned. +If both a to_address and from_address are provided, quarantined funds will be returned regardless of whether they've been declined. + +Examples: + $ simd query quarantine funds + $ simd query quarantine funds cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 + $ simd query quarantine funds cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut + +Usage: + simd query quarantine funds [ []] [flags] +``` + +Standard pagination flags are also available for this command. + +#### AutoResponses + +```shell +$ simd query quarantine auto-responses --help +Query auto-responses. + +If only a to_address is provided, all auto-responses set up for that address are returned. This will only contain accept or decline entries. +If both a to_address and from_address are provided, exactly one result will be returned. This can be accept, decline or unspecified. + +Examples: + $ simd query quarantine auto-responses cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 + $ simd query quarantine auto-responses cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut + +Usage: + simd query quarantine auto-responses [] [flags] + +Aliases: + auto-responses, auto, ar +``` + +Standard pagination flags are also available for this command. + +## REST + +Each of the quarantine `gRPC` query endpoints is also available through one or more `REST` endpoints. + +| Name | URL | +|-----------------------------|----------------------------------------------------------------| +| IsQuarantined | `/cosmos/quarantine/v1beta1/active/{to_address}` | +| QuarantinedFunds - all | `/cosmos/quarantine/v1beta1/funds` | +| QuarantinedFunds - some | `/cosmos/quarantine/v1beta1/funds/{to_address}` | +| QuarantinedFunds - specific | `/cosmos/quarantine/v1beta1/funds/{to_address}/{from_address}` | +| AutoResponses - some | `/cosmos/quarantine/v1beta1/auto/{to_address}` | +| AutoResponses - specific | `/cosmos/quarantine/v1beta1/auto/{to_address}/{from_address}` | + +For `QuarantinedFunds` and `AutoResponses`, pagination parameters can be provided using the standard pagination query parameters. \ No newline at end of file diff --git a/x/quarantine/spec/README.md b/x/quarantine/spec/README.md new file mode 100644 index 0000000000..8e2cbe1fc9 --- /dev/null +++ b/x/quarantine/spec/README.md @@ -0,0 +1,45 @@ + + +# Quarantine Module + +## Abstract + +This module allows management of quarantined accounts and funds. +It also injects restrictions into the `x/bank` module to enforce account quarantines. + +## Contents + +1. **[Concepts](01_concepts.md)** + - [Quarantined Account](01_concepts.md#quarantined-account) + - [Opt-In](01_concepts.md#opt-in) + - [Quarantined Funds](01_concepts.md#quarantined-funds) + - [Auto-Responses](01_concepts.md#auto-responses) +2. **[State](02_state.md)** + - [Quarantined Accounts](02_state.md#quarantined-accounts) + - [Auto-Responses](02_state.md#auto-responses) + - [Quarantine Records](02_state.md#quarantine-records) + - [Quarantine Records Suffix Index](02_state.md#quarantine-records-suffix-index) +3. **[Msg Service](03_messages.md)** + - [Msg/OptIn](03_messages.md#msgoptin) + - [Msg/OptOut](03_messages.md#msgoptout) + - [Msg/Accept](03_messages.md#msgaccept) + - [Msg/Decline](03_messages.md#msgdecline) + - [Msg/UpdateAutoResponses](03_messages.md#msgupdateautoresponses) +4. **[Events](04_events.md)** + - [EventOptIn](04_events.md#eventoptin) + - [EventOptOut](04_events.md#eventoptout) + - [EventFundsQuarantined](04_events.md#eventfundsquarantined) + - [EventFundsReleased](04_events.md#eventfundsreleased) +5. **[gRPC Queries](05_queries.md)** + - [Query/IsQuarantined](05_queries.md#queryisquarantined) + - [Query/QuarantinedFunds](05_queries.md#queryquarantinedfunds) + - [Query/AutoResponses](05_queries.md#queryautoresponses) +6. **[Client](06_client.md)** + - [gRPC](06_client.md#grpc) + - [CLI](06_client.md#cli) + - [REST](06_client.md#rest) diff --git a/x/quarantine/testutil/test_helpers.go b/x/quarantine/testutil/test_helpers.go new file mode 100644 index 0000000000..dade9d8857 --- /dev/null +++ b/x/quarantine/testutil/test_helpers.go @@ -0,0 +1,261 @@ +package testutil + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + "github.com/cosmos/cosmos-sdk/x/quarantine" +) + +// This file contains some functions handy for doing unit tests. + +// AssertErrorContents asserts that, if contains is empty, there's no error. +// Otherwise, asserts that there is an error, and that it contains each of the provided strings. +func AssertErrorContents(t *testing.T, theError error, contains []string, msgAndArgs ...interface{}) bool { + t.Helper() + if len(contains) == 0 { + return assert.NoError(t, theError, msgAndArgs) + } + rv := assert.Error(t, theError, msgAndArgs...) + if rv { + for _, expInErr := range contains { + rv = assert.ErrorContains(t, theError, expInErr, msgAndArgs...) && rv + } + } + return rv +} + +// MakeTestAddr makes an AccAddress that's 20 bytes long. +// The first byte is the index. The next bytes are the base. +// The byte after that is 97 (a) + the index. +// Each other byte is one more than the previous. +// Panics if the base is too long or index too high. +func MakeTestAddr(base string, index uint8) sdk.AccAddress { + return makePrefixedIncAddr(20, 97, base, index) +} + +// MakeLongAddr makes an AccAddress that's 32 bytes long. +// The first byte is the index. The next bytes are the base. +// The byte after that is 65 (A) + the index. +// Each other byte is one more than the previous. +// Panics if the base is too long or index too high. +func MakeLongAddr(base string, index uint8) sdk.AccAddress { + return makePrefixedIncAddr(32, 65, base, index) +} + +// MakeBadAddr makes an address that's longer than the max length allowed. +// The first byte is the index. The next bytes are the base. +// The byte after that is 33 (!) + the index. +// Each other byte is one more than the previous wrapping back to 0 after 255. +// Panics if the base is too long or index too high. +func MakeBadAddr(base string, index uint8) sdk.AccAddress { + return makePrefixedIncAddr(address.MaxAddrLen+1, 33, base, index) +} + +// makePrefixedIncAddr creates an sdk.AccAddress with the provided length. +// The first byte will be the index. +// The next bytes will be the base. +// The byte after that will be the rootChar+index. +// Each other byte is one more than the previous, skipping 127, and wrapping back to 33 after 254. +// Panics if the base is longer than 8 chars. Keep it short. There aren't that many bytes to work with here. +// Panics if the index is larger than 30. You don't need that many. +// Panics if rootChar+index is not 33 to 126 or 128 to 254 (inclusive). Keep them printable. +// +// You're probably looking for MakeTestAddr, MakeLongAddr, or MakeBadAddr. +func makePrefixedIncAddr(length uint, rootChar uint8, base string, index uint8) sdk.AccAddress { + // panics are used because this is for test setup and should be mostly hard-coded stuff anyway. + // 8 is picked because if the length is 20, that would only leave 11 more bytes, which isn't many. + if len(base) > 8 { + panic(fmt.Sprintf("base too long %q; got: %d, max: 8", base, len(base))) + } + // 25 is picked so the long and test addresses always start with a letter. + if index > 25 { + panic(fmt.Sprintf("index too large; got: %d, max: 30", index)) + } + rv := makeIncAddr(length, uint(1+len(base))+1, rootChar+index) + rv[0] = index + copy(rv[1:], base) + return rv +} + +// makeIncAddr creates an sdk.AccAddress with the provided length. +// The first firstCharLen bytes will be the firstChar. +// Each other byte is one more than the previous, skipping 127, and wrapping back to 33 after 254. +// Basically using only bytes that are printable as ascii. +// If the firstChar is anything other than 33 to 126 or 128 to 254 (inclusive), you're gonna have a bad time. +// +// You're probably looking for MakeTestAddr, MakeLongAddr, or MakeBadAddr. +func makeIncAddr(length, firstCharLen uint, firstChar uint8) sdk.AccAddress { + // At one point I used math and mod stuff to wrap the provided first char into the right range, + // but this is for tests and should be from mostly hard-coded stuff anyway, so panics are used. + if firstChar < 33 || firstChar > 254 || firstChar == 127 { + panic(fmt.Sprintf("illegal shift (5-yard penalty, retry down): expected 33-126 or 128-254, got: %d", firstChar)) + } + b := firstChar + rv := make(sdk.AccAddress, length) + for i := uint(0); i < length; i++ { + if i >= firstCharLen { + switch { + case b == 126: + b = 128 + case b >= 254: + b = 33 + default: + b++ + } + } + rv[i] = b + } + return rv +} + +// MakeCopyOfCoins makes a deep copy of some Coins. +func MakeCopyOfCoins(orig sdk.Coins) sdk.Coins { + if orig == nil { + return nil + } + rv := make(sdk.Coins, len(orig)) + for i, coin := range orig { + rv[i] = sdk.Coin{ + Denom: coin.Denom, + Amount: coin.Amount.AddRaw(0), + } + } + return rv +} + +// MakeCopyOfQuarantinedFunds makes a deep copy of a QuarantinedFunds. +func MakeCopyOfQuarantinedFunds(orig *quarantine.QuarantinedFunds) *quarantine.QuarantinedFunds { + return &quarantine.QuarantinedFunds{ + ToAddress: orig.ToAddress, + UnacceptedFromAddresses: MakeCopyOfStringSlice(orig.UnacceptedFromAddresses), + Coins: MakeCopyOfCoins(orig.Coins), + Declined: orig.Declined, + } +} + +// MakeCopyOfQuarantinedFundsSlice makes a deep copy of a slice of QuarantinedFunds. +func MakeCopyOfQuarantinedFundsSlice(orig []*quarantine.QuarantinedFunds) []*quarantine.QuarantinedFunds { + if orig == nil { + return orig + } + rv := make([]*quarantine.QuarantinedFunds, len(orig)) + for i, qf := range orig { + rv[i] = MakeCopyOfQuarantinedFunds(qf) + } + return rv +} + +// MakeCopyOfStringSlice makes a deep copy of a slice of strings. +func MakeCopyOfStringSlice(orig []string) []string { + if orig == nil { + return nil + } + rv := make([]string, len(orig)) + copy(rv, orig) + return rv +} + +// MakeCopyOfQuarantineRecord makes a deep copy of a QuarantineRecord. +func MakeCopyOfQuarantineRecord(orig *quarantine.QuarantineRecord) *quarantine.QuarantineRecord { + return &quarantine.QuarantineRecord{ + UnacceptedFromAddresses: MakeCopyOfAccAddresses(orig.UnacceptedFromAddresses), + AcceptedFromAddresses: MakeCopyOfAccAddresses(orig.AcceptedFromAddresses), + Coins: MakeCopyOfCoins(orig.Coins), + Declined: orig.Declined, + } +} + +// MakeCopyOfAccAddress makes a deep copy of an AccAddress. +func MakeCopyOfAccAddress(orig sdk.AccAddress) sdk.AccAddress { + if orig == nil { + return orig + } + rv := make(sdk.AccAddress, len(orig)) + copy(rv, orig) + return rv +} + +// MakeCopyOfAccAddresses makes a deep copy of a slice of AccAddresses. +func MakeCopyOfAccAddresses(orig []sdk.AccAddress) []sdk.AccAddress { + if orig == nil { + return nil + } + rv := make([]sdk.AccAddress, len(orig)) + for i, addr := range orig { + rv[i] = MakeCopyOfAccAddress(addr) + } + return rv +} + +// MakeCopyOfByteSlice makes a deep copy of a byte slice. +func MakeCopyOfByteSlice(orig []byte) []byte { + if orig == nil { + return nil + } + rv := make([]byte, len(orig)) + copy(rv, orig) + return rv +} + +// MakeCopyOfByteSliceSlice makes a deep copy of a slice of byte slices. +func MakeCopyOfByteSliceSlice(orig [][]byte) [][]byte { + if orig == nil { + return nil + } + rv := make([][]byte, len(orig)) + for i, bz := range orig { + rv[i] = MakeCopyOfByteSlice(bz) + } + return rv +} + +// MakeCopyOfGenesisState makes a deep copy of a GenesisState. +func MakeCopyOfGenesisState(orig *quarantine.GenesisState) *quarantine.GenesisState { + if orig == nil { + return nil + } + return &quarantine.GenesisState{ + QuarantinedAddresses: MakeCopyOfStringSlice(orig.QuarantinedAddresses), + AutoResponses: MakeCopyOfAutoResponseEntries(orig.AutoResponses), + QuarantinedFunds: MakeCopyOfQuarantinedFundsSlice(orig.QuarantinedFunds), + } +} + +// MakeCopyOfAutoResponseEntries makes a deep copy of a slice of AutoResponseEntries. +func MakeCopyOfAutoResponseEntries(orig []*quarantine.AutoResponseEntry) []*quarantine.AutoResponseEntry { + if orig == nil { + return nil + } + rv := make([]*quarantine.AutoResponseEntry, len(orig)) + for i, entry := range orig { + rv[i] = MakeCopyOfAutoResponseEntry(entry) + } + return rv +} + +// MakeCopyOfAutoResponseEntry makes a deep copy of an AutoResponseEntry. +func MakeCopyOfAutoResponseEntry(orig *quarantine.AutoResponseEntry) *quarantine.AutoResponseEntry { + if orig == nil { + return nil + } + return &quarantine.AutoResponseEntry{ + ToAddress: orig.ToAddress, + FromAddress: orig.FromAddress, + Response: orig.Response, + } +} + +// MakeCopyOfQuarantineRecordSuffixIndex makes a deep copy of a QuarantineRecordSuffixIndex +func MakeCopyOfQuarantineRecordSuffixIndex(orig *quarantine.QuarantineRecordSuffixIndex) *quarantine.QuarantineRecordSuffixIndex { + if orig == nil { + return nil + } + return &quarantine.QuarantineRecordSuffixIndex{ + RecordSuffixes: MakeCopyOfByteSliceSlice(orig.RecordSuffixes), + } +} diff --git a/x/quarantine/tx.pb.go b/x/quarantine/tx.pb.go new file mode 100644 index 0000000000..8182d41923 --- /dev/null +++ b/x/quarantine/tx.pb.go @@ -0,0 +1,2209 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/quarantine/v1beta1/tx.proto + +package quarantine + +import ( + context "context" + 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/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgOptIn represents a message for opting in to account quarantine. +type MsgOptIn struct { + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` +} + +func (m *MsgOptIn) Reset() { *m = MsgOptIn{} } +func (m *MsgOptIn) String() string { return proto.CompactTextString(m) } +func (*MsgOptIn) ProtoMessage() {} +func (*MsgOptIn) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{0} +} +func (m *MsgOptIn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptIn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptIn.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 *MsgOptIn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptIn.Merge(m, src) +} +func (m *MsgOptIn) XXX_Size() int { + return m.Size() +} +func (m *MsgOptIn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptIn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptIn proto.InternalMessageInfo + +func (m *MsgOptIn) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +// MsgOptInResponse defines the Msg/OptIn response type. +type MsgOptInResponse struct { +} + +func (m *MsgOptInResponse) Reset() { *m = MsgOptInResponse{} } +func (m *MsgOptInResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOptInResponse) ProtoMessage() {} +func (*MsgOptInResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{1} +} +func (m *MsgOptInResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptInResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptInResponse.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 *MsgOptInResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptInResponse.Merge(m, src) +} +func (m *MsgOptInResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOptInResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptInResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptInResponse proto.InternalMessageInfo + +// MsgOptOut represents a message for opting in to account quarantine. +type MsgOptOut struct { + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` +} + +func (m *MsgOptOut) Reset() { *m = MsgOptOut{} } +func (m *MsgOptOut) String() string { return proto.CompactTextString(m) } +func (*MsgOptOut) ProtoMessage() {} +func (*MsgOptOut) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{2} +} +func (m *MsgOptOut) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptOut) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptOut.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 *MsgOptOut) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptOut.Merge(m, src) +} +func (m *MsgOptOut) XXX_Size() int { + return m.Size() +} +func (m *MsgOptOut) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptOut.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptOut proto.InternalMessageInfo + +func (m *MsgOptOut) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +// MsgOptOutResponse defines the Msg/OptOut response type. +type MsgOptOutResponse struct { +} + +func (m *MsgOptOutResponse) Reset() { *m = MsgOptOutResponse{} } +func (m *MsgOptOutResponse) String() string { return proto.CompactTextString(m) } +func (*MsgOptOutResponse) ProtoMessage() {} +func (*MsgOptOutResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{3} +} +func (m *MsgOptOutResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgOptOutResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgOptOutResponse.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 *MsgOptOutResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgOptOutResponse.Merge(m, src) +} +func (m *MsgOptOutResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgOptOutResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgOptOutResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgOptOutResponse proto.InternalMessageInfo + +// MsgAccept represents a message for accepting quarantined funds. +type MsgAccept struct { + // to_address is the address of the quarantined account that is accepting funds. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // from_addresses is one or more addresses that have sent funds to the quarantined account. + // All funds quarantined for to_address from any from_addresses are marked as accepted and released if appropriate. + // At least one is required. + FromAddresses []string `protobuf:"bytes,2,rep,name=from_addresses,json=fromAddresses,proto3" json:"from_addresses,omitempty"` + // permanent, if true, sets up auto-accept for the to_address from each from_address. + // If false (default), only the currently quarantined funds will be accepted. + Permanent bool `protobuf:"varint,3,opt,name=permanent,proto3" json:"permanent,omitempty"` +} + +func (m *MsgAccept) Reset() { *m = MsgAccept{} } +func (m *MsgAccept) String() string { return proto.CompactTextString(m) } +func (*MsgAccept) ProtoMessage() {} +func (*MsgAccept) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{4} +} +func (m *MsgAccept) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAccept) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAccept.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 *MsgAccept) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAccept.Merge(m, src) +} +func (m *MsgAccept) XXX_Size() int { + return m.Size() +} +func (m *MsgAccept) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAccept.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAccept proto.InternalMessageInfo + +func (m *MsgAccept) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *MsgAccept) GetFromAddresses() []string { + if m != nil { + return m.FromAddresses + } + return nil +} + +func (m *MsgAccept) GetPermanent() bool { + if m != nil { + return m.Permanent + } + return false +} + +// MsgAcceptResponse defines the Msg/Accept response type. +type MsgAcceptResponse struct { + // funds_released is the amount that was quarantined but has now been released and sent to the requester. + FundsReleased github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=funds_released,json=fundsReleased,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"funds_released"` +} + +func (m *MsgAcceptResponse) Reset() { *m = MsgAcceptResponse{} } +func (m *MsgAcceptResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAcceptResponse) ProtoMessage() {} +func (*MsgAcceptResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{5} +} +func (m *MsgAcceptResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAcceptResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAcceptResponse.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 *MsgAcceptResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAcceptResponse.Merge(m, src) +} +func (m *MsgAcceptResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAcceptResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAcceptResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAcceptResponse proto.InternalMessageInfo + +func (m *MsgAcceptResponse) GetFundsReleased() github_com_cosmos_cosmos_sdk_types.Coins { + if m != nil { + return m.FundsReleased + } + return nil +} + +// MsgDecline represents a message for declining quarantined funds. +type MsgDecline struct { + // to_address is the address of the quarantined account that is accepting funds. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // from_addresses is one or more addresses that have sent funds to the quarantined account. + // All funds quarantined for to_address from any from_addresses are marked as declined. + // At least one is required. + FromAddresses []string `protobuf:"bytes,2,rep,name=from_addresses,json=fromAddresses,proto3" json:"from_addresses,omitempty"` + // permanent, if true, sets up auto-decline for the to_address from each from_address. + // If false (default), only the currently quarantined funds will be declined. + Permanent bool `protobuf:"varint,3,opt,name=permanent,proto3" json:"permanent,omitempty"` +} + +func (m *MsgDecline) Reset() { *m = MsgDecline{} } +func (m *MsgDecline) String() string { return proto.CompactTextString(m) } +func (*MsgDecline) ProtoMessage() {} +func (*MsgDecline) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{6} +} +func (m *MsgDecline) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDecline) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDecline.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 *MsgDecline) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDecline.Merge(m, src) +} +func (m *MsgDecline) XXX_Size() int { + return m.Size() +} +func (m *MsgDecline) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDecline.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDecline proto.InternalMessageInfo + +func (m *MsgDecline) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *MsgDecline) GetFromAddresses() []string { + if m != nil { + return m.FromAddresses + } + return nil +} + +func (m *MsgDecline) GetPermanent() bool { + if m != nil { + return m.Permanent + } + return false +} + +// MsgDeclineResponse defines the Msg/Decline response type. +type MsgDeclineResponse struct { +} + +func (m *MsgDeclineResponse) Reset() { *m = MsgDeclineResponse{} } +func (m *MsgDeclineResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDeclineResponse) ProtoMessage() {} +func (*MsgDeclineResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{7} +} +func (m *MsgDeclineResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeclineResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeclineResponse.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 *MsgDeclineResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeclineResponse.Merge(m, src) +} +func (m *MsgDeclineResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDeclineResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeclineResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeclineResponse proto.InternalMessageInfo + +// MsgUpdateAutoResponses represents a message for updating quarantine auto-responses for a receiving address. +type MsgUpdateAutoResponses struct { + // to_address is the quarantined address that would be accepting or declining funds. + ToAddress string `protobuf:"bytes,1,opt,name=to_address,json=toAddress,proto3" json:"to_address,omitempty"` + // updates is the list of addresses and auto-responses that should be updated for the to_address. + Updates []*AutoResponseUpdate `protobuf:"bytes,2,rep,name=updates,proto3" json:"updates,omitempty"` +} + +func (m *MsgUpdateAutoResponses) Reset() { *m = MsgUpdateAutoResponses{} } +func (m *MsgUpdateAutoResponses) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateAutoResponses) ProtoMessage() {} +func (*MsgUpdateAutoResponses) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{8} +} +func (m *MsgUpdateAutoResponses) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateAutoResponses) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateAutoResponses.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 *MsgUpdateAutoResponses) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateAutoResponses.Merge(m, src) +} +func (m *MsgUpdateAutoResponses) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateAutoResponses) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateAutoResponses.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateAutoResponses proto.InternalMessageInfo + +func (m *MsgUpdateAutoResponses) GetToAddress() string { + if m != nil { + return m.ToAddress + } + return "" +} + +func (m *MsgUpdateAutoResponses) GetUpdates() []*AutoResponseUpdate { + if m != nil { + return m.Updates + } + return nil +} + +// MsgUpdateAutoResponsesResponse defines the Msg/UpdateAutoResponse response type. +type MsgUpdateAutoResponsesResponse struct { +} + +func (m *MsgUpdateAutoResponsesResponse) Reset() { *m = MsgUpdateAutoResponsesResponse{} } +func (m *MsgUpdateAutoResponsesResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateAutoResponsesResponse) ProtoMessage() {} +func (*MsgUpdateAutoResponsesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d2d4535ca5d9aa17, []int{9} +} +func (m *MsgUpdateAutoResponsesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateAutoResponsesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateAutoResponsesResponse.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 *MsgUpdateAutoResponsesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateAutoResponsesResponse.Merge(m, src) +} +func (m *MsgUpdateAutoResponsesResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateAutoResponsesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateAutoResponsesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateAutoResponsesResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgOptIn)(nil), "cosmos.quarantine.v1beta1.MsgOptIn") + proto.RegisterType((*MsgOptInResponse)(nil), "cosmos.quarantine.v1beta1.MsgOptInResponse") + proto.RegisterType((*MsgOptOut)(nil), "cosmos.quarantine.v1beta1.MsgOptOut") + proto.RegisterType((*MsgOptOutResponse)(nil), "cosmos.quarantine.v1beta1.MsgOptOutResponse") + proto.RegisterType((*MsgAccept)(nil), "cosmos.quarantine.v1beta1.MsgAccept") + proto.RegisterType((*MsgAcceptResponse)(nil), "cosmos.quarantine.v1beta1.MsgAcceptResponse") + proto.RegisterType((*MsgDecline)(nil), "cosmos.quarantine.v1beta1.MsgDecline") + proto.RegisterType((*MsgDeclineResponse)(nil), "cosmos.quarantine.v1beta1.MsgDeclineResponse") + proto.RegisterType((*MsgUpdateAutoResponses)(nil), "cosmos.quarantine.v1beta1.MsgUpdateAutoResponses") + proto.RegisterType((*MsgUpdateAutoResponsesResponse)(nil), "cosmos.quarantine.v1beta1.MsgUpdateAutoResponsesResponse") +} + +func init() { + proto.RegisterFile("cosmos/quarantine/v1beta1/tx.proto", fileDescriptor_d2d4535ca5d9aa17) +} + +var fileDescriptor_d2d4535ca5d9aa17 = []byte{ + // 598 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xbf, 0x6f, 0xd3, 0x4e, + 0x14, 0xcf, 0x7d, 0xf3, 0xa5, 0x6d, 0x5e, 0xd5, 0x02, 0x6e, 0x05, 0xa9, 0x85, 0xdc, 0x28, 0x80, + 0x14, 0x0a, 0xb1, 0x49, 0x18, 0x10, 0x2c, 0x28, 0x29, 0x12, 0x62, 0x88, 0x22, 0x19, 0x3a, 0x80, + 0x90, 0x22, 0xc7, 0xbe, 0x1a, 0x8b, 0xe6, 0xce, 0xf5, 0x9d, 0xab, 0x76, 0xa5, 0x03, 0x2b, 0x7f, + 0x07, 0x2c, 0x0c, 0xe5, 0x7f, 0xe8, 0x58, 0x31, 0x31, 0x01, 0x4a, 0x06, 0xfe, 0x0d, 0x14, 0xdf, + 0x9d, 0x63, 0xd1, 0x34, 0x09, 0x15, 0x0b, 0x93, 0x2f, 0xf7, 0x3e, 0xbf, 0x5e, 0xf4, 0x9e, 0x0d, + 0x65, 0x97, 0xb2, 0x1e, 0x65, 0xd6, 0x6e, 0xec, 0x44, 0x0e, 0xe1, 0x01, 0xc1, 0xd6, 0x5e, 0xad, + 0x8b, 0xb9, 0x53, 0xb3, 0xf8, 0xbe, 0x19, 0x46, 0x94, 0x53, 0x6d, 0x4d, 0x60, 0xcc, 0x11, 0xc6, + 0x94, 0x18, 0x7d, 0x43, 0xd2, 0xbb, 0x0e, 0xc3, 0xd6, 0x6e, 0x8c, 0xa3, 0x83, 0x94, 0x1e, 0x3a, + 0x7e, 0x40, 0x1c, 0x1e, 0x50, 0x22, 0x64, 0x74, 0x23, 0x8b, 0x55, 0x28, 0x97, 0x06, 0xaa, 0x7e, + 0x55, 0xd6, 0x7b, 0xcc, 0xb7, 0xf6, 0x6a, 0xc3, 0x87, 0x2c, 0x6c, 0x9c, 0x9d, 0x31, 0x13, 0x49, + 0x60, 0x65, 0xd6, 0x4e, 0xf2, 0xcb, 0x92, 0xc1, 0x45, 0x69, 0xd5, 0xa7, 0x3e, 0x15, 0xf7, 0xc3, + 0x93, 0xb8, 0x2d, 0x3f, 0x87, 0x85, 0x16, 0xf3, 0xdb, 0x21, 0x7f, 0x4a, 0xb4, 0xfb, 0x00, 0x9c, + 0x76, 0x1c, 0xcf, 0x8b, 0x30, 0x63, 0x45, 0x54, 0x42, 0x95, 0x42, 0xb3, 0xf8, 0xe5, 0xa8, 0xba, + 0x2a, 0x75, 0x1a, 0xa2, 0xf2, 0x8c, 0x47, 0x01, 0xf1, 0xed, 0x02, 0xa7, 0xf2, 0xe2, 0xe1, 0xc5, + 0xb7, 0x3f, 0x3f, 0x6d, 0x64, 0xb8, 0x65, 0x0d, 0x2e, 0x29, 0x55, 0x1b, 0xb3, 0x90, 0x12, 0x86, + 0xcb, 0x5b, 0x50, 0x10, 0x77, 0xed, 0x98, 0xff, 0x45, 0xab, 0x15, 0xb8, 0x9c, 0xca, 0xa6, 0x5e, + 0x47, 0x28, 0x31, 0x6b, 0xb8, 0x2e, 0x0e, 0xcf, 0x6f, 0xa6, 0x3d, 0x82, 0xe5, 0xed, 0x88, 0xf6, + 0x14, 0x15, 0xb3, 0xe2, 0x7f, 0xa5, 0xfc, 0x44, 0xf2, 0xd2, 0x10, 0xdf, 0x50, 0x70, 0xed, 0x1a, + 0x14, 0x42, 0x1c, 0xf5, 0x1c, 0x82, 0x09, 0x2f, 0xe6, 0x4b, 0xa8, 0xb2, 0x60, 0x8f, 0x2e, 0x4e, + 0xf7, 0xf2, 0x0e, 0x25, 0xcd, 0x88, 0xd8, 0xaa, 0x19, 0x2d, 0x82, 0xe5, 0xed, 0x98, 0x78, 0xac, + 0x13, 0xe1, 0x1d, 0xec, 0x30, 0xec, 0x15, 0x51, 0x29, 0x5f, 0x59, 0xac, 0xaf, 0x99, 0x32, 0xc2, + 0x70, 0xa2, 0xd4, 0x48, 0x9a, 0x9b, 0x34, 0x20, 0xcd, 0xbb, 0xc7, 0xdf, 0xd6, 0x73, 0x1f, 0xbe, + 0xaf, 0x57, 0xfc, 0x80, 0xbf, 0x8e, 0xbb, 0xa6, 0x4b, 0x7b, 0x72, 0x18, 0xe4, 0xa3, 0xca, 0xbc, + 0x37, 0x16, 0x3f, 0x08, 0x31, 0x4b, 0x08, 0xcc, 0x5e, 0x4a, 0x2c, 0x6c, 0xe9, 0x50, 0xfe, 0x8c, + 0x00, 0x5a, 0xcc, 0x7f, 0x8c, 0xdd, 0x9d, 0x80, 0xe0, 0x7f, 0xe7, 0x1f, 0x5c, 0x05, 0x6d, 0x14, + 0x3b, 0x1d, 0x87, 0x8f, 0x08, 0xae, 0xb4, 0x98, 0xbf, 0x15, 0x7a, 0x0e, 0xc7, 0x8d, 0x98, 0x53, + 0x55, 0x61, 0xe7, 0xef, 0xec, 0x09, 0xcc, 0xc7, 0x89, 0x9e, 0x68, 0x69, 0xb1, 0x5e, 0x35, 0xcf, + 0x7c, 0x4f, 0x98, 0x59, 0x4f, 0x91, 0xc2, 0x56, 0xec, 0xd3, 0x3d, 0x94, 0xc0, 0x18, 0x1f, 0x56, + 0x1d, 0xea, 0x87, 0xff, 0x43, 0xbe, 0xc5, 0x7c, 0xed, 0x05, 0x5c, 0x10, 0x9b, 0x7b, 0x7d, 0x82, + 0xb7, 0x5a, 0x44, 0xfd, 0xf6, 0x0c, 0xa0, 0x74, 0xe8, 0x5e, 0xc1, 0x9c, 0x5c, 0xd5, 0x1b, 0x53, + 0x69, 0xed, 0x98, 0xeb, 0x77, 0x66, 0x41, 0x65, 0xd5, 0xe5, 0x6e, 0x4e, 0x51, 0x17, 0xa8, 0x69, + 0xea, 0xbf, 0x2d, 0x4c, 0x07, 0xe6, 0xd5, 0xe0, 0xde, 0x9c, 0x4c, 0x94, 0x30, 0xbd, 0x3a, 0x13, + 0x2c, 0x35, 0x38, 0x44, 0xb0, 0x32, 0x6e, 0x98, 0x6a, 0x93, 0x65, 0xc6, 0x50, 0xf4, 0x07, 0x7f, + 0x4c, 0x51, 0x87, 0xe6, 0xe6, 0x71, 0xdf, 0x40, 0x27, 0x7d, 0x03, 0xfd, 0xe8, 0x1b, 0xe8, 0xfd, + 0xc0, 0xc8, 0x9d, 0x0c, 0x8c, 0xdc, 0xd7, 0x81, 0x91, 0x7b, 0x79, 0x6b, 0xe2, 0xda, 0xef, 0x67, + 0x3e, 0x1b, 0xdd, 0xb9, 0xe4, 0x33, 0x70, 0xef, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x24, 0x6d, + 0x04, 0x5d, 0x09, 0x07, 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 { + // OptIn defines a method for opting in to account quarantine. + // Funds sent to a quarantined account must be approved before they can be received. + OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOption) (*MsgOptInResponse, error) + // OptOut defines a method for opting out of account quarantine. + // Any pending funds for the account must still be accepted, but new sends will no longer be quarantined. + OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.CallOption) (*MsgOptOutResponse, error) + // Accept defines a method for accepting quarantined funds. + Accept(ctx context.Context, in *MsgAccept, opts ...grpc.CallOption) (*MsgAcceptResponse, error) + // Decline defines a method for declining quarantined funds. + Decline(ctx context.Context, in *MsgDecline, opts ...grpc.CallOption) (*MsgDeclineResponse, error) + // UpdateAutoResponses defines a method for updating the auto-response settings for a quarantined address. + UpdateAutoResponses(ctx context.Context, in *MsgUpdateAutoResponses, opts ...grpc.CallOption) (*MsgUpdateAutoResponsesResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOption) (*MsgOptInResponse, error) { + out := new(MsgOptInResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/OptIn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.CallOption) (*MsgOptOutResponse, error) { + out := new(MsgOptOutResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/OptOut", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Accept(ctx context.Context, in *MsgAccept, opts ...grpc.CallOption) (*MsgAcceptResponse, error) { + out := new(MsgAcceptResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/Accept", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Decline(ctx context.Context, in *MsgDecline, opts ...grpc.CallOption) (*MsgDeclineResponse, error) { + out := new(MsgDeclineResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/Decline", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateAutoResponses(ctx context.Context, in *MsgUpdateAutoResponses, opts ...grpc.CallOption) (*MsgUpdateAutoResponsesResponse, error) { + out := new(MsgUpdateAutoResponsesResponse) + err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/UpdateAutoResponses", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // OptIn defines a method for opting in to account quarantine. + // Funds sent to a quarantined account must be approved before they can be received. + OptIn(context.Context, *MsgOptIn) (*MsgOptInResponse, error) + // OptOut defines a method for opting out of account quarantine. + // Any pending funds for the account must still be accepted, but new sends will no longer be quarantined. + OptOut(context.Context, *MsgOptOut) (*MsgOptOutResponse, error) + // Accept defines a method for accepting quarantined funds. + Accept(context.Context, *MsgAccept) (*MsgAcceptResponse, error) + // Decline defines a method for declining quarantined funds. + Decline(context.Context, *MsgDecline) (*MsgDeclineResponse, error) + // UpdateAutoResponses defines a method for updating the auto-response settings for a quarantined address. + UpdateAutoResponses(context.Context, *MsgUpdateAutoResponses) (*MsgUpdateAutoResponsesResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) OptIn(ctx context.Context, req *MsgOptIn) (*MsgOptInResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OptIn not implemented") +} +func (*UnimplementedMsgServer) OptOut(ctx context.Context, req *MsgOptOut) (*MsgOptOutResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method OptOut not implemented") +} +func (*UnimplementedMsgServer) Accept(ctx context.Context, req *MsgAccept) (*MsgAcceptResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Accept not implemented") +} +func (*UnimplementedMsgServer) Decline(ctx context.Context, req *MsgDecline) (*MsgDeclineResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Decline not implemented") +} +func (*UnimplementedMsgServer) UpdateAutoResponses(ctx context.Context, req *MsgUpdateAutoResponses) (*MsgUpdateAutoResponsesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateAutoResponses not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_OptIn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOptIn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OptIn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Msg/OptIn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OptIn(ctx, req.(*MsgOptIn)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_OptOut_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgOptOut) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).OptOut(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Msg/OptOut", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).OptOut(ctx, req.(*MsgOptOut)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Accept_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAccept) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Accept(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Msg/Accept", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Accept(ctx, req.(*MsgAccept)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Decline_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDecline) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Decline(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Msg/Decline", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Decline(ctx, req.(*MsgDecline)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateAutoResponses_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateAutoResponses) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateAutoResponses(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.quarantine.v1beta1.Msg/UpdateAutoResponses", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateAutoResponses(ctx, req.(*MsgUpdateAutoResponses)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cosmos.quarantine.v1beta1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "OptIn", + Handler: _Msg_OptIn_Handler, + }, + { + MethodName: "OptOut", + Handler: _Msg_OptOut_Handler, + }, + { + MethodName: "Accept", + Handler: _Msg_Accept_Handler, + }, + { + MethodName: "Decline", + Handler: _Msg_Decline_Handler, + }, + { + MethodName: "UpdateAutoResponses", + Handler: _Msg_UpdateAutoResponses_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cosmos/quarantine/v1beta1/tx.proto", +} + +func (m *MsgOptIn) 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 *MsgOptIn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptIn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOptInResponse) 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 *MsgOptInResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptInResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgOptOut) 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 *MsgOptOut) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptOut) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgOptOutResponse) 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 *MsgOptOutResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgOptOutResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgAccept) 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 *MsgAccept) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAccept) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Permanent { + i-- + if m.Permanent { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.FromAddresses) > 0 { + for iNdEx := len(m.FromAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.FromAddresses[iNdEx]) + copy(dAtA[i:], m.FromAddresses[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.FromAddresses[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAcceptResponse) 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 *MsgAcceptResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAcceptResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.FundsReleased) > 0 { + for iNdEx := len(m.FundsReleased) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.FundsReleased[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *MsgDecline) 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 *MsgDecline) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDecline) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Permanent { + i-- + if m.Permanent { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.FromAddresses) > 0 { + for iNdEx := len(m.FromAddresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.FromAddresses[iNdEx]) + copy(dAtA[i:], m.FromAddresses[iNdEx]) + i = encodeVarintTx(dAtA, i, uint64(len(m.FromAddresses[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgDeclineResponse) 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 *MsgDeclineResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeclineResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateAutoResponses) 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 *MsgUpdateAutoResponses) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateAutoResponses) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Updates) > 0 { + for iNdEx := len(m.Updates) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Updates[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.ToAddress) > 0 { + i -= len(m.ToAddress) + copy(dAtA[i:], m.ToAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ToAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateAutoResponsesResponse) 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 *MsgUpdateAutoResponsesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateAutoResponsesResponse) 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 *MsgOptIn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOptInResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgOptOut) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgOptOutResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgAccept) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.FromAddresses) > 0 { + for _, s := range m.FromAddresses { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + if m.Permanent { + n += 2 + } + return n +} + +func (m *MsgAcceptResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.FundsReleased) > 0 { + for _, e := range m.FundsReleased { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgDecline) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.FromAddresses) > 0 { + for _, s := range m.FromAddresses { + l = len(s) + n += 1 + l + sovTx(uint64(l)) + } + } + if m.Permanent { + n += 2 + } + return n +} + +func (m *MsgDeclineResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateAutoResponses) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ToAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Updates) > 0 { + for _, e := range m.Updates { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgUpdateAutoResponsesResponse) 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 *MsgOptIn) 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: MsgOptIn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptIn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = 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 *MsgOptInResponse) 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: MsgOptInResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptInResponse: 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 *MsgOptOut) 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: MsgOptOut: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptOut: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = 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 *MsgOptOutResponse) 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: MsgOptOutResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgOptOutResponse: 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 *MsgAccept) 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: MsgAccept: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAccept: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddresses", 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.FromAddresses = append(m.FromAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permanent", 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.Permanent = 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 *MsgAcceptResponse) 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: MsgAcceptResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAcceptResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FundsReleased", 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.FundsReleased = append(m.FundsReleased, types.Coin{}) + if err := m.FundsReleased[len(m.FundsReleased)-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 *MsgDecline) 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: MsgDecline: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDecline: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FromAddresses", 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.FromAddresses = append(m.FromAddresses, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permanent", 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.Permanent = 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 *MsgDeclineResponse) 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: MsgDeclineResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDeclineResponse: 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 *MsgUpdateAutoResponses) 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: MsgUpdateAutoResponses: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateAutoResponses: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ToAddress", 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.ToAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Updates", 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.Updates = append(m.Updates, &AutoResponseUpdate{}) + if err := m.Updates[len(m.Updates)-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 *MsgUpdateAutoResponsesResponse) 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: MsgUpdateAutoResponsesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateAutoResponsesResponse: 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") +) From 0af665bcf54d529dac3eae9b9ae50150da0fe66d Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 15:13:19 -0700 Subject: [PATCH 02/20] [1752]: Update the protos to be in a provenance package and be v1 instead of v1beta1. Regenerate the go stuff from that change. --- docs/proto-docs.md | 559 ++++++++++++++++++ .../quarantine/{v1beta1 => v1}/events.proto | 4 +- .../quarantine/{v1beta1 => v1}/genesis.proto | 6 +- .../{v1beta1 => v1}/quarantine.proto | 4 +- .../quarantine/{v1beta1 => v1}/query.proto | 24 +- .../quarantine/{v1beta1 => v1}/tx.proto | 6 +- x/quarantine/events.pb.go | 71 +-- x/quarantine/genesis.pb.go | 50 +- x/quarantine/quarantine.pb.go | 111 ++-- x/quarantine/query.pb.go | 129 ++-- x/quarantine/query.pb.gw.go | 24 +- x/quarantine/tx.pb.go | 157 +++-- 12 files changed, 840 insertions(+), 305 deletions(-) rename proto/provenance/quarantine/{v1beta1 => v1}/events.proto (91%) rename proto/provenance/quarantine/{v1beta1 => v1}/genesis.proto (78%) rename proto/provenance/quarantine/{v1beta1 => v1}/quarantine.proto (97%) rename proto/provenance/quarantine/{v1beta1 => v1}/query.proto (85%) rename proto/provenance/quarantine/{v1beta1 => v1}/tx.proto (96%) diff --git a/docs/proto-docs.md b/docs/proto-docs.md index cbcf40e138..82e72d45c8 100644 --- a/docs/proto-docs.md +++ b/docs/proto-docs.md @@ -610,6 +610,48 @@ - [Msg](#provenance.oracle.v1.Msg) +- [provenance/quarantine/v1/events.proto](#provenance/quarantine/v1/events.proto) + - [EventFundsQuarantined](#provenance.quarantine.v1.EventFundsQuarantined) + - [EventFundsReleased](#provenance.quarantine.v1.EventFundsReleased) + - [EventOptIn](#provenance.quarantine.v1.EventOptIn) + - [EventOptOut](#provenance.quarantine.v1.EventOptOut) + +- [provenance/quarantine/v1/quarantine.proto](#provenance/quarantine/v1/quarantine.proto) + - [AutoResponseEntry](#provenance.quarantine.v1.AutoResponseEntry) + - [AutoResponseUpdate](#provenance.quarantine.v1.AutoResponseUpdate) + - [QuarantineRecord](#provenance.quarantine.v1.QuarantineRecord) + - [QuarantineRecordSuffixIndex](#provenance.quarantine.v1.QuarantineRecordSuffixIndex) + - [QuarantinedFunds](#provenance.quarantine.v1.QuarantinedFunds) + + - [AutoResponse](#provenance.quarantine.v1.AutoResponse) + +- [provenance/quarantine/v1/genesis.proto](#provenance/quarantine/v1/genesis.proto) + - [GenesisState](#provenance.quarantine.v1.GenesisState) + +- [provenance/quarantine/v1/query.proto](#provenance/quarantine/v1/query.proto) + - [QueryAutoResponsesRequest](#provenance.quarantine.v1.QueryAutoResponsesRequest) + - [QueryAutoResponsesResponse](#provenance.quarantine.v1.QueryAutoResponsesResponse) + - [QueryIsQuarantinedRequest](#provenance.quarantine.v1.QueryIsQuarantinedRequest) + - [QueryIsQuarantinedResponse](#provenance.quarantine.v1.QueryIsQuarantinedResponse) + - [QueryQuarantinedFundsRequest](#provenance.quarantine.v1.QueryQuarantinedFundsRequest) + - [QueryQuarantinedFundsResponse](#provenance.quarantine.v1.QueryQuarantinedFundsResponse) + + - [Query](#provenance.quarantine.v1.Query) + +- [provenance/quarantine/v1/tx.proto](#provenance/quarantine/v1/tx.proto) + - [MsgAccept](#provenance.quarantine.v1.MsgAccept) + - [MsgAcceptResponse](#provenance.quarantine.v1.MsgAcceptResponse) + - [MsgDecline](#provenance.quarantine.v1.MsgDecline) + - [MsgDeclineResponse](#provenance.quarantine.v1.MsgDeclineResponse) + - [MsgOptIn](#provenance.quarantine.v1.MsgOptIn) + - [MsgOptInResponse](#provenance.quarantine.v1.MsgOptInResponse) + - [MsgOptOut](#provenance.quarantine.v1.MsgOptOut) + - [MsgOptOutResponse](#provenance.quarantine.v1.MsgOptOutResponse) + - [MsgUpdateAutoResponses](#provenance.quarantine.v1.MsgUpdateAutoResponses) + - [MsgUpdateAutoResponsesResponse](#provenance.quarantine.v1.MsgUpdateAutoResponsesResponse) + + - [Msg](#provenance.quarantine.v1.Msg) + - [provenance/reward/v1/reward.proto](#provenance/reward/v1/reward.proto) - [ActionCounter](#provenance.reward.v1.ActionCounter) - [ActionDelegate](#provenance.reward.v1.ActionDelegate) @@ -9306,6 +9348,523 @@ Msg + +

Top

+ +## provenance/quarantine/v1/events.proto + + + + + +### EventFundsQuarantined +EventFundsQuarantined is an event emitted when funds are quarantined. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | | +| `coins` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | + + + + + + + + +### EventFundsReleased +EventFundsReleased is an event emitted when quarantined funds are accepted and released. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | | +| `coins` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | | + + + + + + + + +### EventOptIn +EventOptIn is an event emitted when an address opts into quarantine. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | | + + + + + + + + +### EventOptOut +EventOptOut is an event emitted when an address opts out of quarantine. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | | + + + + + + + + + + + + + + + + +

Top

+ +## provenance/quarantine/v1/quarantine.proto + + + + + +### AutoResponseEntry +AutoResponseEntry defines the auto response to one address from another. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the receiving address. | +| `from_address` | [string](#string) | | from_address is the sending address. | +| `response` | [AutoResponse](#provenance.quarantine.v1.AutoResponse) | | response is the auto-response setting for these two addresses. | + + + + + + + + +### AutoResponseUpdate +AutoResponseUpdate defines a quarantine auto response update that should be applied. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `from_address` | [string](#string) | | from_address is the address that funds would be coming from. | +| `response` | [AutoResponse](#provenance.quarantine.v1.AutoResponse) | | response is the automatic action to take on funds sent from from_address. Provide AUTO_RESPONSE_UNSPECIFIED to turn off an auto-response. | + + + + + + + + +### QuarantineRecord +QuarantineRecord defines information regarding quarantined funds that is stored in state. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `unaccepted_from_addresses` | [bytes](#bytes) | repeated | unaccepted_from_addresses are the senders that have not been part of an accept yet for these coins. | +| `accepted_from_addresses` | [bytes](#bytes) | repeated | accepted_from_addresses are the senders that have already been part of an accept for these coins. | +| `coins` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | coins is the amount that has been quarantined. | +| `declined` | [bool](#bool) | | declined is whether these funds have been declined. | + + + + + + + + +### QuarantineRecordSuffixIndex +QuarantineRecordSuffixIndex defines a list of record suffixes that can be stored in state and used as an index. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `record_suffixes` | [bytes](#bytes) | repeated | | + + + + + + + + +### QuarantinedFunds +QuarantinedFunds defines structure that represents coins that have been quarantined. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the intended recipient of the coins that have been quarantined. | +| `unaccepted_from_addresses` | [string](#string) | repeated | unaccepted_from_addresses are the senders that have not been part of an accept yet for these coins. | +| `coins` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | coins is the amount currently in quarantined for the two addresses. | +| `declined` | [bool](#bool) | | declined is true if these funds were previously declined. | + + + + + + + + + + +### AutoResponse +AutoResponse enumerates the quarantine auto-response options. + +| Name | Number | Description | +| ---- | ------ | ----------- | +| AUTO_RESPONSE_UNSPECIFIED | 0 | AUTO_RESPONSE_UNSPECIFIED defines that an automatic response has not been specified. This means that no automatic action should be taken, i.e. this auto-response is off, and default quarantine behavior is used. | +| AUTO_RESPONSE_ACCEPT | 1 | AUTO_RESPONSE_ACCEPT defines that sends should be automatically accepted, bypassing quarantine. | +| AUTO_RESPONSE_DECLINE | 2 | AUTO_RESPONSE_DECLINE defines that sends should be automatically declined. | + + + + + + + + + + + +

Top

+ +## provenance/quarantine/v1/genesis.proto + + + + + +### GenesisState +GenesisState defines the quarantine module's genesis state. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `quarantined_addresses` | [string](#string) | repeated | quarantined_addresses defines account addresses that are opted into quarantine. | +| `auto_responses` | [AutoResponseEntry](#provenance.quarantine.v1.AutoResponseEntry) | repeated | auto_responses defines the quarantine auto-responses for addresses. | +| `quarantined_funds` | [QuarantinedFunds](#provenance.quarantine.v1.QuarantinedFunds) | repeated | quarantined_funds defines funds that are quarantined. | + + + + + + + + + + + + + + + + +

Top

+ +## provenance/quarantine/v1/query.proto + + + + + +### QueryAutoResponsesRequest +QueryAutoResponsesRequest defines the RPC request for getting auto-response settings for an address. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the quarantined account to get info on. | +| `from_address` | [string](#string) | | from_address is an optional sender address to limit results. | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines optional pagination parameters for the request. | + + + + + + + + +### QueryAutoResponsesResponse +QueryAutoResponsesResponse defines the RPC response of a AutoResponses query. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `auto_responses` | [AutoResponseEntry](#provenance.quarantine.v1.AutoResponseEntry) | repeated | auto_responses are the auto-response entries from the provided query. | +| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination parameters of the response. | + + + + + + + + +### QueryIsQuarantinedRequest +QueryIsQuarantinedRequest defines the RPC request for checking if an account has opted into quarantine. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the address to check. | + + + + + + + + +### QueryIsQuarantinedResponse +QueryIsQuarantinedResponse defines the RPC response of an IsQuarantined query. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `is_quarantined` | [bool](#bool) | | is_quarantined is true if the to_address has opted into quarantine. | + + + + + + + + +### QueryQuarantinedFundsRequest +QueryQuarantinedFundsRequest defines the RPC request for looking up quarantined funds. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the intended recipient of the coins that have been quarantined. | +| `from_address` | [string](#string) | | from_address is the sender of the coins. If provided, a to_address must also be provided. | +| `pagination` | [cosmos.base.query.v1beta1.PageRequest](#cosmos.base.query.v1beta1.PageRequest) | | pagination defines optional pagination parameters for the request. | + + + + + + + + +### QueryQuarantinedFundsResponse +QueryQuarantinedFundsResponse defines the RPC response of a QuarantinedFunds query. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `quarantinedFunds` | [QuarantinedFunds](#provenance.quarantine.v1.QuarantinedFunds) | repeated | quarantinedFunds is info about coins sitting in quarantine. | +| `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination parameters of the response. | + + + + + + + + + + + + + + +### Query +Query defines the quarantine gRPC query service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `IsQuarantined` | [QueryIsQuarantinedRequest](#provenance.quarantine.v1.QueryIsQuarantinedRequest) | [QueryIsQuarantinedResponse](#provenance.quarantine.v1.QueryIsQuarantinedResponse) | IsQuarantined checks if an account has opted into quarantine. | GET|/cosmos/quarantine/v1beta1/active/{to_address}| +| `QuarantinedFunds` | [QueryQuarantinedFundsRequest](#provenance.quarantine.v1.QueryQuarantinedFundsRequest) | [QueryQuarantinedFundsResponse](#provenance.quarantine.v1.QueryQuarantinedFundsResponse) | QuarantinedFunds gets information about funds that have been quarantined. + +If both a to_address and from_address are provided, any such quarantined funds will be returned regardless of whether they've been declined. If only a to_address is provided, the unaccepted and undeclined funds waiting on a response from to_address will be returned. If neither a to_address nor from_address is provided, all non-declined quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. | GET|/cosmos/quarantine/v1beta1/fundsGET|/cosmos/quarantine/v1beta1/funds/{to_address}GET|/cosmos/quarantine/v1beta1/funds/{to_address}/{from_address}| +| `AutoResponses` | [QueryAutoResponsesRequest](#provenance.quarantine.v1.QueryAutoResponsesRequest) | [QueryAutoResponsesResponse](#provenance.quarantine.v1.QueryAutoResponsesResponse) | AutoResponses gets the auto-response settings for a quarantined account. + +The to_address is required. If a from_address is provided only the auto response for that from_address will be returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. | GET|/cosmos/quarantine/v1beta1/auto/{to_address}GET|/cosmos/quarantine/v1beta1/auto/{to_address}/{from_address}| + + + + + + +

Top

+ +## provenance/quarantine/v1/tx.proto + + + + + +### MsgAccept +MsgAccept represents a message for accepting quarantined funds. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the address of the quarantined account that is accepting funds. | +| `from_addresses` | [string](#string) | repeated | from_addresses is one or more addresses that have sent funds to the quarantined account. All funds quarantined for to_address from any from_addresses are marked as accepted and released if appropriate. At least one is required. | +| `permanent` | [bool](#bool) | | permanent, if true, sets up auto-accept for the to_address from each from_address. If false (default), only the currently quarantined funds will be accepted. | + + + + + + + + +### MsgAcceptResponse +MsgAcceptResponse defines the Msg/Accept response type. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `funds_released` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | funds_released is the amount that was quarantined but has now been released and sent to the requester. | + + + + + + + + +### MsgDecline +MsgDecline represents a message for declining quarantined funds. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the address of the quarantined account that is accepting funds. | +| `from_addresses` | [string](#string) | repeated | from_addresses is one or more addresses that have sent funds to the quarantined account. All funds quarantined for to_address from any from_addresses are marked as declined. At least one is required. | +| `permanent` | [bool](#bool) | | permanent, if true, sets up auto-decline for the to_address from each from_address. If false (default), only the currently quarantined funds will be declined. | + + + + + + + + +### MsgDeclineResponse +MsgDeclineResponse defines the Msg/Decline response type. + + + + + + + + +### MsgOptIn +MsgOptIn represents a message for opting in to account quarantine. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | | + + + + + + + + +### MsgOptInResponse +MsgOptInResponse defines the Msg/OptIn response type. + + + + + + + + +### MsgOptOut +MsgOptOut represents a message for opting in to account quarantine. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | | + + + + + + + + +### MsgOptOutResponse +MsgOptOutResponse defines the Msg/OptOut response type. + + + + + + + + +### MsgUpdateAutoResponses +MsgUpdateAutoResponses represents a message for updating quarantine auto-responses for a receiving address. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `to_address` | [string](#string) | | to_address is the quarantined address that would be accepting or declining funds. | +| `updates` | [AutoResponseUpdate](#provenance.quarantine.v1.AutoResponseUpdate) | repeated | updates is the list of addresses and auto-responses that should be updated for the to_address. | + + + + + + + + +### MsgUpdateAutoResponsesResponse +MsgUpdateAutoResponsesResponse defines the Msg/UpdateAutoResponse response type. + + + + + + + + + + + + + + +### Msg +Query defines the quarantine gRPC msg service. + +| Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | +| ----------- | ------------ | ------------- | ------------| ------- | -------- | +| `OptIn` | [MsgOptIn](#provenance.quarantine.v1.MsgOptIn) | [MsgOptInResponse](#provenance.quarantine.v1.MsgOptInResponse) | OptIn defines a method for opting in to account quarantine. Funds sent to a quarantined account must be approved before they can be received. | | +| `OptOut` | [MsgOptOut](#provenance.quarantine.v1.MsgOptOut) | [MsgOptOutResponse](#provenance.quarantine.v1.MsgOptOutResponse) | OptOut defines a method for opting out of account quarantine. Any pending funds for the account must still be accepted, but new sends will no longer be quarantined. | | +| `Accept` | [MsgAccept](#provenance.quarantine.v1.MsgAccept) | [MsgAcceptResponse](#provenance.quarantine.v1.MsgAcceptResponse) | Accept defines a method for accepting quarantined funds. | | +| `Decline` | [MsgDecline](#provenance.quarantine.v1.MsgDecline) | [MsgDeclineResponse](#provenance.quarantine.v1.MsgDeclineResponse) | Decline defines a method for declining quarantined funds. | | +| `UpdateAutoResponses` | [MsgUpdateAutoResponses](#provenance.quarantine.v1.MsgUpdateAutoResponses) | [MsgUpdateAutoResponsesResponse](#provenance.quarantine.v1.MsgUpdateAutoResponsesResponse) | UpdateAutoResponses defines a method for updating the auto-response settings for a quarantined address. | | + + + + +

Top

diff --git a/proto/provenance/quarantine/v1beta1/events.proto b/proto/provenance/quarantine/v1/events.proto similarity index 91% rename from proto/provenance/quarantine/v1beta1/events.proto rename to proto/provenance/quarantine/v1/events.proto index 01151d8c47..4d8cd849c6 100644 --- a/proto/provenance/quarantine/v1beta1/events.proto +++ b/proto/provenance/quarantine/v1/events.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package cosmos.quarantine.v1beta1; +package provenance.quarantine.v1; import "cosmos/base/v1beta1/coin.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; +option go_package = "github.com/provenance-io/provenance/x/quarantine"; // EventOptIn is an event emitted when an address opts into quarantine. message EventOptIn { diff --git a/proto/provenance/quarantine/v1beta1/genesis.proto b/proto/provenance/quarantine/v1/genesis.proto similarity index 78% rename from proto/provenance/quarantine/v1beta1/genesis.proto rename to proto/provenance/quarantine/v1/genesis.proto index 7e8fea369c..3b2c26aa3e 100644 --- a/proto/provenance/quarantine/v1beta1/genesis.proto +++ b/proto/provenance/quarantine/v1/genesis.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package cosmos.quarantine.v1beta1; +package provenance.quarantine.v1; -import "cosmos/quarantine/v1beta1/quarantine.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; +import "provenance/quarantine/v1/quarantine.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; +option go_package = "github.com/provenance-io/provenance/x/quarantine"; // GenesisState defines the quarantine module's genesis state. message GenesisState { diff --git a/proto/provenance/quarantine/v1beta1/quarantine.proto b/proto/provenance/quarantine/v1/quarantine.proto similarity index 97% rename from proto/provenance/quarantine/v1beta1/quarantine.proto rename to proto/provenance/quarantine/v1/quarantine.proto index c89e3c321e..8eae0293ed 100644 --- a/proto/provenance/quarantine/v1beta1/quarantine.proto +++ b/proto/provenance/quarantine/v1/quarantine.proto @@ -1,11 +1,11 @@ syntax = "proto3"; -package cosmos.quarantine.v1beta1; +package provenance.quarantine.v1; import "cosmos/base/v1beta1/coin.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; +option go_package = "github.com/provenance-io/provenance/x/quarantine"; // QuarantinedFunds defines structure that represents coins that have been quarantined. message QuarantinedFunds { diff --git a/proto/provenance/quarantine/v1beta1/query.proto b/proto/provenance/quarantine/v1/query.proto similarity index 85% rename from proto/provenance/quarantine/v1beta1/query.proto rename to proto/provenance/quarantine/v1/query.proto index bed3dc09e1..537fe45db6 100644 --- a/proto/provenance/quarantine/v1beta1/query.proto +++ b/proto/provenance/quarantine/v1/query.proto @@ -1,18 +1,18 @@ syntax = "proto3"; -package cosmos.quarantine.v1beta1; +package provenance.quarantine.v1; import "cosmos/base/query/v1beta1/pagination.proto"; -import "cosmos/quarantine/v1beta1/quarantine.proto"; import "cosmos_proto/cosmos.proto"; import "google/api/annotations.proto"; +import "provenance/quarantine/v1/quarantine.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; +option go_package = "github.com/provenance-io/provenance/x/quarantine"; // Query defines the quarantine gRPC query service. service Query { // IsQuarantined checks if an account has opted into quarantine. rpc IsQuarantined(QueryIsQuarantinedRequest) returns (QueryIsQuarantinedResponse) { - option (google.api.http).get = "/cosmos/quarantine/v1beta1/active/{to_address}"; + option (google.api.http).get = "/provenance/quarantine/v1/active/{to_address}"; } // QuarantinedFunds gets information about funds that have been quarantined. @@ -23,13 +23,9 @@ service Query { // quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. rpc QuarantinedFunds(QueryQuarantinedFundsRequest) returns (QueryQuarantinedFundsResponse) { option (google.api.http) = { - get: "/cosmos/quarantine/v1beta1/funds" - additional_bindings: { - get: "/cosmos/quarantine/v1beta1/funds/{to_address}" - } - additional_bindings: { - get: "/cosmos/quarantine/v1beta1/funds/{to_address}/{from_address}" - } + get: "/provenance/quarantine/v1/funds" + additional_bindings: {get: "/provenance/quarantine/v1/funds/{to_address}"} + additional_bindings: {get: "/provenance/quarantine/v1/funds/{to_address}/{from_address}"} }; } @@ -39,10 +35,8 @@ service Query { // returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. rpc AutoResponses(QueryAutoResponsesRequest) returns (QueryAutoResponsesResponse) { option (google.api.http) = { - get: "/cosmos/quarantine/v1beta1/auto/{to_address}" - additional_bindings: { - get: "/cosmos/quarantine/v1beta1/auto/{to_address}/{from_address}" - } + get: "/provenance/quarantine/v1/auto/{to_address}" + additional_bindings: {get: "/provenance/quarantine/v1/auto/{to_address}/{from_address}"} }; } } diff --git a/proto/provenance/quarantine/v1beta1/tx.proto b/proto/provenance/quarantine/v1/tx.proto similarity index 96% rename from proto/provenance/quarantine/v1beta1/tx.proto rename to proto/provenance/quarantine/v1/tx.proto index 9b799e8ba2..602e3daf05 100644 --- a/proto/provenance/quarantine/v1beta1/tx.proto +++ b/proto/provenance/quarantine/v1/tx.proto @@ -1,14 +1,14 @@ syntax = "proto3"; -package cosmos.quarantine.v1beta1; +package provenance.quarantine.v1; import "cosmos/base/query/v1beta1/pagination.proto"; import "cosmos/base/v1beta1/coin.proto"; import "cosmos/msg/v1/msg.proto"; -import "cosmos/quarantine/v1beta1/quarantine.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; +import "provenance/quarantine/v1/quarantine.proto"; -option go_package = "github.com/cosmos/cosmos-sdk/x/quarantine"; +option go_package = "github.com/provenance-io/provenance/x/quarantine"; // Query defines the quarantine gRPC msg service. service Msg { diff --git a/x/quarantine/events.pb.go b/x/quarantine/events.pb.go index bbff480e7f..a1108c26e3 100644 --- a/x/quarantine/events.pb.go +++ b/x/quarantine/events.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/quarantine/v1beta1/events.proto +// source: provenance/quarantine/v1/events.proto package quarantine @@ -35,7 +35,7 @@ func (m *EventOptIn) Reset() { *m = EventOptIn{} } func (m *EventOptIn) String() string { return proto.CompactTextString(m) } func (*EventOptIn) ProtoMessage() {} func (*EventOptIn) Descriptor() ([]byte, []int) { - return fileDescriptor_33c74f079d23a045, []int{0} + return fileDescriptor_d1d107943ecc1086, []int{0} } func (m *EventOptIn) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -80,7 +80,7 @@ func (m *EventOptOut) Reset() { *m = EventOptOut{} } func (m *EventOptOut) String() string { return proto.CompactTextString(m) } func (*EventOptOut) ProtoMessage() {} func (*EventOptOut) Descriptor() ([]byte, []int) { - return fileDescriptor_33c74f079d23a045, []int{1} + return fileDescriptor_d1d107943ecc1086, []int{1} } func (m *EventOptOut) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -126,7 +126,7 @@ func (m *EventFundsQuarantined) Reset() { *m = EventFundsQuarantined{} } func (m *EventFundsQuarantined) String() string { return proto.CompactTextString(m) } func (*EventFundsQuarantined) ProtoMessage() {} func (*EventFundsQuarantined) Descriptor() ([]byte, []int) { - return fileDescriptor_33c74f079d23a045, []int{2} + return fileDescriptor_d1d107943ecc1086, []int{2} } func (m *EventFundsQuarantined) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -179,7 +179,7 @@ func (m *EventFundsReleased) Reset() { *m = EventFundsReleased{} } func (m *EventFundsReleased) String() string { return proto.CompactTextString(m) } func (*EventFundsReleased) ProtoMessage() {} func (*EventFundsReleased) Descriptor() ([]byte, []int) { - return fileDescriptor_33c74f079d23a045, []int{3} + return fileDescriptor_d1d107943ecc1086, []int{3} } func (m *EventFundsReleased) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -223,39 +223,40 @@ func (m *EventFundsReleased) GetCoins() github_com_cosmos_cosmos_sdk_types.Coins } func init() { - proto.RegisterType((*EventOptIn)(nil), "cosmos.quarantine.v1beta1.EventOptIn") - proto.RegisterType((*EventOptOut)(nil), "cosmos.quarantine.v1beta1.EventOptOut") - proto.RegisterType((*EventFundsQuarantined)(nil), "cosmos.quarantine.v1beta1.EventFundsQuarantined") - proto.RegisterType((*EventFundsReleased)(nil), "cosmos.quarantine.v1beta1.EventFundsReleased") + proto.RegisterType((*EventOptIn)(nil), "provenance.quarantine.v1.EventOptIn") + proto.RegisterType((*EventOptOut)(nil), "provenance.quarantine.v1.EventOptOut") + proto.RegisterType((*EventFundsQuarantined)(nil), "provenance.quarantine.v1.EventFundsQuarantined") + proto.RegisterType((*EventFundsReleased)(nil), "provenance.quarantine.v1.EventFundsReleased") } func init() { - proto.RegisterFile("cosmos/quarantine/v1beta1/events.proto", fileDescriptor_33c74f079d23a045) -} - -var fileDescriptor_33c74f079d23a045 = []byte{ - // 322 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4b, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x2f, 0x2c, 0x4d, 0x2c, 0x4a, 0xcc, 0x2b, 0xc9, 0xcc, 0x4b, 0xd5, 0x2f, 0x33, - 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x2d, 0x4b, 0xcd, 0x2b, 0x29, 0xd6, 0x2b, 0x28, 0xca, - 0x2f, 0xc9, 0x17, 0x92, 0x84, 0xa8, 0xd3, 0x43, 0xa8, 0xd3, 0x83, 0xaa, 0x93, 0x92, 0x83, 0x1a, - 0x91, 0x94, 0x58, 0x8c, 0xd0, 0x9c, 0x9c, 0x9f, 0x99, 0x07, 0xd1, 0x2a, 0x05, 0xd5, 0x1a, 0x0f, - 0xe6, 0xe9, 0x43, 0xcd, 0x81, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x43, 0xc4, 0x41, 0x2c, 0x88, - 0xa8, 0x92, 0x2b, 0x17, 0x97, 0x2b, 0xc8, 0x6e, 0xff, 0x82, 0x12, 0xcf, 0x3c, 0x21, 0x73, 0x2e, - 0xae, 0x92, 0xfc, 0xf8, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, 0x62, 0x09, 0x46, 0x05, 0x46, 0x0d, - 0x4e, 0x27, 0x89, 0x4b, 0x5b, 0x74, 0x45, 0xa0, 0x26, 0x39, 0x42, 0x64, 0x82, 0x4b, 0x8a, 0x32, - 0xf3, 0xd2, 0x83, 0x38, 0x4b, 0xf2, 0xa1, 0x02, 0x4a, 0x6e, 0x5c, 0xdc, 0x30, 0x63, 0xfc, 0x4b, - 0x4b, 0xc8, 0x37, 0x67, 0x33, 0x23, 0x97, 0x28, 0xd8, 0x20, 0xb7, 0xd2, 0xbc, 0x94, 0xe2, 0x40, - 0x78, 0x00, 0xa4, 0x90, 0x6d, 0xa4, 0x50, 0x22, 0x17, 0x2b, 0x28, 0x80, 0x8a, 0x25, 0x98, 0x14, - 0x98, 0x35, 0xb8, 0x8d, 0x24, 0xf5, 0xa0, 0x1a, 0x40, 0x41, 0x08, 0x0b, 0x57, 0x3d, 0xe7, 0xfc, - 0xcc, 0x3c, 0x27, 0x83, 0x13, 0xf7, 0xe4, 0x19, 0x56, 0xdd, 0x97, 0xd7, 0x48, 0xcf, 0x2c, 0xc9, - 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0x85, 0x06, 0x21, 0x94, 0xd2, 0x2d, 0x4e, 0xc9, 0xd6, 0x2f, - 0xa9, 0x2c, 0x48, 0x2d, 0x06, 0x6b, 0x28, 0x0e, 0x82, 0x98, 0xac, 0xb4, 0x81, 0x91, 0x4b, 0x08, - 0xe1, 0xea, 0xa0, 0xd4, 0x9c, 0xd4, 0xc4, 0xe2, 0xc1, 0xed, 0x64, 0x27, 0xe7, 0x13, 0x8f, 0xe4, - 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, - 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0xc4, 0x6b, 0x54, 0x05, 0x52, 0xea, 0x4d, 0x62, - 0x03, 0xa7, 0x21, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x10, 0x51, 0x65, 0x46, 0xd9, 0x02, - 0x00, 0x00, + proto.RegisterFile("provenance/quarantine/v1/events.proto", fileDescriptor_d1d107943ecc1086) +} + +var fileDescriptor_d1d107943ecc1086 = []byte{ + // 340 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x92, 0xbf, 0x4e, 0xeb, 0x30, + 0x14, 0xc6, 0xe3, 0x7b, 0x75, 0xaf, 0x54, 0x77, 0x8b, 0x8a, 0x94, 0x76, 0x70, 0xab, 0x4a, 0x48, + 0x5d, 0x6a, 0xb7, 0x30, 0x30, 0x53, 0xd4, 0x4a, 0xb0, 0x54, 0x94, 0x8d, 0xa5, 0x72, 0x12, 0x2b, + 0x44, 0x50, 0x9f, 0x10, 0x3b, 0x11, 0xbc, 0x05, 0xcf, 0xc1, 0x84, 0x04, 0x0f, 0xd1, 0xb1, 0x62, + 0x62, 0x02, 0xd4, 0xbe, 0x08, 0x4a, 0x6c, 0x48, 0xe7, 0x4e, 0x4c, 0xf6, 0xf9, 0xf3, 0xfd, 0x7c, + 0xfc, 0xe9, 0xe0, 0xfd, 0x24, 0x85, 0x5c, 0x48, 0x2e, 0x03, 0xc1, 0x6e, 0x33, 0x9e, 0x72, 0xa9, + 0x63, 0x29, 0x58, 0x3e, 0x64, 0x22, 0x17, 0x52, 0x2b, 0x9a, 0xa4, 0xa0, 0xc1, 0xf5, 0xaa, 0x36, + 0x5a, 0xb5, 0xd1, 0x7c, 0xd8, 0x22, 0x01, 0xa8, 0x05, 0x28, 0xe6, 0x73, 0x55, 0xc8, 0x7c, 0xa1, + 0xf9, 0x90, 0x05, 0x10, 0x4b, 0xa3, 0x6c, 0x35, 0x4d, 0x7d, 0x5e, 0x46, 0xcc, 0x04, 0xb6, 0xd4, + 0x88, 0x20, 0x02, 0x93, 0x2f, 0x6e, 0x26, 0xdb, 0x1d, 0x63, 0x3c, 0x2e, 0x9e, 0x9e, 0x26, 0xfa, + 0x54, 0xba, 0x47, 0x18, 0x6b, 0x98, 0xf3, 0x30, 0x4c, 0x85, 0x52, 0x1e, 0xea, 0xa0, 0x5e, 0x6d, + 0xe4, 0xbd, 0xbe, 0xf4, 0x1b, 0x96, 0x74, 0x6c, 0x2a, 0x17, 0x3a, 0x8d, 0x65, 0x34, 0xab, 0x69, + 0xb0, 0x89, 0xee, 0x04, 0xd7, 0xbf, 0x31, 0xd3, 0x4c, 0xef, 0xce, 0x79, 0x46, 0x78, 0xaf, 0x04, + 0x4d, 0x32, 0x19, 0xaa, 0xf3, 0x9f, 0xbf, 0x87, 0x3b, 0x23, 0x5d, 0x8e, 0xff, 0x15, 0x06, 0x29, + 0xef, 0x4f, 0xe7, 0x6f, 0xaf, 0x7e, 0xd0, 0xa4, 0x56, 0x50, 0x58, 0x48, 0xad, 0x85, 0xf4, 0x04, + 0x62, 0x39, 0x1a, 0x2c, 0xdf, 0xdb, 0xce, 0xe3, 0x47, 0xbb, 0x17, 0xc5, 0xfa, 0x2a, 0xf3, 0x69, + 0x00, 0x0b, 0x6b, 0xa1, 0x3d, 0xfa, 0x2a, 0xbc, 0x66, 0xfa, 0x3e, 0x11, 0xaa, 0x14, 0xa8, 0x99, + 0x21, 0x77, 0x9f, 0x10, 0x76, 0xab, 0xa9, 0x67, 0xe2, 0x46, 0x70, 0xf5, 0xbb, 0x47, 0x1e, 0x9d, + 0x2d, 0xd7, 0x04, 0xad, 0xd6, 0x04, 0x7d, 0xae, 0x09, 0x7a, 0xd8, 0x10, 0x67, 0xb5, 0x21, 0xce, + 0xdb, 0x86, 0x38, 0x97, 0x83, 0x2d, 0x54, 0xb5, 0x87, 0xfd, 0x18, 0xb6, 0x22, 0x76, 0xb7, 0xb5, + 0xbe, 0xfe, 0xff, 0x72, 0x95, 0x0e, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x86, 0xec, 0xeb, 0xe5, + 0xde, 0x02, 0x00, 0x00, } func (m *EventOptIn) Marshal() (dAtA []byte, err error) { diff --git a/x/quarantine/genesis.pb.go b/x/quarantine/genesis.pb.go index c17519d745..3e05a9bad1 100644 --- a/x/quarantine/genesis.pb.go +++ b/x/quarantine/genesis.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/quarantine/v1beta1/genesis.proto +// source: provenance/quarantine/v1/genesis.proto package quarantine @@ -38,7 +38,7 @@ func (m *GenesisState) Reset() { *m = GenesisState{} } func (m *GenesisState) String() string { return proto.CompactTextString(m) } func (*GenesisState) ProtoMessage() {} func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_1a60633c09654351, []int{0} + return fileDescriptor_632eb3150c8160d7, []int{0} } func (m *GenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -89,34 +89,34 @@ func (m *GenesisState) GetQuarantinedFunds() []*QuarantinedFunds { } func init() { - proto.RegisterType((*GenesisState)(nil), "cosmos.quarantine.v1beta1.GenesisState") + proto.RegisterType((*GenesisState)(nil), "provenance.quarantine.v1.GenesisState") } func init() { - proto.RegisterFile("cosmos/quarantine/v1beta1/genesis.proto", fileDescriptor_1a60633c09654351) + proto.RegisterFile("provenance/quarantine/v1/genesis.proto", fileDescriptor_632eb3150c8160d7) } -var fileDescriptor_1a60633c09654351 = []byte{ - // 300 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4f, 0xce, 0x2f, 0xce, - 0xcd, 0x2f, 0xd6, 0x2f, 0x2c, 0x4d, 0x2c, 0x4a, 0xcc, 0x2b, 0xc9, 0xcc, 0x4b, 0xd5, 0x2f, 0x33, - 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, - 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x84, 0x28, 0xd4, 0x43, 0x28, 0xd4, 0x83, 0x2a, 0x94, 0xd2, 0xc2, - 0x6d, 0x06, 0x92, 0x6a, 0xb0, 0x31, 0x52, 0x50, 0x63, 0xe2, 0xc1, 0x3c, 0x7d, 0xa8, 0x99, 0x10, - 0x29, 0x91, 0xf4, 0xfc, 0xf4, 0x7c, 0x88, 0x38, 0x88, 0x05, 0x11, 0x55, 0xea, 0x61, 0xe2, 0xe2, - 0x71, 0x87, 0xb8, 0x24, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x97, 0x4b, 0x14, 0x61, 0x6a, 0x4a, - 0x7c, 0x62, 0x4a, 0x4a, 0x51, 0x6a, 0x71, 0x71, 0x6a, 0xb1, 0x04, 0xa3, 0x02, 0xb3, 0x06, 0xa7, - 0x93, 0xc4, 0xa5, 0x2d, 0xba, 0x22, 0x50, 0x73, 0x1d, 0x21, 0x72, 0xc1, 0x25, 0x45, 0x99, 0x79, - 0xe9, 0x41, 0x22, 0x48, 0xda, 0x1c, 0x61, 0xba, 0x84, 0x82, 0xb9, 0xf8, 0x12, 0x4b, 0x4b, 0xf2, - 0xe3, 0x8b, 0x52, 0x8b, 0x0b, 0xf2, 0xf3, 0x40, 0xe6, 0x30, 0x29, 0x30, 0x6b, 0x70, 0x1b, 0xe9, - 0xe8, 0xe1, 0xf4, 0xb0, 0x9e, 0x63, 0x69, 0x49, 0x7e, 0x10, 0x54, 0xbd, 0x6b, 0x5e, 0x49, 0x51, - 0x65, 0x10, 0x6f, 0x22, 0x92, 0x50, 0xb1, 0x50, 0x04, 0x97, 0x20, 0xb2, 0x1b, 0xd3, 0x4a, 0xf3, - 0x52, 0x8a, 0x25, 0x98, 0xc1, 0xe6, 0x6a, 0xe3, 0x31, 0x37, 0x10, 0xa1, 0xc7, 0x0d, 0xa4, 0x25, - 0x48, 0xa0, 0x10, 0x4d, 0xc4, 0xc9, 0xf9, 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, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xa1, 0xe1, 0x0a, 0xa5, - 0x74, 0x8b, 0x53, 0xb2, 0xf5, 0x2b, 0x90, 0xa2, 0x22, 0x89, 0x0d, 0x1c, 0xb4, 0xc6, 0x80, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xa3, 0xc7, 0x7f, 0xa7, 0xfd, 0x01, 0x00, 0x00, +var fileDescriptor_632eb3150c8160d7 = []byte{ + // 304 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2b, 0x28, 0xca, 0x2f, + 0x4b, 0xcd, 0x4b, 0xcc, 0x4b, 0x4e, 0xd5, 0x2f, 0x2c, 0x4d, 0x2c, 0x4a, 0xcc, 0x2b, 0xc9, 0xcc, + 0x4b, 0xd5, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, + 0x2f, 0xc9, 0x17, 0x92, 0x40, 0xa8, 0xd3, 0x43, 0xa8, 0xd3, 0x2b, 0x33, 0x94, 0x92, 0x4c, 0xce, + 0x2f, 0xce, 0xcd, 0x2f, 0x8e, 0x07, 0xab, 0xd3, 0x87, 0x70, 0x20, 0x9a, 0xa4, 0x44, 0xd2, 0xf3, + 0xd3, 0xf3, 0x21, 0xe2, 0x20, 0x16, 0x54, 0x54, 0x13, 0xa7, 0x95, 0x48, 0x06, 0x83, 0x95, 0x2a, + 0x75, 0x31, 0x71, 0xf1, 0xb8, 0x43, 0xdc, 0x11, 0x5c, 0x92, 0x58, 0x92, 0x2a, 0xe4, 0xcb, 0x25, + 0x8a, 0x50, 0x94, 0x12, 0x9f, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x9c, 0x5a, 0x2c, 0xc1, 0xa8, + 0xc0, 0xac, 0xc1, 0xe9, 0x24, 0x71, 0x69, 0x8b, 0xae, 0x08, 0xd4, 0x09, 0x8e, 0x10, 0xb9, 0xe0, + 0x92, 0xa2, 0xcc, 0xbc, 0xf4, 0x20, 0x11, 0x24, 0x6d, 0x8e, 0x30, 0x5d, 0x42, 0x41, 0x5c, 0x7c, + 0x89, 0xa5, 0x25, 0xf9, 0xf1, 0x45, 0xa9, 0xc5, 0x05, 0xf9, 0x79, 0x20, 0x73, 0x98, 0x14, 0x98, + 0x35, 0xb8, 0x8d, 0xb4, 0xf5, 0x70, 0x79, 0x57, 0xcf, 0xb1, 0xb4, 0x24, 0x3f, 0x08, 0xaa, 0xdc, + 0x35, 0xaf, 0xa4, 0xa8, 0x32, 0x88, 0x37, 0x11, 0x49, 0xa8, 0x58, 0x28, 0x9c, 0x4b, 0x10, 0xd9, + 0x89, 0x69, 0xa5, 0x79, 0x29, 0xc5, 0x12, 0xcc, 0x60, 0x63, 0xb5, 0x70, 0x1b, 0x1b, 0x88, 0xd0, + 0xe2, 0x06, 0xd2, 0x11, 0x24, 0x50, 0x88, 0x26, 0xe2, 0xe4, 0x75, 0xe2, 0x91, 0x1c, 0xe3, 0x85, + 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, + 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x06, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, + 0xfa, 0x08, 0x1b, 0x74, 0x33, 0xf3, 0x91, 0x78, 0xfa, 0x15, 0x48, 0xc1, 0x9b, 0xc4, 0x06, 0x0e, + 0x5f, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x61, 0xde, 0x56, 0xff, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/quarantine/quarantine.pb.go b/x/quarantine/quarantine.pb.go index 2b78c26f3d..962dd29f63 100644 --- a/x/quarantine/quarantine.pb.go +++ b/x/quarantine/quarantine.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/quarantine/v1beta1/quarantine.proto +// source: provenance/quarantine/v1/quarantine.proto package quarantine @@ -57,7 +57,7 @@ func (x AutoResponse) String() string { } func (AutoResponse) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_0b055d4922680476, []int{0} + return fileDescriptor_e595c18096245a7e, []int{0} } // QuarantinedFunds defines structure that represents coins that have been quarantined. @@ -76,7 +76,7 @@ func (m *QuarantinedFunds) Reset() { *m = QuarantinedFunds{} } func (m *QuarantinedFunds) String() string { return proto.CompactTextString(m) } func (*QuarantinedFunds) ProtoMessage() {} func (*QuarantinedFunds) Descriptor() ([]byte, []int) { - return fileDescriptor_0b055d4922680476, []int{0} + return fileDescriptor_e595c18096245a7e, []int{0} } func (m *QuarantinedFunds) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -140,14 +140,14 @@ type AutoResponseEntry struct { // from_address is the sending address. FromAddress string `protobuf:"bytes,2,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` // response is the auto-response setting for these two addresses. - Response AutoResponse `protobuf:"varint,3,opt,name=response,proto3,enum=cosmos.quarantine.v1beta1.AutoResponse" json:"response,omitempty"` + Response AutoResponse `protobuf:"varint,3,opt,name=response,proto3,enum=provenance.quarantine.v1.AutoResponse" json:"response,omitempty"` } func (m *AutoResponseEntry) Reset() { *m = AutoResponseEntry{} } func (m *AutoResponseEntry) String() string { return proto.CompactTextString(m) } func (*AutoResponseEntry) ProtoMessage() {} func (*AutoResponseEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_0b055d4922680476, []int{1} + return fileDescriptor_e595c18096245a7e, []int{1} } func (m *AutoResponseEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -203,14 +203,14 @@ type AutoResponseUpdate struct { FromAddress string `protobuf:"bytes,1,opt,name=from_address,json=fromAddress,proto3" json:"from_address,omitempty"` // response is the automatic action to take on funds sent from from_address. // Provide AUTO_RESPONSE_UNSPECIFIED to turn off an auto-response. - Response AutoResponse `protobuf:"varint,2,opt,name=response,proto3,enum=cosmos.quarantine.v1beta1.AutoResponse" json:"response,omitempty"` + Response AutoResponse `protobuf:"varint,2,opt,name=response,proto3,enum=provenance.quarantine.v1.AutoResponse" json:"response,omitempty"` } func (m *AutoResponseUpdate) Reset() { *m = AutoResponseUpdate{} } func (m *AutoResponseUpdate) String() string { return proto.CompactTextString(m) } func (*AutoResponseUpdate) ProtoMessage() {} func (*AutoResponseUpdate) Descriptor() ([]byte, []int) { - return fileDescriptor_0b055d4922680476, []int{2} + return fileDescriptor_e595c18096245a7e, []int{2} } func (m *AutoResponseUpdate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -269,7 +269,7 @@ func (m *QuarantineRecord) Reset() { *m = QuarantineRecord{} } func (m *QuarantineRecord) String() string { return proto.CompactTextString(m) } func (*QuarantineRecord) ProtoMessage() {} func (*QuarantineRecord) Descriptor() ([]byte, []int) { - return fileDescriptor_0b055d4922680476, []int{3} + return fileDescriptor_e595c18096245a7e, []int{3} } func (m *QuarantineRecord) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -335,7 +335,7 @@ func (m *QuarantineRecordSuffixIndex) Reset() { *m = QuarantineRecordSuf func (m *QuarantineRecordSuffixIndex) String() string { return proto.CompactTextString(m) } func (*QuarantineRecordSuffixIndex) ProtoMessage() {} func (*QuarantineRecordSuffixIndex) Descriptor() ([]byte, []int) { - return fileDescriptor_0b055d4922680476, []int{4} + return fileDescriptor_e595c18096245a7e, []int{4} } func (m *QuarantineRecordSuffixIndex) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -372,55 +372,56 @@ func (m *QuarantineRecordSuffixIndex) GetRecordSuffixes() [][]byte { } func init() { - proto.RegisterEnum("cosmos.quarantine.v1beta1.AutoResponse", AutoResponse_name, AutoResponse_value) - proto.RegisterType((*QuarantinedFunds)(nil), "cosmos.quarantine.v1beta1.QuarantinedFunds") - proto.RegisterType((*AutoResponseEntry)(nil), "cosmos.quarantine.v1beta1.AutoResponseEntry") - proto.RegisterType((*AutoResponseUpdate)(nil), "cosmos.quarantine.v1beta1.AutoResponseUpdate") - proto.RegisterType((*QuarantineRecord)(nil), "cosmos.quarantine.v1beta1.QuarantineRecord") - proto.RegisterType((*QuarantineRecordSuffixIndex)(nil), "cosmos.quarantine.v1beta1.QuarantineRecordSuffixIndex") + proto.RegisterEnum("provenance.quarantine.v1.AutoResponse", AutoResponse_name, AutoResponse_value) + proto.RegisterType((*QuarantinedFunds)(nil), "provenance.quarantine.v1.QuarantinedFunds") + proto.RegisterType((*AutoResponseEntry)(nil), "provenance.quarantine.v1.AutoResponseEntry") + proto.RegisterType((*AutoResponseUpdate)(nil), "provenance.quarantine.v1.AutoResponseUpdate") + proto.RegisterType((*QuarantineRecord)(nil), "provenance.quarantine.v1.QuarantineRecord") + proto.RegisterType((*QuarantineRecordSuffixIndex)(nil), "provenance.quarantine.v1.QuarantineRecordSuffixIndex") } func init() { - proto.RegisterFile("cosmos/quarantine/v1beta1/quarantine.proto", fileDescriptor_0b055d4922680476) -} - -var fileDescriptor_0b055d4922680476 = []byte{ - // 562 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0x41, 0x8f, 0xd2, 0x40, - 0x18, 0xed, 0xc0, 0x6a, 0x76, 0x67, 0x37, 0x2b, 0x4e, 0xd8, 0x6c, 0xc1, 0x58, 0x1a, 0x2e, 0x5b, - 0x37, 0xa1, 0xc8, 0x7a, 0xf0, 0xe0, 0xa9, 0x74, 0x4b, 0x42, 0x62, 0x58, 0x2c, 0x70, 0xf1, 0xd2, - 0x94, 0x76, 0x60, 0x1b, 0xa5, 0x83, 0x33, 0x53, 0xc3, 0xfe, 0x03, 0x8f, 0x9e, 0x3c, 0x9b, 0x78, - 0xf3, 0xec, 0x8f, 0xd8, 0x93, 0xd9, 0x78, 0xf2, 0xb4, 0x1a, 0x38, 0xfa, 0x0f, 0x3c, 0x19, 0xe8, - 0x00, 0x45, 0xb3, 0x68, 0x38, 0x79, 0x82, 0xf9, 0xde, 0xbc, 0x37, 0xaf, 0x6f, 0x5e, 0x06, 0x1e, - 0x7b, 0x84, 0x0d, 0x08, 0x2b, 0xbf, 0x8a, 0x5c, 0xea, 0x86, 0x3c, 0x08, 0x71, 0xf9, 0x75, 0xa5, - 0x8b, 0xb9, 0x5b, 0x49, 0x8c, 0xf4, 0x21, 0x25, 0x9c, 0xa0, 0x5c, 0xbc, 0x57, 0x4f, 0x00, 0x62, - 0x6f, 0x5e, 0x11, 0x32, 0x5d, 0x97, 0x2d, 0x05, 0x3c, 0x12, 0x84, 0x31, 0x35, 0x2f, 0xa8, 0xce, - 0x6c, 0x55, 0x16, 0x3a, 0x31, 0x94, 0xed, 0x93, 0x3e, 0x89, 0xe7, 0xd3, 0x7f, 0xf1, 0xb4, 0xf8, - 0x3e, 0x05, 0x33, 0xcf, 0x16, 0xe7, 0xf8, 0xb5, 0x28, 0xf4, 0x19, 0x7a, 0x0c, 0x21, 0x27, 0x8e, - 0xeb, 0xfb, 0x14, 0x33, 0x26, 0x03, 0x15, 0x68, 0x3b, 0x55, 0xf9, 0xcb, 0xa7, 0x52, 0x56, 0x08, - 0x1a, 0x31, 0xd2, 0xe2, 0x34, 0x08, 0xfb, 0xf6, 0x0e, 0x27, 0x62, 0x80, 0xda, 0x30, 0x17, 0x85, - 0xae, 0xe7, 0xe1, 0x21, 0xc7, 0xbe, 0xd3, 0xa3, 0x64, 0x30, 0x57, 0xc1, 0x4c, 0x4e, 0xa9, 0xe9, - 0xb5, 0x3a, 0x87, 0x4b, 0x6a, 0x8d, 0x92, 0x81, 0x31, 0x27, 0x22, 0x17, 0xde, 0x9a, 0x7e, 0x22, - 0x93, 0xd3, 0x6a, 0x5a, 0xdb, 0x3d, 0xc9, 0xe9, 0x82, 0x3e, 0x0d, 0x61, 0x9e, 0x8c, 0x6e, 0x92, - 0x20, 0xac, 0x3e, 0xbc, 0xbc, 0x2e, 0x48, 0x1f, 0xbf, 0x15, 0xb4, 0x7e, 0xc0, 0xcf, 0xa3, 0xae, - 0xee, 0x91, 0x81, 0x08, 0x41, 0xfc, 0x94, 0x98, 0xff, 0xa2, 0xcc, 0x2f, 0x86, 0x98, 0xcd, 0x08, - 0xcc, 0x8e, 0x95, 0x51, 0x1e, 0x6e, 0xfb, 0xd8, 0x7b, 0x39, 0x8d, 0x40, 0xde, 0x52, 0x81, 0xb6, - 0x6d, 0x2f, 0xd6, 0xc5, 0xcf, 0x00, 0xde, 0x35, 0x22, 0x4e, 0x6c, 0xcc, 0x86, 0x24, 0x64, 0xd8, - 0x0a, 0x39, 0xbd, 0xd8, 0x3c, 0xa3, 0x27, 0x70, 0x2f, 0x19, 0x8c, 0x9c, 0xfa, 0x0b, 0x75, 0xb7, - 0xb7, 0x0c, 0x03, 0x99, 0x70, 0x9b, 0x0a, 0x1b, 0x72, 0x5a, 0x05, 0xda, 0xfe, 0xc9, 0x91, 0x7e, - 0x63, 0x5b, 0xf4, 0xa4, 0x6b, 0x7b, 0x41, 0x2c, 0xbe, 0x03, 0x10, 0x25, 0xa1, 0xce, 0xd0, 0x77, - 0x39, 0xfe, 0xc3, 0x18, 0xd8, 0xd4, 0x58, 0x6a, 0x53, 0x63, 0x3f, 0x56, 0xca, 0x68, 0x63, 0x8f, - 0x50, 0x1f, 0x0d, 0xd6, 0x75, 0x0a, 0xa8, 0x69, 0x6d, 0xaf, 0x5a, 0xf9, 0x79, 0x5d, 0x28, 0xfd, - 0xc3, 0x95, 0x1b, 0x9e, 0x27, 0xfc, 0xde, 0x5c, 0xb6, 0x00, 0x1e, 0xae, 0x2b, 0xf0, 0x46, 0x87, - 0x1d, 0xfc, 0x97, 0xbd, 0xae, 0xc1, 0x7b, 0xbf, 0x87, 0xdd, 0x8a, 0x7a, 0xbd, 0x60, 0x54, 0x0f, - 0x7d, 0x3c, 0x42, 0x47, 0xf0, 0x0e, 0x9d, 0x0d, 0x1d, 0x36, 0x9b, 0xce, 0xd3, 0xb6, 0xf7, 0x69, - 0x62, 0x2f, 0x66, 0xc7, 0xe7, 0x70, 0x2f, 0x79, 0x9f, 0xe8, 0x3e, 0xcc, 0x19, 0x9d, 0xf6, 0x99, - 0x63, 0x5b, 0xad, 0xe6, 0x59, 0xa3, 0x65, 0x39, 0x9d, 0x46, 0xab, 0x69, 0x99, 0xf5, 0x5a, 0xdd, - 0x3a, 0xcd, 0x48, 0x48, 0x86, 0xd9, 0x55, 0xd8, 0x30, 0x4d, 0xab, 0xd9, 0xce, 0x00, 0x94, 0x83, - 0x07, 0xab, 0xc8, 0xa9, 0x65, 0x3e, 0xad, 0x37, 0xac, 0x4c, 0x2a, 0xbf, 0xf5, 0xe6, 0x83, 0x22, - 0x55, 0xcd, 0xcb, 0xb1, 0x02, 0xae, 0xc6, 0x0a, 0xf8, 0x3e, 0x56, 0xc0, 0xdb, 0x89, 0x22, 0x5d, - 0x4d, 0x14, 0xe9, 0xeb, 0x44, 0x91, 0x9e, 0x3f, 0x58, 0x1b, 0xcc, 0x28, 0xf1, 0xc6, 0x76, 0x6f, - 0xcf, 0x1e, 0xbe, 0x47, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x97, 0x30, 0xea, 0x7d, 0x92, 0x05, + proto.RegisterFile("provenance/quarantine/v1/quarantine.proto", fileDescriptor_e595c18096245a7e) +} + +var fileDescriptor_e595c18096245a7e = []byte{ + // 578 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0x31, 0x6f, 0xd3, 0x40, + 0x18, 0xf5, 0x25, 0x05, 0xb5, 0xd7, 0xaa, 0x84, 0x53, 0xab, 0x3a, 0x41, 0xb8, 0x56, 0x07, 0x30, + 0x48, 0xb1, 0x9b, 0x32, 0x30, 0x30, 0x39, 0xa9, 0x23, 0x05, 0xa1, 0x36, 0x38, 0xc9, 0xc2, 0x62, + 0x39, 0xf6, 0x25, 0xb5, 0x20, 0x77, 0xe6, 0xee, 0x1c, 0xa5, 0xff, 0x80, 0x91, 0x85, 0x1d, 0x89, + 0x8d, 0x99, 0x1f, 0xd1, 0x05, 0xa9, 0x62, 0x62, 0x2a, 0x28, 0x19, 0xf9, 0x07, 0x4c, 0x28, 0xb1, + 0x93, 0x38, 0xa0, 0x06, 0x94, 0x89, 0xc9, 0xfe, 0xbe, 0x77, 0xef, 0xbb, 0x77, 0xef, 0x9e, 0x0e, + 0x3e, 0x08, 0x19, 0xed, 0x63, 0xe2, 0x12, 0x0f, 0x1b, 0xaf, 0x23, 0x97, 0xb9, 0x44, 0x04, 0x04, + 0x1b, 0xfd, 0x52, 0xaa, 0xd2, 0x43, 0x46, 0x05, 0x45, 0xf2, 0x7c, 0xa9, 0x9e, 0x02, 0xfb, 0xa5, + 0x82, 0xe2, 0x51, 0xde, 0xa3, 0xdc, 0x68, 0xbb, 0x7c, 0x4c, 0x6d, 0x63, 0xe1, 0x96, 0x0c, 0x8f, + 0x06, 0x24, 0x66, 0x16, 0xf2, 0x31, 0xee, 0x4c, 0x2a, 0x23, 0x2e, 0x12, 0x68, 0xa7, 0x4b, 0xbb, + 0x34, 0xee, 0x8f, 0xff, 0xe2, 0xee, 0xc1, 0xfb, 0x0c, 0xcc, 0x3d, 0x9f, 0x6d, 0xe1, 0x57, 0x23, + 0xe2, 0x73, 0xf4, 0x18, 0x42, 0x41, 0x1d, 0xd7, 0xf7, 0x19, 0xe6, 0x5c, 0x06, 0x2a, 0xd0, 0x36, + 0xca, 0xf2, 0x97, 0x4f, 0xc5, 0x9d, 0x64, 0xa0, 0x19, 0x23, 0x0d, 0xc1, 0x02, 0xd2, 0xb5, 0x37, + 0x04, 0x4d, 0x1a, 0xa8, 0x09, 0xf3, 0x11, 0x71, 0x3d, 0x0f, 0x87, 0x02, 0xfb, 0x4e, 0x87, 0xd1, + 0xde, 0x74, 0x0a, 0xe6, 0x72, 0x46, 0xcd, 0x2e, 0x9d, 0xb3, 0x37, 0xa7, 0x56, 0x19, 0xed, 0x99, + 0x53, 0x22, 0x72, 0xe1, 0x8d, 0xf1, 0x11, 0xb9, 0x9c, 0x55, 0xb3, 0xda, 0xe6, 0x51, 0x5e, 0x4f, + 0xe8, 0x63, 0x13, 0xf4, 0xc4, 0x04, 0xbd, 0x42, 0x03, 0x52, 0x3e, 0xbc, 0xb8, 0xda, 0x97, 0x3e, + 0x7e, 0xdb, 0xd7, 0xba, 0x81, 0x38, 0x8b, 0xda, 0xba, 0x47, 0x7b, 0x89, 0x09, 0xc9, 0xa7, 0xc8, + 0xfd, 0x97, 0x86, 0x38, 0x0f, 0x31, 0x9f, 0x10, 0xb8, 0x1d, 0x4f, 0x46, 0x05, 0xb8, 0xee, 0x63, + 0xef, 0xd5, 0xd8, 0x02, 0x79, 0x4d, 0x05, 0xda, 0xba, 0x3d, 0xab, 0x0f, 0x3e, 0x03, 0x78, 0xdb, + 0x8c, 0x04, 0xb5, 0x31, 0x0f, 0x29, 0xe1, 0xd8, 0x22, 0x82, 0x9d, 0xaf, 0xee, 0xd1, 0x13, 0xb8, + 0x95, 0x36, 0x46, 0xce, 0xfc, 0x85, 0xba, 0xd9, 0x99, 0x9b, 0x81, 0xca, 0x70, 0x9d, 0x25, 0x32, + 0xe4, 0xac, 0x0a, 0xb4, 0xed, 0xa3, 0x7b, 0xfa, 0x75, 0x61, 0xd1, 0xd3, 0xa2, 0xed, 0x19, 0xef, + 0xe0, 0x1d, 0x80, 0x28, 0x0d, 0xb5, 0x42, 0xdf, 0x15, 0xf8, 0x0f, 0x5d, 0x60, 0x55, 0x5d, 0x99, + 0x15, 0x75, 0xfd, 0x58, 0x88, 0xa2, 0x8d, 0x3d, 0xca, 0x7c, 0xd4, 0x5b, 0x96, 0x28, 0xa0, 0x66, + 0xb5, 0xad, 0x72, 0xe9, 0xe7, 0xd5, 0x7e, 0xf1, 0x1f, 0x2e, 0xdc, 0xf4, 0xbc, 0x44, 0xee, 0xf5, + 0x51, 0x0b, 0xe0, 0xde, 0xb2, 0xf8, 0xae, 0xb4, 0xd9, 0xee, 0x7f, 0x99, 0xea, 0x2a, 0xbc, 0xf3, + 0xbb, 0xd9, 0x8d, 0xa8, 0xd3, 0x09, 0x06, 0x35, 0xe2, 0xe3, 0x01, 0xba, 0x0f, 0x6f, 0xb1, 0x49, + 0xd3, 0xe1, 0x93, 0xee, 0xd4, 0x6d, 0x7b, 0x9b, 0xa5, 0xd6, 0x62, 0xfe, 0xf0, 0x0c, 0x6e, 0xa5, + 0xef, 0x13, 0xdd, 0x85, 0x79, 0xb3, 0xd5, 0x3c, 0x75, 0x6c, 0xab, 0x51, 0x3f, 0x3d, 0x69, 0x58, + 0x4e, 0xeb, 0xa4, 0x51, 0xb7, 0x2a, 0xb5, 0x6a, 0xcd, 0x3a, 0xce, 0x49, 0x48, 0x86, 0x3b, 0x8b, + 0xb0, 0x59, 0xa9, 0x58, 0xf5, 0x66, 0x0e, 0xa0, 0x3c, 0xdc, 0x5d, 0x44, 0x8e, 0xad, 0xca, 0xb3, + 0xda, 0x89, 0x95, 0xcb, 0x14, 0xd6, 0xde, 0x7c, 0x50, 0xa4, 0xf2, 0xd3, 0x8b, 0xa1, 0x02, 0x2e, + 0x87, 0x0a, 0xf8, 0x3e, 0x54, 0xc0, 0xdb, 0x91, 0x22, 0x5d, 0x8e, 0x14, 0xe9, 0xeb, 0x48, 0x91, + 0x5e, 0x1c, 0xa6, 0x8c, 0x99, 0xa7, 0xae, 0x18, 0xd0, 0x54, 0x65, 0x0c, 0x52, 0xef, 0x6c, 0xfb, + 0xe6, 0xe4, 0xf5, 0x7b, 0xf4, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x20, 0x00, 0x90, 0x86, 0x95, 0x05, 0x00, 0x00, } diff --git a/x/quarantine/query.pb.go b/x/quarantine/query.pb.go index f53a45b414..41ce61d9dd 100644 --- a/x/quarantine/query.pb.go +++ b/x/quarantine/query.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/quarantine/v1beta1/query.proto +// source: provenance/quarantine/v1/query.proto package quarantine @@ -40,7 +40,7 @@ func (m *QueryIsQuarantinedRequest) Reset() { *m = QueryIsQuarantinedReq func (m *QueryIsQuarantinedRequest) String() string { return proto.CompactTextString(m) } func (*QueryIsQuarantinedRequest) ProtoMessage() {} func (*QueryIsQuarantinedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6e6232ebe830d056, []int{0} + return fileDescriptor_6d60739bf6ede825, []int{0} } func (m *QueryIsQuarantinedRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -86,7 +86,7 @@ func (m *QueryIsQuarantinedResponse) Reset() { *m = QueryIsQuarantinedRe func (m *QueryIsQuarantinedResponse) String() string { return proto.CompactTextString(m) } func (*QueryIsQuarantinedResponse) ProtoMessage() {} func (*QueryIsQuarantinedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6e6232ebe830d056, []int{1} + return fileDescriptor_6d60739bf6ede825, []int{1} } func (m *QueryIsQuarantinedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -136,7 +136,7 @@ func (m *QueryQuarantinedFundsRequest) Reset() { *m = QueryQuarantinedFu func (m *QueryQuarantinedFundsRequest) String() string { return proto.CompactTextString(m) } func (*QueryQuarantinedFundsRequest) ProtoMessage() {} func (*QueryQuarantinedFundsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6e6232ebe830d056, []int{2} + return fileDescriptor_6d60739bf6ede825, []int{2} } func (m *QueryQuarantinedFundsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -198,7 +198,7 @@ func (m *QueryQuarantinedFundsResponse) Reset() { *m = QueryQuarantinedF func (m *QueryQuarantinedFundsResponse) String() string { return proto.CompactTextString(m) } func (*QueryQuarantinedFundsResponse) ProtoMessage() {} func (*QueryQuarantinedFundsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6e6232ebe830d056, []int{3} + return fileDescriptor_6d60739bf6ede825, []int{3} } func (m *QueryQuarantinedFundsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -255,7 +255,7 @@ func (m *QueryAutoResponsesRequest) Reset() { *m = QueryAutoResponsesReq func (m *QueryAutoResponsesRequest) String() string { return proto.CompactTextString(m) } func (*QueryAutoResponsesRequest) ProtoMessage() {} func (*QueryAutoResponsesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_6e6232ebe830d056, []int{4} + return fileDescriptor_6d60739bf6ede825, []int{4} } func (m *QueryAutoResponsesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -317,7 +317,7 @@ func (m *QueryAutoResponsesResponse) Reset() { *m = QueryAutoResponsesRe func (m *QueryAutoResponsesResponse) String() string { return proto.CompactTextString(m) } func (*QueryAutoResponsesResponse) ProtoMessage() {} func (*QueryAutoResponsesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_6e6232ebe830d056, []int{5} + return fileDescriptor_6d60739bf6ede825, []int{5} } func (m *QueryAutoResponsesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -361,58 +361,59 @@ func (m *QueryAutoResponsesResponse) GetPagination() *query.PageResponse { } func init() { - proto.RegisterType((*QueryIsQuarantinedRequest)(nil), "cosmos.quarantine.v1beta1.QueryIsQuarantinedRequest") - proto.RegisterType((*QueryIsQuarantinedResponse)(nil), "cosmos.quarantine.v1beta1.QueryIsQuarantinedResponse") - proto.RegisterType((*QueryQuarantinedFundsRequest)(nil), "cosmos.quarantine.v1beta1.QueryQuarantinedFundsRequest") - proto.RegisterType((*QueryQuarantinedFundsResponse)(nil), "cosmos.quarantine.v1beta1.QueryQuarantinedFundsResponse") - proto.RegisterType((*QueryAutoResponsesRequest)(nil), "cosmos.quarantine.v1beta1.QueryAutoResponsesRequest") - proto.RegisterType((*QueryAutoResponsesResponse)(nil), "cosmos.quarantine.v1beta1.QueryAutoResponsesResponse") + proto.RegisterType((*QueryIsQuarantinedRequest)(nil), "provenance.quarantine.v1.QueryIsQuarantinedRequest") + proto.RegisterType((*QueryIsQuarantinedResponse)(nil), "provenance.quarantine.v1.QueryIsQuarantinedResponse") + proto.RegisterType((*QueryQuarantinedFundsRequest)(nil), "provenance.quarantine.v1.QueryQuarantinedFundsRequest") + proto.RegisterType((*QueryQuarantinedFundsResponse)(nil), "provenance.quarantine.v1.QueryQuarantinedFundsResponse") + proto.RegisterType((*QueryAutoResponsesRequest)(nil), "provenance.quarantine.v1.QueryAutoResponsesRequest") + proto.RegisterType((*QueryAutoResponsesResponse)(nil), "provenance.quarantine.v1.QueryAutoResponsesResponse") } func init() { - proto.RegisterFile("cosmos/quarantine/v1beta1/query.proto", fileDescriptor_6e6232ebe830d056) -} - -var fileDescriptor_6e6232ebe830d056 = []byte{ - // 605 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0x4f, 0x6b, 0x13, 0x41, - 0x1c, 0xed, 0x44, 0x2a, 0x76, 0x62, 0x4a, 0x19, 0x3c, 0xa4, 0xa1, 0x2e, 0x61, 0xa1, 0x1a, 0xb5, - 0x99, 0xb1, 0xf1, 0x4f, 0x85, 0xaa, 0xd0, 0x16, 0x2b, 0xde, 0x6c, 0x2a, 0x08, 0xb9, 0x84, 0x49, - 0x76, 0xba, 0x2e, 0x9a, 0x99, 0x64, 0x67, 0xb6, 0x58, 0x4a, 0x2f, 0x7e, 0x02, 0xa1, 0x37, 0x8f, - 0x7e, 0x86, 0x9e, 0xbc, 0x79, 0xf3, 0x58, 0xf4, 0xa0, 0x82, 0x07, 0x49, 0xfc, 0x02, 0x7e, 0x03, - 0xc9, 0xce, 0x24, 0xd9, 0xa4, 0xd9, 0x2c, 0x41, 0x4f, 0x9e, 0x42, 0xf6, 0xf7, 0xde, 0xfb, 0xfd, - 0xde, 0xbe, 0xdf, 0xcc, 0xc2, 0xe5, 0xba, 0x90, 0x0d, 0x21, 0x49, 0x2b, 0xa0, 0x3e, 0xe5, 0xca, - 0xe3, 0x8c, 0xec, 0xaf, 0xd6, 0x98, 0xa2, 0xab, 0xa4, 0x15, 0x30, 0xff, 0x00, 0x37, 0x7d, 0xa1, - 0x04, 0x5a, 0xd4, 0x30, 0x3c, 0x80, 0x61, 0x03, 0xcb, 0x5d, 0x37, 0x0a, 0x35, 0x2a, 0x99, 0xe6, - 0xf4, 0x15, 0x9a, 0xd4, 0xf5, 0x38, 0x55, 0x9e, 0xe0, 0x5a, 0xa6, 0x8f, 0x1d, 0xdb, 0xad, 0xaf, - 0xac, 0xb1, 0xa6, 0x65, 0x35, 0xfc, 0x47, 0x4c, 0x7f, 0x5d, 0x5a, 0x72, 0x85, 0x70, 0x5f, 0x31, - 0x42, 0x9b, 0x1e, 0xa1, 0x9c, 0x0b, 0x15, 0xf6, 0x30, 0x55, 0xfb, 0x19, 0x5c, 0xdc, 0xe9, 0x8e, - 0xf1, 0x44, 0xee, 0xf4, 0x35, 0x9d, 0x32, 0x6b, 0x05, 0x4c, 0x2a, 0xb4, 0x06, 0xa1, 0x12, 0x55, - 0xea, 0x38, 0x3e, 0x93, 0x32, 0x0b, 0xf2, 0xa0, 0x30, 0xb7, 0x99, 0xfd, 0x7c, 0x52, 0xbc, 0x64, - 0x1a, 0x6c, 0xe8, 0xca, 0xae, 0xf2, 0x3d, 0xee, 0x96, 0xe7, 0x94, 0x30, 0x0f, 0xec, 0x2d, 0x98, - 0x1b, 0xa7, 0x2a, 0x9b, 0x82, 0x4b, 0x86, 0x96, 0xe1, 0xbc, 0x27, 0xab, 0x03, 0x0f, 0x4e, 0x28, - 0x7d, 0xa1, 0x9c, 0xf1, 0xa2, 0x70, 0xfb, 0x07, 0x80, 0x4b, 0xa1, 0x4a, 0xe4, 0xe1, 0x76, 0xc0, - 0x1d, 0xf9, 0xb7, 0xe3, 0xa1, 0x75, 0x78, 0x71, 0xcf, 0x17, 0x8d, 0x3e, 0x35, 0x95, 0x40, 0x4d, - 0x77, 0xd1, 0x3d, 0xf2, 0x36, 0x84, 0x83, 0xa8, 0xb2, 0xf5, 0x3c, 0x28, 0xa4, 0x4b, 0x57, 0xb0, - 0xe1, 0x75, 0x73, 0xc5, 0x7a, 0x17, 0x4c, 0x56, 0xf8, 0x29, 0x75, 0x99, 0x99, 0xb8, 0x1c, 0x61, - 0xda, 0x1f, 0x01, 0xbc, 0x1c, 0x63, 0xcf, 0xbc, 0xa7, 0xe7, 0x70, 0xa1, 0x35, 0x52, 0xcb, 0x82, - 0xfc, 0xb9, 0x42, 0xba, 0x74, 0x03, 0xc7, 0xae, 0x18, 0x3e, 0x23, 0x77, 0x46, 0x04, 0x3d, 0x1e, - 0x63, 0xe1, 0x6a, 0xa2, 0x05, 0x3d, 0xd5, 0x90, 0x87, 0xef, 0xc0, 0xac, 0xcf, 0x46, 0xa0, 0x44, - 0x0f, 0xf1, 0x9f, 0xe4, 0xf3, 0x01, 0x98, 0x25, 0x1e, 0xf1, 0x66, 0xc2, 0xd9, 0x85, 0xf3, 0x34, - 0x50, 0xa2, 0xea, 0xf7, 0x2a, 0x26, 0x9a, 0x95, 0x09, 0xd1, 0x44, 0x95, 0x1e, 0x71, 0xe5, 0x1f, - 0x94, 0x33, 0x34, 0x2a, 0xfe, 0xcf, 0x82, 0x29, 0x7d, 0x9d, 0x85, 0xb3, 0xe1, 0xf0, 0xe8, 0x04, - 0xc0, 0xcc, 0xd0, 0x31, 0x44, 0xb7, 0x27, 0x2e, 0x4f, 0xcc, 0x5d, 0x90, 0xbb, 0x33, 0x25, 0x4b, - 0x0f, 0x65, 0xdf, 0x7d, 0xf3, 0xe5, 0xd7, 0x71, 0xea, 0x26, 0xc2, 0x24, 0xfe, 0x36, 0xa3, 0x75, - 0xe5, 0xed, 0x33, 0x72, 0x38, 0x58, 0x96, 0x23, 0xf4, 0x3e, 0x05, 0x17, 0x46, 0x37, 0x19, 0xad, - 0x25, 0xcd, 0x10, 0x73, 0x53, 0xe4, 0xee, 0x4d, 0x4f, 0x34, 0xf3, 0xbf, 0x03, 0xa1, 0x81, 0x63, - 0x80, 0xf2, 0x13, 0x1c, 0xec, 0x75, 0x39, 0x15, 0x82, 0x8a, 0x49, 0x98, 0x21, 0x93, 0x95, 0x87, - 0xe8, 0xfe, 0x54, 0x04, 0x72, 0x18, 0x3d, 0x16, 0x47, 0xe8, 0x37, 0x80, 0x99, 0xa1, 0xed, 0x4c, - 0xce, 0x76, 0xdc, 0x41, 0x4d, 0xce, 0x76, 0xec, 0x11, 0xb0, 0x65, 0xf8, 0x6a, 0x1a, 0x68, 0x65, - 0x52, 0xb6, 0x81, 0x12, 0xc3, 0xa6, 0x1f, 0xa0, 0xf5, 0x69, 0xf0, 0x23, 0x9e, 0x37, 0xb7, 0x3e, - 0xb5, 0x2d, 0x70, 0xda, 0xb6, 0xc0, 0xcf, 0xb6, 0x05, 0xde, 0x76, 0xac, 0x99, 0xd3, 0x8e, 0x35, - 0xf3, 0xad, 0x63, 0xcd, 0x54, 0xae, 0xb9, 0x9e, 0x7a, 0x11, 0xd4, 0x70, 0x5d, 0x34, 0x7a, 0x0d, - 0xf4, 0x4f, 0x51, 0x3a, 0x2f, 0xc9, 0xeb, 0x48, 0xb7, 0xda, 0xf9, 0xf0, 0xe3, 0x77, 0xeb, 0x4f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xa4, 0xc3, 0x3c, 0x9b, 0xd1, 0x07, 0x00, 0x00, + proto.RegisterFile("provenance/quarantine/v1/query.proto", fileDescriptor_6d60739bf6ede825) +} + +var fileDescriptor_6d60739bf6ede825 = []byte{ + // 616 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0x4f, 0x6f, 0x12, 0x4f, + 0x18, 0x66, 0xf8, 0xa5, 0xbf, 0xd8, 0x41, 0x9a, 0x66, 0xe2, 0x81, 0x92, 0xba, 0x21, 0x1b, 0xff, + 0x60, 0x95, 0x9d, 0x42, 0x4d, 0x7b, 0xa8, 0x9a, 0xb4, 0xc6, 0x1a, 0x3d, 0xd9, 0xd5, 0x78, 0xe0, + 0x42, 0x06, 0x98, 0xae, 0x93, 0xc8, 0x0c, 0xec, 0xcc, 0x12, 0x9b, 0xa6, 0x17, 0x3f, 0x81, 0x49, + 0x6f, 0x9e, 0xfc, 0x0c, 0xc6, 0x8b, 0x37, 0x8f, 0x1e, 0xab, 0x5e, 0x34, 0xf1, 0x60, 0xc0, 0xbb, + 0x5f, 0xc1, 0xb0, 0x3b, 0xb0, 0xbb, 0x14, 0xd8, 0x10, 0x3d, 0x79, 0x9c, 0x7d, 0xdf, 0xe7, 0xe5, + 0x79, 0xe6, 0x79, 0xe6, 0x05, 0x5e, 0x6a, 0xbb, 0xa2, 0x4b, 0x39, 0xe1, 0x0d, 0x8a, 0x3b, 0x1e, + 0x71, 0x09, 0x57, 0x8c, 0x53, 0xdc, 0x2d, 0xe3, 0x8e, 0x47, 0xdd, 0x43, 0xab, 0xed, 0x0a, 0x25, + 0x50, 0x2e, 0xec, 0xb2, 0xc2, 0x2e, 0xab, 0x5b, 0xce, 0xaf, 0x35, 0x84, 0x6c, 0x09, 0x89, 0xeb, + 0x44, 0xd2, 0x00, 0x82, 0xbb, 0xe5, 0x3a, 0x55, 0xa4, 0x8c, 0xdb, 0xc4, 0x61, 0x9c, 0x28, 0x26, + 0x78, 0x30, 0x25, 0xbf, 0x12, 0xf4, 0xd6, 0xfc, 0x13, 0x0e, 0x0e, 0xba, 0xb4, 0xea, 0x08, 0xe1, + 0x3c, 0xa7, 0x98, 0xb4, 0x19, 0x26, 0x9c, 0x0b, 0xe5, 0xe3, 0x86, 0xd5, 0x6b, 0x33, 0x48, 0x8e, + 0xc8, 0xf8, 0xad, 0xe6, 0x13, 0xb8, 0xb2, 0x3f, 0x60, 0xf1, 0x40, 0xee, 0x8f, 0x4a, 0x4d, 0x9b, + 0x76, 0x3c, 0x2a, 0x15, 0xda, 0x82, 0x50, 0x89, 0x1a, 0x69, 0x36, 0x5d, 0x2a, 0x65, 0x0e, 0x14, + 0x40, 0x71, 0x71, 0x37, 0xf7, 0xf9, 0x5d, 0xe9, 0x82, 0xe6, 0xb2, 0x13, 0x54, 0x1e, 0x2b, 0x97, + 0x71, 0xc7, 0x5e, 0x54, 0x42, 0x7f, 0x30, 0xef, 0xc2, 0xfc, 0xa4, 0xa9, 0xb2, 0x2d, 0xb8, 0xa4, + 0xe8, 0x32, 0x5c, 0x62, 0xb2, 0x16, 0x52, 0x69, 0xfa, 0xa3, 0xcf, 0xd9, 0x59, 0x16, 0x6d, 0x37, + 0xbf, 0x03, 0xb8, 0xea, 0x4f, 0x89, 0x7c, 0xdc, 0xf3, 0x78, 0x53, 0xfe, 0x29, 0x3d, 0xb4, 0x0d, + 0xcf, 0x1f, 0xb8, 0xa2, 0x35, 0x82, 0xa6, 0x13, 0xa0, 0x99, 0x41, 0xf7, 0x10, 0xbc, 0x07, 0x61, + 0xe8, 0x54, 0xae, 0x51, 0x00, 0xc5, 0x4c, 0xe5, 0x8a, 0xa5, 0x71, 0x03, 0x5b, 0xad, 0x20, 0x09, + 0xda, 0x56, 0xeb, 0x11, 0x71, 0xa8, 0x66, 0x6c, 0x47, 0x90, 0xe6, 0x07, 0x00, 0x2f, 0x4e, 0x91, + 0xa7, 0xef, 0xe9, 0x29, 0x5c, 0xee, 0x8c, 0xd5, 0x72, 0xa0, 0xf0, 0x5f, 0x31, 0x53, 0x59, 0xb3, + 0xa6, 0x05, 0xcc, 0x3a, 0x33, 0xed, 0xcc, 0x0c, 0x74, 0x7f, 0x82, 0x82, 0xab, 0x89, 0x0a, 0x02, + 0x52, 0x31, 0x09, 0xdf, 0x80, 0x4e, 0xcf, 0x8e, 0xa7, 0xc4, 0xb0, 0xe3, 0x1f, 0xb1, 0xe7, 0x3d, + 0xd0, 0x19, 0x1e, 0xd3, 0xa6, 0xbd, 0xb1, 0xe1, 0x12, 0xf1, 0x94, 0xa8, 0xb9, 0xc3, 0x8a, 0x76, + 0xe6, 0xfa, 0x74, 0x67, 0xa2, 0x83, 0xee, 0x71, 0xe5, 0x1e, 0xda, 0x59, 0x12, 0x9d, 0xfd, 0xd7, + 0x7c, 0xa9, 0x7c, 0x5a, 0x80, 0x0b, 0x3e, 0x77, 0xf4, 0x16, 0xc0, 0x6c, 0xec, 0x11, 0xa2, 0x8d, + 0x59, 0xd1, 0x99, 0xb2, 0x08, 0xf2, 0x37, 0xe7, 0x03, 0x05, 0x94, 0xcc, 0xcd, 0x97, 0x5f, 0x7e, + 0x9e, 0xa4, 0xd7, 0x91, 0xa5, 0x77, 0x57, 0x7c, 0x17, 0x05, 0x4b, 0x8f, 0x34, 0x14, 0xeb, 0x52, + 0x7c, 0x14, 0x26, 0xe5, 0x18, 0xbd, 0x49, 0xc3, 0xe5, 0xf1, 0x18, 0xa3, 0xcd, 0x04, 0x0a, 0x53, + 0x96, 0x44, 0x7e, 0x6b, 0x6e, 0x9c, 0x66, 0xff, 0x1a, 0xf8, 0xf4, 0x4f, 0x00, 0x2a, 0xcc, 0xe0, + 0x7f, 0x30, 0xc0, 0x54, 0x31, 0x2a, 0x25, 0xf5, 0xc4, 0x24, 0x56, 0xef, 0xa0, 0x5b, 0x73, 0x01, + 0xf0, 0x51, 0xf4, 0x45, 0x1c, 0xa3, 0x5f, 0x00, 0x66, 0x63, 0xc1, 0x4c, 0xf4, 0x75, 0xd2, 0x13, + 0x4d, 0xf4, 0x75, 0x62, 0xf6, 0x4d, 0xe9, 0x5f, 0x4c, 0x0b, 0xdd, 0x98, 0xe5, 0xab, 0xa7, 0x44, + 0x5c, 0xf2, 0x6d, 0xb4, 0x3d, 0x4f, 0xff, 0x98, 0xe2, 0xdd, 0x87, 0x1f, 0x7b, 0x06, 0x38, 0xed, + 0x19, 0xe0, 0x47, 0xcf, 0x00, 0xaf, 0xfa, 0x46, 0xea, 0xb4, 0x6f, 0xa4, 0xbe, 0xf6, 0x8d, 0x54, + 0x75, 0xdd, 0x61, 0xea, 0x99, 0x57, 0xb7, 0x1a, 0xa2, 0x85, 0x43, 0x39, 0x25, 0x26, 0x22, 0x27, + 0xfc, 0x22, 0xf2, 0xa3, 0xf5, 0xff, 0xfd, 0xff, 0xbe, 0x8d, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, + 0xab, 0x34, 0xfe, 0x1c, 0xcd, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -453,7 +454,7 @@ func NewQueryClient(cc grpc1.ClientConn) QueryClient { func (c *queryClient) IsQuarantined(ctx context.Context, in *QueryIsQuarantinedRequest, opts ...grpc.CallOption) (*QueryIsQuarantinedResponse, error) { out := new(QueryIsQuarantinedResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Query/IsQuarantined", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Query/IsQuarantined", in, out, opts...) if err != nil { return nil, err } @@ -462,7 +463,7 @@ func (c *queryClient) IsQuarantined(ctx context.Context, in *QueryIsQuarantinedR func (c *queryClient) QuarantinedFunds(ctx context.Context, in *QueryQuarantinedFundsRequest, opts ...grpc.CallOption) (*QueryQuarantinedFundsResponse, error) { out := new(QueryQuarantinedFundsResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Query/QuarantinedFunds", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Query/QuarantinedFunds", in, out, opts...) if err != nil { return nil, err } @@ -471,7 +472,7 @@ func (c *queryClient) QuarantinedFunds(ctx context.Context, in *QueryQuarantined func (c *queryClient) AutoResponses(ctx context.Context, in *QueryAutoResponsesRequest, opts ...grpc.CallOption) (*QueryAutoResponsesResponse, error) { out := new(QueryAutoResponsesResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Query/AutoResponses", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Query/AutoResponses", in, out, opts...) if err != nil { return nil, err } @@ -524,7 +525,7 @@ func _Query_IsQuarantined_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Query/IsQuarantined", + FullMethod: "/provenance.quarantine.v1.Query/IsQuarantined", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).IsQuarantined(ctx, req.(*QueryIsQuarantinedRequest)) @@ -542,7 +543,7 @@ func _Query_QuarantinedFunds_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Query/QuarantinedFunds", + FullMethod: "/provenance.quarantine.v1.Query/QuarantinedFunds", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).QuarantinedFunds(ctx, req.(*QueryQuarantinedFundsRequest)) @@ -560,7 +561,7 @@ func _Query_AutoResponses_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Query/AutoResponses", + FullMethod: "/provenance.quarantine.v1.Query/AutoResponses", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(QueryServer).AutoResponses(ctx, req.(*QueryAutoResponsesRequest)) @@ -569,7 +570,7 @@ func _Query_AutoResponses_Handler(srv interface{}, ctx context.Context, dec func } var _Query_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cosmos.quarantine.v1beta1.Query", + ServiceName: "provenance.quarantine.v1.Query", HandlerType: (*QueryServer)(nil), Methods: []grpc.MethodDesc{ { @@ -586,7 +587,7 @@ var _Query_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cosmos/quarantine/v1beta1/query.proto", + Metadata: "provenance/quarantine/v1/query.proto", } func (m *QueryIsQuarantinedRequest) Marshal() (dAtA []byte, err error) { diff --git a/x/quarantine/query.pb.gw.go b/x/quarantine/query.pb.gw.go index 0fbc4c9143..b5787bdc5f 100644 --- a/x/quarantine/query.pb.gw.go +++ b/x/quarantine/query.pb.gw.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: cosmos/quarantine/v1beta1/query.proto +// source: provenance/quarantine/v1/query.proto /* Package quarantine is a reverse proxy. @@ -20,7 +20,6 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) @@ -31,7 +30,6 @@ var _ status.Status var _ = runtime.String var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage -var _ = metadata.Join func request_Query_IsQuarantined_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryIsQuarantinedRequest @@ -458,14 +456,12 @@ func local_request_Query_AutoResponses_1(ctx context.Context, marshaler runtime. // 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. +// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { mux.Handle("GET", pattern_Query_IsQuarantined_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 { @@ -473,7 +469,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_IsQuarantined_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) @@ -487,8 +482,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv mux.Handle("GET", pattern_Query_QuarantinedFunds_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 { @@ -496,7 +489,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_QuarantinedFunds_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) @@ -510,8 +502,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv mux.Handle("GET", pattern_Query_QuarantinedFunds_1, 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 { @@ -519,7 +509,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_QuarantinedFunds_1(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) @@ -533,8 +522,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv mux.Handle("GET", pattern_Query_QuarantinedFunds_2, 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 { @@ -542,7 +529,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_QuarantinedFunds_2(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) @@ -556,8 +542,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv mux.Handle("GET", pattern_Query_AutoResponses_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 { @@ -565,7 +549,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_AutoResponses_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) @@ -579,8 +562,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv mux.Handle("GET", pattern_Query_AutoResponses_1, 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 { @@ -588,7 +569,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } resp, md, err := local_request_Query_AutoResponses_1(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) diff --git a/x/quarantine/tx.pb.go b/x/quarantine/tx.pb.go index 8182d41923..16eb979713 100644 --- a/x/quarantine/tx.pb.go +++ b/x/quarantine/tx.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: cosmos/quarantine/v1beta1/tx.proto +// source: provenance/quarantine/v1/tx.proto package quarantine @@ -42,7 +42,7 @@ func (m *MsgOptIn) Reset() { *m = MsgOptIn{} } func (m *MsgOptIn) String() string { return proto.CompactTextString(m) } func (*MsgOptIn) ProtoMessage() {} func (*MsgOptIn) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{0} + return fileDescriptor_cc32ebc8daaef0eb, []int{0} } func (m *MsgOptIn) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -86,7 +86,7 @@ func (m *MsgOptInResponse) Reset() { *m = MsgOptInResponse{} } func (m *MsgOptInResponse) String() string { return proto.CompactTextString(m) } func (*MsgOptInResponse) ProtoMessage() {} func (*MsgOptInResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{1} + return fileDescriptor_cc32ebc8daaef0eb, []int{1} } func (m *MsgOptInResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -124,7 +124,7 @@ func (m *MsgOptOut) Reset() { *m = MsgOptOut{} } func (m *MsgOptOut) String() string { return proto.CompactTextString(m) } func (*MsgOptOut) ProtoMessage() {} func (*MsgOptOut) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{2} + return fileDescriptor_cc32ebc8daaef0eb, []int{2} } func (m *MsgOptOut) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -168,7 +168,7 @@ func (m *MsgOptOutResponse) Reset() { *m = MsgOptOutResponse{} } func (m *MsgOptOutResponse) String() string { return proto.CompactTextString(m) } func (*MsgOptOutResponse) ProtoMessage() {} func (*MsgOptOutResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{3} + return fileDescriptor_cc32ebc8daaef0eb, []int{3} } func (m *MsgOptOutResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -214,7 +214,7 @@ func (m *MsgAccept) Reset() { *m = MsgAccept{} } func (m *MsgAccept) String() string { return proto.CompactTextString(m) } func (*MsgAccept) ProtoMessage() {} func (*MsgAccept) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{4} + return fileDescriptor_cc32ebc8daaef0eb, []int{4} } func (m *MsgAccept) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -274,7 +274,7 @@ func (m *MsgAcceptResponse) Reset() { *m = MsgAcceptResponse{} } func (m *MsgAcceptResponse) String() string { return proto.CompactTextString(m) } func (*MsgAcceptResponse) ProtoMessage() {} func (*MsgAcceptResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{5} + return fileDescriptor_cc32ebc8daaef0eb, []int{5} } func (m *MsgAcceptResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -327,7 +327,7 @@ func (m *MsgDecline) Reset() { *m = MsgDecline{} } func (m *MsgDecline) String() string { return proto.CompactTextString(m) } func (*MsgDecline) ProtoMessage() {} func (*MsgDecline) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{6} + return fileDescriptor_cc32ebc8daaef0eb, []int{6} } func (m *MsgDecline) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -385,7 +385,7 @@ func (m *MsgDeclineResponse) Reset() { *m = MsgDeclineResponse{} } func (m *MsgDeclineResponse) String() string { return proto.CompactTextString(m) } func (*MsgDeclineResponse) ProtoMessage() {} func (*MsgDeclineResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{7} + return fileDescriptor_cc32ebc8daaef0eb, []int{7} } func (m *MsgDeclineResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -426,7 +426,7 @@ func (m *MsgUpdateAutoResponses) Reset() { *m = MsgUpdateAutoResponses{} func (m *MsgUpdateAutoResponses) String() string { return proto.CompactTextString(m) } func (*MsgUpdateAutoResponses) ProtoMessage() {} func (*MsgUpdateAutoResponses) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{8} + return fileDescriptor_cc32ebc8daaef0eb, []int{8} } func (m *MsgUpdateAutoResponses) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -477,7 +477,7 @@ func (m *MsgUpdateAutoResponsesResponse) Reset() { *m = MsgUpdateAutoRes func (m *MsgUpdateAutoResponsesResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateAutoResponsesResponse) ProtoMessage() {} func (*MsgUpdateAutoResponsesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_d2d4535ca5d9aa17, []int{9} + return fileDescriptor_cc32ebc8daaef0eb, []int{9} } func (m *MsgUpdateAutoResponsesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -507,62 +507,61 @@ func (m *MsgUpdateAutoResponsesResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateAutoResponsesResponse proto.InternalMessageInfo func init() { - proto.RegisterType((*MsgOptIn)(nil), "cosmos.quarantine.v1beta1.MsgOptIn") - proto.RegisterType((*MsgOptInResponse)(nil), "cosmos.quarantine.v1beta1.MsgOptInResponse") - proto.RegisterType((*MsgOptOut)(nil), "cosmos.quarantine.v1beta1.MsgOptOut") - proto.RegisterType((*MsgOptOutResponse)(nil), "cosmos.quarantine.v1beta1.MsgOptOutResponse") - proto.RegisterType((*MsgAccept)(nil), "cosmos.quarantine.v1beta1.MsgAccept") - proto.RegisterType((*MsgAcceptResponse)(nil), "cosmos.quarantine.v1beta1.MsgAcceptResponse") - proto.RegisterType((*MsgDecline)(nil), "cosmos.quarantine.v1beta1.MsgDecline") - proto.RegisterType((*MsgDeclineResponse)(nil), "cosmos.quarantine.v1beta1.MsgDeclineResponse") - proto.RegisterType((*MsgUpdateAutoResponses)(nil), "cosmos.quarantine.v1beta1.MsgUpdateAutoResponses") - proto.RegisterType((*MsgUpdateAutoResponsesResponse)(nil), "cosmos.quarantine.v1beta1.MsgUpdateAutoResponsesResponse") -} - -func init() { - proto.RegisterFile("cosmos/quarantine/v1beta1/tx.proto", fileDescriptor_d2d4535ca5d9aa17) -} - -var fileDescriptor_d2d4535ca5d9aa17 = []byte{ - // 598 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xbf, 0x6f, 0xd3, 0x4e, - 0x14, 0xcf, 0x7d, 0xf3, 0xa5, 0x6d, 0x5e, 0xd5, 0x02, 0x6e, 0x05, 0xa9, 0x85, 0xdc, 0x28, 0x80, - 0x14, 0x0a, 0xb1, 0x49, 0x18, 0x10, 0x2c, 0x28, 0x29, 0x12, 0x62, 0x88, 0x22, 0x19, 0x3a, 0x80, - 0x90, 0x22, 0xc7, 0xbe, 0x1a, 0x8b, 0xe6, 0xce, 0xf5, 0x9d, 0xab, 0x76, 0xa5, 0x03, 0x2b, 0x7f, - 0x07, 0x2c, 0x0c, 0xe5, 0x7f, 0xe8, 0x58, 0x31, 0x31, 0x01, 0x4a, 0x06, 0xfe, 0x0d, 0x14, 0xdf, - 0x9d, 0x63, 0xd1, 0x34, 0x09, 0x15, 0x0b, 0x93, 0x2f, 0xf7, 0x3e, 0xbf, 0x5e, 0xf4, 0x9e, 0x0d, - 0x65, 0x97, 0xb2, 0x1e, 0x65, 0xd6, 0x6e, 0xec, 0x44, 0x0e, 0xe1, 0x01, 0xc1, 0xd6, 0x5e, 0xad, - 0x8b, 0xb9, 0x53, 0xb3, 0xf8, 0xbe, 0x19, 0x46, 0x94, 0x53, 0x6d, 0x4d, 0x60, 0xcc, 0x11, 0xc6, - 0x94, 0x18, 0x7d, 0x43, 0xd2, 0xbb, 0x0e, 0xc3, 0xd6, 0x6e, 0x8c, 0xa3, 0x83, 0x94, 0x1e, 0x3a, - 0x7e, 0x40, 0x1c, 0x1e, 0x50, 0x22, 0x64, 0x74, 0x23, 0x8b, 0x55, 0x28, 0x97, 0x06, 0xaa, 0x7e, - 0x55, 0xd6, 0x7b, 0xcc, 0xb7, 0xf6, 0x6a, 0xc3, 0x87, 0x2c, 0x6c, 0x9c, 0x9d, 0x31, 0x13, 0x49, - 0x60, 0x65, 0xd6, 0x4e, 0xf2, 0xcb, 0x92, 0xc1, 0x45, 0x69, 0xd5, 0xa7, 0x3e, 0x15, 0xf7, 0xc3, - 0x93, 0xb8, 0x2d, 0x3f, 0x87, 0x85, 0x16, 0xf3, 0xdb, 0x21, 0x7f, 0x4a, 0xb4, 0xfb, 0x00, 0x9c, - 0x76, 0x1c, 0xcf, 0x8b, 0x30, 0x63, 0x45, 0x54, 0x42, 0x95, 0x42, 0xb3, 0xf8, 0xe5, 0xa8, 0xba, - 0x2a, 0x75, 0x1a, 0xa2, 0xf2, 0x8c, 0x47, 0x01, 0xf1, 0xed, 0x02, 0xa7, 0xf2, 0xe2, 0xe1, 0xc5, - 0xb7, 0x3f, 0x3f, 0x6d, 0x64, 0xb8, 0x65, 0x0d, 0x2e, 0x29, 0x55, 0x1b, 0xb3, 0x90, 0x12, 0x86, - 0xcb, 0x5b, 0x50, 0x10, 0x77, 0xed, 0x98, 0xff, 0x45, 0xab, 0x15, 0xb8, 0x9c, 0xca, 0xa6, 0x5e, - 0x47, 0x28, 0x31, 0x6b, 0xb8, 0x2e, 0x0e, 0xcf, 0x6f, 0xa6, 0x3d, 0x82, 0xe5, 0xed, 0x88, 0xf6, - 0x14, 0x15, 0xb3, 0xe2, 0x7f, 0xa5, 0xfc, 0x44, 0xf2, 0xd2, 0x10, 0xdf, 0x50, 0x70, 0xed, 0x1a, - 0x14, 0x42, 0x1c, 0xf5, 0x1c, 0x82, 0x09, 0x2f, 0xe6, 0x4b, 0xa8, 0xb2, 0x60, 0x8f, 0x2e, 0x4e, - 0xf7, 0xf2, 0x0e, 0x25, 0xcd, 0x88, 0xd8, 0xaa, 0x19, 0x2d, 0x82, 0xe5, 0xed, 0x98, 0x78, 0xac, - 0x13, 0xe1, 0x1d, 0xec, 0x30, 0xec, 0x15, 0x51, 0x29, 0x5f, 0x59, 0xac, 0xaf, 0x99, 0x32, 0xc2, - 0x70, 0xa2, 0xd4, 0x48, 0x9a, 0x9b, 0x34, 0x20, 0xcd, 0xbb, 0xc7, 0xdf, 0xd6, 0x73, 0x1f, 0xbe, - 0xaf, 0x57, 0xfc, 0x80, 0xbf, 0x8e, 0xbb, 0xa6, 0x4b, 0x7b, 0x72, 0x18, 0xe4, 0xa3, 0xca, 0xbc, - 0x37, 0x16, 0x3f, 0x08, 0x31, 0x4b, 0x08, 0xcc, 0x5e, 0x4a, 0x2c, 0x6c, 0xe9, 0x50, 0xfe, 0x8c, - 0x00, 0x5a, 0xcc, 0x7f, 0x8c, 0xdd, 0x9d, 0x80, 0xe0, 0x7f, 0xe7, 0x1f, 0x5c, 0x05, 0x6d, 0x14, - 0x3b, 0x1d, 0x87, 0x8f, 0x08, 0xae, 0xb4, 0x98, 0xbf, 0x15, 0x7a, 0x0e, 0xc7, 0x8d, 0x98, 0x53, - 0x55, 0x61, 0xe7, 0xef, 0xec, 0x09, 0xcc, 0xc7, 0x89, 0x9e, 0x68, 0x69, 0xb1, 0x5e, 0x35, 0xcf, - 0x7c, 0x4f, 0x98, 0x59, 0x4f, 0x91, 0xc2, 0x56, 0xec, 0xd3, 0x3d, 0x94, 0xc0, 0x18, 0x1f, 0x56, - 0x1d, 0xea, 0x87, 0xff, 0x43, 0xbe, 0xc5, 0x7c, 0xed, 0x05, 0x5c, 0x10, 0x9b, 0x7b, 0x7d, 0x82, - 0xb7, 0x5a, 0x44, 0xfd, 0xf6, 0x0c, 0xa0, 0x74, 0xe8, 0x5e, 0xc1, 0x9c, 0x5c, 0xd5, 0x1b, 0x53, - 0x69, 0xed, 0x98, 0xeb, 0x77, 0x66, 0x41, 0x65, 0xd5, 0xe5, 0x6e, 0x4e, 0x51, 0x17, 0xa8, 0x69, - 0xea, 0xbf, 0x2d, 0x4c, 0x07, 0xe6, 0xd5, 0xe0, 0xde, 0x9c, 0x4c, 0x94, 0x30, 0xbd, 0x3a, 0x13, - 0x2c, 0x35, 0x38, 0x44, 0xb0, 0x32, 0x6e, 0x98, 0x6a, 0x93, 0x65, 0xc6, 0x50, 0xf4, 0x07, 0x7f, - 0x4c, 0x51, 0x87, 0xe6, 0xe6, 0x71, 0xdf, 0x40, 0x27, 0x7d, 0x03, 0xfd, 0xe8, 0x1b, 0xe8, 0xfd, - 0xc0, 0xc8, 0x9d, 0x0c, 0x8c, 0xdc, 0xd7, 0x81, 0x91, 0x7b, 0x79, 0x6b, 0xe2, 0xda, 0xef, 0x67, - 0x3e, 0x1b, 0xdd, 0xb9, 0xe4, 0x33, 0x70, 0xef, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x24, 0x6d, - 0x04, 0x5d, 0x09, 0x07, 0x00, 0x00, + proto.RegisterType((*MsgOptIn)(nil), "provenance.quarantine.v1.MsgOptIn") + proto.RegisterType((*MsgOptInResponse)(nil), "provenance.quarantine.v1.MsgOptInResponse") + proto.RegisterType((*MsgOptOut)(nil), "provenance.quarantine.v1.MsgOptOut") + proto.RegisterType((*MsgOptOutResponse)(nil), "provenance.quarantine.v1.MsgOptOutResponse") + proto.RegisterType((*MsgAccept)(nil), "provenance.quarantine.v1.MsgAccept") + proto.RegisterType((*MsgAcceptResponse)(nil), "provenance.quarantine.v1.MsgAcceptResponse") + proto.RegisterType((*MsgDecline)(nil), "provenance.quarantine.v1.MsgDecline") + proto.RegisterType((*MsgDeclineResponse)(nil), "provenance.quarantine.v1.MsgDeclineResponse") + proto.RegisterType((*MsgUpdateAutoResponses)(nil), "provenance.quarantine.v1.MsgUpdateAutoResponses") + proto.RegisterType((*MsgUpdateAutoResponsesResponse)(nil), "provenance.quarantine.v1.MsgUpdateAutoResponsesResponse") +} + +func init() { proto.RegisterFile("provenance/quarantine/v1/tx.proto", fileDescriptor_cc32ebc8daaef0eb) } + +var fileDescriptor_cc32ebc8daaef0eb = []byte{ + // 613 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0x3f, 0x6f, 0xd3, 0x40, + 0x14, 0xcf, 0x11, 0xd1, 0x36, 0x57, 0xb5, 0x80, 0x5b, 0x81, 0x6b, 0x21, 0x37, 0x04, 0x86, 0x50, + 0x5a, 0x3b, 0x09, 0x03, 0x88, 0x05, 0x25, 0x20, 0x24, 0x90, 0xa2, 0x48, 0x86, 0x0a, 0xa9, 0x12, + 0x8a, 0x1c, 0xfb, 0x7a, 0x58, 0xd4, 0x77, 0xc6, 0x77, 0x8e, 0xda, 0x11, 0x16, 0x56, 0x3e, 0x47, + 0x27, 0x86, 0xf2, 0x1d, 0x3a, 0x56, 0x4c, 0x4c, 0x80, 0x92, 0x81, 0xcf, 0xc0, 0x86, 0xe2, 0xbb, + 0x4b, 0x2c, 0x9a, 0x3f, 0xa5, 0x62, 0x61, 0xca, 0xdd, 0x7b, 0xbf, 0x3f, 0xef, 0x45, 0xef, 0xf9, + 0xe0, 0x8d, 0x28, 0xa6, 0x5d, 0x44, 0x5c, 0xe2, 0x21, 0xfb, 0x6d, 0xe2, 0xc6, 0x2e, 0xe1, 0x01, + 0x41, 0x76, 0xb7, 0x6a, 0xf3, 0x7d, 0x2b, 0x8a, 0x29, 0xa7, 0x9a, 0x3e, 0x82, 0x58, 0x23, 0x88, + 0xd5, 0xad, 0x1a, 0x1b, 0x1e, 0x65, 0x21, 0x65, 0x76, 0xc7, 0x65, 0x03, 0x36, 0x8a, 0x0f, 0xec, + 0x6e, 0xb5, 0x83, 0xb8, 0x5b, 0xb5, 0x23, 0x17, 0x07, 0xc4, 0xe5, 0x01, 0x25, 0x42, 0xc5, 0x30, + 0xb3, 0x58, 0x85, 0xf2, 0x68, 0xa0, 0xf2, 0xd7, 0x64, 0x3e, 0x64, 0x78, 0xe0, 0x1e, 0x32, 0x2c, + 0x13, 0x6b, 0x22, 0xd1, 0x4e, 0x6f, 0xb6, 0xb8, 0xc8, 0xd4, 0x2a, 0xa6, 0x98, 0x8a, 0xf8, 0xe0, + 0x24, 0xa3, 0xb7, 0x27, 0xb6, 0x94, 0xa9, 0x3e, 0x85, 0x96, 0x5e, 0xc0, 0x85, 0x26, 0xc3, 0xad, + 0x88, 0x3f, 0x25, 0xda, 0x3d, 0x08, 0x39, 0x6d, 0xbb, 0xbe, 0x1f, 0x23, 0xc6, 0x74, 0x50, 0x04, + 0xe5, 0x42, 0x43, 0xff, 0x72, 0xb4, 0xb5, 0x2a, 0x2d, 0xeb, 0x22, 0xf3, 0x9c, 0xc7, 0x01, 0xc1, + 0x4e, 0x81, 0x53, 0x19, 0x78, 0x70, 0xe9, 0xfd, 0xcf, 0x4f, 0x1b, 0x19, 0x6e, 0x49, 0x83, 0x97, + 0x95, 0xaa, 0x83, 0x58, 0x44, 0x09, 0x43, 0xa5, 0x6d, 0x58, 0x10, 0xb1, 0x56, 0xc2, 0xff, 0xa1, + 0xd5, 0x0a, 0xbc, 0x32, 0x94, 0x1d, 0x7a, 0x1d, 0x81, 0xd4, 0xac, 0xee, 0x79, 0x28, 0x3a, 0xbf, + 0x99, 0xf6, 0x10, 0x2e, 0xef, 0xc6, 0x34, 0x54, 0x54, 0xc4, 0xf4, 0x0b, 0xc5, 0xfc, 0x54, 0xf2, + 0xd2, 0x00, 0x5f, 0x57, 0x70, 0xed, 0x3a, 0x2c, 0x44, 0x28, 0x0e, 0x5d, 0x82, 0x08, 0xd7, 0xf3, + 0x45, 0x50, 0x5e, 0x70, 0x46, 0x81, 0xd3, 0xbd, 0x7c, 0x00, 0x69, 0x33, 0xa2, 0x6c, 0xd5, 0x8c, + 0x16, 0xc3, 0xe5, 0xdd, 0x84, 0xf8, 0xac, 0x1d, 0xa3, 0x3d, 0xe4, 0x32, 0xe4, 0xeb, 0xa0, 0x98, + 0x2f, 0x2f, 0xd6, 0xd6, 0x2c, 0x59, 0xc2, 0x60, 0xa0, 0x2c, 0x39, 0x50, 0xd6, 0x23, 0x1a, 0x90, + 0x46, 0xe5, 0xf8, 0xdb, 0x7a, 0xee, 0xf0, 0xfb, 0x7a, 0x19, 0x07, 0xfc, 0x75, 0xd2, 0xb1, 0x3c, + 0x1a, 0xca, 0xb9, 0x91, 0x3f, 0x5b, 0xcc, 0x7f, 0x63, 0xf3, 0x83, 0x08, 0xb1, 0x94, 0xc0, 0x9c, + 0xa5, 0xd4, 0xc2, 0x91, 0x0e, 0xa5, 0xcf, 0x00, 0xc2, 0x26, 0xc3, 0x8f, 0x91, 0xb7, 0x17, 0x10, + 0xf4, 0xff, 0xfc, 0x83, 0xab, 0x50, 0x1b, 0x95, 0x3d, 0x1c, 0x87, 0x43, 0x00, 0xaf, 0x36, 0x19, + 0xde, 0x8e, 0x7c, 0x97, 0xa3, 0x7a, 0xc2, 0xa9, 0xca, 0xb0, 0xf3, 0x77, 0xf6, 0x04, 0xce, 0x27, + 0xa9, 0x9e, 0x68, 0x69, 0xb1, 0xb6, 0x69, 0x4d, 0xfa, 0x4a, 0x58, 0x59, 0x4b, 0x51, 0x84, 0xa3, + 0xc8, 0xa7, 0x5b, 0x28, 0x42, 0x73, 0x7c, 0xad, 0xea, 0x50, 0xfb, 0x95, 0x87, 0xf9, 0x26, 0xc3, + 0xda, 0x4b, 0x78, 0x51, 0x2c, 0x6e, 0x69, 0xb2, 0xb5, 0x5a, 0x43, 0x63, 0x63, 0x36, 0x66, 0x38, + 0x71, 0x3b, 0x70, 0x4e, 0xee, 0xe9, 0xcd, 0x59, 0xac, 0x56, 0xc2, 0x8d, 0x3b, 0x67, 0x00, 0x65, + 0xb5, 0xe5, 0x5a, 0x4e, 0xd7, 0x16, 0xa0, 0x19, 0xda, 0x7f, 0x6c, 0xca, 0x2b, 0x38, 0xaf, 0x26, + 0xf6, 0xd6, 0x54, 0x9e, 0x44, 0x19, 0x9b, 0x67, 0x41, 0x0d, 0xe5, 0xdf, 0x01, 0xb8, 0x32, 0x6e, + 0x86, 0x2a, 0x53, 0x55, 0xc6, 0x30, 0x8c, 0xfb, 0x7f, 0xcb, 0x50, 0x87, 0xc6, 0xb3, 0xe3, 0x9e, + 0x09, 0x4e, 0x7a, 0x26, 0xf8, 0xd1, 0x33, 0xc1, 0xc7, 0xbe, 0x99, 0x3b, 0xe9, 0x9b, 0xb9, 0xaf, + 0x7d, 0x33, 0xb7, 0x53, 0xc9, 0xec, 0xfa, 0x48, 0x7d, 0x2b, 0xa0, 0x99, 0x9b, 0xbd, 0x9f, 0x79, + 0x01, 0x3a, 0x73, 0xe9, 0x13, 0x70, 0xf7, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x05, 0xff, 0xa3, + 0xff, 0x02, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -601,7 +600,7 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { func (c *msgClient) OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOption) (*MsgOptInResponse, error) { out := new(MsgOptInResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/OptIn", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Msg/OptIn", in, out, opts...) if err != nil { return nil, err } @@ -610,7 +609,7 @@ func (c *msgClient) OptIn(ctx context.Context, in *MsgOptIn, opts ...grpc.CallOp func (c *msgClient) OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.CallOption) (*MsgOptOutResponse, error) { out := new(MsgOptOutResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/OptOut", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Msg/OptOut", in, out, opts...) if err != nil { return nil, err } @@ -619,7 +618,7 @@ func (c *msgClient) OptOut(ctx context.Context, in *MsgOptOut, opts ...grpc.Call func (c *msgClient) Accept(ctx context.Context, in *MsgAccept, opts ...grpc.CallOption) (*MsgAcceptResponse, error) { out := new(MsgAcceptResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/Accept", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Msg/Accept", in, out, opts...) if err != nil { return nil, err } @@ -628,7 +627,7 @@ func (c *msgClient) Accept(ctx context.Context, in *MsgAccept, opts ...grpc.Call func (c *msgClient) Decline(ctx context.Context, in *MsgDecline, opts ...grpc.CallOption) (*MsgDeclineResponse, error) { out := new(MsgDeclineResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/Decline", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Msg/Decline", in, out, opts...) if err != nil { return nil, err } @@ -637,7 +636,7 @@ func (c *msgClient) Decline(ctx context.Context, in *MsgDecline, opts ...grpc.Ca func (c *msgClient) UpdateAutoResponses(ctx context.Context, in *MsgUpdateAutoResponses, opts ...grpc.CallOption) (*MsgUpdateAutoResponsesResponse, error) { out := new(MsgUpdateAutoResponsesResponse) - err := c.cc.Invoke(ctx, "/cosmos.quarantine.v1beta1.Msg/UpdateAutoResponses", in, out, opts...) + err := c.cc.Invoke(ctx, "/provenance.quarantine.v1.Msg/UpdateAutoResponses", in, out, opts...) if err != nil { return nil, err } @@ -694,7 +693,7 @@ func _Msg_OptIn_Handler(srv interface{}, ctx context.Context, dec func(interface } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Msg/OptIn", + FullMethod: "/provenance.quarantine.v1.Msg/OptIn", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).OptIn(ctx, req.(*MsgOptIn)) @@ -712,7 +711,7 @@ func _Msg_OptOut_Handler(srv interface{}, ctx context.Context, dec func(interfac } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Msg/OptOut", + FullMethod: "/provenance.quarantine.v1.Msg/OptOut", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).OptOut(ctx, req.(*MsgOptOut)) @@ -730,7 +729,7 @@ func _Msg_Accept_Handler(srv interface{}, ctx context.Context, dec func(interfac } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Msg/Accept", + FullMethod: "/provenance.quarantine.v1.Msg/Accept", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).Accept(ctx, req.(*MsgAccept)) @@ -748,7 +747,7 @@ func _Msg_Decline_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Msg/Decline", + FullMethod: "/provenance.quarantine.v1.Msg/Decline", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).Decline(ctx, req.(*MsgDecline)) @@ -766,7 +765,7 @@ func _Msg_UpdateAutoResponses_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/cosmos.quarantine.v1beta1.Msg/UpdateAutoResponses", + FullMethod: "/provenance.quarantine.v1.Msg/UpdateAutoResponses", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(MsgServer).UpdateAutoResponses(ctx, req.(*MsgUpdateAutoResponses)) @@ -775,7 +774,7 @@ func _Msg_UpdateAutoResponses_Handler(srv interface{}, ctx context.Context, dec } var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cosmos.quarantine.v1beta1.Msg", + ServiceName: "provenance.quarantine.v1.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ { @@ -800,7 +799,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cosmos/quarantine/v1beta1/tx.proto", + Metadata: "provenance/quarantine/v1/tx.proto", } func (m *MsgOptIn) Marshal() (dAtA []byte, err error) { From eabf1845aa86ceab7ae5453ea1dcfac3bb5638d8 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 15:57:41 -0700 Subject: [PATCH 03/20] [1752]: Copy the x/bank/client/testutil/cli_helpers.go file over since it doesn't come with the impoort (and is needed by the quarantine tests). --- testutil/bank/cli_helpers.go | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 testutil/bank/cli_helpers.go diff --git a/testutil/bank/cli_helpers.go b/testutil/bank/cli_helpers.go new file mode 100644 index 0000000000..6970e987e2 --- /dev/null +++ b/testutil/bank/cli_helpers.go @@ -0,0 +1,41 @@ +package bank + +// The contents of this file were copied from the SDK: x/bank/client/testutil/cli_helpers.go (and the package chagned). + +import ( + "fmt" + + "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/testutil" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli" +) + +func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{from.String(), to.String(), amount.String()} + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, bankcli.NewSendTxCmd(), args) +} + +func MsgMultiSendExec(clientCtx client.Context, from sdk.AccAddress, to []sdk.AccAddress, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{from.String()} + for _, addr := range to { + args = append(args, addr.String()) + } + + args = append(args, amount.String()) + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, bankcli.NewMultiSendTxCmd(), args) +} + +func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) { + args := []string{address.String(), fmt.Sprintf("--%s=json", cli.OutputFlag)} + args = append(args, extraArgs...) + + return clitestutil.ExecTestCLICmd(clientCtx, bankcli.GetBalancesCmd(), args) +} From 210b22a3fc2f283f18d744389c625ef28713645e Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 16:02:55 -0700 Subject: [PATCH 04/20] [1752]: Replace all imports of the SDK x/quarantine stuff with prov stuff. --- app/app.go | 6 +++--- app/sim_test.go | 5 +++-- x/exchange/keeper/keeper.go | 2 +- x/exchange/keeper/mocks_test.go | 2 +- x/marker/keeper/keeper_test.go | 7 ++++--- x/quarantine/client/cli/query.go | 3 ++- x/quarantine/client/cli/tx.go | 3 ++- x/quarantine/client/cli/util.go | 6 ++++-- x/quarantine/client/cli/util_test.go | 5 +++-- x/quarantine/client/testutil/common_test.go | 5 +++-- x/quarantine/client/testutil/query_test.go | 7 ++++--- x/quarantine/client/testutil/tx_test.go | 7 ++++--- x/quarantine/genesis.go | 1 + x/quarantine/genesis_test.go | 4 ++-- x/quarantine/keeper/export_test.go | 3 ++- x/quarantine/keeper/genesis.go | 3 ++- x/quarantine/keeper/grpc_query.go | 8 ++++--- x/quarantine/keeper/grpc_query_test.go | 5 +++-- x/quarantine/keeper/invariants.go | 3 ++- x/quarantine/keeper/invariants_test.go | 5 +++-- x/quarantine/keeper/keeper.go | 3 ++- x/quarantine/keeper/keeper_test.go | 22 ++++++++++---------- x/quarantine/keeper/mock_bank_keeper_test.go | 3 ++- x/quarantine/keeper/msg_server.go | 3 ++- x/quarantine/keeper/msg_server_test.go | 5 +++-- x/quarantine/keeper/send_restriction.go | 3 ++- x/quarantine/keeper/send_restriction_test.go | 5 +++-- x/quarantine/keys_test.go | 7 ++++--- x/quarantine/module/module.go | 12 ++++++----- x/quarantine/msgs.go | 8 ++++--- x/quarantine/msgs_test.go | 4 ++-- x/quarantine/quarantine.go | 13 ++++++------ x/quarantine/quarantine_test.go | 7 ++++--- x/quarantine/send_restriction_test.go | 3 ++- x/quarantine/simulation/decoder.go | 3 ++- x/quarantine/simulation/decoder_test.go | 5 +++-- x/quarantine/simulation/genesis.go | 3 ++- x/quarantine/simulation/genesis_test.go | 22 ++++++++++++-------- x/quarantine/simulation/operations.go | 5 +++-- x/quarantine/simulation/operations_test.go | 16 +++++++------- x/quarantine/testutil/test_helpers.go | 3 ++- 41 files changed, 144 insertions(+), 101 deletions(-) diff --git a/app/app.go b/app/app.go index 1d4a92356b..70f7f718fc 100644 --- a/app/app.go +++ b/app/app.go @@ -86,9 +86,6 @@ import ( 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/quarantine" - quarantinekeeper "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" - quarantinemodule "github.com/cosmos/cosmos-sdk/x/quarantine/module" "github.com/cosmos/cosmos-sdk/x/sanction" sanctionkeeper "github.com/cosmos/cosmos-sdk/x/sanction/keeper" sanctionmodule "github.com/cosmos/cosmos-sdk/x/sanction/module" @@ -162,6 +159,9 @@ import ( oraclekeeper "github.com/provenance-io/provenance/x/oracle/keeper" oraclemodule "github.com/provenance-io/provenance/x/oracle/module" oracletypes "github.com/provenance-io/provenance/x/oracle/types" + "github.com/provenance-io/provenance/x/quarantine" + quarantinekeeper "github.com/provenance-io/provenance/x/quarantine/keeper" + quarantinemodule "github.com/provenance-io/provenance/x/quarantine/module" rewardkeeper "github.com/provenance-io/provenance/x/reward/keeper" rewardmodule "github.com/provenance-io/provenance/x/reward/module" rewardtypes "github.com/provenance-io/provenance/x/reward/types" diff --git a/app/sim_test.go b/app/sim_test.go index 5ebd66a479..0d18709cc4 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -13,9 +13,10 @@ import ( "testing" "time" - icqtypes "github.com/cosmos/ibc-apps/modules/async-icq/v6/types" "github.com/stretchr/testify/require" + icqtypes "github.com/cosmos/ibc-apps/modules/async-icq/v6/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -39,7 +40,6 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" "github.com/cosmos/cosmos-sdk/x/sanction" "github.com/cosmos/cosmos-sdk/x/simulation" slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" @@ -55,6 +55,7 @@ import ( metadatatypes "github.com/provenance-io/provenance/x/metadata/types" msgfeetype "github.com/provenance-io/provenance/x/msgfees/types" nametypes "github.com/provenance-io/provenance/x/name/types" + "github.com/provenance-io/provenance/x/quarantine" triggertypes "github.com/provenance-io/provenance/x/trigger/types" ) diff --git a/x/exchange/keeper/keeper.go b/x/exchange/keeper/keeper.go index 1b99dc55dd..b86a06306f 100644 --- a/x/exchange/keeper/keeper.go +++ b/x/exchange/keeper/keeper.go @@ -15,9 +15,9 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" "github.com/provenance-io/provenance/x/exchange" + "github.com/provenance-io/provenance/x/quarantine" ) var ( diff --git a/x/exchange/keeper/mocks_test.go b/x/exchange/keeper/mocks_test.go index 8b00895d51..562dcf789f 100644 --- a/x/exchange/keeper/mocks_test.go +++ b/x/exchange/keeper/mocks_test.go @@ -8,11 +8,11 @@ import ( 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/cosmos/cosmos-sdk/x/quarantine" attrtypes "github.com/provenance-io/provenance/x/attribute/types" "github.com/provenance-io/provenance/x/exchange" markertypes "github.com/provenance-io/provenance/x/marker/types" + "github.com/provenance-io/provenance/x/quarantine" ) // ############################################################################# diff --git a/x/marker/keeper/keeper_test.go b/x/marker/keeper/keeper_test.go index fa533098e0..d3809fc633 100644 --- a/x/marker/keeper/keeper_test.go +++ b/x/marker/keeper/keeper_test.go @@ -10,6 +10,9 @@ import ( "github.com/stretchr/testify/require" "cosmossdk.io/math" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -19,14 +22,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/feegrant" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - simapp "github.com/provenance-io/provenance/app" markerkeeper "github.com/provenance-io/provenance/x/marker/keeper" "github.com/provenance-io/provenance/x/marker/types" + "github.com/provenance-io/provenance/x/quarantine" rewardtypes "github.com/provenance-io/provenance/x/reward/types" ) diff --git a/x/quarantine/client/cli/query.go b/x/quarantine/client/cli/query.go index d61f83578f..3c5d0d1cff 100644 --- a/x/quarantine/client/cli/query.go +++ b/x/quarantine/client/cli/query.go @@ -8,7 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) // exampleQueryCmdBase is the base command that gets a user to one of the query commands in here. diff --git a/x/quarantine/client/cli/tx.go b/x/quarantine/client/cli/tx.go index 210c712c67..667fb1bc5f 100644 --- a/x/quarantine/client/cli/tx.go +++ b/x/quarantine/client/cli/tx.go @@ -9,7 +9,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/version" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) const ( diff --git a/x/quarantine/client/cli/util.go b/x/quarantine/client/cli/util.go index 7b8c861d8d..8b9d8ca4aa 100644 --- a/x/quarantine/client/cli/util.go +++ b/x/quarantine/client/cli/util.go @@ -4,10 +4,12 @@ import ( "fmt" "strings" + "github.com/tendermint/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/tendermint/tendermint/crypto" + + "github.com/provenance-io/provenance/x/quarantine" ) // exampleAddr creates a consistent example address from the given name string. diff --git a/x/quarantine/client/cli/util_test.go b/x/quarantine/client/cli/util_test.go index 140f175e83..c25c9264b1 100644 --- a/x/quarantine/client/cli/util_test.go +++ b/x/quarantine/client/cli/util_test.go @@ -9,9 +9,10 @@ import ( "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + "github.com/provenance-io/provenance/x/quarantine" + + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) func TestExampleAddress(t *testing.T) { diff --git a/x/quarantine/client/testutil/common_test.go b/x/quarantine/client/testutil/common_test.go index e41f5254cf..9885ab0e78 100644 --- a/x/quarantine/client/testutil/common_test.go +++ b/x/quarantine/client/testutil/common_test.go @@ -12,9 +12,10 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/testutil/network" sdk "github.com/cosmos/cosmos-sdk/types" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + banktestutil "github.com/provenance-io/provenance/testutil/bank" + + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) type IntegrationTestSuite struct { diff --git a/x/quarantine/client/testutil/query_test.go b/x/quarantine/client/testutil/query_test.go index a3f0b52f83..5a9024c6f8 100644 --- a/x/quarantine/client/testutil/query_test.go +++ b/x/quarantine/client/testutil/query_test.go @@ -7,9 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/types/query" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" - "github.com/cosmos/cosmos-sdk/x/quarantine" - client "github.com/cosmos/cosmos-sdk/x/quarantine/client/cli" + + banktestutil "github.com/provenance-io/provenance/testutil/bank" + "github.com/provenance-io/provenance/x/quarantine" + client "github.com/provenance-io/provenance/x/quarantine/client/cli" ) // These tests are initiated by TestIntegrationTestSuite in cli_test.go diff --git a/x/quarantine/client/testutil/tx_test.go b/x/quarantine/client/testutil/tx_test.go index caa33d9cb5..6a1da684b0 100644 --- a/x/quarantine/client/testutil/tx_test.go +++ b/x/quarantine/client/testutil/tx_test.go @@ -7,10 +7,11 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/cli" sdk "github.com/cosmos/cosmos-sdk/types" - banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" - client "github.com/cosmos/cosmos-sdk/x/quarantine/client/cli" + + banktestutil "github.com/provenance-io/provenance/testutil/bank" + "github.com/provenance-io/provenance/x/quarantine" + client "github.com/provenance-io/provenance/x/quarantine/client/cli" ) func (s *IntegrationTestSuite) TestTxOptInCmd() { diff --git a/x/quarantine/genesis.go b/x/quarantine/genesis.go index 9f2dfc3232..bc4b6b0ef8 100644 --- a/x/quarantine/genesis.go +++ b/x/quarantine/genesis.go @@ -2,6 +2,7 @@ package quarantine import ( "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/x/quarantine/genesis_test.go b/x/quarantine/genesis_test.go index fac0d97131..a5d2dcbb28 100644 --- a/x/quarantine/genesis_test.go +++ b/x/quarantine/genesis_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/assert" - . "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + . "github.com/provenance-io/provenance/x/quarantine" + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) func TestGenesisState_Validate(t *testing.T) { diff --git a/x/quarantine/keeper/export_test.go b/x/quarantine/keeper/export_test.go index 7ba420daa2..211fd17f3f 100644 --- a/x/quarantine/keeper/export_test.go +++ b/x/quarantine/keeper/export_test.go @@ -4,7 +4,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) // This file is available only to unit tests and houses functions for doing diff --git a/x/quarantine/keeper/genesis.go b/x/quarantine/keeper/genesis.go index 946453f63d..ff5807039b 100644 --- a/x/quarantine/keeper/genesis.go +++ b/x/quarantine/keeper/genesis.go @@ -4,7 +4,8 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) // InitGenesis updates this keeper's store using the provided GenesisState. diff --git a/x/quarantine/keeper/grpc_query.go b/x/quarantine/keeper/grpc_query.go index c41a7d7020..b6f954aacc 100644 --- a/x/quarantine/keeper/grpc_query.go +++ b/x/quarantine/keeper/grpc_query.go @@ -3,11 +3,13 @@ package keeper import ( "context" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - "github.com/cosmos/cosmos-sdk/x/quarantine" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + + "github.com/provenance-io/provenance/x/quarantine" ) var _ quarantine.QueryServer = Keeper{} diff --git a/x/quarantine/keeper/grpc_query_test.go b/x/quarantine/keeper/grpc_query_test.go index 220cfcdbf0..01fcb43011 100644 --- a/x/quarantine/keeper/grpc_query_test.go +++ b/x/quarantine/keeper/grpc_query_test.go @@ -4,9 +4,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + "github.com/provenance-io/provenance/x/quarantine" + + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) // These tests are initiated by TestKeeperTestSuite in keeper_test.go diff --git a/x/quarantine/keeper/invariants.go b/x/quarantine/keeper/invariants.go index 8866b4cf49..0be59eb7d7 100644 --- a/x/quarantine/keeper/invariants.go +++ b/x/quarantine/keeper/invariants.go @@ -5,7 +5,8 @@ import ( "strings" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) const balanceInvariant = "Funds-Holder-Balance" diff --git a/x/quarantine/keeper/invariants_test.go b/x/quarantine/keeper/invariants_test.go index 0f8d165681..f3c90b9f69 100644 --- a/x/quarantine/keeper/invariants_test.go +++ b/x/quarantine/keeper/invariants_test.go @@ -2,8 +2,9 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" - "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + + "github.com/provenance-io/provenance/x/quarantine/keeper" + "github.com/provenance-io/provenance/x/quarantine/testutil" ) // These tests are initiated by TestKeeperTestSuite in keeper_test.go diff --git a/x/quarantine/keeper/keeper.go b/x/quarantine/keeper/keeper.go index c7a0f78617..9e7c94d569 100644 --- a/x/quarantine/keeper/keeper.go +++ b/x/quarantine/keeper/keeper.go @@ -9,7 +9,8 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) type Keeper struct { diff --git a/x/quarantine/keeper/keeper_test.go b/x/quarantine/keeper/keeper_test.go index 5e45e83bef..1bbdc8cb60 100644 --- a/x/quarantine/keeper/keeper_test.go +++ b/x/quarantine/keeper/keeper_test.go @@ -9,21 +9,21 @@ import ( "time" "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" - "github.com/stretchr/testify/suite" - - "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - tmtime "github.com/tendermint/tendermint/types/time" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/keeper" + + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) // updateQR updates the AccAddresses using the provided addrs. @@ -68,7 +68,7 @@ func accs(accz ...sdk.AccAddress) []sdk.AccAddress { type TestSuite struct { suite.Suite - app *simapp.SimApp + app *app.App sdkCtx sdk.Context stdlibCtx context.Context keeper keeper.Keeper @@ -84,13 +84,13 @@ type TestSuite struct { func (s *TestSuite) SetupTest() { s.blockTime = tmtime.Now() - s.app = simapp.Setup(s.T(), false) + s.app = app.Setup(s.T()) s.sdkCtx = s.app.BaseApp.NewContext(false, tmproto.Header{}).WithBlockHeader(tmproto.Header{Time: s.blockTime}) s.stdlibCtx = sdk.WrapSDKContext(s.sdkCtx) s.keeper = s.app.QuarantineKeeper s.bankKeeper = s.app.BankKeeper - addrs := simapp.AddTestAddrsIncremental(s.app, s.sdkCtx, 5, sdk.NewInt(1_000_000_000)) + addrs := app.AddTestAddrsIncremental(s.app, s.sdkCtx, 5, sdk.NewInt(1_000_000_000)) s.addr1 = addrs[0] s.addr2 = addrs[1] s.addr3 = addrs[2] diff --git a/x/quarantine/keeper/mock_bank_keeper_test.go b/x/quarantine/keeper/mock_bank_keeper_test.go index d84e2c969b..ed277c40e0 100644 --- a/x/quarantine/keeper/mock_bank_keeper_test.go +++ b/x/quarantine/keeper/mock_bank_keeper_test.go @@ -3,7 +3,8 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) // Define a Mock Bank Keeper that defining of SendCoins errors and diff --git a/x/quarantine/keeper/msg_server.go b/x/quarantine/keeper/msg_server.go index 228d793788..9bbc508113 100644 --- a/x/quarantine/keeper/msg_server.go +++ b/x/quarantine/keeper/msg_server.go @@ -5,7 +5,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) var _ quarantine.MsgServer = Keeper{} diff --git a/x/quarantine/keeper/msg_server_test.go b/x/quarantine/keeper/msg_server_test.go index 6a6d93d3ff..09741df01c 100644 --- a/x/quarantine/keeper/msg_server_test.go +++ b/x/quarantine/keeper/msg_server_test.go @@ -2,9 +2,10 @@ package keeper_test import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + "github.com/provenance-io/provenance/x/quarantine" + + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) // These tests are initiated by TestKeeperTestSuite in keeper_test.go diff --git a/x/quarantine/keeper/send_restriction.go b/x/quarantine/keeper/send_restriction.go index e5f6bbd5ab..de6f1185fb 100644 --- a/x/quarantine/keeper/send_restriction.go +++ b/x/quarantine/keeper/send_restriction.go @@ -4,7 +4,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) var _ banktypes.SendRestrictionFn = Keeper{}.SendRestrictionFn diff --git a/x/quarantine/keeper/send_restriction_test.go b/x/quarantine/keeper/send_restriction_test.go index a256fb9204..99adc2a63e 100644 --- a/x/quarantine/keeper/send_restriction_test.go +++ b/x/quarantine/keeper/send_restriction_test.go @@ -4,8 +4,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/testutil" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" + + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/keeper" ) // These tests are initiated by TestKeeperTestSuite in keeper_test.go diff --git a/x/quarantine/keys_test.go b/x/quarantine/keys_test.go index 4d6a91aa37..72635ec3fd 100644 --- a/x/quarantine/keys_test.go +++ b/x/quarantine/keys_test.go @@ -4,12 +4,13 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/assert" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" - "github.com/stretchr/testify/assert" - . "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + . "github.com/provenance-io/provenance/x/quarantine" + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) func TestPrefixValues(t *testing.T) { diff --git a/x/quarantine/module/module.go b/x/quarantine/module/module.go index 3d7e9c257e..aa8b30137c 100644 --- a/x/quarantine/module/module.go +++ b/x/quarantine/module/module.go @@ -9,17 +9,19 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" + abci "github.com/tendermint/tendermint/abci/types" + sdkclient "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/client/cli" - "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" - "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" - abci "github.com/tendermint/tendermint/abci/types" + + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/client/cli" + "github.com/provenance-io/provenance/x/quarantine/keeper" + "github.com/provenance-io/provenance/x/quarantine/simulation" ) var ( diff --git a/x/quarantine/msgs.go b/x/quarantine/msgs.go index c0403118d8..e7a786510d 100644 --- a/x/quarantine/msgs.go +++ b/x/quarantine/msgs.go @@ -1,10 +1,12 @@ package quarantine import ( - "cosmossdk.io/errors" + cerrs "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - qerrors "github.com/cosmos/cosmos-sdk/x/quarantine/errors" + + qerrors "github.com/provenance-io/provenance/x/quarantine/errors" ) var _ sdk.Msg = &MsgOptIn{} @@ -139,7 +141,7 @@ func (msg MsgUpdateAutoResponses) ValidateBasic() error { } for i, update := range msg.Updates { if err := update.Validate(); err != nil { - return errors.Wrapf(err, "invalid update %d", i+1) + return cerrs.Wrapf(err, "invalid update %d", i+1) } } return nil diff --git a/x/quarantine/msgs_test.go b/x/quarantine/msgs_test.go index 2d3b4ef449..c6872b9852 100644 --- a/x/quarantine/msgs_test.go +++ b/x/quarantine/msgs_test.go @@ -7,8 +7,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - . "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + . "github.com/provenance-io/provenance/x/quarantine" + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) func TestNewMsgOptIn(t *testing.T) { diff --git a/x/quarantine/quarantine.go b/x/quarantine/quarantine.go index ae85fc8510..195e527798 100644 --- a/x/quarantine/quarantine.go +++ b/x/quarantine/quarantine.go @@ -6,7 +6,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/quarantine/errors" + + qerrors "github.com/provenance-io/provenance/x/quarantine/errors" ) // containsAddress returns true if the addrToFind is an entry in the addrs. @@ -72,7 +73,7 @@ func (f QuarantinedFunds) Validate() error { return sdkerrors.ErrInvalidAddress.Wrapf("invalid to address: %v", err) } if len(f.UnacceptedFromAddresses) == 0 { - return errors.ErrInvalidValue.Wrap("at least one unaccepted from address is required") + return qerrors.ErrInvalidValue.Wrap("at least one unaccepted from address is required") } seen := make(map[string]struct{}) for i, addr := range f.UnacceptedFromAddresses { @@ -80,7 +81,7 @@ func (f QuarantinedFunds) Validate() error { return sdkerrors.ErrInvalidAddress.Wrapf("invalid unaccepted from address[%d]: %v", i, err) } if _, found := seen[addr]; found { - return errors.ErrInvalidValue.Wrapf("duplicate unaccepted from address: %q", addr) + return qerrors.ErrInvalidValue.Wrapf("duplicate unaccepted from address: %q", addr) } seen[addr] = struct{}{} } @@ -108,7 +109,7 @@ func (e AutoResponseEntry) Validate() error { return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %v", err) } if !e.Response.IsValid() { - return errors.ErrInvalidValue.Wrapf("unknown auto-response value: %d", e.Response) + return qerrors.ErrInvalidValue.Wrapf("unknown auto-response value: %d", e.Response) } return nil } @@ -119,7 +120,7 @@ func (u AutoResponseUpdate) Validate() error { return sdkerrors.ErrInvalidAddress.Wrapf("invalid from address: %s", err) } if !u.Response.IsValid() { - return errors.ErrInvalidValue.Wrapf("unknown auto-response value: %d", u.Response) + return qerrors.ErrInvalidValue.Wrapf("unknown auto-response value: %d", u.Response) } return nil } @@ -194,7 +195,7 @@ func NewQuarantineRecord(unacceptedFromAddrs []string, coins sdk.Coins, declined // Validate does simple stateless validation of these quarantined funds. func (r QuarantineRecord) Validate() error { if len(r.UnacceptedFromAddresses) == 0 { - return errors.ErrInvalidValue.Wrap("at least one unaccepted from address is required") + return qerrors.ErrInvalidValue.Wrap("at least one unaccepted from address is required") } return r.Coins.Validate() } diff --git a/x/quarantine/quarantine_test.go b/x/quarantine/quarantine_test.go index 4c8764d8d5..8b5dee76da 100644 --- a/x/quarantine/quarantine_test.go +++ b/x/quarantine/quarantine_test.go @@ -4,11 +4,12 @@ import ( "fmt" "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" - . "github.com/cosmos/cosmos-sdk/x/quarantine" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + + . "github.com/provenance-io/provenance/x/quarantine" + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) type coinMaker func() sdk.Coins diff --git a/x/quarantine/send_restriction_test.go b/x/quarantine/send_restriction_test.go index 4b59267132..3e0ed0c194 100644 --- a/x/quarantine/send_restriction_test.go +++ b/x/quarantine/send_restriction_test.go @@ -5,8 +5,9 @@ import ( "github.com/stretchr/testify/assert" - sdk "github.com/cosmos/cosmos-sdk/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + sdk "github.com/cosmos/cosmos-sdk/types" ) func TestSendRestrictionContextFuncs(t *testing.T) { diff --git a/x/quarantine/simulation/decoder.go b/x/quarantine/simulation/decoder.go index 9b00596af7..2c4c46a201 100644 --- a/x/quarantine/simulation/decoder.go +++ b/x/quarantine/simulation/decoder.go @@ -6,7 +6,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) // NewDecodeStore returns a decoder function closure that unmarshals the KVPair's diff --git a/x/quarantine/simulation/decoder_test.go b/x/quarantine/simulation/decoder_test.go index ee7651982c..b096a08241 100644 --- a/x/quarantine/simulation/decoder_test.go +++ b/x/quarantine/simulation/decoder_test.go @@ -10,8 +10,9 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" + + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/simulation" ) func TestDecodeStore(t *testing.T) { diff --git a/x/quarantine/simulation/genesis.go b/x/quarantine/simulation/genesis.go index 33c052d9e1..e62fc34b8a 100644 --- a/x/quarantine/simulation/genesis.go +++ b/x/quarantine/simulation/genesis.go @@ -8,7 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) const ( diff --git a/x/quarantine/simulation/genesis_test.go b/x/quarantine/simulation/genesis_test.go index 26c934573b..a428a69aa8 100644 --- a/x/quarantine/simulation/genesis_test.go +++ b/x/quarantine/simulation/genesis_test.go @@ -9,18 +9,22 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - . "github.com/cosmos/cosmos-sdk/x/quarantine/testutil" + "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/simulation" + + . "github.com/provenance-io/provenance/x/quarantine/testutil" ) func TestRandomizedGenState(t *testing.T) { @@ -113,22 +117,22 @@ func TestRandomizedGenStateImportExport(t *testing.T) { err = simState.Cdc.UnmarshalJSON(simState.GenState[banktypes.ModuleName], &bankGen) require.NoError(t, err, "UnmarshalJSON on bank genesis state") - app := simapp.Setup(t, false) - ctx := app.BaseApp.NewContext(false, tmproto.Header{}) + testApp := app.Setup(t) + ctx := testApp.BaseApp.NewContext(false, tmproto.Header{}) testBankInit := func() { - app.BankKeeper.InitGenesis(ctx, &bankGen) + testApp.BankKeeper.InitGenesis(ctx, &bankGen) } require.NotPanics(t, testBankInit, "bank InitGenesis") testInit := func() { - app.QuarantineKeeper.InitGenesis(ctx, &randomGenState) + testApp.QuarantineKeeper.InitGenesis(ctx, &randomGenState) } require.NotPanics(t, testInit, "quarantine InitGenesis") var actualGenState *quarantine.GenesisState testExport := func() { - actualGenState = app.QuarantineKeeper.ExportGenesis(ctx) + actualGenState = testApp.QuarantineKeeper.ExportGenesis(ctx) } require.NotPanics(t, testExport, "ExportGenesis") diff --git a/x/quarantine/simulation/operations.go b/x/quarantine/simulation/operations.go index b60deb60fe..88cd350391 100644 --- a/x/quarantine/simulation/operations.go +++ b/x/quarantine/simulation/operations.go @@ -12,9 +12,10 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/keeper" "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/keeper" ) // Quarantine message types. diff --git a/x/quarantine/simulation/operations_test.go b/x/quarantine/simulation/operations_test.go index 8075825a09..0edf3f2133 100644 --- a/x/quarantine/simulation/operations_test.go +++ b/x/quarantine/simulation/operations_test.go @@ -7,21 +7,23 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/cosmos-sdk/simapp" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/cosmos/cosmos-sdk/x/quarantine" - "github.com/cosmos/cosmos-sdk/x/quarantine/simulation" - abci "github.com/tendermint/tendermint/abci/types" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/provenance-io/provenance/app" + "github.com/provenance-io/provenance/x/quarantine" + "github.com/provenance-io/provenance/x/quarantine/simulation" ) type SimTestSuite struct { suite.Suite ctx sdk.Context - app *simapp.SimApp + app *app.App } func TestSimTestSuite(t *testing.T) { @@ -45,7 +47,7 @@ func (s *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Accoun } func (s *SimTestSuite) SetupTest() { - s.app = simapp.Setup(s.T(), false) + s.app = app.Setup(s.T()) s.ctx = s.app.BaseApp.NewContext(false, tmproto.Header{}) } diff --git a/x/quarantine/testutil/test_helpers.go b/x/quarantine/testutil/test_helpers.go index dade9d8857..f11da97562 100644 --- a/x/quarantine/testutil/test_helpers.go +++ b/x/quarantine/testutil/test_helpers.go @@ -8,7 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/address" - "github.com/cosmos/cosmos-sdk/x/quarantine" + + "github.com/provenance-io/provenance/x/quarantine" ) // This file contains some functions handy for doing unit tests. From 889381d3b65c7a2a255c5f7c62a320f80ad0642e Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 16:07:26 -0700 Subject: [PATCH 05/20] [1752]: Lint fixes. --- x/quarantine/client/cli/util.go | 4 ++-- x/quarantine/keys.go | 8 ++++---- x/quarantine/quarantine.go | 5 +---- x/quarantine/simulation/operations.go | 6 +++--- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/x/quarantine/client/cli/util.go b/x/quarantine/client/cli/util.go index 8b9d8ca4aa..f22620a1aa 100644 --- a/x/quarantine/client/cli/util.go +++ b/x/quarantine/client/cli/util.go @@ -69,12 +69,12 @@ func ParseAutoResponseUpdatesFromArgs(args []string, startIndex int) ([]*quarant // Slightly different message on purpose. Makes it easier to track down the source of an error. return nil, fmt.Errorf("invalid arg %d: last arg cannot be an auto-response, got: %q", i+startIndex+1, arg) } - arArgCount += 1 + arArgCount++ ar = newAr lastArArg = arg arAddrCount = 0 } else { - arAddrCount += 1 + arAddrCount++ fromAddr, err := validateAddress(arg, "from_address") if err != nil { return nil, fmt.Errorf("unknown arg %d %q: auto-response %d %q: from_address %d: %w", i+startIndex+1, arg, arArgCount, lastArArg, arAddrCount, err) diff --git a/x/quarantine/keys.go b/x/quarantine/keys.go index c22418cf39..2f7cfff293 100644 --- a/x/quarantine/keys.go +++ b/x/quarantine/keys.go @@ -99,8 +99,8 @@ func CreateRecordKey(toAddr sdk.AccAddress, fromAddrs ...sdk.AccAddress) []byte // This is designed such that a known record suffix can be provided // as a single "from address" to create the key with that suffix. toAddrPreBz := CreateRecordToAddrPrefix(toAddr) - recordId := address.MustLengthPrefix(createRecordSuffix(fromAddrs)) - return MakeKey(toAddrPreBz, recordId) + recordID := address.MustLengthPrefix(createRecordSuffix(fromAddrs)) + return MakeKey(toAddrPreBz, recordID) } // createRecordSuffix creates a single "address" to use for the provided from addresses. @@ -162,8 +162,8 @@ func CreateRecordIndexToAddrPrefix(toAddr sdk.AccAddress) []byte { // CreateRecordIndexKey creates the key for the quarantine record suffix index. func CreateRecordIndexKey(toAddr, fromAddr sdk.AccAddress) []byte { toAddrPreBz := CreateRecordIndexToAddrPrefix(toAddr) - recordId := address.MustLengthPrefix(fromAddr) - return MakeKey(toAddrPreBz, recordId) + recordID := address.MustLengthPrefix(fromAddr) + return MakeKey(toAddrPreBz, recordID) } // ParseRecordIndexKey extracts the to address and from address from the provided quarantine record index key. diff --git a/x/quarantine/quarantine.go b/x/quarantine/quarantine.go index 195e527798..90b61a886a 100644 --- a/x/quarantine/quarantine.go +++ b/x/quarantine/quarantine.go @@ -85,10 +85,7 @@ func (f QuarantinedFunds) Validate() error { } seen[addr] = struct{}{} } - if err := f.Coins.Validate(); err != nil { - return err - } - return nil + return f.Coins.Validate() } // NewAutoResponseEntry creates a new quarantined auto-response entry. diff --git a/x/quarantine/simulation/operations.go b/x/quarantine/simulation/operations.go index 88cd350391..15f8a17da5 100644 --- a/x/quarantine/simulation/operations.go +++ b/x/quarantine/simulation/operations.go @@ -48,7 +48,7 @@ const ( // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( appParams simtypes.AppParams, cdc codec.JSONCodec, - ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker, + ak quarantine.AccountKeeper, bk quarantine.BankKeeper, k keeper.Keeper, _ cdctypes.AnyUnpacker, ) simulation.WeightedOperations { var ( weightMsgOptIn int @@ -366,8 +366,8 @@ func SimulateMsgUpdateAutoResponses(ak quarantine.AccountKeeper, bk quarantine.B entryCount := r.Intn(3) + 1 for len(msg.Updates) < entryCount { entry := &quarantine.AutoResponseUpdate{} - acct, _ := simtypes.RandomAcc(r, accs) - entry.FromAddress = acct.Address.String() + rAcct, _ := simtypes.RandomAcc(r, accs) + entry.FromAddress = rAcct.Address.String() respR := r.Intn(20) switch respR { case 0: From 71c0b6dbd8ff9adc0d7f04ea651c2f3a91832f12 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 16:35:00 -0700 Subject: [PATCH 06/20] [1752]: Switch the sdk to a version that uses a different namespace for the quarantine and sanction error codes, but is otherwise exactly the same as v0.46.13-pio-2. --- go.mod | 4 +++- go.sum | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4bf6bae9db..3763933e1d 100644 --- a/go.mod +++ b/go.mod @@ -182,7 +182,9 @@ require ( replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 -replace github.com/cosmos/cosmos-sdk => github.com/provenance-io/cosmos-sdk v0.46.13-pio-2 +//replace github.com/cosmos/cosmos-sdk => github.com/provenance-io/cosmos-sdk v0.46.13-pio-2 +// v0.46.13-pio-2.0.20231117232244-16a8b3956dd2 is tag err-namespace-fix-v0.46.13-pio-2 on dwedul/v0.46.x-1752-error-namespace-fix. +replace github.com/cosmos/cosmos-sdk => github.com/provenance-io/cosmos-sdk v0.46.13-pio-2.0.20231117232244-16a8b3956dd2 replace github.com/cosmos/ibc-go/v6 => github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1 diff --git a/go.sum b/go.sum index 1a53025175..03c69fbe01 100644 --- a/go.sum +++ b/go.sum @@ -1008,8 +1008,8 @@ github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/provenance-io/cosmos-sdk v0.46.13-pio-2 h1:P+MZTl8x1BoUYgwbXlKu12JRdQ9SIz/ZnASABJmNBek= -github.com/provenance-io/cosmos-sdk v0.46.13-pio-2/go.mod h1:H7JTxq/UEPvM/LSs5bNYvMwmZlVl2NBT5UlqNe8tjEU= +github.com/provenance-io/cosmos-sdk v0.46.13-pio-2.0.20231117232244-16a8b3956dd2 h1:Xj7YS0ayZAQfuJPgjFh3LFmjkS+e1eUL1SyNYXO6+u4= +github.com/provenance-io/cosmos-sdk v0.46.13-pio-2.0.20231117232244-16a8b3956dd2/go.mod h1:H7JTxq/UEPvM/LSs5bNYvMwmZlVl2NBT5UlqNe8tjEU= github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1 h1:IQ+H6+PiRJhGmSjNxA+5VmX34M3sWG5iQI99WbKgbeA= github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1/go.mod h1:ZxvTNnra+3aTGaKeg0GR0C8do06lAVdSGmMJHe2fkOM= github.com/provenance-io/wasmd v0.30.0-pio-5 h1:SNEZDiCC4LJdcLpINhhz5Jf0zddIQ76QIwScy4uxebM= From 75a019e84502c39e78d035dd826ee744915fbb92 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 16:35:51 -0700 Subject: [PATCH 07/20] [1752]: Get rid of RegisterLegacyAminoCodec since it's not needed but was causing problems due to double registration. --- x/quarantine/codec.go | 17 ----------------- x/quarantine/module/module.go | 4 +--- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/x/quarantine/codec.go b/x/quarantine/codec.go index c52e954984..8b04d03468 100644 --- a/x/quarantine/codec.go +++ b/x/quarantine/codec.go @@ -2,24 +2,12 @@ package quarantine import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/codec/legacy" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" - authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" ) -// RegisterLegacyAminoCodec registers all the necessary types and interfaces for the -// governance module. -func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - legacy.RegisterAminoMsg(cdc, &MsgOptIn{}, "cosmos-sdk/MsgQuarantineOptIn") - legacy.RegisterAminoMsg(cdc, &MsgOptOut{}, "cosmos-sdk/MsgQuarantineOptOut") - legacy.RegisterAminoMsg(cdc, &MsgAccept{}, "cosmos-sdk/MsgQuarantineAccept") - legacy.RegisterAminoMsg(cdc, &MsgDecline{}, "cosmos-sdk/MsgQuarantineDecline") - legacy.RegisterAminoMsg(cdc, &MsgUpdateAutoResponses{}, "cosmos-sdk/MsgUpdateQuarantineAutoResp") -} - func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*sdk.Msg)(nil), &MsgOptIn{}, @@ -45,11 +33,6 @@ var ( ) func init() { - RegisterLegacyAminoCodec(amino) cryptocodec.RegisterCrypto(amino) sdk.RegisterLegacyAminoCodec(amino) - - // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be - // used to properly serialize MsgGrant and MsgExec instances - RegisterLegacyAminoCodec(authzcodec.Amino) } diff --git a/x/quarantine/module/module.go b/x/quarantine/module/module.go index aa8b30137c..3f086d6eb3 100644 --- a/x/quarantine/module/module.go +++ b/x/quarantine/module/module.go @@ -93,9 +93,7 @@ func (AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) { } // RegisterLegacyAminoCodec registers the quarantine module's types for the given codec. -func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { - quarantine.RegisterLegacyAminoCodec(cdc) -} +func (AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) {} // Name returns the quarantine module's name. func (AppModule) Name() string { From 28f2d31ede80204f95d351d72eba92574062b863 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 16:55:27 -0700 Subject: [PATCH 08/20] [1752]: Fix the broken cli unit tests to create the right network. Fix a couple event tests to expect the new type. --- x/quarantine/client/testutil/cli_test.go | 10 ++++++---- x/quarantine/keeper/keeper_test.go | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/x/quarantine/client/testutil/cli_test.go b/x/quarantine/client/testutil/cli_test.go index 3fb9f23836..cfd14f6864 100644 --- a/x/quarantine/client/testutil/cli_test.go +++ b/x/quarantine/client/testutil/cli_test.go @@ -9,12 +9,14 @@ import ( "github.com/stretchr/testify/suite" - "github.com/cosmos/cosmos-sdk/testutil/network" + "github.com/provenance-io/provenance/internal/pioconfig" + "github.com/provenance-io/provenance/testutil" ) func TestIntegrationTestSuite(t *testing.T) { - cfg := network.DefaultConfig() - cfg.NumValidators = 2 - cfg.TimeoutCommit = 1 * time.Second + pioconfig.SetProvenanceConfig("stake", 0) + cfg := testutil.DefaultTestNetworkConfig() + cfg.NumValidators = 1 + cfg.TimeoutCommit = 500 * time.Millisecond suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/quarantine/keeper/keeper_test.go b/x/quarantine/keeper/keeper_test.go index 1bbdc8cb60..110009e33e 100644 --- a/x/quarantine/keeper/keeper_test.go +++ b/x/quarantine/keeper/keeper_test.go @@ -178,7 +178,7 @@ func (s *TestSuite) TestQuarantineOptInOut() { expected := sdk.Events{ { - Type: "cosmos.quarantine.v1beta1.EventOptIn", + Type: "provenance.quarantine.v1.EventOptIn", Attributes: []abci.EventAttribute{ { Key: []byte("to_address"), @@ -198,7 +198,7 @@ func (s *TestSuite) TestQuarantineOptInOut() { expected := sdk.Events{ { - Type: "cosmos.quarantine.v1beta1.EventOptOut", + Type: "provenance.quarantine.v1.EventOptOut", Attributes: []abci.EventAttribute{ { Key: []byte("to_address"), From de7e1619765db85028b196de581adc584302062a Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 17:11:28 -0700 Subject: [PATCH 09/20] [1752]: Fix spec docs: remove order comments, fix event type strings, use links for the stuff in this repo, change addresses to hrp pb (instead of cosmos). --- x/quarantine/spec/01_concepts.md | 4 --- x/quarantine/spec/02_state.md | 4 --- x/quarantine/spec/03_messages.md | 17 ++++------ x/quarantine/spec/04_events.md | 12 +++---- x/quarantine/spec/05_queries.md | 20 +++++------ x/quarantine/spec/06_client.md | 58 +++++++++++++++----------------- x/quarantine/spec/README.md | 7 ---- 7 files changed, 46 insertions(+), 76 deletions(-) diff --git a/x/quarantine/spec/01_concepts.md b/x/quarantine/spec/01_concepts.md index fe7cc03f3a..325e8c661c 100644 --- a/x/quarantine/spec/01_concepts.md +++ b/x/quarantine/spec/01_concepts.md @@ -1,7 +1,3 @@ - - # Concepts ## Quarantined Account diff --git a/x/quarantine/spec/02_state.md b/x/quarantine/spec/02_state.md index 312f31d4ec..bc56842b30 100644 --- a/x/quarantine/spec/02_state.md +++ b/x/quarantine/spec/02_state.md @@ -1,7 +1,3 @@ - - # State The `x/quarantine` module uses key/value pairs to store quarantine-related data in state. diff --git a/x/quarantine/spec/03_messages.md b/x/quarantine/spec/03_messages.md index eeafe060d9..8ea5910f0e 100644 --- a/x/quarantine/spec/03_messages.md +++ b/x/quarantine/spec/03_messages.md @@ -1,7 +1,3 @@ - - # Msg Service ## Msg/OptIn @@ -9,16 +5,17 @@ order: 3 An account can activate quarantine using a `MsgOptIn`. It contains only the address to quarantine. -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L33-L38 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L33-L38 It is expected to fail if the `to_address` is invalid. + ## Msg/OptOut An account can deactivate quarantine using a `MsgOptOut`. It contains only the address to unquarantine. -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L43-L48 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L43-L48 It is expected to fail if the `to_address` is invalid. @@ -28,7 +25,7 @@ Quarantined funds can be accepted by the intended receiver using a `MsgAccept`. It contains a `to_address` (receiver) and one or more `from_addresses` (senders). It also contains a flag to indicate whether auto-accept should be set up for all provided addresses. -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L53-L67 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L53-L67 Any quarantined funds for the `to_address` from any `from_address` are accepted (regardless of whether they've been previously declined). @@ -44,7 +41,7 @@ It is expected to fail if: The response will contain a total of all funds released. -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L69-L74 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L69-L74 ## Msg/Decline @@ -52,7 +49,7 @@ Quarantined funds can be declined by the intended receiver using a `MsgDecline`. It contains a `to_address` (receiver) and one or more `from_addresses` (senders). It also contains a flag to indicate whether auto-decline should be set up for all provided addresses. -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L76-L90 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L76-L90 Any quarantined funds for the `to_address` from any `from_address` are declined. @@ -71,7 +68,7 @@ It is expected to fail if: Auto-Responses can be defined either through the `permanent` flags with a `MsgAccept` or `MsgDecline`, or using a `MsgUpdateAutoResponses`. It contains a `to_address` and a list of `updates`. Each `AutoResponseUpdate` contains a `from_address` and the desired `response` for it. -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/tx.proto#L95-L104 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L95-L104 Providing a `response` of `AUTO_RESPONSE_UNSPECIFIED` will cause the applicable entry to be deleted, allowing users to un-set previous auto-responses. diff --git a/x/quarantine/spec/04_events.md b/x/quarantine/spec/04_events.md index 58548bdcf0..b12f79543b 100644 --- a/x/quarantine/spec/04_events.md +++ b/x/quarantine/spec/04_events.md @@ -1,7 +1,3 @@ - - # Events The `x/quarantine` module emits the following events: @@ -10,7 +6,7 @@ The `x/quarantine` module emits the following events: This event is emitted when an account opts into quarantine. -`@Type`: `/cosmos.quarantine.v1beta1.EventOptIn` +`@Type`: `/provenance.quarantine.v1.EventOptIn` | Attribute Key | Attribute Value | | ------------- |----------------------------------------| @@ -20,7 +16,7 @@ This event is emitted when an account opts into quarantine. This event is emitted when an account opts out of quarantine. -`@Type`: `/cosmos.quarantine.v1beta1.EventOptOut` +`@Type`: `/provenance.quarantine.v1.EventOptOut` | Attribute Key | Attribute Value | |---------------|----------------------------------------| @@ -31,7 +27,7 @@ This event is emitted when an account opts out of quarantine. When funds are quarantined, the `recipient` in events emitted by the `x/bank` module will be the quarantined funds holder account instead of the intended recipient. The following event is also emitted. -`@Type`: `/cosmos.quarantine.v1beta1.EventFundsQuarantined` +`@Type`: `/provenance.quarantine.v1.EventFundsQuarantined` | Attribute Key | Attribute Value | | ------------- |---------------------------------------| @@ -42,7 +38,7 @@ The following event is also emitted. This event is emitted when funds are fully accepted and sent from the quarantine funds holder to the originally intended recipient. -`@Type`: `/cosmos.quarantine.v1beta1.EventFundsReleased` +`@Type`: `/provenance.quarantine.v1.EventFundsReleased` | Attribute Key | Attribute Value | | ------------- |-------------------------------| diff --git a/x/quarantine/spec/05_queries.md b/x/quarantine/spec/05_queries.md index 16cdbdcfae..cc6b0c5e16 100644 --- a/x/quarantine/spec/05_queries.md +++ b/x/quarantine/spec/05_queries.md @@ -1,7 +1,3 @@ - - # gRPC Queries ## Query/IsQuarantined @@ -11,11 +7,11 @@ The query takes in a `to_address` and outputs `true` if the address is quarantin Request: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L46-L50 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L44-L48 Response: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L52-L56 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L50-L54 It is expected to fail if the `to_address` is invalid. @@ -26,15 +22,15 @@ This query takes in an optional `to_address` and optional `from_address` and out Request: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L58-L67 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L56-L65 Response: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L69-L76 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L67-L74 QuarantinedFunds: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/quarantine.proto#L10-L21 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/quarantine.proto#L10-L21 - If neither a `to_address` nor `from_address` are provided, all non-declined quarantined funds for any addresses will be returned. - If the request contains a `to_address` but no `from_address`, all non-declined quarantined funds for the `to_address` are returned. @@ -54,15 +50,15 @@ This query takes in a `to_address` and optional `from_address` and outputs infor Request: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L78-L87 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L76-L85 Response: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/query.proto#L89-L96 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L87-L94 AutoResponseEntry: -+++ https://github.com/provenance-io/cosmos-sdk/blob/da2ea8a8139ae9e110de0776baffa1d0dd97db5e/proto/cosmos/quarantine/v1beta1/quarantine.proto#L23-L31 ++++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/quarantine.proto#L23-L31 - If no `from_address` is provided, all auto-response entries for the provided `to_address` are returned. The results will not contain any entries for `AUTO_RESPONSE_UNSPECIFIED`. - If a `from_address` is provided, the auto-response setting that `to_address` has from `from_address` is returned. This result might be `AUTO_RESPONSE_UNSPECIFIED`. diff --git a/x/quarantine/spec/06_client.md b/x/quarantine/spec/06_client.md index 49711d06d4..a79e22cb83 100644 --- a/x/quarantine/spec/06_client.md +++ b/x/quarantine/spec/06_client.md @@ -1,7 +1,3 @@ - - # Client A user can interact with the `x/quarantine` module using `gRPC`, `CLI`, or `REST`. @@ -36,9 +32,9 @@ Usage: Examples: -$ simd tx quarantine opt-in cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-in pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e $ simd tx quarantine opt-in personal -$ simd tx quarantine opt-in --from cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-in --from pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e $ simd tx quarantine opt-in --from personal ``` @@ -54,9 +50,9 @@ Usage: Examples: -$ simd tx quarantine opt-out cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-out pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e $ simd tx quarantine opt-out personal -$ simd tx quarantine opt-out --from cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 +$ simd tx quarantine opt-out --from pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e $ simd tx quarantine opt-out --from personal ``` @@ -72,9 +68,9 @@ Usage: Examples: -$ simd tx quarantine accept cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut -$ simd tx quarantine accept personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut -$ simd tx quarantine accept personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut cosmos1phx24ecmuw3s7fmy8c87gh3rdq5lwskqur3t00 +$ simd tx quarantine accept pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ simd tx quarantine accept personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ simd tx quarantine accept personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn ``` At least one `` is required, but multiple can be provided. @@ -97,9 +93,9 @@ Usage: Examples: -$ simd tx quarantine decline cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut -$ simd tx quarantine decline personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut -$ simd tx quarantine decline personal cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut cosmos1phx24ecmuw3s7fmy8c87gh3rdq5lwskqur3t00 +$ simd tx quarantine decline pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ simd tx quarantine decline personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ simd tx quarantine decline personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn ``` At least one `` is required, but multiple can be provided. @@ -136,9 +132,9 @@ Aliases: Examples: -$ simd tx quarantine update-auto-responses cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 accept cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut -$ simd tx quarantine update-auto-responses personal decline cosmos1phx24ecmuw3s7fmy8c87gh3rdq5lwskqur3t00 unspecified cosmos1lfuwk97g6y9du8altct63vwgz5620t929n8g9l -$ simd tx quarantine auto-responses personal accept cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut cosmos1qsjw3kjaf33qk2urxg54lzxkw525ngghzneujh off cosmos1lfuwk97g6y9du8altct63vwgz5620t929n8g9l +$ simd tx quarantine update-auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e accept pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ simd tx quarantine update-auto-responses personal decline pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn unspecified pb1lfuwk97g6y9du8altct63vwgz5620t92vavdgr +$ simd tx quarantine auto-responses personal accept pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1qsjw3kjaf33qk2urxg54lzxkw525ngghtajelt off pb1lfuwk97g6y9du8altct63vwgz5620t92vavdgr ``` ### Queries @@ -153,8 +149,8 @@ $ simd query quarantine is-quarantined --help Query whether an account is opted into quarantined. Examples: - $ simd query quarantine is-quarantined cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 - $ simd query quarantine is cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut + $ simd query quarantine is-quarantined pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e + $ simd query quarantine is pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h Usage: simd query quarantine is-quarantined [flags] @@ -175,8 +171,8 @@ If both a to_address and from_address are provided, quarantined funds will be re Examples: $ simd query quarantine funds - $ simd query quarantine funds cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 - $ simd query quarantine funds cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut + $ simd query quarantine funds pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e + $ simd query quarantine funds pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h Usage: simd query quarantine funds [ []] [flags] @@ -194,8 +190,8 @@ If only a to_address is provided, all auto-responses set up for that address are If both a to_address and from_address are provided, exactly one result will be returned. This can be accept, decline or unspecified. Examples: - $ simd query quarantine auto-responses cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 - $ simd query quarantine auto-responses cosmos1c7p4v02eayvag8nswm4f5q664twfe6dxjha389 cosmos1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrk9vrut + $ simd query quarantine auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e + $ simd query quarantine auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h Usage: simd query quarantine auto-responses [] [flags] @@ -210,13 +206,13 @@ Standard pagination flags are also available for this command. Each of the quarantine `gRPC` query endpoints is also available through one or more `REST` endpoints. -| Name | URL | -|-----------------------------|----------------------------------------------------------------| -| IsQuarantined | `/cosmos/quarantine/v1beta1/active/{to_address}` | -| QuarantinedFunds - all | `/cosmos/quarantine/v1beta1/funds` | -| QuarantinedFunds - some | `/cosmos/quarantine/v1beta1/funds/{to_address}` | -| QuarantinedFunds - specific | `/cosmos/quarantine/v1beta1/funds/{to_address}/{from_address}` | -| AutoResponses - some | `/cosmos/quarantine/v1beta1/auto/{to_address}` | -| AutoResponses - specific | `/cosmos/quarantine/v1beta1/auto/{to_address}/{from_address}` | +| Name | URL | +|-----------------------------|---------------------------------------------------------------| +| IsQuarantined | `/provenance/quarantine/v1/active/{to_address}` | +| QuarantinedFunds - all | `/provenance/quarantine/v1/funds` | +| QuarantinedFunds - some | `/provenance/quarantine/v1/funds/{to_address}` | +| QuarantinedFunds - specific | `/provenance/quarantine/v1/funds/{to_address}/{from_address}` | +| AutoResponses - some | `/provenance/quarantine/v1/auto/{to_address}` | +| AutoResponses - specific | `/provenance/quarantine/v1/auto/{to_address}/{from_address}` | For `QuarantinedFunds` and `AutoResponses`, pagination parameters can be provided using the standard pagination query parameters. \ No newline at end of file diff --git a/x/quarantine/spec/README.md b/x/quarantine/spec/README.md index 8e2cbe1fc9..10da297be3 100644 --- a/x/quarantine/spec/README.md +++ b/x/quarantine/spec/README.md @@ -1,10 +1,3 @@ - - # Quarantine Module ## Abstract From 723debe379d80419067416316ae07a8aea24dd8a Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 17:22:32 -0700 Subject: [PATCH 10/20] [1752]: Fix some lint issues in the protos. --- docs/proto-docs.md | 8 +- proto/provenance/quarantine/v1/genesis.proto | 1 - proto/provenance/quarantine/v1/query.proto | 4 +- proto/provenance/quarantine/v1/tx.proto | 1 - x/quarantine/genesis.pb.go | 33 ++++---- x/quarantine/query.pb.go | 82 ++++++++++---------- x/quarantine/query.pb.gw.go | 12 +-- x/quarantine/tx.pb.go | 80 ++++++++++--------- 8 files changed, 108 insertions(+), 113 deletions(-) diff --git a/docs/proto-docs.md b/docs/proto-docs.md index 82e72d45c8..cf9df6db6a 100644 --- a/docs/proto-docs.md +++ b/docs/proto-docs.md @@ -9667,7 +9667,7 @@ QueryQuarantinedFundsResponse defines the RPC response of a QuarantinedFunds que | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| `quarantinedFunds` | [QuarantinedFunds](#provenance.quarantine.v1.QuarantinedFunds) | repeated | quarantinedFunds is info about coins sitting in quarantine. | +| `quarantined_funds` | [QuarantinedFunds](#provenance.quarantine.v1.QuarantinedFunds) | repeated | quarantined_funds is info about coins sitting in quarantine. | | `pagination` | [cosmos.base.query.v1beta1.PageResponse](#cosmos.base.query.v1beta1.PageResponse) | | pagination defines the pagination parameters of the response. | @@ -9688,13 +9688,13 @@ Query defines the quarantine gRPC query service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | -| `IsQuarantined` | [QueryIsQuarantinedRequest](#provenance.quarantine.v1.QueryIsQuarantinedRequest) | [QueryIsQuarantinedResponse](#provenance.quarantine.v1.QueryIsQuarantinedResponse) | IsQuarantined checks if an account has opted into quarantine. | GET|/cosmos/quarantine/v1beta1/active/{to_address}| +| `IsQuarantined` | [QueryIsQuarantinedRequest](#provenance.quarantine.v1.QueryIsQuarantinedRequest) | [QueryIsQuarantinedResponse](#provenance.quarantine.v1.QueryIsQuarantinedResponse) | IsQuarantined checks if an account has opted into quarantine. | GET|/provenance/quarantine/v1/active/{to_address}| | `QuarantinedFunds` | [QueryQuarantinedFundsRequest](#provenance.quarantine.v1.QueryQuarantinedFundsRequest) | [QueryQuarantinedFundsResponse](#provenance.quarantine.v1.QueryQuarantinedFundsResponse) | QuarantinedFunds gets information about funds that have been quarantined. -If both a to_address and from_address are provided, any such quarantined funds will be returned regardless of whether they've been declined. If only a to_address is provided, the unaccepted and undeclined funds waiting on a response from to_address will be returned. If neither a to_address nor from_address is provided, all non-declined quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. | GET|/cosmos/quarantine/v1beta1/fundsGET|/cosmos/quarantine/v1beta1/funds/{to_address}GET|/cosmos/quarantine/v1beta1/funds/{to_address}/{from_address}| +If both a to_address and from_address are provided, any such quarantined funds will be returned regardless of whether they've been declined. If only a to_address is provided, the unaccepted and undeclined funds waiting on a response from to_address will be returned. If neither a to_address nor from_address is provided, all non-declined quarantined funds for any address will be returned. The request is invalid if only a from_address is provided. | GET|/provenance/quarantine/v1/fundsGET|/provenance/quarantine/v1/funds/{to_address}GET|/provenance/quarantine/v1/funds/{to_address}/{from_address}| | `AutoResponses` | [QueryAutoResponsesRequest](#provenance.quarantine.v1.QueryAutoResponsesRequest) | [QueryAutoResponsesResponse](#provenance.quarantine.v1.QueryAutoResponsesResponse) | AutoResponses gets the auto-response settings for a quarantined account. -The to_address is required. If a from_address is provided only the auto response for that from_address will be returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. | GET|/cosmos/quarantine/v1beta1/auto/{to_address}GET|/cosmos/quarantine/v1beta1/auto/{to_address}/{from_address}| +The to_address is required. If a from_address is provided only the auto response for that from_address will be returned. If no from_address is provided, all auto-response settings for the given to_address will be returned. | GET|/provenance/quarantine/v1/auto/{to_address}GET|/provenance/quarantine/v1/auto/{to_address}/{from_address}| diff --git a/proto/provenance/quarantine/v1/genesis.proto b/proto/provenance/quarantine/v1/genesis.proto index 3b2c26aa3e..b1243eb0b6 100644 --- a/proto/provenance/quarantine/v1/genesis.proto +++ b/proto/provenance/quarantine/v1/genesis.proto @@ -2,7 +2,6 @@ syntax = "proto3"; package provenance.quarantine.v1; import "cosmos_proto/cosmos.proto"; -import "gogoproto/gogo.proto"; import "provenance/quarantine/v1/quarantine.proto"; option go_package = "github.com/provenance-io/provenance/x/quarantine"; diff --git a/proto/provenance/quarantine/v1/query.proto b/proto/provenance/quarantine/v1/query.proto index 537fe45db6..d81277fa72 100644 --- a/proto/provenance/quarantine/v1/query.proto +++ b/proto/provenance/quarantine/v1/query.proto @@ -66,8 +66,8 @@ message QueryQuarantinedFundsRequest { // QueryQuarantinedFundsResponse defines the RPC response of a QuarantinedFunds query. message QueryQuarantinedFundsResponse { - // quarantinedFunds is info about coins sitting in quarantine. - repeated QuarantinedFunds quarantinedFunds = 1; + // quarantined_funds is info about coins sitting in quarantine. + repeated QuarantinedFunds quarantined_funds = 1; // pagination defines the pagination parameters of the response. cosmos.base.query.v1beta1.PageResponse pagination = 99; diff --git a/proto/provenance/quarantine/v1/tx.proto b/proto/provenance/quarantine/v1/tx.proto index 602e3daf05..ee71f728b0 100644 --- a/proto/provenance/quarantine/v1/tx.proto +++ b/proto/provenance/quarantine/v1/tx.proto @@ -1,7 +1,6 @@ syntax = "proto3"; package provenance.quarantine.v1; -import "cosmos/base/query/v1beta1/pagination.proto"; import "cosmos/base/v1beta1/coin.proto"; import "cosmos/msg/v1/msg.proto"; import "cosmos_proto/cosmos.proto"; diff --git a/x/quarantine/genesis.pb.go b/x/quarantine/genesis.pb.go index 3e05a9bad1..58bb4f7b56 100644 --- a/x/quarantine/genesis.pb.go +++ b/x/quarantine/genesis.pb.go @@ -6,7 +6,6 @@ package quarantine import ( fmt "fmt" _ "github.com/cosmos/cosmos-proto" - _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" io "io" math "math" @@ -97,26 +96,26 @@ func init() { } var fileDescriptor_632eb3150c8160d7 = []byte{ - // 304 bytes of a gzipped FileDescriptorProto + // 293 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2b, 0x28, 0xca, 0x2f, 0x4b, 0xcd, 0x4b, 0xcc, 0x4b, 0x4e, 0xd5, 0x2f, 0x2c, 0x4d, 0x2c, 0x4a, 0xcc, 0x2b, 0xc9, 0xcc, 0x4b, 0xd5, 0x2f, 0x33, 0xd4, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x92, 0x40, 0xa8, 0xd3, 0x43, 0xa8, 0xd3, 0x2b, 0x33, 0x94, 0x92, 0x4c, 0xce, - 0x2f, 0xce, 0xcd, 0x2f, 0x8e, 0x07, 0xab, 0xd3, 0x87, 0x70, 0x20, 0x9a, 0xa4, 0x44, 0xd2, 0xf3, - 0xd3, 0xf3, 0x21, 0xe2, 0x20, 0x16, 0x54, 0x54, 0x13, 0xa7, 0x95, 0x48, 0x06, 0x83, 0x95, 0x2a, - 0x75, 0x31, 0x71, 0xf1, 0xb8, 0x43, 0xdc, 0x11, 0x5c, 0x92, 0x58, 0x92, 0x2a, 0xe4, 0xcb, 0x25, - 0x8a, 0x50, 0x94, 0x12, 0x9f, 0x98, 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x9c, 0x5a, 0x2c, 0xc1, 0xa8, - 0xc0, 0xac, 0xc1, 0xe9, 0x24, 0x71, 0x69, 0x8b, 0xae, 0x08, 0xd4, 0x09, 0x8e, 0x10, 0xb9, 0xe0, - 0x92, 0xa2, 0xcc, 0xbc, 0xf4, 0x20, 0x11, 0x24, 0x6d, 0x8e, 0x30, 0x5d, 0x42, 0x41, 0x5c, 0x7c, - 0x89, 0xa5, 0x25, 0xf9, 0xf1, 0x45, 0xa9, 0xc5, 0x05, 0xf9, 0x79, 0x20, 0x73, 0x98, 0x14, 0x98, - 0x35, 0xb8, 0x8d, 0xb4, 0xf5, 0x70, 0x79, 0x57, 0xcf, 0xb1, 0xb4, 0x24, 0x3f, 0x08, 0xaa, 0xdc, - 0x35, 0xaf, 0xa4, 0xa8, 0x32, 0x88, 0x37, 0x11, 0x49, 0xa8, 0x58, 0x28, 0x9c, 0x4b, 0x10, 0xd9, - 0x89, 0x69, 0xa5, 0x79, 0x29, 0xc5, 0x12, 0xcc, 0x60, 0x63, 0xb5, 0x70, 0x1b, 0x1b, 0x88, 0xd0, - 0xe2, 0x06, 0xd2, 0x11, 0x24, 0x50, 0x88, 0x26, 0xe2, 0xe4, 0x75, 0xe2, 0x91, 0x1c, 0xe3, 0x85, - 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, - 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x06, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, - 0xfa, 0x08, 0x1b, 0x74, 0x33, 0xf3, 0x91, 0x78, 0xfa, 0x15, 0x48, 0xc1, 0x9b, 0xc4, 0x06, 0x0e, - 0x5f, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xeb, 0x61, 0xde, 0x56, 0xff, 0x01, 0x00, 0x00, + 0x2f, 0xce, 0xcd, 0x2f, 0x8e, 0x07, 0xab, 0xd3, 0x87, 0x70, 0x20, 0x9a, 0xa4, 0x34, 0x71, 0x1a, + 0x8e, 0x64, 0x04, 0x58, 0xa9, 0x52, 0x17, 0x13, 0x17, 0x8f, 0x3b, 0xc4, 0xc6, 0xe0, 0x92, 0xc4, + 0x92, 0x54, 0x21, 0x5f, 0x2e, 0x51, 0x84, 0xa2, 0x94, 0xf8, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2, + 0xe2, 0xd4, 0x62, 0x09, 0x46, 0x05, 0x66, 0x0d, 0x4e, 0x27, 0x89, 0x4b, 0x5b, 0x74, 0x45, 0xa0, + 0x96, 0x39, 0x42, 0xe4, 0x82, 0x4b, 0x8a, 0x32, 0xf3, 0xd2, 0x83, 0x44, 0x90, 0xb4, 0x39, 0xc2, + 0x74, 0x09, 0x05, 0x71, 0xf1, 0x25, 0x96, 0x96, 0xe4, 0xc7, 0x17, 0xa5, 0x16, 0x17, 0xe4, 0xe7, + 0x81, 0xcc, 0x61, 0x52, 0x60, 0xd6, 0xe0, 0x36, 0xd2, 0xd6, 0xc3, 0xe5, 0x31, 0x3d, 0xc7, 0xd2, + 0x92, 0xfc, 0x20, 0xa8, 0x72, 0xd7, 0xbc, 0x92, 0xa2, 0xca, 0x20, 0xde, 0x44, 0x24, 0xa1, 0x62, + 0xa1, 0x70, 0x2e, 0x41, 0x64, 0x27, 0xa6, 0x95, 0xe6, 0xa5, 0x14, 0x4b, 0x30, 0x83, 0x8d, 0xd5, + 0xc2, 0x6d, 0x6c, 0x20, 0x42, 0x8b, 0x1b, 0x48, 0x47, 0x90, 0x40, 0x21, 0x9a, 0x88, 0x93, 0xd7, + 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, + 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0x19, 0xa4, 0x67, 0x96, 0x64, 0x94, + 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x23, 0x6c, 0xd0, 0xcd, 0xcc, 0x47, 0xe2, 0xe9, 0x57, 0x20, + 0x05, 0x6f, 0x12, 0x1b, 0x38, 0x7c, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3f, 0xe8, 0x26, + 0x1c, 0xe9, 0x01, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/quarantine/query.pb.go b/x/quarantine/query.pb.go index 41ce61d9dd..cb642d81be 100644 --- a/x/quarantine/query.pb.go +++ b/x/quarantine/query.pb.go @@ -188,8 +188,8 @@ func (m *QueryQuarantinedFundsRequest) GetPagination() *query.PageRequest { // QueryQuarantinedFundsResponse defines the RPC response of a QuarantinedFunds query. type QueryQuarantinedFundsResponse struct { - // quarantinedFunds is info about coins sitting in quarantine. - QuarantinedFunds []*QuarantinedFunds `protobuf:"bytes,1,rep,name=quarantinedFunds,proto3" json:"quarantinedFunds,omitempty"` + // quarantined_funds is info about coins sitting in quarantine. + QuarantinedFunds []*QuarantinedFunds `protobuf:"bytes,1,rep,name=quarantined_funds,json=quarantinedFunds,proto3" json:"quarantined_funds,omitempty"` // pagination defines the pagination parameters of the response. Pagination *query.PageResponse `protobuf:"bytes,99,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -375,45 +375,45 @@ func init() { var fileDescriptor_6d60739bf6ede825 = []byte{ // 616 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0x4f, 0x6f, 0x12, 0x4f, - 0x18, 0x66, 0xf8, 0xa5, 0xbf, 0xd8, 0x41, 0x9a, 0x66, 0xe2, 0x81, 0x92, 0xba, 0x21, 0x1b, 0xff, - 0x60, 0x95, 0x9d, 0x42, 0x4d, 0x7b, 0xa8, 0x9a, 0xb4, 0xc6, 0x1a, 0x3d, 0xd9, 0xd5, 0x78, 0xe0, - 0x42, 0x06, 0x98, 0xae, 0x93, 0xc8, 0x0c, 0xec, 0xcc, 0x12, 0x9b, 0xa6, 0x17, 0x3f, 0x81, 0x49, - 0x6f, 0x9e, 0xfc, 0x0c, 0xc6, 0x8b, 0x37, 0x8f, 0x1e, 0xab, 0x5e, 0x34, 0xf1, 0x60, 0xc0, 0xbb, - 0x5f, 0xc1, 0xb0, 0x3b, 0xb0, 0xbb, 0x14, 0xd8, 0x10, 0x3d, 0x79, 0x9c, 0x7d, 0xdf, 0xe7, 0xe5, - 0x79, 0xe6, 0x79, 0xe6, 0x05, 0x5e, 0x6a, 0xbb, 0xa2, 0x4b, 0x39, 0xe1, 0x0d, 0x8a, 0x3b, 0x1e, - 0x71, 0x09, 0x57, 0x8c, 0x53, 0xdc, 0x2d, 0xe3, 0x8e, 0x47, 0xdd, 0x43, 0xab, 0xed, 0x0a, 0x25, - 0x50, 0x2e, 0xec, 0xb2, 0xc2, 0x2e, 0xab, 0x5b, 0xce, 0xaf, 0x35, 0x84, 0x6c, 0x09, 0x89, 0xeb, - 0x44, 0xd2, 0x00, 0x82, 0xbb, 0xe5, 0x3a, 0x55, 0xa4, 0x8c, 0xdb, 0xc4, 0x61, 0x9c, 0x28, 0x26, - 0x78, 0x30, 0x25, 0xbf, 0x12, 0xf4, 0xd6, 0xfc, 0x13, 0x0e, 0x0e, 0xba, 0xb4, 0xea, 0x08, 0xe1, - 0x3c, 0xa7, 0x98, 0xb4, 0x19, 0x26, 0x9c, 0x0b, 0xe5, 0xe3, 0x86, 0xd5, 0x6b, 0x33, 0x48, 0x8e, - 0xc8, 0xf8, 0xad, 0xe6, 0x13, 0xb8, 0xb2, 0x3f, 0x60, 0xf1, 0x40, 0xee, 0x8f, 0x4a, 0x4d, 0x9b, - 0x76, 0x3c, 0x2a, 0x15, 0xda, 0x82, 0x50, 0x89, 0x1a, 0x69, 0x36, 0x5d, 0x2a, 0x65, 0x0e, 0x14, - 0x40, 0x71, 0x71, 0x37, 0xf7, 0xf9, 0x5d, 0xe9, 0x82, 0xe6, 0xb2, 0x13, 0x54, 0x1e, 0x2b, 0x97, - 0x71, 0xc7, 0x5e, 0x54, 0x42, 0x7f, 0x30, 0xef, 0xc2, 0xfc, 0xa4, 0xa9, 0xb2, 0x2d, 0xb8, 0xa4, - 0xe8, 0x32, 0x5c, 0x62, 0xb2, 0x16, 0x52, 0x69, 0xfa, 0xa3, 0xcf, 0xd9, 0x59, 0x16, 0x6d, 0x37, - 0xbf, 0x03, 0xb8, 0xea, 0x4f, 0x89, 0x7c, 0xdc, 0xf3, 0x78, 0x53, 0xfe, 0x29, 0x3d, 0xb4, 0x0d, - 0xcf, 0x1f, 0xb8, 0xa2, 0x35, 0x82, 0xa6, 0x13, 0xa0, 0x99, 0x41, 0xf7, 0x10, 0xbc, 0x07, 0x61, - 0xe8, 0x54, 0xae, 0x51, 0x00, 0xc5, 0x4c, 0xe5, 0x8a, 0xa5, 0x71, 0x03, 0x5b, 0xad, 0x20, 0x09, - 0xda, 0x56, 0xeb, 0x11, 0x71, 0xa8, 0x66, 0x6c, 0x47, 0x90, 0xe6, 0x07, 0x00, 0x2f, 0x4e, 0x91, - 0xa7, 0xef, 0xe9, 0x29, 0x5c, 0xee, 0x8c, 0xd5, 0x72, 0xa0, 0xf0, 0x5f, 0x31, 0x53, 0x59, 0xb3, - 0xa6, 0x05, 0xcc, 0x3a, 0x33, 0xed, 0xcc, 0x0c, 0x74, 0x7f, 0x82, 0x82, 0xab, 0x89, 0x0a, 0x02, - 0x52, 0x31, 0x09, 0xdf, 0x80, 0x4e, 0xcf, 0x8e, 0xa7, 0xc4, 0xb0, 0xe3, 0x1f, 0xb1, 0xe7, 0x3d, - 0xd0, 0x19, 0x1e, 0xd3, 0xa6, 0xbd, 0xb1, 0xe1, 0x12, 0xf1, 0x94, 0xa8, 0xb9, 0xc3, 0x8a, 0x76, - 0xe6, 0xfa, 0x74, 0x67, 0xa2, 0x83, 0xee, 0x71, 0xe5, 0x1e, 0xda, 0x59, 0x12, 0x9d, 0xfd, 0xd7, - 0x7c, 0xa9, 0x7c, 0x5a, 0x80, 0x0b, 0x3e, 0x77, 0xf4, 0x16, 0xc0, 0x6c, 0xec, 0x11, 0xa2, 0x8d, - 0x59, 0xd1, 0x99, 0xb2, 0x08, 0xf2, 0x37, 0xe7, 0x03, 0x05, 0x94, 0xcc, 0xcd, 0x97, 0x5f, 0x7e, - 0x9e, 0xa4, 0xd7, 0x91, 0xa5, 0x77, 0x57, 0x7c, 0x17, 0x05, 0x4b, 0x8f, 0x34, 0x14, 0xeb, 0x52, - 0x7c, 0x14, 0x26, 0xe5, 0x18, 0xbd, 0x49, 0xc3, 0xe5, 0xf1, 0x18, 0xa3, 0xcd, 0x04, 0x0a, 0x53, - 0x96, 0x44, 0x7e, 0x6b, 0x6e, 0x9c, 0x66, 0xff, 0x1a, 0xf8, 0xf4, 0x4f, 0x00, 0x2a, 0xcc, 0xe0, - 0x7f, 0x30, 0xc0, 0x54, 0x31, 0x2a, 0x25, 0xf5, 0xc4, 0x24, 0x56, 0xef, 0xa0, 0x5b, 0x73, 0x01, - 0xf0, 0x51, 0xf4, 0x45, 0x1c, 0xa3, 0x5f, 0x00, 0x66, 0x63, 0xc1, 0x4c, 0xf4, 0x75, 0xd2, 0x13, - 0x4d, 0xf4, 0x75, 0x62, 0xf6, 0x4d, 0xe9, 0x5f, 0x4c, 0x0b, 0xdd, 0x98, 0xe5, 0xab, 0xa7, 0x44, - 0x5c, 0xf2, 0x6d, 0xb4, 0x3d, 0x4f, 0xff, 0x98, 0xe2, 0xdd, 0x87, 0x1f, 0x7b, 0x06, 0x38, 0xed, - 0x19, 0xe0, 0x47, 0xcf, 0x00, 0xaf, 0xfa, 0x46, 0xea, 0xb4, 0x6f, 0xa4, 0xbe, 0xf6, 0x8d, 0x54, - 0x75, 0xdd, 0x61, 0xea, 0x99, 0x57, 0xb7, 0x1a, 0xa2, 0x85, 0x43, 0x39, 0x25, 0x26, 0x22, 0x27, - 0xfc, 0x22, 0xf2, 0xa3, 0xf5, 0xff, 0xfd, 0xff, 0xbe, 0x8d, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, - 0xab, 0x34, 0xfe, 0x1c, 0xcd, 0x07, 0x00, 0x00, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x55, 0x4f, 0x6b, 0x13, 0x41, + 0x1c, 0xcd, 0x44, 0x2a, 0x76, 0x62, 0x4a, 0x1d, 0x3c, 0xa4, 0xa1, 0xae, 0x61, 0xf1, 0x4f, 0x6c, + 0xcd, 0x8e, 0x49, 0xd5, 0x82, 0xd5, 0x43, 0x2b, 0x56, 0xf4, 0x64, 0x57, 0x41, 0xc8, 0x25, 0x4c, + 0x92, 0xe9, 0xba, 0x68, 0x66, 0x92, 0x9d, 0xd9, 0x60, 0x29, 0xbd, 0xf8, 0x09, 0x0a, 0x1e, 0x3c, + 0xf9, 0x21, 0x04, 0x2f, 0x1e, 0xbd, 0x09, 0x5e, 0x8a, 0x5e, 0x14, 0x3c, 0x48, 0xe2, 0xd5, 0xef, + 0x20, 0xd9, 0x9d, 0x24, 0x93, 0x98, 0xcd, 0x12, 0xf4, 0xd4, 0xe3, 0xce, 0xef, 0xbd, 0xdf, 0xbc, + 0xdf, 0xbc, 0x37, 0xb3, 0xf0, 0x42, 0xd3, 0xe3, 0x6d, 0xca, 0x08, 0xab, 0x51, 0xdc, 0xf2, 0x89, + 0x47, 0x98, 0x74, 0x19, 0xc5, 0xed, 0x22, 0x6e, 0xf9, 0xd4, 0xdb, 0xb3, 0x9a, 0x1e, 0x97, 0x1c, + 0x65, 0x86, 0x28, 0x6b, 0x88, 0xb2, 0xda, 0xc5, 0xec, 0x4a, 0x8d, 0x8b, 0x06, 0x17, 0xb8, 0x4a, + 0x04, 0x0d, 0x29, 0xb8, 0x5d, 0xac, 0x52, 0x49, 0x8a, 0xb8, 0x49, 0x1c, 0x97, 0x11, 0xe9, 0x72, + 0x16, 0x76, 0xc9, 0x2e, 0x85, 0xd8, 0x4a, 0xf0, 0x85, 0xc3, 0x0f, 0x55, 0x5a, 0x76, 0x38, 0x77, + 0x5e, 0x50, 0x4c, 0x9a, 0x2e, 0x26, 0x8c, 0x71, 0x19, 0xf0, 0xfa, 0xd5, 0x2b, 0x53, 0x44, 0x0e, + 0xc4, 0x04, 0x50, 0xf3, 0x09, 0x5c, 0xda, 0xe9, 0xa9, 0x78, 0x20, 0x76, 0x06, 0xa5, 0xba, 0x4d, + 0x5b, 0x3e, 0x15, 0x12, 0xad, 0x43, 0x28, 0x79, 0x85, 0xd4, 0xeb, 0x1e, 0x15, 0x22, 0x03, 0x72, + 0x20, 0x3f, 0xbf, 0x95, 0xf9, 0xf2, 0xbe, 0x70, 0x56, 0x69, 0xd9, 0x0c, 0x2b, 0x8f, 0xa5, 0xe7, + 0x32, 0xc7, 0x9e, 0x97, 0x5c, 0x2d, 0x98, 0x77, 0x61, 0x76, 0x52, 0x57, 0xd1, 0xe4, 0x4c, 0x50, + 0x74, 0x11, 0x2e, 0xb8, 0xa2, 0x32, 0x94, 0x52, 0x0f, 0x5a, 0x9f, 0xb2, 0xd3, 0xae, 0x0e, 0x37, + 0x7f, 0x00, 0xb8, 0x1c, 0x74, 0xd1, 0x16, 0xb7, 0x7d, 0x56, 0x17, 0xff, 0x2a, 0x0f, 0x6d, 0xc0, + 0xd3, 0xbb, 0x1e, 0x6f, 0x0c, 0xa8, 0xc9, 0x18, 0x6a, 0xaa, 0x87, 0xee, 0x93, 0xb7, 0x21, 0x1c, + 0x3a, 0x95, 0xa9, 0xe5, 0x40, 0x3e, 0x55, 0xba, 0x64, 0x29, 0x5e, 0xcf, 0x56, 0x2b, 0x4c, 0x82, + 0xb2, 0xd5, 0x7a, 0x44, 0x1c, 0xaa, 0x14, 0xdb, 0x1a, 0xd3, 0xfc, 0x08, 0xe0, 0xb9, 0x88, 0xf1, + 0xd4, 0x39, 0x3d, 0x85, 0x67, 0xb4, 0x43, 0xaa, 0xec, 0xf6, 0x8a, 0x19, 0x90, 0x3b, 0x91, 0x4f, + 0x95, 0x56, 0xac, 0xa8, 0x84, 0x59, 0x7f, 0xb5, 0x5b, 0x6c, 0x8d, 0xad, 0xa0, 0xfb, 0x13, 0x46, + 0xb8, 0x1c, 0x3b, 0x42, 0xa8, 0x6a, 0x64, 0x86, 0xef, 0x40, 0xc5, 0x67, 0xd3, 0x97, 0xbc, 0x8f, + 0x38, 0x26, 0xfe, 0x7c, 0x00, 0x2a, 0xc4, 0x63, 0xb3, 0x29, 0x73, 0x6c, 0xb8, 0x40, 0x7c, 0xc9, + 0x2b, 0x5e, 0xbf, 0xa2, 0x9c, 0x59, 0x8d, 0x76, 0x46, 0x6f, 0x74, 0x8f, 0x49, 0x6f, 0xcf, 0x4e, + 0x13, 0xbd, 0xf7, 0x7f, 0xf3, 0xa5, 0xf4, 0x79, 0x0e, 0xce, 0x05, 0xda, 0xd1, 0x3b, 0x00, 0xd3, + 0x23, 0xb7, 0x10, 0xad, 0x4d, 0x8b, 0x4e, 0xc4, 0x4b, 0x90, 0xbd, 0x3e, 0x1b, 0x29, 0x94, 0x64, + 0xde, 0x78, 0xf5, 0xf5, 0xd7, 0xeb, 0x24, 0x46, 0x05, 0x1c, 0xf9, 0x20, 0x91, 0x9a, 0x74, 0xdb, + 0x14, 0xef, 0x0f, 0x83, 0x72, 0x80, 0xde, 0x26, 0xe1, 0xe2, 0x78, 0x8a, 0xd1, 0xcd, 0x18, 0x05, + 0x11, 0x8f, 0x44, 0x76, 0x7d, 0x66, 0x9e, 0x12, 0xff, 0x06, 0x04, 0xea, 0x0f, 0x01, 0x3a, 0x1f, + 0x2d, 0x3f, 0xb8, 0x93, 0x65, 0x0b, 0x5d, 0x8d, 0x81, 0x8c, 0x0c, 0x58, 0xbe, 0x83, 0x36, 0x66, + 0xc1, 0xe3, 0x7d, 0xfd, 0x36, 0x1c, 0xa0, 0xdf, 0x00, 0xa6, 0x47, 0x42, 0x19, 0xeb, 0xe9, 0xa4, + 0xeb, 0x19, 0xeb, 0xe9, 0xc4, 0xdc, 0x9b, 0xad, 0xe0, 0x54, 0x9e, 0xa3, 0xd5, 0x29, 0x9e, 0xfa, + 0x92, 0x8f, 0x0e, 0x7c, 0x1b, 0xdd, 0x9a, 0x01, 0x3e, 0x36, 0xef, 0xd6, 0xc3, 0x4f, 0x1d, 0x03, + 0x1c, 0x75, 0x0c, 0xf0, 0xb3, 0x63, 0x80, 0xc3, 0xae, 0x91, 0x38, 0xea, 0x1a, 0x89, 0x6f, 0x5d, + 0x23, 0x51, 0xbe, 0xe6, 0xb8, 0xf2, 0x99, 0x5f, 0xb5, 0x6a, 0xbc, 0xa1, 0xf5, 0x2f, 0xb8, 0x5c, + 0xdf, 0xed, 0xa5, 0xb6, 0x5f, 0xf5, 0x64, 0xf0, 0xdb, 0x5b, 0xfb, 0x13, 0x00, 0x00, 0xff, 0xff, + 0x39, 0xc4, 0xd5, 0xb4, 0xc8, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/x/quarantine/query.pb.gw.go b/x/quarantine/query.pb.gw.go index b5787bdc5f..c8990de115 100644 --- a/x/quarantine/query.pb.gw.go +++ b/x/quarantine/query.pb.gw.go @@ -744,17 +744,17 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie } var ( - pattern_Query_IsQuarantined_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "quarantine", "v1beta1", "active", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_IsQuarantined_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"provenance", "quarantine", "v1", "active", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QuarantinedFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "quarantine", "v1beta1", "funds"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QuarantinedFunds_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"provenance", "quarantine", "v1", "funds"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QuarantinedFunds_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "quarantine", "v1beta1", "funds", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QuarantinedFunds_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"provenance", "quarantine", "v1", "funds", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_QuarantinedFunds_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "quarantine", "v1beta1", "funds", "to_address", "from_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_QuarantinedFunds_2 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"provenance", "quarantine", "v1", "funds", "to_address", "from_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AutoResponses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "quarantine", "v1beta1", "auto", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_AutoResponses_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"provenance", "quarantine", "v1", "auto", "to_address"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_AutoResponses_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "quarantine", "v1beta1", "auto", "to_address", "from_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_AutoResponses_1 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"provenance", "quarantine", "v1", "auto", "to_address", "from_address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( diff --git a/x/quarantine/tx.pb.go b/x/quarantine/tx.pb.go index 16eb979713..d5c99b5563 100644 --- a/x/quarantine/tx.pb.go +++ b/x/quarantine/tx.pb.go @@ -10,7 +10,6 @@ import ( github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" - _ "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -522,46 +521,45 @@ func init() { func init() { proto.RegisterFile("provenance/quarantine/v1/tx.proto", fileDescriptor_cc32ebc8daaef0eb) } var fileDescriptor_cc32ebc8daaef0eb = []byte{ - // 613 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0x3f, 0x6f, 0xd3, 0x40, - 0x14, 0xcf, 0x11, 0xd1, 0x36, 0x57, 0xb5, 0x80, 0x5b, 0x81, 0x6b, 0x21, 0x37, 0x04, 0x86, 0x50, - 0x5a, 0x3b, 0x09, 0x03, 0x88, 0x05, 0x25, 0x20, 0x24, 0x90, 0xa2, 0x48, 0x86, 0x0a, 0xa9, 0x12, - 0x8a, 0x1c, 0xfb, 0x7a, 0x58, 0xd4, 0x77, 0xc6, 0x77, 0x8e, 0xda, 0x11, 0x16, 0x56, 0x3e, 0x47, - 0x27, 0x86, 0xf2, 0x1d, 0x3a, 0x56, 0x4c, 0x4c, 0x80, 0x92, 0x81, 0xcf, 0xc0, 0x86, 0xe2, 0xbb, - 0x4b, 0x2c, 0x9a, 0x3f, 0xa5, 0x62, 0x61, 0xca, 0xdd, 0x7b, 0xbf, 0x3f, 0xef, 0x45, 0xef, 0xf9, - 0xe0, 0x8d, 0x28, 0xa6, 0x5d, 0x44, 0x5c, 0xe2, 0x21, 0xfb, 0x6d, 0xe2, 0xc6, 0x2e, 0xe1, 0x01, - 0x41, 0x76, 0xb7, 0x6a, 0xf3, 0x7d, 0x2b, 0x8a, 0x29, 0xa7, 0x9a, 0x3e, 0x82, 0x58, 0x23, 0x88, - 0xd5, 0xad, 0x1a, 0x1b, 0x1e, 0x65, 0x21, 0x65, 0x76, 0xc7, 0x65, 0x03, 0x36, 0x8a, 0x0f, 0xec, - 0x6e, 0xb5, 0x83, 0xb8, 0x5b, 0xb5, 0x23, 0x17, 0x07, 0xc4, 0xe5, 0x01, 0x25, 0x42, 0xc5, 0x30, - 0xb3, 0x58, 0x85, 0xf2, 0x68, 0xa0, 0xf2, 0xd7, 0x64, 0x3e, 0x64, 0x78, 0xe0, 0x1e, 0x32, 0x2c, - 0x13, 0x6b, 0x22, 0xd1, 0x4e, 0x6f, 0xb6, 0xb8, 0xc8, 0xd4, 0x2a, 0xa6, 0x98, 0x8a, 0xf8, 0xe0, - 0x24, 0xa3, 0xb7, 0x27, 0xb6, 0x94, 0xa9, 0x3e, 0x85, 0x96, 0x5e, 0xc0, 0x85, 0x26, 0xc3, 0xad, - 0x88, 0x3f, 0x25, 0xda, 0x3d, 0x08, 0x39, 0x6d, 0xbb, 0xbe, 0x1f, 0x23, 0xc6, 0x74, 0x50, 0x04, - 0xe5, 0x42, 0x43, 0xff, 0x72, 0xb4, 0xb5, 0x2a, 0x2d, 0xeb, 0x22, 0xf3, 0x9c, 0xc7, 0x01, 0xc1, - 0x4e, 0x81, 0x53, 0x19, 0x78, 0x70, 0xe9, 0xfd, 0xcf, 0x4f, 0x1b, 0x19, 0x6e, 0x49, 0x83, 0x97, - 0x95, 0xaa, 0x83, 0x58, 0x44, 0x09, 0x43, 0xa5, 0x6d, 0x58, 0x10, 0xb1, 0x56, 0xc2, 0xff, 0xa1, - 0xd5, 0x0a, 0xbc, 0x32, 0x94, 0x1d, 0x7a, 0x1d, 0x81, 0xd4, 0xac, 0xee, 0x79, 0x28, 0x3a, 0xbf, - 0x99, 0xf6, 0x10, 0x2e, 0xef, 0xc6, 0x34, 0x54, 0x54, 0xc4, 0xf4, 0x0b, 0xc5, 0xfc, 0x54, 0xf2, - 0xd2, 0x00, 0x5f, 0x57, 0x70, 0xed, 0x3a, 0x2c, 0x44, 0x28, 0x0e, 0x5d, 0x82, 0x08, 0xd7, 0xf3, - 0x45, 0x50, 0x5e, 0x70, 0x46, 0x81, 0xd3, 0xbd, 0x7c, 0x00, 0x69, 0x33, 0xa2, 0x6c, 0xd5, 0x8c, - 0x16, 0xc3, 0xe5, 0xdd, 0x84, 0xf8, 0xac, 0x1d, 0xa3, 0x3d, 0xe4, 0x32, 0xe4, 0xeb, 0xa0, 0x98, - 0x2f, 0x2f, 0xd6, 0xd6, 0x2c, 0x59, 0xc2, 0x60, 0xa0, 0x2c, 0x39, 0x50, 0xd6, 0x23, 0x1a, 0x90, - 0x46, 0xe5, 0xf8, 0xdb, 0x7a, 0xee, 0xf0, 0xfb, 0x7a, 0x19, 0x07, 0xfc, 0x75, 0xd2, 0xb1, 0x3c, - 0x1a, 0xca, 0xb9, 0x91, 0x3f, 0x5b, 0xcc, 0x7f, 0x63, 0xf3, 0x83, 0x08, 0xb1, 0x94, 0xc0, 0x9c, - 0xa5, 0xd4, 0xc2, 0x91, 0x0e, 0xa5, 0xcf, 0x00, 0xc2, 0x26, 0xc3, 0x8f, 0x91, 0xb7, 0x17, 0x10, - 0xf4, 0xff, 0xfc, 0x83, 0xab, 0x50, 0x1b, 0x95, 0x3d, 0x1c, 0x87, 0x43, 0x00, 0xaf, 0x36, 0x19, - 0xde, 0x8e, 0x7c, 0x97, 0xa3, 0x7a, 0xc2, 0xa9, 0xca, 0xb0, 0xf3, 0x77, 0xf6, 0x04, 0xce, 0x27, - 0xa9, 0x9e, 0x68, 0x69, 0xb1, 0xb6, 0x69, 0x4d, 0xfa, 0x4a, 0x58, 0x59, 0x4b, 0x51, 0x84, 0xa3, - 0xc8, 0xa7, 0x5b, 0x28, 0x42, 0x73, 0x7c, 0xad, 0xea, 0x50, 0xfb, 0x95, 0x87, 0xf9, 0x26, 0xc3, - 0xda, 0x4b, 0x78, 0x51, 0x2c, 0x6e, 0x69, 0xb2, 0xb5, 0x5a, 0x43, 0x63, 0x63, 0x36, 0x66, 0x38, - 0x71, 0x3b, 0x70, 0x4e, 0xee, 0xe9, 0xcd, 0x59, 0xac, 0x56, 0xc2, 0x8d, 0x3b, 0x67, 0x00, 0x65, - 0xb5, 0xe5, 0x5a, 0x4e, 0xd7, 0x16, 0xa0, 0x19, 0xda, 0x7f, 0x6c, 0xca, 0x2b, 0x38, 0xaf, 0x26, - 0xf6, 0xd6, 0x54, 0x9e, 0x44, 0x19, 0x9b, 0x67, 0x41, 0x0d, 0xe5, 0xdf, 0x01, 0xb8, 0x32, 0x6e, - 0x86, 0x2a, 0x53, 0x55, 0xc6, 0x30, 0x8c, 0xfb, 0x7f, 0xcb, 0x50, 0x87, 0xc6, 0xb3, 0xe3, 0x9e, - 0x09, 0x4e, 0x7a, 0x26, 0xf8, 0xd1, 0x33, 0xc1, 0xc7, 0xbe, 0x99, 0x3b, 0xe9, 0x9b, 0xb9, 0xaf, - 0x7d, 0x33, 0xb7, 0x53, 0xc9, 0xec, 0xfa, 0x48, 0x7d, 0x2b, 0xa0, 0x99, 0x9b, 0xbd, 0x9f, 0x79, - 0x01, 0x3a, 0x73, 0xe9, 0x13, 0x70, 0xf7, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x05, 0xff, 0xa3, - 0xff, 0x02, 0x07, 0x00, 0x00, + // 596 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xbf, 0x6f, 0xd3, 0x4e, + 0x14, 0xcf, 0x7d, 0xa3, 0x6f, 0xdb, 0xbc, 0xaa, 0x05, 0xdc, 0x0a, 0x5c, 0x0b, 0xb9, 0x21, 0x30, + 0x84, 0xd2, 0xd8, 0x49, 0x18, 0x40, 0x2c, 0x28, 0x01, 0x21, 0x81, 0x14, 0x45, 0x32, 0x54, 0x48, + 0x95, 0x50, 0xe4, 0xd8, 0x57, 0x63, 0x51, 0xdf, 0x19, 0xdf, 0x39, 0x2a, 0x23, 0x2c, 0xac, 0xfc, + 0x1d, 0x9d, 0x18, 0xca, 0xff, 0xd0, 0xb1, 0x62, 0x62, 0x02, 0x94, 0x0c, 0xfc, 0x0d, 0x6c, 0x28, + 0xbe, 0x73, 0x62, 0xd1, 0xfc, 0x28, 0x15, 0x0b, 0x93, 0xef, 0xde, 0xfb, 0xfc, 0x78, 0xcf, 0x7a, + 0x4f, 0x07, 0xd7, 0xc2, 0x88, 0xf6, 0x30, 0xb1, 0x89, 0x83, 0xcd, 0xd7, 0xb1, 0x1d, 0xd9, 0x84, + 0xfb, 0x04, 0x9b, 0xbd, 0x9a, 0xc9, 0x0f, 0x8c, 0x30, 0xa2, 0x9c, 0x2a, 0xea, 0x18, 0x62, 0x8c, + 0x21, 0x46, 0xaf, 0xa6, 0xe9, 0x0e, 0x65, 0x01, 0x65, 0x66, 0xd7, 0x66, 0x43, 0x4a, 0x17, 0x73, + 0xbb, 0x66, 0x3a, 0xd4, 0x27, 0x82, 0xa9, 0x5d, 0x91, 0xf9, 0x80, 0x79, 0x43, 0xc5, 0x80, 0x79, + 0x32, 0xb1, 0x21, 0x12, 0x9d, 0xe4, 0x66, 0x8a, 0x8b, 0x4c, 0xad, 0x7b, 0xd4, 0xa3, 0x22, 0x3e, + 0x3c, 0xc9, 0xe8, 0xcd, 0xa9, 0x65, 0x66, 0x2a, 0x4a, 0xa0, 0xa5, 0x67, 0xb0, 0xd4, 0x62, 0x5e, + 0x3b, 0xe4, 0x8f, 0x89, 0x72, 0x07, 0x80, 0xd3, 0x8e, 0xed, 0xba, 0x11, 0x66, 0x4c, 0x45, 0x45, + 0x54, 0x2e, 0x34, 0xd5, 0xcf, 0x47, 0x95, 0x75, 0x69, 0xd9, 0x10, 0x99, 0xa7, 0x3c, 0xf2, 0x89, + 0x67, 0x15, 0x38, 0x95, 0x81, 0x7b, 0x17, 0xde, 0xfd, 0xf8, 0xb8, 0x95, 0xe1, 0x96, 0x14, 0xb8, + 0x98, 0xaa, 0x5a, 0x98, 0x85, 0x94, 0x30, 0x5c, 0xda, 0x81, 0x82, 0x88, 0xb5, 0x63, 0xfe, 0x17, + 0xad, 0xd6, 0xe0, 0xd2, 0x48, 0x76, 0xe4, 0x75, 0x84, 0x12, 0xb3, 0x86, 0xe3, 0xe0, 0xf0, 0xfc, + 0x66, 0xca, 0x7d, 0x58, 0xdd, 0x8b, 0x68, 0x90, 0x52, 0x31, 0x53, 0xff, 0x2b, 0xe6, 0x67, 0x92, + 0x57, 0x86, 0xf8, 0x46, 0x0a, 0x57, 0xae, 0x42, 0x21, 0xc4, 0x51, 0x60, 0x13, 0x4c, 0xb8, 0x9a, + 0x2f, 0xa2, 0xf2, 0x92, 0x35, 0x0e, 0x9c, 0xee, 0xe5, 0x3d, 0x4a, 0x9a, 0x11, 0x65, 0xa7, 0xcd, + 0x28, 0x11, 0xac, 0xee, 0xc5, 0xc4, 0x65, 0x9d, 0x08, 0xef, 0x63, 0x9b, 0x61, 0x57, 0x45, 0xc5, + 0x7c, 0x79, 0xb9, 0xbe, 0x61, 0xc8, 0x12, 0x86, 0x03, 0x65, 0xc8, 0x81, 0x32, 0x1e, 0x50, 0x9f, + 0x34, 0xab, 0xc7, 0x5f, 0x37, 0x73, 0x87, 0xdf, 0x36, 0xcb, 0x9e, 0xcf, 0x5f, 0xc6, 0x5d, 0xc3, + 0xa1, 0x81, 0x9c, 0x1b, 0xf9, 0xa9, 0x30, 0xf7, 0x95, 0xc9, 0xdf, 0x84, 0x98, 0x25, 0x04, 0x66, + 0xad, 0x24, 0x16, 0x96, 0x74, 0x28, 0x7d, 0x42, 0x00, 0x2d, 0xe6, 0x3d, 0xc4, 0xce, 0xbe, 0x4f, + 0xf0, 0xbf, 0xf3, 0x07, 0xd7, 0x41, 0x19, 0x97, 0x3d, 0x1a, 0x87, 0x43, 0x04, 0x97, 0x5b, 0xcc, + 0xdb, 0x09, 0x5d, 0x9b, 0xe3, 0x46, 0xcc, 0x69, 0x9a, 0x61, 0xe7, 0xef, 0xec, 0x11, 0x2c, 0xc6, + 0x89, 0x9e, 0x68, 0x69, 0xb9, 0xbe, 0x6d, 0x4c, 0xdb, 0x7c, 0x23, 0x6b, 0x29, 0x8a, 0xb0, 0x52, + 0xf2, 0xe9, 0x16, 0x8a, 0xa0, 0x4f, 0xae, 0x35, 0x3d, 0xd4, 0x7f, 0xe6, 0x21, 0xdf, 0x62, 0x9e, + 0xf2, 0x1c, 0xfe, 0x17, 0x8b, 0x5b, 0x9a, 0x6e, 0x9d, 0xae, 0xa1, 0xb6, 0x35, 0x1f, 0x33, 0x9a, + 0xb8, 0x5d, 0x58, 0x90, 0x7b, 0x7a, 0x7d, 0x1e, 0xab, 0x1d, 0x73, 0xed, 0xd6, 0x19, 0x40, 0x59, + 0x6d, 0xb9, 0x96, 0xb3, 0xb5, 0x05, 0x68, 0x8e, 0xf6, 0x6f, 0x9b, 0xf2, 0x02, 0x16, 0xd3, 0x89, + 0xbd, 0x31, 0x93, 0x27, 0x51, 0xda, 0xf6, 0x59, 0x50, 0x23, 0xf9, 0xb7, 0x08, 0xd6, 0x26, 0xcd, + 0x50, 0x75, 0xa6, 0xca, 0x04, 0x86, 0x76, 0xf7, 0x4f, 0x19, 0xe9, 0xa1, 0xf9, 0xe4, 0xb8, 0xaf, + 0xa3, 0x93, 0xbe, 0x8e, 0xbe, 0xf7, 0x75, 0xf4, 0x61, 0xa0, 0xe7, 0x4e, 0x06, 0x7a, 0xee, 0xcb, + 0x40, 0xcf, 0xed, 0x56, 0x33, 0xbb, 0x3e, 0x56, 0xaf, 0xf8, 0x34, 0x73, 0x33, 0x0f, 0x32, 0x2f, + 0x40, 0x77, 0x21, 0x79, 0x02, 0x6e, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0x79, 0xe1, 0xe8, 0x27, + 0xd6, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 738cbe97a6d8488ac28e11932932c5cb4041a03b Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Fri, 17 Nov 2023 17:27:43 -0700 Subject: [PATCH 11/20] [1759]: Update spec links since the protos changed slightly. --- x/quarantine/spec/03_messages.md | 12 ++++++------ x/quarantine/spec/05_queries.md | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/x/quarantine/spec/03_messages.md b/x/quarantine/spec/03_messages.md index 8ea5910f0e..2f6b95600b 100644 --- a/x/quarantine/spec/03_messages.md +++ b/x/quarantine/spec/03_messages.md @@ -5,7 +5,7 @@ An account can activate quarantine using a `MsgOptIn`. It contains only the address to quarantine. -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L33-L38 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/tx.proto#L32-L37 It is expected to fail if the `to_address` is invalid. @@ -15,7 +15,7 @@ It is expected to fail if the `to_address` is invalid. An account can deactivate quarantine using a `MsgOptOut`. It contains only the address to unquarantine. -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L43-L48 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/tx.proto#L42-L47 It is expected to fail if the `to_address` is invalid. @@ -25,7 +25,7 @@ Quarantined funds can be accepted by the intended receiver using a `MsgAccept`. It contains a `to_address` (receiver) and one or more `from_addresses` (senders). It also contains a flag to indicate whether auto-accept should be set up for all provided addresses. -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L53-L67 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/tx.proto#L52-L66 Any quarantined funds for the `to_address` from any `from_address` are accepted (regardless of whether they've been previously declined). @@ -41,7 +41,7 @@ It is expected to fail if: The response will contain a total of all funds released. -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L69-L74 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/tx.proto#L68-L73 ## Msg/Decline @@ -49,7 +49,7 @@ Quarantined funds can be declined by the intended receiver using a `MsgDecline`. It contains a `to_address` (receiver) and one or more `from_addresses` (senders). It also contains a flag to indicate whether auto-decline should be set up for all provided addresses. -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L76-L90 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/tx.proto#L75-L89 Any quarantined funds for the `to_address` from any `from_address` are declined. @@ -68,7 +68,7 @@ It is expected to fail if: Auto-Responses can be defined either through the `permanent` flags with a `MsgAccept` or `MsgDecline`, or using a `MsgUpdateAutoResponses`. It contains a `to_address` and a list of `updates`. Each `AutoResponseUpdate` contains a `from_address` and the desired `response` for it. -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/tx.proto#L95-L104 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/tx.proto#L94-L103 Providing a `response` of `AUTO_RESPONSE_UNSPECIFIED` will cause the applicable entry to be deleted, allowing users to un-set previous auto-responses. diff --git a/x/quarantine/spec/05_queries.md b/x/quarantine/spec/05_queries.md index cc6b0c5e16..bec3620e79 100644 --- a/x/quarantine/spec/05_queries.md +++ b/x/quarantine/spec/05_queries.md @@ -7,11 +7,11 @@ The query takes in a `to_address` and outputs `true` if the address is quarantin Request: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L44-L48 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/query.proto#L44-L48 Response: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L50-L54 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/query.proto#L50-L54 It is expected to fail if the `to_address` is invalid. @@ -22,15 +22,15 @@ This query takes in an optional `to_address` and optional `from_address` and out Request: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L56-L65 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/query.proto#L56-L65 Response: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L67-L74 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/query.proto#L67-L74 QuarantinedFunds: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/quarantine.proto#L10-L21 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/quarantine.proto#L10-L21 - If neither a `to_address` nor `from_address` are provided, all non-declined quarantined funds for any addresses will be returned. - If the request contains a `to_address` but no `from_address`, all non-declined quarantined funds for the `to_address` are returned. @@ -50,15 +50,15 @@ This query takes in a `to_address` and optional `from_address` and outputs infor Request: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L76-L85 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/query.proto#L76-L85 Response: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/query.proto#L87-L94 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/query.proto#L87-L94 AutoResponseEntry: -+++ https://github.com/provenance-io/provenance/blob/28f2d31ede80204f95d351d72eba92574062b863/proto/provenance/quarantine/v1/quarantine.proto#L23-L31 ++++ https://github.com/provenance-io/provenance/blob/723debe379d80419067416316ae07a8aea24dd8a/proto/provenance/quarantine/v1/quarantine.proto#L23-L31 - If no `from_address` is provided, all auto-response entries for the provided `to_address` are returned. The results will not contain any entries for `AUTO_RESPONSE_UNSPECIFIED`. - If a `from_address` is provided, the auto-response setting that `to_address` has from `from_address` is returned. This result might be `AUTO_RESPONSE_UNSPECIFIED`. From 7d1bebe158198a25b9a3de2ceb7255b7dd5fbf4a Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 20 Nov 2023 12:21:59 -0700 Subject: [PATCH 12/20] [1752]: Go back to importing our full SDK version and just make a note in error/errors.go for what to do later. --- go.mod | 4 +--- go.sum | 4 ++-- x/quarantine/errors/errors.go | 19 +++++++++++++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 3763933e1d..4bf6bae9db 100644 --- a/go.mod +++ b/go.mod @@ -182,9 +182,7 @@ require ( replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 -//replace github.com/cosmos/cosmos-sdk => github.com/provenance-io/cosmos-sdk v0.46.13-pio-2 -// v0.46.13-pio-2.0.20231117232244-16a8b3956dd2 is tag err-namespace-fix-v0.46.13-pio-2 on dwedul/v0.46.x-1752-error-namespace-fix. -replace github.com/cosmos/cosmos-sdk => github.com/provenance-io/cosmos-sdk v0.46.13-pio-2.0.20231117232244-16a8b3956dd2 +replace github.com/cosmos/cosmos-sdk => github.com/provenance-io/cosmos-sdk v0.46.13-pio-2 replace github.com/cosmos/ibc-go/v6 => github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1 diff --git a/go.sum b/go.sum index 03c69fbe01..1a53025175 100644 --- a/go.sum +++ b/go.sum @@ -1008,8 +1008,8 @@ github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/provenance-io/cosmos-sdk v0.46.13-pio-2.0.20231117232244-16a8b3956dd2 h1:Xj7YS0ayZAQfuJPgjFh3LFmjkS+e1eUL1SyNYXO6+u4= -github.com/provenance-io/cosmos-sdk v0.46.13-pio-2.0.20231117232244-16a8b3956dd2/go.mod h1:H7JTxq/UEPvM/LSs5bNYvMwmZlVl2NBT5UlqNe8tjEU= +github.com/provenance-io/cosmos-sdk v0.46.13-pio-2 h1:P+MZTl8x1BoUYgwbXlKu12JRdQ9SIz/ZnASABJmNBek= +github.com/provenance-io/cosmos-sdk v0.46.13-pio-2/go.mod h1:H7JTxq/UEPvM/LSs5bNYvMwmZlVl2NBT5UlqNe8tjEU= github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1 h1:IQ+H6+PiRJhGmSjNxA+5VmX34M3sWG5iQI99WbKgbeA= github.com/provenance-io/ibc-go/v6 v6.2.0-pio-1/go.mod h1:ZxvTNnra+3aTGaKeg0GR0C8do06lAVdSGmMJHe2fkOM= github.com/provenance-io/wasmd v0.30.0-pio-5 h1:SNEZDiCC4LJdcLpINhhz5Jf0zddIQ76QIwScy4uxebM= diff --git a/x/quarantine/errors/errors.go b/x/quarantine/errors/errors.go index 25fffc66e4..a795be73b2 100644 --- a/x/quarantine/errors/errors.go +++ b/x/quarantine/errors/errors.go @@ -1,8 +1,19 @@ package errors -import "cosmossdk.io/errors" +import sdkqerrs "github.com/cosmos/cosmos-sdk/x/quarantine/errors" -// quarantineCodespace is the codespace for all errors defined in quarantine package -const quarantineCodespace = "quarantine" +var ErrInvalidValue = sdkqerrs.ErrInvalidValue -var ErrInvalidValue = errors.Register(quarantineCodespace, 2, "invalid value") +// TODO: Once we have an official version of the SDK without the quarantine module: +// 1. Delete everything above this comment. +// 2. Uncomment everything below this comment. +// 3. Delete this comment. + +// package errors +// +// import cerrs "cosmossdk.io/errors" +// +// // quarantineCodespace is the codespace for all errors defined in quarantine package +// const quarantineCodespace = "quarantine" +// +// var ErrInvalidValue = cerrs.Register(quarantineCodespace, 2, "invalid value") From 0c2ac07ff9b8c52ddc248c9aebc6fc2c9283130a Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 20 Nov 2023 12:42:00 -0700 Subject: [PATCH 13/20] [1752]: Add some changelog entries. --- CHANGELOG.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35ef98e915..134753ba7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,11 +27,12 @@ Types of changes (Stanzas): "Features" for new features. "Improvements" for changes in existing functionality. -"Deprecated" for soon-to-be removed features. "Bug Fixes" for any bug fixes. +"Deprecated" for soon-to-be removed features. "Client Breaking" for breaking CLI commands and REST routes used by end-users. "API Breaking" for breaking exported APIs used by developers building on SDK. "State Machine Breaking" for any changes that result in a different AppState given same genesisState and txList. +"Dependencies" lists version bumps and is mostly managed automatically in dependabot PRs. Ref: https://keepachangelog.com/en/1.0.0/ --> @@ -40,6 +41,20 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * Add upgrade handler for 1.18 [#1756](https://github.com/provenance-io/provenance/pull/1756). +* Move the quarantine module into this repo (from our fork of the SDK) [#1752](https://github.com/provenance-io/provenance/issues/1752). + +### Deprecated + +* The `cosmos.quarantine.v1beta1` protos have been fully deprecated and are replaced with those in `provenance.quarantine.v1` [#1752](https://github.com/provenance-io/provenance/issues/1752). + +### Client Breaking + +* The REST query endpoints under `/cosmos/quarantine/v1beta1/` have been moved to `/provenance/quarantine/v1/` [#1752](https://github.com/provenance-io/provenance/issues/1752). + +### API Breaking + +* The quarantine proto messages have moved to `provenance.quarantine.v1` (from `cosmos.quarantine.v1beta1`) [#1752](https://github.com/provenance-io/provenance/issues/1752). +* The `QueryQuarantinedFundsResponse.quarantinedFunds` field has been renamed to `quarantined_funds` [#1752](https://github.com/provenance-io/provenance/issues/1752). ### Dependencies From 77e8535994c0886504153a8d8016d867a7f8ac1c Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 20 Nov 2023 12:56:55 -0700 Subject: [PATCH 14/20] [1752]: Clean up codec.go by getting rid of the amino codec stuff and switching to the allRequestMsgs pattern used in other modules. --- x/quarantine/codec.go | 33 +++++++-------------------------- x/quarantine/msgs.go | 16 +++++++--------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/x/quarantine/codec.go b/x/quarantine/codec.go index 8b04d03468..5298e67a26 100644 --- a/x/quarantine/codec.go +++ b/x/quarantine/codec.go @@ -1,38 +1,19 @@ package quarantine import ( - "github.com/cosmos/cosmos-sdk/codec" + "github.com/gogo/protobuf/proto" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" ) func RegisterInterfaces(registry codectypes.InterfaceRegistry) { - registry.RegisterImplementations((*sdk.Msg)(nil), - &MsgOptIn{}, - &MsgOptOut{}, - &MsgAccept{}, - &MsgDecline{}, - &MsgUpdateAutoResponses{}, - ) + messages := make([]proto.Message, len(allRequestMsgs)) + for i, msg := range allRequestMsgs { + messages[i] = msg + } + registry.RegisterImplementations((*sdk.Msg)(nil), messages...) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } - -var ( - amino = codec.NewLegacyAmino() - - // ModuleCdc references the global x/quarantine module codec. Note, the codec should - // ONLY be used in certain instances of tests and for JSON encoding as Amino is - // still used for that purpose. - // - // The actual codec used for serialization should be provided to x/quarantine and - // defined at the application level. - ModuleCdc = codec.NewAminoCodec(amino) -) - -func init() { - cryptocodec.RegisterCrypto(amino) - sdk.RegisterLegacyAminoCodec(amino) -} diff --git a/x/quarantine/msgs.go b/x/quarantine/msgs.go index e7a786510d..033b1be934 100644 --- a/x/quarantine/msgs.go +++ b/x/quarantine/msgs.go @@ -9,7 +9,13 @@ import ( qerrors "github.com/provenance-io/provenance/x/quarantine/errors" ) -var _ sdk.Msg = &MsgOptIn{} +var allRequestMsgs = []sdk.Msg{ + (*MsgOptIn)(nil), + (*MsgOptOut)(nil), + (*MsgAccept)(nil), + (*MsgDecline)(nil), + (*MsgUpdateAutoResponses)(nil), +} // NewMsgOptIn creates a new msg to opt in to account quarantine. func NewMsgOptIn(toAddr sdk.AccAddress) *MsgOptIn { @@ -32,8 +38,6 @@ func (msg MsgOptIn) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -var _ sdk.Msg = &MsgOptOut{} - // NewMsgOptOut creates a new msg to opt out of account quarantine. func NewMsgOptOut(toAddr sdk.AccAddress) *MsgOptOut { return &MsgOptOut{ @@ -55,8 +59,6 @@ func (msg MsgOptOut) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -var _ sdk.Msg = &MsgAccept{} - // NewMsgAccept creates a new msg to accept quarantined funds. func NewMsgAccept(toAddr sdk.AccAddress, fromAddrsStrs []string, permanent bool) *MsgAccept { return &MsgAccept{ @@ -88,8 +90,6 @@ func (msg MsgAccept) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -var _ sdk.Msg = &MsgDecline{} - // NewMsgDecline creates a new msg to decline quarantined funds. func NewMsgDecline(toAddr sdk.AccAddress, fromAddrsStrs []string, permanent bool) *MsgDecline { return &MsgDecline{ @@ -121,8 +121,6 @@ func (msg MsgDecline) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{addr} } -var _ sdk.Msg = &MsgUpdateAutoResponses{} - // NewMsgUpdateAutoResponses creates a new msg to update quarantined auto-responses. func NewMsgUpdateAutoResponses(toAddr sdk.AccAddress, updates []*AutoResponseUpdate) *MsgUpdateAutoResponses { return &MsgUpdateAutoResponses{ From 4bbb95d133bad540660e95d0526816d69fe7d892 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 20 Nov 2023 13:45:26 -0700 Subject: [PATCH 15/20] [1752]: Fix client spec docs to use provenanced (instead of simd). --- x/quarantine/spec/06_client.md | 80 +++++++++++++++++----------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/x/quarantine/spec/06_client.md b/x/quarantine/spec/06_client.md index a79e22cb83..ce99680b34 100644 --- a/x/quarantine/spec/06_client.md +++ b/x/quarantine/spec/06_client.md @@ -23,54 +23,54 @@ The `--from` flag is ignored since that is being conveyed using the `] [flags] + provenanced tx quarantine opt-in [] [flags] Examples: -$ simd tx quarantine opt-in pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e -$ simd tx quarantine opt-in personal -$ simd tx quarantine opt-in --from pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e -$ simd tx quarantine opt-in --from personal +$ provenanced tx quarantine opt-in pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e +$ provenanced tx quarantine opt-in personal +$ provenanced tx quarantine opt-in --from pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e +$ provenanced tx quarantine opt-in --from personal ``` #### OptOut ```shell -$ simd tx quarantine opt-out --help +$ provenanced tx quarantine opt-out --help Deactivate quarantine for an account. Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). Usage: - simd tx quarantine opt-out [] [flags] + provenanced tx quarantine opt-out [] [flags] Examples: -$ simd tx quarantine opt-out pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e -$ simd tx quarantine opt-out personal -$ simd tx quarantine opt-out --from pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e -$ simd tx quarantine opt-out --from personal +$ provenanced tx quarantine opt-out pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e +$ provenanced tx quarantine opt-out personal +$ provenanced tx quarantine opt-out --from pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e +$ provenanced tx quarantine opt-out --from personal ``` #### Accept ```shell -$ ./build/simd tx quarantine accept --help +$ provenanced tx quarantine accept --help Accept quarantined funds sent to from . Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). Usage: - simd tx quarantine accept [ ...] [flags] + provenanced tx quarantine accept [ ...] [flags] Examples: -$ simd tx quarantine accept pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h -$ simd tx quarantine accept personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h -$ simd tx quarantine accept personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn +$ provenanced tx quarantine accept pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ provenanced tx quarantine accept personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ provenanced tx quarantine accept personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn ``` At least one `` is required, but multiple can be provided. @@ -84,18 +84,18 @@ A `--permanent` flag is also available with this command: #### Decline ```shell -$ simd tx quarantine decline --help +$ provenanced tx quarantine decline --help Decline quarantined funds sent to from . Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). Usage: - simd tx quarantine decline [ ...] [flags] + provenanced tx quarantine decline [ ...] [flags] Examples: -$ simd tx quarantine decline pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h -$ simd tx quarantine decline personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h -$ simd tx quarantine decline personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn +$ provenanced tx quarantine decline pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ provenanced tx quarantine decline personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ provenanced tx quarantine decline personal pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn ``` At least one `` is required, but multiple can be provided. @@ -109,7 +109,7 @@ A `--permanent` flag is also available with this command: #### UpdateAutoResponses ```shell -$ simd tx quarantine update-auto-responses --help +$ provenanced tx quarantine update-auto-responses --help Update auto-responses for transfers to from one or more addresses. Note, the '--from' flag is ignored as it is implied from [to_name_or_address] (the signer of the message). @@ -125,16 +125,16 @@ Each value can be repeated as an arg as many times as needed as Each will be assigned the nearest preceding value. Usage: - simd tx quarantine update-auto-responses [ ...] [ [ ...] ...] [flags] + provenanced tx quarantine update-auto-responses [ ...] [ [ ...] ...] [flags] Aliases: update-auto-responses, auto-responses, uar Examples: -$ simd tx quarantine update-auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e accept pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h -$ simd tx quarantine update-auto-responses personal decline pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn unspecified pb1lfuwk97g6y9du8altct63vwgz5620t92vavdgr -$ simd tx quarantine auto-responses personal accept pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1qsjw3kjaf33qk2urxg54lzxkw525ngghtajelt off pb1lfuwk97g6y9du8altct63vwgz5620t92vavdgr +$ provenanced tx quarantine update-auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e accept pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h +$ provenanced tx quarantine update-auto-responses personal decline pb1phx24ecmuw3s7fmy8c87gh3rdq5lwskq4d6wzn unspecified pb1lfuwk97g6y9du8altct63vwgz5620t92vavdgr +$ provenanced tx quarantine auto-responses personal accept pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h pb1qsjw3kjaf33qk2urxg54lzxkw525ngghtajelt off pb1lfuwk97g6y9du8altct63vwgz5620t92vavdgr ``` ### Queries @@ -145,15 +145,15 @@ Standard `query` flags are available unless otherwise noted. #### IsQuarantined ```shell -$ simd query quarantine is-quarantined --help +$ provenanced query quarantine is-quarantined --help Query whether an account is opted into quarantined. Examples: - $ simd query quarantine is-quarantined pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e - $ simd query quarantine is pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h + $ provenanced query quarantine is-quarantined pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e + $ provenanced query quarantine is pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h Usage: - simd query quarantine is-quarantined [flags] + provenanced query quarantine is-quarantined [flags] Aliases: is-quarantined, is @@ -162,7 +162,7 @@ Aliases: #### QuarantinedFunds ```shell -simd query quarantine funds --help +provenanced query quarantine funds --help Query for quarantined funds. If no arguments are provided, all quarantined funds will be returned. @@ -170,12 +170,12 @@ If only a to_address is provided, only undeclined funds quarantined for that add If both a to_address and from_address are provided, quarantined funds will be returned regardless of whether they've been declined. Examples: - $ simd query quarantine funds - $ simd query quarantine funds pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e - $ simd query quarantine funds pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h + $ provenanced query quarantine funds + $ provenanced query quarantine funds pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e + $ provenanced query quarantine funds pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h Usage: - simd query quarantine funds [ []] [flags] + provenanced query quarantine funds [ []] [flags] ``` Standard pagination flags are also available for this command. @@ -183,18 +183,18 @@ Standard pagination flags are also available for this command. #### AutoResponses ```shell -$ simd query quarantine auto-responses --help +$ provenanced query quarantine auto-responses --help Query auto-responses. If only a to_address is provided, all auto-responses set up for that address are returned. This will only contain accept or decline entries. If both a to_address and from_address are provided, exactly one result will be returned. This can be accept, decline or unspecified. Examples: - $ simd query quarantine auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e - $ simd query quarantine auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h + $ provenanced query quarantine auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e + $ provenanced query quarantine auto-responses pb1c7p4v02eayvag8nswm4f5q664twfe6dxmek52e pb1ld2qyt9pq5n8dxkp58jn3jyxh8u8ztmrlt8x3h Usage: - simd query quarantine auto-responses [] [flags] + provenanced query quarantine auto-responses [] [flags] Aliases: auto-responses, auto, ar From 72e856068c901a5003735592c50924659324307d Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 20 Nov 2023 13:53:35 -0700 Subject: [PATCH 16/20] [1752]: Delete accidentally added empty line from messages spec. --- x/quarantine/spec/03_messages.md | 1 - 1 file changed, 1 deletion(-) diff --git a/x/quarantine/spec/03_messages.md b/x/quarantine/spec/03_messages.md index 2f6b95600b..b0778e3e0e 100644 --- a/x/quarantine/spec/03_messages.md +++ b/x/quarantine/spec/03_messages.md @@ -9,7 +9,6 @@ It contains only the address to quarantine. It is expected to fail if the `to_address` is invalid. - ## Msg/OptOut An account can deactivate quarantine using a `MsgOptOut`. From ef13852e2c62267eb1cdbf4992cc6db12536a8a2 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 20 Nov 2023 15:09:33 -0700 Subject: [PATCH 17/20] [1752]: Fix typo in comment at the top of testutil/bank/cli_helpers.go. --- testutil/bank/cli_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testutil/bank/cli_helpers.go b/testutil/bank/cli_helpers.go index 6970e987e2..be8b085051 100644 --- a/testutil/bank/cli_helpers.go +++ b/testutil/bank/cli_helpers.go @@ -1,6 +1,6 @@ package bank -// The contents of this file were copied from the SDK: x/bank/client/testutil/cli_helpers.go (and the package chagned). +// The contents of this file were copied from the SDK: x/bank/client/testutil/cli_helpers.go (and the package changed). import ( "fmt" From 39530f6f2244aa501480a4626fc699f9968258eb Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Mon, 27 Nov 2023 17:25:29 -0700 Subject: [PATCH 18/20] [1752]: Bring the quarantine spec docs in line with the others. --- x/README.md | 1 + x/quarantine/spec/04_events.md | 26 +++++++++++++------------- x/quarantine/spec/README.md | 25 +------------------------ 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/x/README.md b/x/README.md index af055f45b4..34e0ca12fa 100644 --- a/x/README.md +++ b/x/README.md @@ -18,5 +18,6 @@ Provenance uses inherited modules from the Cosmos SDK, and has also developed mo * [msgfees](./msgfees/README.md) - Manages additional fees that can be applied to tx msgs. * [Name](./name/README.md) - Provides a system for providing human-readable names as aliases for addresses. * [Oracle](./oracle/README.md) - Provides the capability to dynamically expose query endpoints. +* [Quarantine](./quarantine/spec/README.md) - Allows extra account security from unwanted funds. * [Reward](./reward/README.md) - Provides a system for distributing rewards to accounts. * [Trigger](./trigger/README.md) - Provides a system for triggering transactions based on predeterminded events. diff --git a/x/quarantine/spec/04_events.md b/x/quarantine/spec/04_events.md index b12f79543b..6ce2fd2a3f 100644 --- a/x/quarantine/spec/04_events.md +++ b/x/quarantine/spec/04_events.md @@ -9,8 +9,8 @@ This event is emitted when an account opts into quarantine. `@Type`: `/provenance.quarantine.v1.EventOptIn` | Attribute Key | Attribute Value | -| ------------- |----------------------------------------| -| to_address | {bech32 string of account opting in} | +|---------------|----------------------------------------| +| to_address | \{bech32 string of account opting in\} | ## EventOptOut @@ -18,9 +18,9 @@ This event is emitted when an account opts out of quarantine. `@Type`: `/provenance.quarantine.v1.EventOptOut` -| Attribute Key | Attribute Value | -|---------------|----------------------------------------| -| to_address | {bech32 string of account opting out} | +| Attribute Key | Attribute Value | +|---------------|-----------------------------------------| +| to_address | \{bech32 string of account opting out\} | ## EventFundsQuarantined @@ -29,10 +29,10 @@ The following event is also emitted. `@Type`: `/provenance.quarantine.v1.EventFundsQuarantined` -| Attribute Key | Attribute Value | -| ------------- |---------------------------------------| -| to_address | {bech32 string of intended recipient} | -| coins | {sdk.Coins of funds quarantined} | +| Attribute Key | Attribute Value | +|---------------|-----------------------------------------| +| to_address | \{bech32 string of intended recipient\} | +| coins | \{sdk.Coins of funds quarantined\} | ## EventFundsReleased @@ -40,7 +40,7 @@ This event is emitted when funds are fully accepted and sent from the quarantine `@Type`: `/provenance.quarantine.v1.EventFundsReleased` -| Attribute Key | Attribute Value | -| ------------- |-------------------------------| -| to_address | {bech32 string of recipient} | -| coins | {sdk.Coins of funds released} | +| Attribute Key | Attribute Value | +|---------------|---------------------------------| +| to_address | \{bech32 string of recipient\} | +| coins | \{sdk.Coins of funds released\} | diff --git a/x/quarantine/spec/README.md b/x/quarantine/spec/README.md index 10da297be3..d2828476de 100644 --- a/x/quarantine/spec/README.md +++ b/x/quarantine/spec/README.md @@ -1,4 +1,4 @@ -# Quarantine Module +# `x/quarantine` ## Abstract @@ -8,31 +8,8 @@ It also injects restrictions into the `x/bank` module to enforce account quarant ## Contents 1. **[Concepts](01_concepts.md)** - - [Quarantined Account](01_concepts.md#quarantined-account) - - [Opt-In](01_concepts.md#opt-in) - - [Quarantined Funds](01_concepts.md#quarantined-funds) - - [Auto-Responses](01_concepts.md#auto-responses) 2. **[State](02_state.md)** - - [Quarantined Accounts](02_state.md#quarantined-accounts) - - [Auto-Responses](02_state.md#auto-responses) - - [Quarantine Records](02_state.md#quarantine-records) - - [Quarantine Records Suffix Index](02_state.md#quarantine-records-suffix-index) 3. **[Msg Service](03_messages.md)** - - [Msg/OptIn](03_messages.md#msgoptin) - - [Msg/OptOut](03_messages.md#msgoptout) - - [Msg/Accept](03_messages.md#msgaccept) - - [Msg/Decline](03_messages.md#msgdecline) - - [Msg/UpdateAutoResponses](03_messages.md#msgupdateautoresponses) 4. **[Events](04_events.md)** - - [EventOptIn](04_events.md#eventoptin) - - [EventOptOut](04_events.md#eventoptout) - - [EventFundsQuarantined](04_events.md#eventfundsquarantined) - - [EventFundsReleased](04_events.md#eventfundsreleased) 5. **[gRPC Queries](05_queries.md)** - - [Query/IsQuarantined](05_queries.md#queryisquarantined) - - [Query/QuarantinedFunds](05_queries.md#queryquarantinedfunds) - - [Query/AutoResponses](05_queries.md#queryautoresponses) 6. **[Client](06_client.md)** - - [gRPC](06_client.md#grpc) - - [CLI](06_client.md#cli) - - [REST](06_client.md#rest) From aafd441e5a732a06feeecc02d9bd898ca810408a Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Tue, 28 Nov 2023 10:10:22 -0700 Subject: [PATCH 19/20] [1752]: Put back period in changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce06589ab2..b94b787224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements * Add upgrade handler for 1.18 [#1756](https://github.com/provenance-io/provenance/pull/1756). -* Updated documentation for each module to work with docusaurus [PR 1763](https://github.com/provenance-io/provenance/pull/1763) +* Updated documentation for each module to work with docusaurus [PR 1763](https://github.com/provenance-io/provenance/pull/1763). * Create a default market in `make run`, `localnet`, `devnet` and the `provenanced testnet` command [#1757](https://github.com/provenance-io/provenance/issues/1757). * Move the quarantine module into this repo (from our fork of the SDK) [#1752](https://github.com/provenance-io/provenance/issues/1752). From 331aca2921dc67bcbdec95dcdfcabc64664b5ec7 Mon Sep 17 00:00:00 2001 From: Daniel Wedul Date: Tue, 28 Nov 2023 13:33:24 -0700 Subject: [PATCH 20/20] [1752]: Tag 1760 in the TODO in errors.go. --- x/quarantine/errors/errors.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/x/quarantine/errors/errors.go b/x/quarantine/errors/errors.go index a795be73b2..53c5be5d42 100644 --- a/x/quarantine/errors/errors.go +++ b/x/quarantine/errors/errors.go @@ -4,10 +4,10 @@ import sdkqerrs "github.com/cosmos/cosmos-sdk/x/quarantine/errors" var ErrInvalidValue = sdkqerrs.ErrInvalidValue -// TODO: Once we have an official version of the SDK without the quarantine module: -// 1. Delete everything above this comment. -// 2. Uncomment everything below this comment. -// 3. Delete this comment. +// TODO[1760]: Once we have an official version of the SDK without the quarantine module: +// 1. Delete everything above this comment. +// 2. Uncomment everything below this comment. +// 3. Delete this comment. // package errors //