Remove IBC from the SDK (#8735)

This commit is contained in:
colin axnér 2021-03-04 14:11:34 +01:00 committed by GitHub
parent c66f1f7efe
commit da064e13d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
385 changed files with 19 additions and 106289 deletions

View File

@ -63,6 +63,10 @@ For more, please go to the [Cosmos SDK Docs](./docs/).
The Cosmos Hub application, `gaia`, has moved to its [own repository](https://github.com/cosmos/gaia). Go there to join the Cosmos Hub mainnet and more.
## Interblockchain Communication (IBC)
The IBC module for the SDK has moved to its [own repository](https://github.com/cosmos/ibc-go). Go there to build and integrate with the IBC module.
## Starport
If you are starting a new app or a new module you can use [Starport](https://github.com/tendermint/starport) to help you get started and speed up development. If you have any questions or find a bug, feel free to open an issue in the repo.

File diff suppressed because it is too large Load Diff

View File

@ -14,5 +14,7 @@ This repository contains reference documentation for the IBC protocol integratio
4. [Relayer](./relayer.md)
5. [Governance Proposals](./proposals.md)
**NOTE**: The IBC module has been moved to its [own repository](https://github.com/cosmos/ibc-go).
After reading about IBC, head on to the [Building Modules
documentation](../building-modules/README.md) to learn more about the process of building modules.

View File

@ -1,18 +0,0 @@
syntax = "proto3";
package ibc.applications.transfer.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types";
import "gogoproto/gogo.proto";
import "ibc/applications/transfer/v1/transfer.proto";
// GenesisState defines the ibc-transfer genesis state
message GenesisState {
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
repeated DenomTrace denom_traces = 2 [
(gogoproto.castrepeated) = "Traces",
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"denom_traces\""
];
Params params = 3 [(gogoproto.nullable) = false];
}

View File

@ -1,66 +0,0 @@
syntax = "proto3";
package ibc.applications.transfer.v1;
import "gogoproto/gogo.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "ibc/applications/transfer/v1/transfer.proto";
import "google/api/annotations.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types";
// Query provides defines the gRPC querier service.
service Query {
// DenomTrace queries a denomination trace information.
rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) {
option (google.api.http).get = "/ibc/applications/transfer/v1beta1/denom_traces/{hash}";
}
// DenomTraces queries all denomination traces.
rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) {
option (google.api.http).get = "/ibc/applications/transfer/v1beta1/denom_traces";
}
// Params queries all parameters of the ibc-transfer module.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/ibc/applications/transfer/v1beta1/params";
}
}
// QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC
// method
message QueryDenomTraceRequest {
// hash (in hex format) of the denomination trace information.
string hash = 1;
}
// QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC
// method.
message QueryDenomTraceResponse {
// denom_trace returns the requested denomination trace information.
DenomTrace denom_trace = 1;
}
// QueryConnectionsRequest is the request type for the Query/DenomTraces RPC
// method
message QueryDenomTracesRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryConnectionsResponse is the response type for the Query/DenomTraces RPC
// method.
message QueryDenomTracesResponse {
// denom_traces returns all denominations trace information.
repeated DenomTrace denom_traces = 1 [(gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false];
// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryParamsRequest is the request type for the Query/Params RPC method.
message QueryParamsRequest {}
// QueryParamsResponse is the response type for the Query/Params RPC method.
message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1;
}

View File

@ -1,43 +0,0 @@
syntax = "proto3";
package ibc.applications.transfer.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types";
import "gogoproto/gogo.proto";
// FungibleTokenPacketData defines a struct for the packet payload
// See FungibleTokenPacketData spec:
// https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures
message FungibleTokenPacketData {
// the token denomination to be transferred
string denom = 1;
// the token amount to be transferred
uint64 amount = 2;
// the sender address
string sender = 3;
// the recipient address on the destination chain
string receiver = 4;
}
// DenomTrace contains the base denomination for ICS20 fungible tokens and the
// source tracing information path.
message DenomTrace {
// path defines the chain of port/channel identifiers used for tracing the
// source of the fungible token.
string path = 1;
// base denomination of the relayed fungible token.
string base_denom = 2;
}
// Params defines the set of IBC transfer parameters.
// NOTE: To prevent a single token from being transferred, set the
// TransfersEnabled parameter to true and then set the bank module's SendEnabled
// parameter for the denomination to false.
message Params {
// send_enabled enables or disables all cross-chain token transfers from this
// chain.
bool send_enabled = 1 [(gogoproto.moretags) = "yaml:\"send_enabled\""];
// receive_enabled enables or disables all cross-chain token transfers to this
// chain.
bool receive_enabled = 2 [(gogoproto.moretags) = "yaml:\"receive_enabled\""];
}

View File

@ -1,43 +0,0 @@
syntax = "proto3";
package ibc.applications.transfer.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "ibc/core/client/v1/client.proto";
// Msg defines the ibc/transfer Msg service.
service Msg {
// Transfer defines a rpc handler method for MsgTransfer.
rpc Transfer(MsgTransfer) returns (MsgTransferResponse);
}
// MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between
// ICS20 enabled chains. See ICS Spec here:
// https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#data-structures
message MsgTransfer {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// the port on which the packet will be sent
string source_port = 1 [(gogoproto.moretags) = "yaml:\"source_port\""];
// the channel by which the packet will be sent
string source_channel = 2 [(gogoproto.moretags) = "yaml:\"source_channel\""];
// the tokens to be transferred
cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false];
// the sender address
string sender = 4;
// the recipient address on the destination chain
string receiver = 5;
// Timeout height relative to the current block height.
// The timeout is disabled when set to 0.
ibc.core.client.v1.Height timeout_height = 6
[(gogoproto.moretags) = "yaml:\"timeout_height\"", (gogoproto.nullable) = false];
// Timeout timestamp (in nanoseconds) relative to the current block timestamp.
// The timeout is disabled when set to 0.
uint64 timeout_timestamp = 7 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""];
}
// MsgTransferResponse defines the Msg/Transfer response type.
message MsgTransferResponse {}

View File

@ -1,147 +0,0 @@
syntax = "proto3";
package ibc.core.channel.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types";
import "gogoproto/gogo.proto";
import "ibc/core/client/v1/client.proto";
// Channel defines pipeline for exactly-once packet delivery between specific
// modules on separate blockchains, which has at least one end capable of
// sending packets and one end capable of receiving packets.
message Channel {
option (gogoproto.goproto_getters) = false;
// current state of the channel end
State state = 1;
// whether the channel is ordered or unordered
Order ordering = 2;
// counterparty channel end
Counterparty counterparty = 3 [(gogoproto.nullable) = false];
// list of connection identifiers, in order, along which packets sent on
// this channel will travel
repeated string connection_hops = 4 [(gogoproto.moretags) = "yaml:\"connection_hops\""];
// opaque channel version, which is agreed upon during the handshake
string version = 5;
}
// IdentifiedChannel defines a channel with additional port and channel
// identifier fields.
message IdentifiedChannel {
option (gogoproto.goproto_getters) = false;
// current state of the channel end
State state = 1;
// whether the channel is ordered or unordered
Order ordering = 2;
// counterparty channel end
Counterparty counterparty = 3 [(gogoproto.nullable) = false];
// list of connection identifiers, in order, along which packets sent on
// this channel will travel
repeated string connection_hops = 4 [(gogoproto.moretags) = "yaml:\"connection_hops\""];
// opaque channel version, which is agreed upon during the handshake
string version = 5;
// port identifier
string port_id = 6;
// channel identifier
string channel_id = 7;
}
// State defines if a channel is in one of the following states:
// CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED.
enum State {
option (gogoproto.goproto_enum_prefix) = false;
// Default State
STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"];
// A channel has just started the opening handshake.
STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"];
// A channel has acknowledged the handshake step on the counterparty chain.
STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"];
// A channel has completed the handshake. Open channels are
// ready to send and receive packets.
STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"];
// A channel has been closed and can no longer be used to send or receive
// packets.
STATE_CLOSED = 4 [(gogoproto.enumvalue_customname) = "CLOSED"];
}
// Order defines if a channel is ORDERED or UNORDERED
enum Order {
option (gogoproto.goproto_enum_prefix) = false;
// zero-value for channel ordering
ORDER_NONE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "NONE"];
// packets can be delivered in any order, which may differ from the order in
// which they were sent.
ORDER_UNORDERED = 1 [(gogoproto.enumvalue_customname) = "UNORDERED"];
// packets are delivered exactly in the order which they were sent
ORDER_ORDERED = 2 [(gogoproto.enumvalue_customname) = "ORDERED"];
}
// Counterparty defines a channel end counterparty
message Counterparty {
option (gogoproto.goproto_getters) = false;
// port on the counterparty chain which owns the other end of the channel.
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
// channel end on the counterparty chain
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
}
// Packet defines a type that carries data across different chains through IBC
message Packet {
option (gogoproto.goproto_getters) = false;
// number corresponds to the order of sends and receives, where a Packet
// with an earlier sequence number must be sent and received before a Packet
// with a later sequence number.
uint64 sequence = 1;
// identifies the port on the sending chain.
string source_port = 2 [(gogoproto.moretags) = "yaml:\"source_port\""];
// identifies the channel end on the sending chain.
string source_channel = 3 [(gogoproto.moretags) = "yaml:\"source_channel\""];
// identifies the port on the receiving chain.
string destination_port = 4 [(gogoproto.moretags) = "yaml:\"destination_port\""];
// identifies the channel end on the receiving chain.
string destination_channel = 5 [(gogoproto.moretags) = "yaml:\"destination_channel\""];
// actual opaque bytes transferred directly to the application module
bytes data = 6;
// block height after which the packet times out
ibc.core.client.v1.Height timeout_height = 7
[(gogoproto.moretags) = "yaml:\"timeout_height\"", (gogoproto.nullable) = false];
// block timestamp (in nanoseconds) after which the packet times out
uint64 timeout_timestamp = 8 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""];
}
// PacketState defines the generic type necessary to retrieve and store
// packet commitments, acknowledgements, and receipts.
// Caller is responsible for knowing the context necessary to interpret this
// state as a commitment, acknowledgement, or a receipt.
message PacketState {
option (gogoproto.goproto_getters) = false;
// channel port identifier.
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
// channel unique identifier.
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
// packet sequence.
uint64 sequence = 3;
// embedded data that represents packet state.
bytes data = 4;
}
// Acknowledgement is the recommended acknowledgement format to be used by
// app-specific protocols.
// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental
// conflicts with other protobuf message formats used for acknowledgements.
// The first byte of any message with this format will be the non-ASCII values
// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS:
// https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope
message Acknowledgement {
// response contains either a result or an error and must be non-empty
oneof response {
bytes result = 21;
string error = 22;
}
}

View File

@ -1,31 +0,0 @@
syntax = "proto3";
package ibc.core.channel.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types";
import "gogoproto/gogo.proto";
import "ibc/core/channel/v1/channel.proto";
// GenesisState defines the ibc channel submodule's genesis state.
message GenesisState {
repeated IdentifiedChannel channels = 1 [(gogoproto.casttype) = "IdentifiedChannel", (gogoproto.nullable) = false];
repeated PacketState acknowledgements = 2 [(gogoproto.nullable) = false];
repeated PacketState commitments = 3 [(gogoproto.nullable) = false];
repeated PacketState receipts = 4 [(gogoproto.nullable) = false];
repeated PacketSequence send_sequences = 5
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"send_sequences\""];
repeated PacketSequence recv_sequences = 6
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"recv_sequences\""];
repeated PacketSequence ack_sequences = 7
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"ack_sequences\""];
// the sequence for the next generated channel identifier
uint64 next_channel_sequence = 8 [(gogoproto.moretags) = "yaml:\"next_channel_sequence\""];
}
// PacketSequence defines the genesis type necessary to retrieve and store
// next send and receive sequences.
message PacketSequence {
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
uint64 sequence = 3;
}

View File

@ -1,367 +0,0 @@
syntax = "proto3";
package ibc.core.channel.v1;
import "ibc/core/client/v1/client.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "ibc/core/channel/v1/channel.proto";
import "google/api/annotations.proto";
import "google/protobuf/any.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types";
// Query provides defines the gRPC querier service
service Query {
// Channel queries an IBC Channel.
rpc Channel(QueryChannelRequest) returns (QueryChannelResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}";
}
// Channels queries all the IBC channels of a chain.
rpc Channels(QueryChannelsRequest) returns (QueryChannelsResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels";
}
// ConnectionChannels queries all the channels associated with a connection
// end.
rpc ConnectionChannels(QueryConnectionChannelsRequest) returns (QueryConnectionChannelsResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/connections/{connection}/channels";
}
// ChannelClientState queries for the client state for the channel associated
// with the provided channel identifiers.
rpc ChannelClientState(QueryChannelClientStateRequest) returns (QueryChannelClientStateResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/client_state";
}
// ChannelConsensusState queries for the consensus state for the channel
// associated with the provided channel identifiers.
rpc ChannelConsensusState(QueryChannelConsensusStateRequest) returns (QueryChannelConsensusStateResponse) {
option (google.api.http).get =
"/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/consensus_state/revision/"
"{revision_number}/height/{revision_height}";
}
// PacketCommitment queries a stored packet commitment hash.
rpc PacketCommitment(QueryPacketCommitmentRequest) returns (QueryPacketCommitmentResponse) {
option (google.api.http).get =
"/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_commitments/{sequence}";
}
// PacketCommitments returns all the packet commitments hashes associated
// with a channel.
rpc PacketCommitments(QueryPacketCommitmentsRequest) returns (QueryPacketCommitmentsResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_commitments";
}
// PacketReceipt queries if a given packet sequence has been received on the queried chain
rpc PacketReceipt(QueryPacketReceiptRequest) returns (QueryPacketReceiptResponse) {
option (google.api.http).get =
"/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_receipts/{sequence}";
}
// PacketAcknowledgement queries a stored packet acknowledgement hash.
rpc PacketAcknowledgement(QueryPacketAcknowledgementRequest) returns (QueryPacketAcknowledgementResponse) {
option (google.api.http).get =
"/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_acks/{sequence}";
}
// PacketAcknowledgements returns all the packet acknowledgements associated
// with a channel.
rpc PacketAcknowledgements(QueryPacketAcknowledgementsRequest) returns (QueryPacketAcknowledgementsResponse) {
option (google.api.http).get =
"/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_acknowledgements";
}
// UnreceivedPackets returns all the unreceived IBC packets associated with a
// channel and sequences.
rpc UnreceivedPackets(QueryUnreceivedPacketsRequest) returns (QueryUnreceivedPacketsResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_commitments/"
"{packet_commitment_sequences}/unreceived_packets";
}
// UnreceivedAcks returns all the unreceived IBC acknowledgements associated with a
// channel and sequences.
rpc UnreceivedAcks(QueryUnreceivedAcksRequest) returns (QueryUnreceivedAcksResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_commitments/"
"{packet_ack_sequences}/unreceived_acks";
}
// NextSequenceReceive returns the next receive sequence for a given channel.
rpc NextSequenceReceive(QueryNextSequenceReceiveRequest) returns (QueryNextSequenceReceiveResponse) {
option (google.api.http).get = "/ibc/core/channel/v1beta1/channels/{channel_id}/ports/{port_id}/next_sequence";
}
}
// QueryChannelRequest is the request type for the Query/Channel RPC method
message QueryChannelRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
}
// QueryChannelResponse is the response type for the Query/Channel RPC method.
// Besides the Channel end, it includes a proof and the height from which the
// proof was retrieved.
message QueryChannelResponse {
// channel associated with the request identifiers
ibc.core.channel.v1.Channel channel = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryChannelsRequest is the request type for the Query/Channels RPC method
message QueryChannelsRequest {
// pagination request
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryChannelsResponse is the response type for the Query/Channels RPC method.
message QueryChannelsResponse {
// list of stored channels of the chain.
repeated ibc.core.channel.v1.IdentifiedChannel channels = 1;
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
// query block height
ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false];
}
// QueryConnectionChannelsRequest is the request type for the
// Query/QueryConnectionChannels RPC method
message QueryConnectionChannelsRequest {
// connection unique identifier
string connection = 1;
// pagination request
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
// QueryConnectionChannelsResponse is the Response type for the
// Query/QueryConnectionChannels RPC method
message QueryConnectionChannelsResponse {
// list of channels associated with a connection.
repeated ibc.core.channel.v1.IdentifiedChannel channels = 1;
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
// query block height
ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false];
}
// QueryChannelClientStateRequest is the request type for the Query/ClientState
// RPC method
message QueryChannelClientStateRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
}
// QueryChannelClientStateResponse is the Response type for the
// Query/QueryChannelClientState RPC method
message QueryChannelClientStateResponse {
// client state associated with the channel
ibc.core.client.v1.IdentifiedClientState identified_client_state = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryChannelConsensusStateRequest is the request type for the
// Query/ConsensusState RPC method
message QueryChannelConsensusStateRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// revision number of the consensus state
uint64 revision_number = 3;
// revision height of the consensus state
uint64 revision_height = 4;
}
// QueryChannelClientStateResponse is the Response type for the
// Query/QueryChannelClientState RPC method
message QueryChannelConsensusStateResponse {
// consensus state associated with the channel
google.protobuf.Any consensus_state = 1;
// client ID associated with the consensus state
string client_id = 2;
// merkle proof of existence
bytes proof = 3;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false];
}
// QueryPacketCommitmentRequest is the request type for the
// Query/PacketCommitment RPC method
message QueryPacketCommitmentRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// packet sequence
uint64 sequence = 3;
}
// QueryPacketCommitmentResponse defines the client query response for a packet
// which also includes a proof and the height from which the proof was
// retrieved
message QueryPacketCommitmentResponse {
// packet associated with the request fields
bytes commitment = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryPacketCommitmentsRequest is the request type for the
// Query/QueryPacketCommitments RPC method
message QueryPacketCommitmentsRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// pagination request
cosmos.base.query.v1beta1.PageRequest pagination = 3;
}
// QueryPacketCommitmentsResponse is the request type for the
// Query/QueryPacketCommitments RPC method
message QueryPacketCommitmentsResponse {
repeated ibc.core.channel.v1.PacketState commitments = 1;
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
// query block height
ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false];
}
// QueryPacketReceiptRequest is the request type for the
// Query/PacketReceipt RPC method
message QueryPacketReceiptRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// packet sequence
uint64 sequence = 3;
}
// QueryPacketReceiptResponse defines the client query response for a packet receipt
// which also includes a proof, and the height from which the proof was
// retrieved
message QueryPacketReceiptResponse {
// success flag for if receipt exists
bool received = 2;
// merkle proof of existence
bytes proof = 3;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false];
}
// QueryPacketAcknowledgementRequest is the request type for the
// Query/PacketAcknowledgement RPC method
message QueryPacketAcknowledgementRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// packet sequence
uint64 sequence = 3;
}
// QueryPacketAcknowledgementResponse defines the client query response for a
// packet which also includes a proof and the height from which the
// proof was retrieved
message QueryPacketAcknowledgementResponse {
// packet associated with the request fields
bytes acknowledgement = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryPacketAcknowledgementsRequest is the request type for the
// Query/QueryPacketCommitments RPC method
message QueryPacketAcknowledgementsRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// pagination request
cosmos.base.query.v1beta1.PageRequest pagination = 3;
}
// QueryPacketAcknowledgemetsResponse is the request type for the
// Query/QueryPacketAcknowledgements RPC method
message QueryPacketAcknowledgementsResponse {
repeated ibc.core.channel.v1.PacketState acknowledgements = 1;
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
// query block height
ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false];
}
// QueryUnreceivedPacketsRequest is the request type for the
// Query/UnreceivedPackets RPC method
message QueryUnreceivedPacketsRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// list of packet sequences
repeated uint64 packet_commitment_sequences = 3;
}
// QueryUnreceivedPacketsResponse is the response type for the
// Query/UnreceivedPacketCommitments RPC method
message QueryUnreceivedPacketsResponse {
// list of unreceived packet sequences
repeated uint64 sequences = 1;
// query block height
ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false];
}
// QueryUnreceivedAcks is the request type for the
// Query/UnreceivedAcks RPC method
message QueryUnreceivedAcksRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// list of acknowledgement sequences
repeated uint64 packet_ack_sequences = 3;
}
// QueryUnreceivedAcksResponse is the response type for the
// Query/UnreceivedAcks RPC method
message QueryUnreceivedAcksResponse {
// list of unreceived acknowledgement sequences
repeated uint64 sequences = 1;
// query block height
ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false];
}
// QueryNextSequenceReceiveRequest is the request type for the
// Query/QueryNextSequenceReceiveRequest RPC method
message QueryNextSequenceReceiveRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
}
// QuerySequenceResponse is the request type for the
// Query/QueryNextSequenceReceiveResponse RPC method
message QueryNextSequenceReceiveResponse {
// next sequence receive number
uint64 next_sequence_receive = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}

View File

@ -1,207 +0,0 @@
syntax = "proto3";
package ibc.core.channel.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types";
import "gogoproto/gogo.proto";
import "ibc/core/client/v1/client.proto";
import "ibc/core/channel/v1/channel.proto";
// Msg defines the ibc/channel Msg service.
service Msg {
// ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit.
rpc ChannelOpenInit(MsgChannelOpenInit) returns (MsgChannelOpenInitResponse);
// ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry.
rpc ChannelOpenTry(MsgChannelOpenTry) returns (MsgChannelOpenTryResponse);
// ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck.
rpc ChannelOpenAck(MsgChannelOpenAck) returns (MsgChannelOpenAckResponse);
// ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm.
rpc ChannelOpenConfirm(MsgChannelOpenConfirm) returns (MsgChannelOpenConfirmResponse);
// ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit.
rpc ChannelCloseInit(MsgChannelCloseInit) returns (MsgChannelCloseInitResponse);
// ChannelCloseConfirm defines a rpc handler method for MsgChannelCloseConfirm.
rpc ChannelCloseConfirm(MsgChannelCloseConfirm) returns (MsgChannelCloseConfirmResponse);
// RecvPacket defines a rpc handler method for MsgRecvPacket.
rpc RecvPacket(MsgRecvPacket) returns (MsgRecvPacketResponse);
// Timeout defines a rpc handler method for MsgTimeout.
rpc Timeout(MsgTimeout) returns (MsgTimeoutResponse);
// TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose.
rpc TimeoutOnClose(MsgTimeoutOnClose) returns (MsgTimeoutOnCloseResponse);
// Acknowledgement defines a rpc handler method for MsgAcknowledgement.
rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse);
}
// MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It
// is called by a relayer on Chain A.
message MsgChannelOpenInit {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
Channel channel = 2 [(gogoproto.nullable) = false];
string signer = 3;
}
// MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type.
message MsgChannelOpenInitResponse {}
// MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel
// on Chain B.
message MsgChannelOpenTry {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
// in the case of crossing hello's, when both chains call OpenInit, we need the channel identifier
// of the previous channel in state INIT
string previous_channel_id = 2 [(gogoproto.moretags) = "yaml:\"previous_channel_id\""];
Channel channel = 3 [(gogoproto.nullable) = false];
string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""];
bytes proof_init = 5 [(gogoproto.moretags) = "yaml:\"proof_init\""];
ibc.core.client.v1.Height proof_height = 6
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 7;
}
// MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type.
message MsgChannelOpenTryResponse {}
// MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge
// the change of channel state to TRYOPEN on Chain B.
message MsgChannelOpenAck {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
string counterparty_channel_id = 3 [(gogoproto.moretags) = "yaml:\"counterparty_channel_id\""];
string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""];
bytes proof_try = 5 [(gogoproto.moretags) = "yaml:\"proof_try\""];
ibc.core.client.v1.Height proof_height = 6
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 7;
}
// MsgChannelOpenAckResponse defines the Msg/ChannelOpenAck response type.
message MsgChannelOpenAckResponse {}
// MsgChannelOpenConfirm defines a msg sent by a Relayer to Chain B to
// acknowledge the change of channel state to OPEN on Chain A.
message MsgChannelOpenConfirm {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
bytes proof_ack = 3 [(gogoproto.moretags) = "yaml:\"proof_ack\""];
ibc.core.client.v1.Height proof_height = 4
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 5;
}
// MsgChannelOpenConfirmResponse defines the Msg/ChannelOpenConfirm response type.
message MsgChannelOpenConfirmResponse {}
// MsgChannelCloseInit defines a msg sent by a Relayer to Chain A
// to close a channel with Chain B.
message MsgChannelCloseInit {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
string signer = 3;
}
// MsgChannelCloseInitResponse defines the Msg/ChannelCloseInit response type.
message MsgChannelCloseInitResponse {}
// MsgChannelCloseConfirm defines a msg sent by a Relayer to Chain B
// to acknowledge the change of channel state to CLOSED on Chain A.
message MsgChannelCloseConfirm {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""];
string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""];
bytes proof_init = 3 [(gogoproto.moretags) = "yaml:\"proof_init\""];
ibc.core.client.v1.Height proof_height = 4
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 5;
}
// MsgChannelCloseConfirmResponse defines the Msg/ChannelCloseConfirm response type.
message MsgChannelCloseConfirmResponse {}
// MsgRecvPacket receives incoming IBC packet
message MsgRecvPacket {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
Packet packet = 1 [(gogoproto.nullable) = false];
bytes proof_commitment = 2 [(gogoproto.moretags) = "yaml:\"proof_commitment\""];
ibc.core.client.v1.Height proof_height = 3
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 4;
}
// MsgRecvPacketResponse defines the Msg/RecvPacket response type.
message MsgRecvPacketResponse {}
// MsgTimeout receives timed-out packet
message MsgTimeout {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
Packet packet = 1 [(gogoproto.nullable) = false];
bytes proof_unreceived = 2 [(gogoproto.moretags) = "yaml:\"proof_unreceived\""];
ibc.core.client.v1.Height proof_height = 3
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
uint64 next_sequence_recv = 4 [(gogoproto.moretags) = "yaml:\"next_sequence_recv\""];
string signer = 5;
}
// MsgTimeoutResponse defines the Msg/Timeout response type.
message MsgTimeoutResponse {}
// MsgTimeoutOnClose timed-out packet upon counterparty channel closure.
message MsgTimeoutOnClose {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
Packet packet = 1 [(gogoproto.nullable) = false];
bytes proof_unreceived = 2 [(gogoproto.moretags) = "yaml:\"proof_unreceived\""];
bytes proof_close = 3 [(gogoproto.moretags) = "yaml:\"proof_close\""];
ibc.core.client.v1.Height proof_height = 4
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
uint64 next_sequence_recv = 5 [(gogoproto.moretags) = "yaml:\"next_sequence_recv\""];
string signer = 6;
}
// MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type.
message MsgTimeoutOnCloseResponse {}
// MsgAcknowledgement receives incoming IBC acknowledgement
message MsgAcknowledgement {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
Packet packet = 1 [(gogoproto.nullable) = false];
bytes acknowledgement = 2;
bytes proof_acked = 3 [(gogoproto.moretags) = "yaml:\"proof_acked\""];
ibc.core.client.v1.Height proof_height = 4
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 5;
}
// MsgAcknowledgementResponse defines the Msg/Acknowledgement response type.
message MsgAcknowledgementResponse {}

View File

@ -1,98 +0,0 @@
syntax = "proto3";
package ibc.core.client.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "cosmos/upgrade/v1beta1/upgrade.proto";
// IdentifiedClientState defines a client state with an additional client
// identifier field.
message IdentifiedClientState {
// client identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// client state
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
}
// ConsensusStateWithHeight defines a consensus state with an additional height field.
message ConsensusStateWithHeight {
// consensus state height
Height height = 1 [(gogoproto.nullable) = false];
// consensus state
google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml\"consensus_state\""];
}
// ClientConsensusStates defines all the stored consensus states for a given
// client.
message ClientConsensusStates {
// client identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// consensus states and their heights associated with the client
repeated ConsensusStateWithHeight consensus_states = 2
[(gogoproto.moretags) = "yaml:\"consensus_states\"", (gogoproto.nullable) = false];
}
// ClientUpdateProposal is a governance proposal. If it passes, the substitute client's
// consensus states starting from the 'initial height' are copied over to the subjects
// client state. The proposal handler may fail if the subject and the substitute do not
// match in client and chain parameters (with exception to latest height, frozen height, and chain-id).
// The updated client must also be valid (cannot be expired).
message ClientUpdateProposal {
option (gogoproto.goproto_getters) = false;
// the title of the update proposal
string title = 1;
// the description of the proposal
string description = 2;
// the client identifier for the client to be updated if the proposal passes
string subject_client_id = 3 [(gogoproto.moretags) = "yaml:\"subject_client_id\""];
// the substitute client identifier for the client standing in for the subject client
string substitute_client_id = 4 [(gogoproto.moretags) = "yaml:\"susbtitute_client_id\""];
// the intital height to copy consensus states from the substitute to the subject
Height initial_height = 5 [(gogoproto.moretags) = "yaml:\"initial_height\"", (gogoproto.nullable) = false];
}
// UpgradeProposal is a gov Content type for initiating an IBC breaking
// upgrade.
message UpgradeProposal {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
option (gogoproto.equal) = true;
string title = 1;
string description = 2;
cosmos.upgrade.v1beta1.Plan plan = 3 [(gogoproto.nullable) = false];
// An UpgradedClientState must be provided to perform an IBC breaking upgrade.
// This will make the chain commit to the correct upgraded (self) client state before the upgrade occurs,
// so that connecting chains can verify that the new upgraded client is valid by verifying a proof on the
// previous version of the chain.
// This will allow IBC connections to persist smoothly across planned chain upgrades
google.protobuf.Any upgraded_client_state = 4 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""];
}
// Height is a monotonically increasing data type
// that can be compared against another Height for the purposes of updating and
// freezing clients
//
// Normally the RevisionHeight is incremented at each height while keeping RevisionNumber
// the same. However some consensus algorithms may choose to reset the
// height in certain conditions e.g. hard forks, state-machine breaking changes
// In these cases, the RevisionNumber is incremented so that height continues to
// be monitonically increasing even as the RevisionHeight gets reset
message Height {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
// the revision that the client is currently on
uint64 revision_number = 1 [(gogoproto.moretags) = "yaml:\"revision_number\""];
// the height within the given revision
uint64 revision_height = 2 [(gogoproto.moretags) = "yaml:\"revision_height\""];
}
// Params defines the set of IBC light client parameters.
message Params {
// allowed_clients defines the list of allowed client state types.
repeated string allowed_clients = 1 [(gogoproto.moretags) = "yaml:\"allowed_clients\""];
}

View File

@ -1,46 +0,0 @@
syntax = "proto3";
package ibc.core.client.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types";
import "ibc/core/client/v1/client.proto";
import "gogoproto/gogo.proto";
// GenesisState defines the ibc client submodule's genesis state.
message GenesisState {
// client states with their corresponding identifiers
repeated IdentifiedClientState clients = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"];
// consensus states from each client
repeated ClientConsensusStates clients_consensus = 2 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "ClientsConsensusStates",
(gogoproto.moretags) = "yaml:\"clients_consensus\""
];
// metadata from each client
repeated IdentifiedGenesisMetadata clients_metadata = 3
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"clients_metadata\""];
Params params = 4 [(gogoproto.nullable) = false];
// create localhost on initialization
bool create_localhost = 5 [(gogoproto.moretags) = "yaml:\"create_localhost\""];
// the sequence for the next generated client identifier
uint64 next_client_sequence = 6 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""];
}
// GenesisMetadata defines the genesis type for metadata that clients may return
// with ExportMetadata
message GenesisMetadata {
option (gogoproto.goproto_getters) = false;
// store key of metadata without clientID-prefix
bytes key = 1;
// metadata value
bytes value = 2;
}
// IdentifiedGenesisMetadata has the client metadata with the corresponding client id.
message IdentifiedGenesisMetadata {
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
repeated GenesisMetadata client_metadata = 2
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_metadata\""];
}

View File

@ -1,152 +0,0 @@
syntax = "proto3";
package ibc.core.client.v1;
import "cosmos/base/query/v1beta1/pagination.proto";
import "ibc/core/client/v1/client.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "gogoproto/gogo.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types";
// Query provides defines the gRPC querier service
service Query {
// ClientState queries an IBC light client.
rpc ClientState(QueryClientStateRequest) returns (QueryClientStateResponse) {
option (google.api.http).get = "/ibc/core/client/v1beta1/client_states/{client_id}";
}
// ClientStates queries all the IBC light clients of a chain.
rpc ClientStates(QueryClientStatesRequest) returns (QueryClientStatesResponse) {
option (google.api.http).get = "/ibc/core/client/v1beta1/client_states";
}
// ConsensusState queries a consensus state associated with a client state at
// a given height.
rpc ConsensusState(QueryConsensusStateRequest) returns (QueryConsensusStateResponse) {
option (google.api.http).get = "/ibc/core/client/v1beta1/consensus_states/{client_id}/revision/{revision_number}/"
"height/{revision_height}";
}
// ConsensusStates queries all the consensus state associated with a given
// client.
rpc ConsensusStates(QueryConsensusStatesRequest) returns (QueryConsensusStatesResponse) {
option (google.api.http).get = "/ibc/core/client/v1beta1/consensus_states/{client_id}";
}
// ClientParams queries all parameters of the ibc client.
rpc ClientParams(QueryClientParamsRequest) returns (QueryClientParamsResponse) {
option (google.api.http).get = "/ibc/client/v1beta1/params";
}
// UpgradedClientState queries an Upgraded IBC light client.
rpc UpgradedClientState(QueryUpgradedClientStateRequest) returns (QueryUpgradedClientStateResponse) {
option (google.api.http).get = "/ibc/core/client/v1/upgraded_client_states/{client_id}";
}
}
// QueryClientStateRequest is the request type for the Query/ClientState RPC
// method
message QueryClientStateRequest {
// client state unique identifier
string client_id = 1;
}
// QueryClientStateResponse is the response type for the Query/ClientState RPC
// method. Besides the client state, it includes a proof and the height from
// which the proof was retrieved.
message QueryClientStateResponse {
// client state associated with the request identifier
google.protobuf.Any client_state = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryClientStatesRequest is the request type for the Query/ClientStates RPC
// method
message QueryClientStatesRequest {
// pagination request
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryClientStatesResponse is the response type for the Query/ClientStates RPC
// method.
message QueryClientStatesResponse {
// list of stored ClientStates of the chain.
repeated IdentifiedClientState client_states = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"];
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryConsensusStateRequest is the request type for the Query/ConsensusState
// RPC method. Besides the consensus state, it includes a proof and the height
// from which the proof was retrieved.
message QueryConsensusStateRequest {
// client identifier
string client_id = 1;
// consensus state revision number
uint64 revision_number = 2;
// consensus state revision height
uint64 revision_height = 3;
// latest_height overrrides the height field and queries the latest stored
// ConsensusState
bool latest_height = 4;
}
// QueryConsensusStateResponse is the response type for the Query/ConsensusState
// RPC method
message QueryConsensusStateResponse {
// consensus state associated with the client identifier at the given height
google.protobuf.Any consensus_state = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryConsensusStatesRequest is the request type for the Query/ConsensusStates
// RPC method.
message QueryConsensusStatesRequest {
// client identifier
string client_id = 1;
// pagination request
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}
// QueryConsensusStatesResponse is the response type for the
// Query/ConsensusStates RPC method
message QueryConsensusStatesResponse {
// consensus states associated with the identifier
repeated ConsensusStateWithHeight consensus_states = 1 [(gogoproto.nullable) = false];
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
// QueryClientParamsRequest is the request type for the Query/ClientParams RPC method.
message QueryClientParamsRequest {}
// QueryClientParamsResponse is the response type for the Query/ClientParams RPC method.
message QueryClientParamsResponse {
// params defines the parameters of the module.
Params params = 1;
}
// QueryUpgradedClientStateRequest is the request type for the Query/UpgradedClientState RPC
// method
message QueryUpgradedClientStateRequest {
// client state unique identifier
string client_id = 1;
// plan height of the current chain must be sent in request
// as this is the height under which upgraded client state is stored
int64 plan_height = 2;
}
// QueryUpgradedClientStateResponse is the response type for the Query/UpgradedClientState RPC
// method.
message QueryUpgradedClientStateResponse {
// client state associated with the request identifier
google.protobuf.Any upgraded_client_state = 1;
}

View File

@ -1,96 +0,0 @@
syntax = "proto3";
package ibc.core.client.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "ibc/core/client/v1/client.proto";
// Msg defines the ibc/client Msg service.
service Msg {
// CreateClient defines a rpc handler method for MsgCreateClient.
rpc CreateClient(MsgCreateClient) returns (MsgCreateClientResponse);
// UpdateClient defines a rpc handler method for MsgUpdateClient.
rpc UpdateClient(MsgUpdateClient) returns (MsgUpdateClientResponse);
// UpgradeClient defines a rpc handler method for MsgUpgradeClient.
rpc UpgradeClient(MsgUpgradeClient) returns (MsgUpgradeClientResponse);
// SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour.
rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse);
}
// MsgCreateClient defines a message to create an IBC client
message MsgCreateClient {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// light client state
google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""];
// consensus state associated with the client that corresponds to a given
// height.
google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
// signer address
string signer = 3;
}
// MsgCreateClientResponse defines the Msg/CreateClient response type.
message MsgCreateClientResponse {}
// MsgUpdateClient defines an sdk.Msg to update a IBC client state using
// the given header.
message MsgUpdateClient {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// client unique identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// header to update the light client
google.protobuf.Any header = 2;
// signer address
string signer = 3;
}
// MsgUpdateClientResponse defines the Msg/UpdateClient response type.
message MsgUpdateClientResponse {}
// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client state
message MsgUpgradeClient {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// client unique identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// upgraded client state
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
// upgraded consensus state, only contains enough information to serve as a basis of trust in update logic
google.protobuf.Any consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
// proof that old chain committed to new client
bytes proof_upgrade_client = 4 [(gogoproto.moretags) = "yaml:\"proof_upgrade_client\""];
// proof that old chain committed to new consensus state
bytes proof_upgrade_consensus_state = 5 [(gogoproto.moretags) = "yaml:\"proof_upgrade_consensus_state\""];
// signer address
string signer = 6;
}
// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type.
message MsgUpgradeClientResponse {}
// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for
// light client misbehaviour.
message MsgSubmitMisbehaviour {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// client unique identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// misbehaviour used for freezing the light client
google.protobuf.Any misbehaviour = 2;
// signer address
string signer = 3;
}
// MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response type.
message MsgSubmitMisbehaviourResponse {}

View File

@ -1,40 +0,0 @@
syntax = "proto3";
package ibc.core.commitment.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/23-commitment/types";
import "gogoproto/gogo.proto";
import "confio/proofs.proto";
// MerkleRoot defines a merkle root hash.
// In the Cosmos SDK, the AppHash of a block header becomes the root.
message MerkleRoot {
option (gogoproto.goproto_getters) = false;
bytes hash = 1;
}
// MerklePrefix is merkle path prefixed to the key.
// The constructed key from the Path and the key will be append(Path.KeyPath,
// append(Path.KeyPrefix, key...))
message MerklePrefix {
bytes key_prefix = 1 [(gogoproto.moretags) = "yaml:\"key_prefix\""];
}
// MerklePath is the path used to verify commitment proofs, which can be an
// arbitrary structured object (defined by a commitment type).
// MerklePath is represented from root-to-leaf
message MerklePath {
option (gogoproto.goproto_stringer) = false;
repeated string key_path = 1 [(gogoproto.moretags) = "yaml:\"key_path\""];
}
// MerkleProof is a wrapper type over a chain of CommitmentProofs.
// It demonstrates membership or non-membership for an element or set of
// elements, verifiable in conjunction with a known commitment root. Proofs
// should be succinct.
// MerkleProofs are ordered from leaf-to-root
message MerkleProof {
repeated ics23.CommitmentProof proofs = 1;
}

View File

@ -1,104 +0,0 @@
syntax = "proto3";
package ibc.core.connection.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types";
import "gogoproto/gogo.proto";
import "ibc/core/commitment/v1/commitment.proto";
// ICS03 - Connection Data Structures as defined in
// https://github.com/cosmos/ics/tree/master/spec/ics-003-connection-semantics#data-structures
// ConnectionEnd defines a stateful object on a chain connected to another
// separate one.
// NOTE: there must only be 2 defined ConnectionEnds to establish
// a connection between two chains.
message ConnectionEnd {
option (gogoproto.goproto_getters) = false;
// client associated with this connection.
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// IBC version which can be utilised to determine encodings or protocols for
// channels or packets utilising this connection.
repeated Version versions = 2;
// current state of the connection end.
State state = 3;
// counterparty chain associated with this connection.
Counterparty counterparty = 4 [(gogoproto.nullable) = false];
// delay period that must pass before a consensus state can be used for packet-verification
// NOTE: delay period logic is only implemented by some clients.
uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""];
}
// IdentifiedConnection defines a connection with additional connection
// identifier field.
message IdentifiedConnection {
option (gogoproto.goproto_getters) = false;
// connection identifier.
string id = 1 [(gogoproto.moretags) = "yaml:\"id\""];
// client associated with this connection.
string client_id = 2 [(gogoproto.moretags) = "yaml:\"client_id\""];
// IBC version which can be utilised to determine encodings or protocols for
// channels or packets utilising this connection
repeated Version versions = 3;
// current state of the connection end.
State state = 4;
// counterparty chain associated with this connection.
Counterparty counterparty = 5 [(gogoproto.nullable) = false];
// delay period associated with this connection.
uint64 delay_period = 6 [(gogoproto.moretags) = "yaml:\"delay_period\""];
}
// State defines if a connection is in one of the following states:
// INIT, TRYOPEN, OPEN or UNINITIALIZED.
enum State {
option (gogoproto.goproto_enum_prefix) = false;
// Default State
STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"];
// A connection end has just started the opening handshake.
STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"];
// A connection end has acknowledged the handshake step on the counterparty
// chain.
STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"];
// A connection end has completed the handshake.
STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"];
}
// Counterparty defines the counterparty chain associated with a connection end.
message Counterparty {
option (gogoproto.goproto_getters) = false;
// identifies the client on the counterparty chain associated with a given
// connection.
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// identifies the connection end on the counterparty chain associated with a
// given connection.
string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""];
// commitment merkle prefix of the counterparty chain.
ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false];
}
// ClientPaths define all the connection paths for a client state.
message ClientPaths {
// list of connection paths
repeated string paths = 1;
}
// ConnectionPaths define all the connection paths for a given client state.
message ConnectionPaths {
// client state unique identifier
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// list of connection paths
repeated string paths = 2;
}
// Version defines the versioning scheme used to negotiate the IBC verison in
// the connection handshake.
message Version {
option (gogoproto.goproto_getters) = false;
// unique version identifier
string identifier = 1;
// list of features compatible with the specified identifier
repeated string features = 2;
}

View File

@ -1,16 +0,0 @@
syntax = "proto3";
package ibc.core.connection.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types";
import "gogoproto/gogo.proto";
import "ibc/core/connection/v1/connection.proto";
// GenesisState defines the ibc connection submodule's genesis state.
message GenesisState {
repeated IdentifiedConnection connections = 1 [(gogoproto.nullable) = false];
repeated ConnectionPaths client_connection_paths = 2
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_connection_paths\""];
// the sequence for the next generated connection identifier
uint64 next_connection_sequence = 3 [(gogoproto.moretags) = "yaml:\"next_connection_sequence\""];
}

View File

@ -1,137 +0,0 @@
syntax = "proto3";
package ibc.core.connection.v1;
import "gogoproto/gogo.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "ibc/core/client/v1/client.proto";
import "ibc/core/connection/v1/connection.proto";
import "google/api/annotations.proto";
import "google/protobuf/any.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types";
// Query provides defines the gRPC querier service
service Query {
// Connection queries an IBC connection end.
rpc Connection(QueryConnectionRequest) returns (QueryConnectionResponse) {
option (google.api.http).get = "/ibc/core/connection/v1beta1/connections/{connection_id}";
}
// Connections queries all the IBC connections of a chain.
rpc Connections(QueryConnectionsRequest) returns (QueryConnectionsResponse) {
option (google.api.http).get = "/ibc/core/connection/v1beta1/connections";
}
// ClientConnections queries the connection paths associated with a client
// state.
rpc ClientConnections(QueryClientConnectionsRequest) returns (QueryClientConnectionsResponse) {
option (google.api.http).get = "/ibc/core/connection/v1beta1/client_connections/{client_id}";
}
// ConnectionClientState queries the client state associated with the
// connection.
rpc ConnectionClientState(QueryConnectionClientStateRequest) returns (QueryConnectionClientStateResponse) {
option (google.api.http).get = "/ibc/core/connection/v1beta1/connections/{connection_id}/client_state";
}
// ConnectionConsensusState queries the consensus state associated with the
// connection.
rpc ConnectionConsensusState(QueryConnectionConsensusStateRequest) returns (QueryConnectionConsensusStateResponse) {
option (google.api.http).get = "/ibc/core/connection/v1beta1/connections/{connection_id}/consensus_state/"
"revision/{revision_number}/height/{revision_height}";
}
}
// QueryConnectionRequest is the request type for the Query/Connection RPC
// method
message QueryConnectionRequest {
// connection unique identifier
string connection_id = 1;
}
// QueryConnectionResponse is the response type for the Query/Connection RPC
// method. Besides the connection end, it includes a proof and the height from
// which the proof was retrieved.
message QueryConnectionResponse {
// connection associated with the request identifier
ibc.core.connection.v1.ConnectionEnd connection = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryConnectionsRequest is the request type for the Query/Connections RPC
// method
message QueryConnectionsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryConnectionsResponse is the response type for the Query/Connections RPC
// method.
message QueryConnectionsResponse {
// list of stored connections of the chain.
repeated ibc.core.connection.v1.IdentifiedConnection connections = 1;
// pagination response
cosmos.base.query.v1beta1.PageResponse pagination = 2;
// query block height
ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false];
}
// QueryClientConnectionsRequest is the request type for the
// Query/ClientConnections RPC method
message QueryClientConnectionsRequest {
// client identifier associated with a connection
string client_id = 1;
}
// QueryClientConnectionsResponse is the response type for the
// Query/ClientConnections RPC method
message QueryClientConnectionsResponse {
// slice of all the connection paths associated with a client.
repeated string connection_paths = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was generated
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryConnectionClientStateRequest is the request type for the
// Query/ConnectionClientState RPC method
message QueryConnectionClientStateRequest {
// connection identifier
string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
}
// QueryConnectionClientStateResponse is the response type for the
// Query/ConnectionClientState RPC method
message QueryConnectionClientStateResponse {
// client state associated with the channel
ibc.core.client.v1.IdentifiedClientState identified_client_state = 1;
// merkle proof of existence
bytes proof = 2;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false];
}
// QueryConnectionConsensusStateRequest is the request type for the
// Query/ConnectionConsensusState RPC method
message QueryConnectionConsensusStateRequest {
// connection identifier
string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
uint64 revision_number = 2;
uint64 revision_height = 3;
}
// QueryConnectionConsensusStateResponse is the response type for the
// Query/ConnectionConsensusState RPC method
message QueryConnectionConsensusStateResponse {
// consensus state associated with the channel
google.protobuf.Any consensus_state = 1;
// client ID associated with the consensus state
string client_id = 2;
// merkle proof of existence
bytes proof = 3;
// height at which the proof was retrieved
ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false];
}

View File

@ -1,115 +0,0 @@
syntax = "proto3";
package ibc.core.connection.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "ibc/core/client/v1/client.proto";
import "ibc/core/connection/v1/connection.proto";
// Msg defines the ibc/connection Msg service.
service Msg {
// ConnectionOpenInit defines a rpc handler method for MsgConnectionOpenInit.
rpc ConnectionOpenInit(MsgConnectionOpenInit) returns (MsgConnectionOpenInitResponse);
// ConnectionOpenTry defines a rpc handler method for MsgConnectionOpenTry.
rpc ConnectionOpenTry(MsgConnectionOpenTry) returns (MsgConnectionOpenTryResponse);
// ConnectionOpenAck defines a rpc handler method for MsgConnectionOpenAck.
rpc ConnectionOpenAck(MsgConnectionOpenAck) returns (MsgConnectionOpenAckResponse);
// ConnectionOpenConfirm defines a rpc handler method for MsgConnectionOpenConfirm.
rpc ConnectionOpenConfirm(MsgConnectionOpenConfirm) returns (MsgConnectionOpenConfirmResponse);
}
// MsgConnectionOpenInit defines the msg sent by an account on Chain A to
// initialize a connection with Chain B.
message MsgConnectionOpenInit {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
Counterparty counterparty = 2 [(gogoproto.nullable) = false];
Version version = 3;
uint64 delay_period = 4 [(gogoproto.moretags) = "yaml:\"delay_period\""];
string signer = 5;
}
// MsgConnectionOpenInitResponse defines the Msg/ConnectionOpenInit response type.
message MsgConnectionOpenInitResponse {}
// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a
// connection on Chain B.
message MsgConnectionOpenTry {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
// in the case of crossing hello's, when both chains call OpenInit, we need the connection identifier
// of the previous connection in state INIT
string previous_connection_id = 2 [(gogoproto.moretags) = "yaml:\"previous_connection_id\""];
google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""];
Counterparty counterparty = 4 [(gogoproto.nullable) = false];
uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""];
repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""];
ibc.core.client.v1.Height proof_height = 7
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
// proof of the initialization the connection on Chain A: `UNITIALIZED ->
// INIT`
bytes proof_init = 8 [(gogoproto.moretags) = "yaml:\"proof_init\""];
// proof of client state included in message
bytes proof_client = 9 [(gogoproto.moretags) = "yaml:\"proof_client\""];
// proof of client consensus state
bytes proof_consensus = 10 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 11
[(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false];
string signer = 12;
}
// MsgConnectionOpenTryResponse defines the Msg/ConnectionOpenTry response type.
message MsgConnectionOpenTryResponse {}
// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to
// acknowledge the change of connection state to TRYOPEN on Chain B.
message MsgConnectionOpenAck {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
string counterparty_connection_id = 2 [(gogoproto.moretags) = "yaml:\"counterparty_connection_id\""];
Version version = 3;
google.protobuf.Any client_state = 4 [(gogoproto.moretags) = "yaml:\"client_state\""];
ibc.core.client.v1.Height proof_height = 5
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
// proof of the initialization the connection on Chain B: `UNITIALIZED ->
// TRYOPEN`
bytes proof_try = 6 [(gogoproto.moretags) = "yaml:\"proof_try\""];
// proof of client state included in message
bytes proof_client = 7 [(gogoproto.moretags) = "yaml:\"proof_client\""];
// proof of client consensus state
bytes proof_consensus = 8 [(gogoproto.moretags) = "yaml:\"proof_consensus\""];
ibc.core.client.v1.Height consensus_height = 9
[(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false];
string signer = 10;
}
// MsgConnectionOpenAckResponse defines the Msg/ConnectionOpenAck response type.
message MsgConnectionOpenAckResponse {}
// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to
// acknowledge the change of connection state to OPEN on Chain A.
message MsgConnectionOpenConfirm {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""];
// proof for the change of the connection state on Chain A: `INIT -> OPEN`
bytes proof_ack = 2 [(gogoproto.moretags) = "yaml:\"proof_ack\""];
ibc.core.client.v1.Height proof_height = 3
[(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false];
string signer = 4;
}
// MsgConnectionOpenConfirmResponse defines the Msg/ConnectionOpenConfirm response type.
message MsgConnectionOpenConfirmResponse {}

View File

@ -1,22 +0,0 @@
syntax = "proto3";
package ibc.core.types.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/core/types";
import "gogoproto/gogo.proto";
import "ibc/core/client/v1/genesis.proto";
import "ibc/core/connection/v1/genesis.proto";
import "ibc/core/channel/v1/genesis.proto";
// GenesisState defines the ibc module's genesis state.
message GenesisState {
// ICS002 - Clients genesis state
ibc.core.client.v1.GenesisState client_genesis = 1
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_genesis\""];
// ICS003 - Connections genesis state
ibc.core.connection.v1.GenesisState connection_genesis = 2
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"connection_genesis\""];
// ICS004 - Channel genesis state
ibc.core.channel.v1.GenesisState channel_genesis = 3
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"channel_genesis\""];
}

View File

@ -1,17 +0,0 @@
syntax = "proto3";
package ibc.lightclients.localhost.v1;
import "gogoproto/gogo.proto";
import "ibc/core/client/v1/client.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/09-localhost/types";
// ClientState defines a loopback (localhost) client. It requires (read-only)
// access to keys outside the client prefix.
message ClientState {
option (gogoproto.goproto_getters) = false;
// self chain ID
string chain_id = 1 [(gogoproto.moretags) = "yaml:\"chain_id\""];
// self latest block height
ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false];
}

View File

@ -1,186 +0,0 @@
syntax = "proto3";
package ibc.lightclients.solomachine.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types";
import "ibc/core/connection/v1/connection.proto";
import "ibc/core/channel/v1/channel.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
// ClientState defines a solo machine client that tracks the current consensus
// state and if the client is frozen.
message ClientState {
option (gogoproto.goproto_getters) = false;
// latest sequence of the client state
uint64 sequence = 1;
// frozen sequence of the solo machine
uint64 frozen_sequence = 2 [(gogoproto.moretags) = "yaml:\"frozen_sequence\""];
ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
// when set to true, will allow governance to update a solo machine client.
// The client will be unfrozen if it is frozen.
bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""];
}
// ConsensusState defines a solo machine consensus state. The sequence of a consensus state
// is contained in the "height" key used in storing the consensus state.
message ConsensusState {
option (gogoproto.goproto_getters) = false;
// public key of the solo machine
google.protobuf.Any public_key = 1 [(gogoproto.moretags) = "yaml:\"public_key\""];
// diversifier allows the same public key to be re-used across different solo machine clients
// (potentially on different chains) without being considered misbehaviour.
string diversifier = 2;
uint64 timestamp = 3;
}
// Header defines a solo machine consensus header
message Header {
option (gogoproto.goproto_getters) = false;
// sequence to update solo machine public key at
uint64 sequence = 1;
uint64 timestamp = 2;
bytes signature = 3;
google.protobuf.Any new_public_key = 4 [(gogoproto.moretags) = "yaml:\"new_public_key\""];
string new_diversifier = 5 [(gogoproto.moretags) = "yaml:\"new_diversifier\""];
}
// Misbehaviour defines misbehaviour for a solo machine which consists
// of a sequence and two signatures over different messages at that sequence.
message Misbehaviour {
option (gogoproto.goproto_getters) = false;
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
uint64 sequence = 2;
SignatureAndData signature_one = 3 [(gogoproto.moretags) = "yaml:\"signature_one\""];
SignatureAndData signature_two = 4 [(gogoproto.moretags) = "yaml:\"signature_two\""];
}
// SignatureAndData contains a signature and the data signed over to create that
// signature.
message SignatureAndData {
option (gogoproto.goproto_getters) = false;
bytes signature = 1;
DataType data_type = 2 [(gogoproto.moretags) = "yaml:\"data_type\""];
bytes data = 3;
uint64 timestamp = 4;
}
// TimestampedSignatureData contains the signature data and the timestamp of the
// signature.
message TimestampedSignatureData {
option (gogoproto.goproto_getters) = false;
bytes signature_data = 1 [(gogoproto.moretags) = "yaml:\"signature_data\""];
uint64 timestamp = 2;
}
// SignBytes defines the signed bytes used for signature verification.
message SignBytes {
option (gogoproto.goproto_getters) = false;
uint64 sequence = 1;
uint64 timestamp = 2;
string diversifier = 3;
// type of the data used
DataType data_type = 4 [(gogoproto.moretags) = "yaml:\"data_type\""];
// marshaled data
bytes data = 5;
}
// DataType defines the type of solo machine proof being created. This is done to preserve uniqueness of different
// data sign byte encodings.
enum DataType {
option (gogoproto.goproto_enum_prefix) = false;
// Default State
DATA_TYPE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"];
// Data type for client state verification
DATA_TYPE_CLIENT_STATE = 1 [(gogoproto.enumvalue_customname) = "CLIENT"];
// Data type for consensus state verification
DATA_TYPE_CONSENSUS_STATE = 2 [(gogoproto.enumvalue_customname) = "CONSENSUS"];
// Data type for connection state verification
DATA_TYPE_CONNECTION_STATE = 3 [(gogoproto.enumvalue_customname) = "CONNECTION"];
// Data type for channel state verification
DATA_TYPE_CHANNEL_STATE = 4 [(gogoproto.enumvalue_customname) = "CHANNEL"];
// Data type for packet commitment verification
DATA_TYPE_PACKET_COMMITMENT = 5 [(gogoproto.enumvalue_customname) = "PACKETCOMMITMENT"];
// Data type for packet acknowledgement verification
DATA_TYPE_PACKET_ACKNOWLEDGEMENT = 6 [(gogoproto.enumvalue_customname) = "PACKETACKNOWLEDGEMENT"];
// Data type for packet receipt absence verification
DATA_TYPE_PACKET_RECEIPT_ABSENCE = 7 [(gogoproto.enumvalue_customname) = "PACKETRECEIPTABSENCE"];
// Data type for next sequence recv verification
DATA_TYPE_NEXT_SEQUENCE_RECV = 8 [(gogoproto.enumvalue_customname) = "NEXTSEQUENCERECV"];
// Data type for header verification
DATA_TYPE_HEADER = 9 [(gogoproto.enumvalue_customname) = "HEADER"];
}
// HeaderData returns the SignBytes data for update verification.
message HeaderData {
option (gogoproto.goproto_getters) = false;
// header public key
google.protobuf.Any new_pub_key = 1 [(gogoproto.moretags) = "yaml:\"new_pub_key\""];
// header diversifier
string new_diversifier = 2 [(gogoproto.moretags) = "yaml:\"new_diversifier\""];
}
// ClientStateData returns the SignBytes data for client state verification.
message ClientStateData {
option (gogoproto.goproto_getters) = false;
bytes path = 1;
google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""];
}
// ConsensusStateData returns the SignBytes data for consensus state
// verification.
message ConsensusStateData {
option (gogoproto.goproto_getters) = false;
bytes path = 1;
google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""];
}
// ConnectionStateData returns the SignBytes data for connection state
// verification.
message ConnectionStateData {
option (gogoproto.goproto_getters) = false;
bytes path = 1;
ibc.core.connection.v1.ConnectionEnd connection = 2;
}
// ChannelStateData returns the SignBytes data for channel state
// verification.
message ChannelStateData {
option (gogoproto.goproto_getters) = false;
bytes path = 1;
ibc.core.channel.v1.Channel channel = 2;
}
// PacketCommitmentData returns the SignBytes data for packet commitment
// verification.
message PacketCommitmentData {
bytes path = 1;
bytes commitment = 2;
}
// PacketAcknowledgementData returns the SignBytes data for acknowledgement
// verification.
message PacketAcknowledgementData {
bytes path = 1;
bytes acknowledgement = 2;
}
// PacketReceiptAbsenceData returns the SignBytes data for
// packet receipt absence verification.
message PacketReceiptAbsenceData {
bytes path = 1;
}
// NextSequenceRecvData returns the SignBytes data for verification of the next
// sequence to be received.
message NextSequenceRecvData {
bytes path = 1;
uint64 next_seq_recv = 2 [(gogoproto.moretags) = "yaml:\"next_seq_recv\""];
}

View File

@ -1,111 +0,0 @@
syntax = "proto3";
package ibc.lightclients.tendermint.v1;
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types";
import "tendermint/types/validator.proto";
import "tendermint/types/types.proto";
import "confio/proofs.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "ibc/core/client/v1/client.proto";
import "ibc/core/commitment/v1/commitment.proto";
import "gogoproto/gogo.proto";
// ClientState from Tendermint tracks the current validator set, latest height,
// and a possible frozen height.
message ClientState {
option (gogoproto.goproto_getters) = false;
string chain_id = 1;
Fraction trust_level = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"trust_level\""];
// duration of the period since the LastestTimestamp during which the
// submitted headers are valid for upgrade
google.protobuf.Duration trusting_period = 3
[(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"trusting_period\""];
// duration of the staking unbonding period
google.protobuf.Duration unbonding_period = 4 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.moretags) = "yaml:\"unbonding_period\""
];
// defines how much new (untrusted) header's Time can drift into the future.
google.protobuf.Duration max_clock_drift = 5
[(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"max_clock_drift\""];
// Block height when the client was frozen due to a misbehaviour
ibc.core.client.v1.Height frozen_height = 6
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"frozen_height\""];
// Latest height the client was updated to
ibc.core.client.v1.Height latest_height = 7
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"latest_height\""];
// Proof specifications used in verifying counterparty state
repeated ics23.ProofSpec proof_specs = 8 [(gogoproto.moretags) = "yaml:\"proof_specs\""];
// Path at which next upgraded client will be committed.
// Each element corresponds to the key for a single CommitmentProof in the chained proof.
// NOTE: ClientState must stored under `{upgradePath}/{upgradeHeight}/clientState`
// ConsensusState must be stored under `{upgradepath}/{upgradeHeight}/consensusState`
// For SDK chains using the default upgrade module, upgrade_path should be []string{"upgrade", "upgradedIBCState"}`
repeated string upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""];
// This flag, when set to true, will allow governance to recover a client
// which has expired
bool allow_update_after_expiry = 10 [(gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""];
// This flag, when set to true, will allow governance to unfreeze a client
// whose chain has experienced a misbehaviour event
bool allow_update_after_misbehaviour = 11 [(gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""];
}
// ConsensusState defines the consensus state from Tendermint.
message ConsensusState {
option (gogoproto.goproto_getters) = false;
// timestamp that corresponds to the block height in which the ConsensusState
// was stored.
google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true];
// commitment root (i.e app hash)
ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false];
bytes next_validators_hash = 3 [
(gogoproto.casttype) = "github.com/tendermint/tendermint/libs/bytes.HexBytes",
(gogoproto.moretags) = "yaml:\"next_validators_hash\""
];
}
// Misbehaviour is a wrapper over two conflicting Headers
// that implements Misbehaviour interface expected by ICS-02
message Misbehaviour {
option (gogoproto.goproto_getters) = false;
string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""];
Header header_1 = 2 [(gogoproto.customname) = "Header1", (gogoproto.moretags) = "yaml:\"header_1\""];
Header header_2 = 3 [(gogoproto.customname) = "Header2", (gogoproto.moretags) = "yaml:\"header_2\""];
}
// Header defines the Tendermint client consensus Header.
// It encapsulates all the information necessary to update from a trusted
// Tendermint ConsensusState. The inclusion of TrustedHeight and
// TrustedValidators allows this update to process correctly, so long as the
// ConsensusState for the TrustedHeight exists, this removes race conditions
// among relayers The SignedHeader and ValidatorSet are the new untrusted update
// fields for the client. The TrustedHeight is the height of a stored
// ConsensusState on the client that will be used to verify the new untrusted
// header. The Trusted ConsensusState must be within the unbonding period of
// current time in order to correctly verify, and the TrustedValidators must
// hash to TrustedConsensusState.NextValidatorsHash since that is the last
// trusted validator set at the TrustedHeight.
message Header {
.tendermint.types.SignedHeader signed_header = 1
[(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"signed_header\""];
.tendermint.types.ValidatorSet validator_set = 2 [(gogoproto.moretags) = "yaml:\"validator_set\""];
ibc.core.client.v1.Height trusted_height = 3
[(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"trusted_height\""];
.tendermint.types.ValidatorSet trusted_validators = 4 [(gogoproto.moretags) = "yaml:\"trusted_validators\""];
}
// Fraction defines the protobuf message type for tmmath.Fraction that only supports positive values.
message Fraction {
uint64 numerator = 1;
uint64 denominator = 2;
}

View File

@ -64,17 +64,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/gov"
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
transfer "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer"
ibctransferkeeper "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/keeper"
ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
ibc "github.com/cosmos/cosmos-sdk/x/ibc/core"
ibcclient "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client"
ibcclientclient "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/client"
ibcclienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
porttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/05-port/types"
ibchost "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/core/keeper"
ibcmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
"github.com/cosmos/cosmos-sdk/x/mint"
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
@ -121,16 +110,13 @@ var (
distr.AppModuleBasic{},
gov.NewAppModuleBasic(
paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler,
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler,
),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
slashing.AppModuleBasic{},
ibc.AppModuleBasic{},
feegrant.AppModuleBasic{},
upgrade.AppModuleBasic{},
evidence.AppModuleBasic{},
transfer.AppModuleBasic{},
authz.AppModuleBasic{},
vesting.AppModuleBasic{},
)
@ -143,7 +129,6 @@ var (
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
govtypes.ModuleName: {authtypes.Burner},
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
}
// module accounts that are allowed to receive tokens
@ -186,16 +171,9 @@ type SimApp struct {
UpgradeKeeper upgradekeeper.Keeper
ParamsKeeper paramskeeper.Keeper
AuthzKeeper authzkeeper.Keeper
IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly
EvidenceKeeper evidencekeeper.Keeper
TransferKeeper ibctransferkeeper.Keeper
FeeGrantKeeper feegrantkeeper.Keeper
// make scoped keepers public for test purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
ScopedTransferKeeper capabilitykeeper.ScopedKeeper
ScopedIBCMockKeeper capabilitykeeper.ScopedKeeper
// the module manager
mm *module.Manager
@ -234,8 +212,8 @@ func NewSimApp(
keys := sdk.NewKVStoreKeys(
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegranttypes.StoreKey,
evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegranttypes.StoreKey,
evidencetypes.StoreKey, capabilitytypes.StoreKey,
authztypes.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
@ -257,13 +235,7 @@ func NewSimApp(
// set the BaseApp's parameter store
bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramskeeper.ConsensusParamsKeyTable()))
// add capability keeper and ScopeToModule for ibc module
app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey])
scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName)
scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName)
// NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do
// note replicate if you do not need to test core IBC or light clients.
scopedIBCMockKeeper := app.CapabilityKeeper.ScopeToModule(ibcmock.ModuleName)
// add keepers
app.AccountKeeper = authkeeper.NewAccountKeeper(
@ -299,11 +271,6 @@ func NewSimApp(
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
)
// Create IBC Keeper
app.IBCKeeper = ibckeeper.NewKeeper(
appCodec, keys[ibchost.StoreKey], app.GetSubspace(ibchost.ModuleName), app.StakingKeeper, app.UpgradeKeeper, scopedIBCKeeper,
)
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authztypes.StoreKey], appCodec, app.BaseApp.MsgServiceRouter())
// register the proposal types
@ -311,31 +278,12 @@ func NewSimApp(
govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper))
app.GovKeeper = govkeeper.NewKeeper(
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
&stakingKeeper, govRouter,
)
// Create Transfer Keepers
app.TransferKeeper = ibctransferkeeper.NewKeeper(
appCodec, keys[ibctransfertypes.StoreKey], app.GetSubspace(ibctransfertypes.ModuleName),
app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper,
app.AccountKeeper, app.BankKeeper, scopedTransferKeeper,
)
transferModule := transfer.NewAppModule(app.TransferKeeper)
// NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do
// note replicate if you do not need to test core IBC or light clients.
mockModule := ibcmock.NewAppModule(scopedIBCMockKeeper)
// Create static IBC router, add transfer route, then set and seal it
ibcRouter := porttypes.NewRouter()
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule)
ibcRouter.AddRoute(ibcmock.ModuleName, mockModule)
app.IBCKeeper.SetRouter(ibcRouter)
// create evidence keeper with router
evidenceKeeper := evidencekeeper.NewKeeper(
appCodec, keys[evidencetypes.StoreKey], &app.StakingKeeper, app.SlashingKeeper,
@ -369,10 +317,8 @@ func NewSimApp(
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
upgrade.NewAppModule(app.UpgradeKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
ibc.NewAppModule(app.IBCKeeper),
params.NewAppModule(app.ParamsKeeper),
authz.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
transferModule,
)
// During begin block slashing happens after distr.BeginBlocker so that
@ -381,7 +327,7 @@ func NewSimApp(
// NOTE: staking module is required if HistoricalEntries param > 0
app.mm.SetOrderBeginBlockers(
upgradetypes.ModuleName, minttypes.ModuleName, distrtypes.ModuleName, slashingtypes.ModuleName,
evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName,
evidencetypes.ModuleName, stakingtypes.ModuleName,
)
app.mm.SetOrderEndBlockers(crisistypes.ModuleName, govtypes.ModuleName, stakingtypes.ModuleName)
@ -393,7 +339,7 @@ func NewSimApp(
app.mm.SetOrderInitGenesis(
capabilitytypes.ModuleName, authtypes.ModuleName, banktypes.ModuleName, distrtypes.ModuleName, stakingtypes.ModuleName,
slashingtypes.ModuleName, govtypes.ModuleName, minttypes.ModuleName, crisistypes.ModuleName,
ibchost.ModuleName, genutiltypes.ModuleName, evidencetypes.ModuleName, authztypes.ModuleName, ibctransfertypes.ModuleName,
genutiltypes.ModuleName, evidencetypes.ModuleName, authztypes.ModuleName,
feegranttypes.ModuleName,
)
@ -422,8 +368,6 @@ func NewSimApp(
params.NewAppModule(app.ParamsKeeper),
evidence.NewAppModule(app.EvidenceKeeper),
authz.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
ibc.NewAppModule(app.IBCKeeper),
transferModule,
)
app.sm.RegisterStoreDecoders()
@ -460,13 +404,6 @@ func NewSimApp(
app.CapabilityKeeper.InitializeAndSeal(ctx)
}
app.ScopedIBCKeeper = scopedIBCKeeper
app.ScopedTransferKeeper = scopedTransferKeeper
// NOTE: the IBC mock keeper and application module is used only for testing core IBC. Do
// note replicate if you do not need to test core IBC or light clients.
app.ScopedIBCMockKeeper = scopedIBCMockKeeper
return app
}
@ -659,8 +596,6 @@ func initParamsKeeper(appCodec codec.BinaryMarshaler, legacyAmino *codec.LegacyA
paramsKeeper.Subspace(slashingtypes.ModuleName)
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable())
paramsKeeper.Subspace(crisistypes.ModuleName)
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
paramsKeeper.Subspace(ibchost.ModuleName)
return paramsKeeper
}

View File

@ -25,8 +25,6 @@ import (
feegrant "github.com/cosmos/cosmos-sdk/x/feegrant"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
transfer "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer"
ibc "github.com/cosmos/cosmos-sdk/x/ibc/core"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
@ -171,11 +169,9 @@ func TestRunMigrations(t *testing.T) {
"slashing": slashing.AppModule{}.ConsensusVersion(),
"gov": gov.AppModule{}.ConsensusVersion(),
"params": params.AppModule{}.ConsensusVersion(),
"ibc": ibc.AppModule{}.ConsensusVersion(),
"upgrade": upgrade.AppModule{}.ConsensusVersion(),
"vesting": vesting.AppModule{}.ConsensusVersion(),
"feegrant": feegrant.AppModule{}.ConsensusVersion(),
"transfer": transfer.AppModule{}.ConsensusVersion(),
"evidence": evidence.AppModule{}.ConsensusVersion(),
"crisis": crisis.AppModule{}.ConsensusVersion(),
"genutil": genutil.AppModule{}.ConsensusVersion(),

View File

@ -25,8 +25,6 @@ import (
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
ibchost "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cosmos/cosmos-sdk/x/simulation"
@ -176,8 +174,6 @@ func TestAppImportExport(t *testing.T) {
{app.keys[govtypes.StoreKey], newApp.keys[govtypes.StoreKey], [][]byte{}},
{app.keys[evidencetypes.StoreKey], newApp.keys[evidencetypes.StoreKey], [][]byte{}},
{app.keys[capabilitytypes.StoreKey], newApp.keys[capabilitytypes.StoreKey], [][]byte{}},
{app.keys[ibchost.StoreKey], newApp.keys[ibchost.StoreKey], [][]byte{}},
{app.keys[ibctransfertypes.StoreKey], newApp.keys[ibctransfertypes.StoreKey], [][]byte{}},
{app.keys[authztypes.StoreKey], newApp.keys[authztypes.StoreKey], [][]byte{}},
}

View File

@ -15,8 +15,6 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio
- [Distribution](distribution/spec/README.md) - Fee distribution, and staking token provision distribution.
- [Evidence](evidence/spec/README.md) - Evidence handling for double signing, misbehaviour, etc.
- [Governance](gov/spec/README.md) - On-chain proposals and voting.
- [IBC](ibc/spec/README.md) - IBC protocol for transport, authentication and ordering.
- [IBC Transfer](ibc/spec/README.md) - Cross-chain fungible token transfer implementation through IBC.
- [Mint](mint/spec/README.md) - Creation of new units of staking token.
- [Params](params/spec/README.md) - Globally available parameter store.
- [Slashing](slashing/spec/README.md) - Validator punishment mechanisms.
@ -24,3 +22,7 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio
- [Upgrade](upgrade/spec/README.md) - Software upgrades handling and coordination.
To learn more about the process of building modules, visit the [building modules reference documentation](../docs/building-modules/README.md).
## IBC
The IBC module for the SDK has moved to its [own repository](https://github.com/cosmos/ibc-go).

View File

@ -482,7 +482,8 @@ func (suite *AnteTestSuite) TestAnteHandlerFees() {
{
"signer as enough funds, should pass",
func() {
accNums = []uint64{7}
accNums = []uint64{acc1.GetAccountNumber()}
modAcc := suite.app.AccountKeeper.GetModuleAccount(suite.ctx, types.FeeCollectorName)
suite.Require().True(suite.app.BankKeeper.GetAllBalances(suite.ctx, modAcc.GetAddress()).Empty())
@ -511,6 +512,7 @@ func (suite *AnteTestSuite) TestAnteHandlerFees() {
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.desc), func() {
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
tc.malleate()

View File

@ -29,8 +29,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/cosmos/cosmos-sdk/x/bank/types"
ibcclientcli "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/client/cli"
ibccli "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/client/cli"
)
type IntegrationTestSuite struct {
@ -98,45 +96,6 @@ func mkStdTx() legacytx.StdTx {
}
}
// Create an IBC tx that's encoded as amino-JSON. Since we can't amino-marshal
// a tx with "cosmos-sdk/MsgTransfer" using the SDK, we just hardcode the tx
// here. But external clients might, see https://github.com/cosmos/cosmos-sdk/issues/8022.
func mkIBCStdTx() []byte {
ibcTx := `{
"account_number": "68",
"chain_id": "stargate-4",
"fee": {
"amount": [
{
"amount": "3500",
"denom": "umuon"
}
],
"gas": "350000"
},
"memo": "",
"msg": [
{
"type": "cosmos-sdk/MsgTransfer",
"value": {
"receiver": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z",
"sender": "cosmos1q9wtnlwdjrhwtcjmt2uq77jrgx7z3usrq2yz7z",
"source_channel": "THEslipperCHANNEL",
"source_port": "transfer",
"token": {
"amount": "1000000",
"denom": "umuon"
}
}
}
],
"sequence": "24"
}`
req := fmt.Sprintf(`{"tx":%s,"mode":"async"}`, ibcTx)
return []byte(req)
}
func (s *IntegrationTestSuite) TestEncodeDecode() {
var require = s.Require()
val := s.network.Validators[0]
@ -182,16 +141,6 @@ func (s *IntegrationTestSuite) TestQueryAccountWithColon() {
s.Require().Contains(string(res), "decoding bech32 failed")
}
func (s *IntegrationTestSuite) TestEncodeIBCTx() {
val := s.network.Validators[0]
req := mkIBCStdTx()
res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", []byte(req))
s.Require().NoError(err)
s.Require().Contains(string(res), authrest.ErrEncodeDecode.Error())
}
func (s *IntegrationTestSuite) TestBroadcastTxRequest() {
stdTx := mkStdTx()
@ -205,16 +154,6 @@ func (s *IntegrationTestSuite) TestBroadcastTxRequest() {
s.Require().NotEmpty(txRes.TxHash)
}
func (s *IntegrationTestSuite) TestBroadcastIBCTxRequest() {
val := s.network.Validators[0]
req := mkIBCStdTx()
res, err := rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", []byte(req))
s.Require().NoError(err)
s.Require().NotContains(string(res), "this transaction cannot be broadcasted via legacy REST endpoints", string(res))
}
// Helper function to test querying txs. We will use it to query StdTx and service `Msg`s.
func (s *IntegrationTestSuite) testQueryTx(txHeight int64, txHash, txRecipient string) {
val0 := s.network.Validators[0]
@ -497,83 +436,6 @@ func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.C
s.Require().Contains(errResp.Error, errMsg)
}
// TestLegacyRestErrMessages creates two IBC txs, one that fails, one that
// succeeds, and make sure we cannot query any of them (with pretty error msg).
// Our intension is to test the error message of querying a message which is
// signed with proto, since IBC won't support legacy amino at all we are
// considering a message from IBC module.
func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
val := s.network.Validators[0]
// Write client state json to temp file, used for an IBC message.
// Generated by printing the result of cdc.MarshalIntefaceJSON on
// a solo machine client state
clientStateJSON := testutil.WriteToNewTempFile(
s.T(),
`{"@type":"/ibc.lightclients.solomachine.v1.ClientState","sequence":"1","frozen_sequence":"0","consensus_state":{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"},"allow_update_after_proposal":false}`,
)
// Write consensus json to temp file, used for an IBC message.
// Generated by printing the result of cdc.MarshalIntefaceJSON on
// a solo machine consensus state
consensusJSON := testutil.WriteToNewTempFile(
s.T(),
`{"@type":"/ibc.lightclients.solomachine.v1.ConsensusState","public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"}`,
)
testCases := []struct {
desc string
cmd *cobra.Command
args []string
code uint32
}{
{
"Failing IBC message",
ibccli.NewChannelCloseInitCmd(),
[]string{
"121", // dummy port-id
"channel-0", // dummy channel-id
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
},
uint32(7),
},
{
"Successful IBC message",
ibcclientcli.NewCreateClientCmd(),
[]string{
clientStateJSON.Name(), // path to client state json
consensusJSON.Name(), // path to consensus json,
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--gas=%d", flags.DefaultGasLimit),
fmt.Sprintf("--%s=%s", flags.FlagFrom, val.Address.String()),
fmt.Sprintf("--%s=foobar", flags.FlagMemo),
},
uint32(0),
},
}
for _, tc := range testCases {
s.Run(fmt.Sprintf("Case %s", tc.desc), func() {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, tc.cmd, tc.args)
s.Require().NoError(err)
var txRes sdk.TxResponse
s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes))
s.Require().Equal(tc.code, txRes.Code)
s.Require().NoError(s.network.WaitForNextBlock())
s.testQueryIBCTx(txRes, tc.cmd, tc.args)
})
}
}
// TestLegacyMultiSig creates a legacy multisig transaction, and makes sure
// we can query it via the legacy REST endpoint.
// ref: https://github.com/cosmos/cosmos-sdk/issues/8679

View File

@ -114,16 +114,6 @@ func (suite *KeeperTestSuite) TestNewCapability() {
suite.Require().Nil(cap)
}
func (suite *KeeperTestSuite) TestOriginalCapabilityKeeper() {
got, ok := suite.app.ScopedIBCKeeper.GetCapability(suite.ctx, "invalid")
suite.Require().False(ok)
suite.Require().Nil(got)
port, ok := suite.app.ScopedIBCKeeper.GetCapability(suite.ctx, "ports/transfer")
suite.Require().True(ok)
suite.Require().NotNil(port)
}
func (suite *KeeperTestSuite) TestAuthenticateCapability() {
sk1 := suite.keeper.ScopeToModule(banktypes.ModuleName)
sk2 := suite.keeper.ScopeToModule(stakingtypes.ModuleName)

View File

@ -1,42 +0,0 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
)
// GetQueryCmd returns the query commands for IBC connections
func GetQueryCmd() *cobra.Command {
queryCmd := &cobra.Command{
Use: "ibc-transfer",
Short: "IBC fungible token transfer query subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}
queryCmd.AddCommand(
GetCmdQueryDenomTrace(),
GetCmdQueryDenomTraces(),
GetCmdParams(),
)
return queryCmd
}
// NewTxCmd returns the transaction commands for IBC fungible token transfer
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: "ibc-transfer",
Short: "IBC fungible token transfer transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
NewTransferTxCmd(),
)
return txCmd
}

View File

@ -1,108 +0,0 @@
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/ibc/applications/transfer/types"
)
// GetCmdQueryDenomTrace defines the command to query a a denomination trace from a given hash.
func GetCmdQueryDenomTrace() *cobra.Command {
cmd := &cobra.Command{
Use: "denom-trace [hash]",
Short: "Query the denom trace info from a given trace hash",
Long: "Query the denom trace info from a given trace hash",
Example: fmt.Sprintf("%s query ibc-transfer denom-trace [hash]", version.AppName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
req := &types.QueryDenomTraceRequest{
Hash: args[0],
}
res, err := queryClient.DenomTrace(cmd.Context(), req)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryDenomTraces defines the command to query all the denomination trace infos
// that this chain mantains.
func GetCmdQueryDenomTraces() *cobra.Command {
cmd := &cobra.Command{
Use: "denom-traces",
Short: "Query the trace info for all token denominations",
Long: "Query the trace info for all token denominations",
Example: fmt.Sprintf("%s query ibc-transfer denom-traces", version.AppName),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
req := &types.QueryDenomTracesRequest{
Pagination: pageReq,
}
res, err := queryClient.DenomTraces(cmd.Context(), req)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "denominations trace")
return cmd
}
// GetCmdParams returns the command handler for ibc-transfer parameter querying.
func GetCmdParams() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Short: "Query the current ibc-transfer parameters",
Long: "Query the current ibc-transfer parameters",
Args: cobra.NoArgs,
Example: fmt.Sprintf("%s query ibc-transfer params", version.AppName),
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, _ := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{})
return clientCtx.PrintProto(res.Params)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

View File

@ -1,117 +0,0 @@
package cli
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
channelutils "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/client/utils"
)
const (
flagPacketTimeoutHeight = "packet-timeout-height"
flagPacketTimeoutTimestamp = "packet-timeout-timestamp"
flagAbsoluteTimeouts = "absolute-timeouts"
)
// NewTransferTxCmd returns the command to create a NewMsgTransfer transaction
func NewTransferTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "transfer [src-port] [src-channel] [receiver] [amount]",
Short: "Transfer a fungible token through IBC",
Long: strings.TrimSpace(`Transfer a fungible token through IBC. Timeouts can be specified
as absolute or relative using the "absolute-timeouts" flag. Timeout height can be set by passing in the height string
in the form {revision}-{height} using the "packet-timeout-height" flag. Relative timeouts are added to
the block height and block timestamp queried from the latest consensus state corresponding
to the counterparty channel. Any timeout set to 0 is disabled.`),
Example: fmt.Sprintf("%s tx ibc-transfer transfer [src-port] [src-channel] [receiver] [amount]", version.AppName),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
sender := clientCtx.GetFromAddress()
srcPort := args[0]
srcChannel := args[1]
receiver := args[2]
coin, err := sdk.ParseCoinNormalized(args[3])
if err != nil {
return err
}
if !strings.HasPrefix(coin.Denom, "ibc/") {
denomTrace := types.ParseDenomTrace(coin.Denom)
coin.Denom = denomTrace.IBCDenom()
}
timeoutHeightStr, err := cmd.Flags().GetString(flagPacketTimeoutHeight)
if err != nil {
return err
}
timeoutHeight, err := clienttypes.ParseHeight(timeoutHeightStr)
if err != nil {
return err
}
timeoutTimestamp, err := cmd.Flags().GetUint64(flagPacketTimeoutTimestamp)
if err != nil {
return err
}
absoluteTimeouts, err := cmd.Flags().GetBool(flagAbsoluteTimeouts)
if err != nil {
return err
}
// if the timeouts are not absolute, retrieve latest block height and block timestamp
// for the consensus state connected to the destination port/channel
if !absoluteTimeouts {
consensusState, height, _, err := channelutils.QueryLatestConsensusState(clientCtx, srcPort, srcChannel)
if err != nil {
return err
}
if !timeoutHeight.IsZero() {
absoluteHeight := height
absoluteHeight.RevisionNumber += timeoutHeight.RevisionNumber
absoluteHeight.RevisionHeight += timeoutHeight.RevisionHeight
timeoutHeight = absoluteHeight
}
if timeoutTimestamp != 0 {
timeoutTimestamp = consensusState.GetTimestamp() + timeoutTimestamp
}
}
msg := types.NewMsgTransfer(
srcPort, srcChannel, coin, sender, receiver, timeoutHeight, timeoutTimestamp,
)
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
msgClient := types.NewMsgClient(svcMsgClientConn)
_, err = msgClient.Transfer(cmd.Context(), msg)
if err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), svcMsgClientConn.GetMsgs()...)
},
}
cmd.Flags().String(flagPacketTimeoutHeight, types.DefaultRelativePacketTimeoutHeight, "Packet timeout block height. The timeout is disabled when set to 0-0.")
cmd.Flags().Uint64(flagPacketTimeoutTimestamp, types.DefaultRelativePacketTimeoutTimestamp, "Packet timeout timestamp in nanoseconds. Default is 10 minutes. The timeout is disabled when set to 0.")
cmd.Flags().Bool(flagAbsoluteTimeouts, false, "Timeout flags are used as absolute timeouts.")
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -1,23 +0,0 @@
package transfer
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// NewHandler returns sdk.Handler for IBC token transfer module messages
func NewHandler(k types.MsgServer) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case *types.MsgTransfer:
res, err := k.Transfer(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ICS-20 transfer message type: %T", msg)
}
}
}

View File

@ -1,123 +0,0 @@
package transfer_test
import (
"testing"
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
type TransferTestSuite struct {
suite.Suite
coordinator *ibctesting.Coordinator
// testing chains used for convenience and readability
chainA *ibctesting.TestChain
chainB *ibctesting.TestChain
chainC *ibctesting.TestChain
}
func (suite *TransferTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
}
// constructs a send from chainA to chainB on the established channel/connection
// and sends the same coin back from chainB to chainA.
func (suite *TransferTestSuite) TestHandleMsgTransfer() {
// setup between chainA and chainB
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB := suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
// originalBalance := suite.chainA.App.BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), sdk.DefaultBondDenom)
timeoutHeight := clienttypes.NewHeight(0, 110)
coinToSendToB := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
// send from chainA to chainB
msg := types.NewMsgTransfer(channelA.PortID, channelA.ID, coinToSendToB, suite.chainA.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0)
err := suite.coordinator.SendMsg(suite.chainA, suite.chainB, clientB, msg)
suite.Require().NoError(err) // message committed
// relay send
fungibleTokenPacket := types.NewFungibleTokenPacketData(coinToSendToB.Denom, coinToSendToB.Amount.Uint64(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, 0)
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
err = suite.coordinator.RelayPacket(suite.chainA, suite.chainB, clientA, clientB, packet, ack.GetBytes())
suite.Require().NoError(err) // relay committed
// check that voucher exists on chain B
voucherDenomTrace := types.ParseDenomTrace(types.GetPrefixedDenom(packet.GetDestPort(), packet.GetDestChannel(), sdk.DefaultBondDenom))
balance := suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())
coinSentFromAToB := types.GetTransferCoin(channelB.PortID, channelB.ID, sdk.DefaultBondDenom, 100)
suite.Require().Equal(coinSentFromAToB, balance)
// setup between chainB to chainC
clientOnBForC, clientOnCForB, connOnBForC, connOnCForB := suite.coordinator.SetupClientConnections(suite.chainB, suite.chainC, exported.Tendermint)
channelOnBForC, channelOnCForB := suite.coordinator.CreateTransferChannels(suite.chainB, suite.chainC, connOnBForC, connOnCForB, channeltypes.UNORDERED)
// send from chainB to chainC
msg = types.NewMsgTransfer(channelOnBForC.PortID, channelOnBForC.ID, coinSentFromAToB, suite.chainB.SenderAccount.GetAddress(), suite.chainC.SenderAccount.GetAddress().String(), timeoutHeight, 0)
err = suite.coordinator.SendMsg(suite.chainB, suite.chainC, clientOnCForB, msg)
suite.Require().NoError(err) // message committed
// relay send
// NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment
fullDenomPath := types.GetPrefixedDenom(channelOnCForB.PortID, channelOnCForB.ID, voucherDenomTrace.GetFullDenomPath())
fungibleTokenPacket = types.NewFungibleTokenPacketData(voucherDenomTrace.GetFullDenomPath(), coinSentFromAToB.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainC.SenderAccount.GetAddress().String())
packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, channelOnBForC.PortID, channelOnBForC.ID, channelOnCForB.PortID, channelOnCForB.ID, timeoutHeight, 0)
err = suite.coordinator.RelayPacket(suite.chainB, suite.chainC, clientOnBForC, clientOnCForB, packet, ack.GetBytes())
suite.Require().NoError(err) // relay committed
coinSentFromBToC := sdk.NewInt64Coin(types.ParseDenomTrace(fullDenomPath).IBCDenom(), 100)
balance = suite.chainC.App.BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccount.GetAddress(), coinSentFromBToC.Denom)
// check that the balance is updated on chainC
suite.Require().Equal(coinSentFromBToC, balance)
// check that balance on chain B is empty
balance = suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), coinSentFromBToC.Denom)
suite.Require().Zero(balance.Amount.Int64())
// send from chainC back to chainB
msg = types.NewMsgTransfer(channelOnCForB.PortID, channelOnCForB.ID, coinSentFromBToC, suite.chainC.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress().String(), timeoutHeight, 0)
err = suite.coordinator.SendMsg(suite.chainC, suite.chainB, clientOnBForC, msg)
suite.Require().NoError(err) // message committed
// relay send
// NOTE: fungible token is prefixed with the full trace in order to verify the packet commitment
fungibleTokenPacket = types.NewFungibleTokenPacketData(fullDenomPath, coinSentFromBToC.Amount.Uint64(), suite.chainC.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet = channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, channelOnCForB.PortID, channelOnCForB.ID, channelOnBForC.PortID, channelOnBForC.ID, timeoutHeight, 0)
err = suite.coordinator.RelayPacket(suite.chainC, suite.chainB, clientOnCForB, clientOnBForC, packet, ack.GetBytes())
suite.Require().NoError(err) // relay committed
balance = suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), suite.chainB.SenderAccount.GetAddress(), coinSentFromAToB.Denom)
// check that the balance on chainA returned back to the original state
suite.Require().Equal(coinSentFromAToB, balance)
// check that module account escrow address is empty
escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel())
balance = suite.chainB.App.BankKeeper.GetBalance(suite.chainB.GetContext(), escrowAddress, sdk.DefaultBondDenom)
suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, sdk.ZeroInt()), balance)
// check that balance on chain B is empty
balance = suite.chainC.App.BankKeeper.GetBalance(suite.chainC.GetContext(), suite.chainC.SenderAccount.GetAddress(), voucherDenomTrace.IBCDenom())
suite.Require().Zero(balance.Amount.Int64())
}
func TestTransferTestSuite(t *testing.T) {
suite.Run(t, new(TransferTestSuite))
}

View File

@ -1,51 +0,0 @@
## Token Transfer Model-based Testing Guide
In the process of IBC Audit performed by Informal Systems, we have implemented
a preliminary set of model-based tests for the ICS-20 Token Transfer implementation.
Model-based tests are based on the formal `TLA+` model of the Token transfer relay functions: see [relay.tla](relay_model/relay.tla).
The tests themselves are simple `TLA+` assertions, that describe the desired shape of execution that send or receive tokens;
see [relay_tests.tla](relay_model/relay_tests.tla) for some examples.
To be able to specify test assertions the TLA+ model contains the `history` variable,
which records the whole execution history.
So, by way of referring to `history` you simply specify declaratively what execution history you want to see.
After you have specified your `TLA+` test, you can run it using [Apalache model checker](https://github.com/informalsystems/apalache).
E.g. for the test `TestUnescrowTokens` run
```bash
apalache-mc check --inv=TestUnescrowTokensInv relay_tests.tla
```
In case there are no error in the TLA+ model or in the test assertions, this will produce a couple of so-called _counterexamples_.
This is a terminology from the model-checking community; for the testing purposes they can be considered simply as model executions.
See the files `counterexample.tla` for human-readable representation, and `counterexample.json` for machine-readable one.
In order to execute the produced test, you need to translate it into another format.
For that translation you need the tool [Jsonatr (JSON Arrifact Translator)](https://github.com/informalsystems/jsonatr).
It performs the translation using this [transformation spec](relay_model/apalache-to-relay-test2.json);
To transform a counterexample into a test, run
```bash
jsonatr --use apalache-to-relay-test2.json --in counterexample.json --out model_based_tests/YourTestName.json
```
Now, if you run `go test` in this directory, the file you have produced above should be picked up by the [model-based test driver](mbt_relay_test.go),
and executed automatically.
The easiest way to run Apalache is by
[using a Docker image](https://github.com/informalsystems/apalache/blob/master/docs/manual.md#useDocker);
to run Jsonatr you need to locally clone the repository, and then,
after building it, add the `target/debug` directory into your `PATH`.
To wrap Apalache docker image into an executable you might create the following executable bash script `apalache-mc`:
```bash
#!/bin/bash
docker run --rm -v $(pwd):/var/apalache apalache/mc $@
```
In case of any questions please don't hesitate to contact Andrey Kuprianov (andrey@informal.systems).

View File

@ -1,35 +0,0 @@
package keeper
import (
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// UnmarshalDenomTrace attempts to decode and return an DenomTrace object from
// raw encoded bytes.
func (k Keeper) UnmarshalDenomTrace(bz []byte) (types.DenomTrace, error) {
var denomTrace types.DenomTrace
if err := k.cdc.UnmarshalBinaryBare(bz, &denomTrace); err != nil {
return types.DenomTrace{}, err
}
return denomTrace, nil
}
// MustUnmarshalDenomTrace attempts to decode and return an DenomTrace object from
// raw encoded bytes. It panics on error.
func (k Keeper) MustUnmarshalDenomTrace(bz []byte) types.DenomTrace {
var denomTrace types.DenomTrace
k.cdc.MustUnmarshalBinaryBare(bz, &denomTrace)
return denomTrace
}
// MarshalDenomTrace attempts to encode an DenomTrace object and returns the
// raw encoded bytes.
func (k Keeper) MarshalDenomTrace(denomTrace types.DenomTrace) ([]byte, error) {
return k.cdc.MarshalBinaryBare(&denomTrace)
}
// MustMarshalDenomTrace attempts to encode an DenomTrace object and returns the
// raw encoded bytes. It panics on error.
func (k Keeper) MustMarshalDenomTrace(denomTrace types.DenomTrace) []byte {
return k.cdc.MustMarshalBinaryBare(&denomTrace)
}

View File

@ -1,45 +0,0 @@
package keeper
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// InitGenesis initializes the ibc-transfer state and binds to PortID.
func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) {
k.SetPort(ctx, state.PortId)
for _, trace := range state.DenomTraces {
k.SetDenomTrace(ctx, trace)
}
// Only try to bind to port if it is not already bound, since we may already own
// port capability from capability InitGenesis
if !k.IsBound(ctx, state.PortId) {
// transfer module binds to the transfer port on InitChain
// and claims the returned capability
err := k.BindPort(ctx, state.PortId)
if err != nil {
panic(fmt.Sprintf("could not claim port capability: %v", err))
}
}
k.SetParams(ctx, state.Params)
// check if the module account exists
moduleAcc := k.GetTransferAccount(ctx)
if moduleAcc == nil {
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
}
}
// ExportGenesis exports ibc-transfer module's portID and denom trace info into its genesis state.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
return &types.GenesisState{
PortId: k.GetPort(ctx),
DenomTraces: k.GetAllDenomTraces(ctx),
Params: k.GetParams(ctx),
}
}

View File

@ -1,39 +0,0 @@
package keeper_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
func (suite *KeeperTestSuite) TestGenesis() {
var (
path string
traces types.Traces
)
for i := 0; i < 5; i++ {
prefix := fmt.Sprintf("transfer/channelToChain%d", i)
if i == 0 {
path = prefix
} else {
path = prefix + "/" + path
}
denomTrace := types.DenomTrace{
BaseDenom: "uatom",
Path: path,
}
traces = append(types.Traces{denomTrace}, traces...)
suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), denomTrace)
}
genesis := suite.chainA.App.TransferKeeper.ExportGenesis(suite.chainA.GetContext())
suite.Require().Equal(types.PortID, genesis.PortId)
suite.Require().Equal(traces.Sort(), genesis.DenomTraces)
suite.Require().NotPanics(func() {
suite.chainA.App.TransferKeeper.InitGenesis(suite.chainA.GetContext(), *genesis)
})
}

View File

@ -1,83 +0,0 @@
package keeper
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
var _ types.QueryServer = Keeper{}
// DenomTrace implements the Query/DenomTrace gRPC method
func (q Keeper) DenomTrace(c context.Context, req *types.QueryDenomTraceRequest) (*types.QueryDenomTraceResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
hash, err := types.ParseHexHash(req.Hash)
if err != nil {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid denom trace hash %s, %s", req.Hash, err))
}
ctx := sdk.UnwrapSDKContext(c)
denomTrace, found := q.GetDenomTrace(ctx, hash)
if !found {
return nil, status.Error(
codes.NotFound,
sdkerrors.Wrap(types.ErrTraceNotFound, req.Hash).Error(),
)
}
return &types.QueryDenomTraceResponse{
DenomTrace: &denomTrace,
}, nil
}
// DenomTraces implements the Query/DenomTraces gRPC method
func (q Keeper) DenomTraces(c context.Context, req *types.QueryDenomTracesRequest) (*types.QueryDenomTracesResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
traces := types.Traces{}
store := prefix.NewStore(ctx.KVStore(q.storeKey), types.DenomTraceKey)
pageRes, err := query.Paginate(store, req.Pagination, func(_, value []byte) error {
result, err := q.UnmarshalDenomTrace(value)
if err != nil {
return err
}
traces = append(traces, result)
return nil
})
if err != nil {
return nil, err
}
return &types.QueryDenomTracesResponse{
DenomTraces: traces.Sort(),
Pagination: pageRes,
}, nil
}
// Params implements the Query/Params gRPC method
func (q Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
params := q.GetParams(ctx)
return &types.QueryParamsResponse{
Params: &params,
}, nil
}

View File

@ -1,142 +0,0 @@
package keeper_test
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
func (suite *KeeperTestSuite) TestQueryDenomTrace() {
var (
req *types.QueryDenomTraceRequest
expTrace types.DenomTrace
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"invalid hex hash",
func() {
req = &types.QueryDenomTraceRequest{
Hash: "!@#!@#!",
}
},
false,
},
{
"not found denom trace",
func() {
expTrace.Path = "transfer/channelToA/transfer/channelToB"
expTrace.BaseDenom = "uatom"
req = &types.QueryDenomTraceRequest{
Hash: expTrace.Hash().String(),
}
},
false,
},
{
"success",
func() {
expTrace.Path = "transfer/channelToA/transfer/channelToB"
expTrace.BaseDenom = "uatom"
suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), expTrace)
req = &types.QueryDenomTraceRequest{
Hash: expTrace.Hash().String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.chainA.GetContext())
res, err := suite.queryClient.DenomTrace(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(&expTrace, res.DenomTrace)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryDenomTraces() {
var (
req *types.QueryDenomTracesRequest
expTraces = types.Traces(nil)
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty pagination",
func() {
req = &types.QueryDenomTracesRequest{}
},
true,
},
{
"success",
func() {
expTraces = append(expTraces, types.DenomTrace{Path: "", BaseDenom: "uatom"})
expTraces = append(expTraces, types.DenomTrace{Path: "transfer/channelToB", BaseDenom: "uatom"})
expTraces = append(expTraces, types.DenomTrace{Path: "transfer/channelToA/transfer/channelToB", BaseDenom: "uatom"})
for _, trace := range expTraces {
suite.chainA.App.TransferKeeper.SetDenomTrace(suite.chainA.GetContext(), trace)
}
req = &types.QueryDenomTracesRequest{
Pagination: &query.PageRequest{
Limit: 5,
CountTotal: false,
},
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.chainA.GetContext())
res, err := suite.queryClient.DenomTraces(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expTraces.Sort(), res.DenomTraces)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryParams() {
ctx := sdk.WrapSDKContext(suite.chainA.GetContext())
expParams := types.DefaultParams()
res, _ := suite.queryClient.Params(ctx, &types.QueryParamsRequest{})
suite.Require().Equal(&expParams, res.Params)
}

View File

@ -1,169 +0,0 @@
package keeper
import (
tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)
// Keeper defines the IBC fungible transfer keeper
type Keeper struct {
storeKey sdk.StoreKey
cdc codec.BinaryMarshaler
paramSpace paramtypes.Subspace
channelKeeper types.ChannelKeeper
portKeeper types.PortKeeper
authKeeper types.AccountKeeper
bankKeeper types.BankKeeper
scopedKeeper capabilitykeeper.ScopedKeeper
}
// NewKeeper creates a new IBC transfer Keeper instance
func NewKeeper(
cdc codec.BinaryMarshaler, key sdk.StoreKey, paramSpace paramtypes.Subspace,
channelKeeper types.ChannelKeeper, portKeeper types.PortKeeper,
authKeeper types.AccountKeeper, bankKeeper types.BankKeeper, scopedKeeper capabilitykeeper.ScopedKeeper,
) Keeper {
// ensure ibc transfer module account is set
if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil {
panic("the IBC transfer module account has not been set")
}
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
}
return Keeper{
cdc: cdc,
storeKey: key,
paramSpace: paramSpace,
channelKeeper: channelKeeper,
portKeeper: portKeeper,
authKeeper: authKeeper,
bankKeeper: bankKeeper,
scopedKeeper: scopedKeeper,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", "x/"+host.ModuleName+"-"+types.ModuleName)
}
// GetTransferAccount returns the ICS20 - transfers ModuleAccount
func (k Keeper) GetTransferAccount(ctx sdk.Context) authtypes.ModuleAccountI {
return k.authKeeper.GetModuleAccount(ctx, types.ModuleName)
}
// ChanCloseInit defines a wrapper function for the channel Keeper's function
// in order to expose it to the ICS20 transfer handler.
func (k Keeper) ChanCloseInit(ctx sdk.Context, portID, channelID string) error {
capName := host.ChannelCapabilityPath(portID, channelID)
chanCap, ok := k.scopedKeeper.GetCapability(ctx, capName)
if !ok {
return sdkerrors.Wrapf(channeltypes.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName)
}
return k.channelKeeper.ChanCloseInit(ctx, portID, channelID, chanCap)
}
// IsBound checks if the transfer module is already bound to the desired port
func (k Keeper) IsBound(ctx sdk.Context, portID string) bool {
_, ok := k.scopedKeeper.GetCapability(ctx, host.PortPath(portID))
return ok
}
// BindPort defines a wrapper function for the ort Keeper's function in
// order to expose it to module's InitGenesis function
func (k Keeper) BindPort(ctx sdk.Context, portID string) error {
cap := k.portKeeper.BindPort(ctx, portID)
return k.ClaimCapability(ctx, cap, host.PortPath(portID))
}
// GetPort returns the portID for the transfer module. Used in ExportGenesis
func (k Keeper) GetPort(ctx sdk.Context) string {
store := ctx.KVStore(k.storeKey)
return string(store.Get(types.PortKey))
}
// SetPort sets the portID for the transfer module. Used in InitGenesis
func (k Keeper) SetPort(ctx sdk.Context, portID string) {
store := ctx.KVStore(k.storeKey)
store.Set(types.PortKey, []byte(portID))
}
// GetDenomTrace retreives the full identifiers trace and base denomination from the store.
func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) (types.DenomTrace, bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey)
bz := store.Get(denomTraceHash)
if bz == nil {
return types.DenomTrace{}, false
}
denomTrace := k.MustUnmarshalDenomTrace(bz)
return denomTrace, true
}
// HasDenomTrace checks if a the key with the given denomination trace hash exists on the store.
func (k Keeper) HasDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) bool {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey)
return store.Has(denomTraceHash)
}
// SetDenomTrace sets a new {trace hash -> denom trace} pair to the store.
func (k Keeper) SetDenomTrace(ctx sdk.Context, denomTrace types.DenomTrace) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey)
bz := k.MustMarshalDenomTrace(denomTrace)
store.Set(denomTrace.Hash(), bz)
}
// GetAllDenomTraces returns the trace information for all the denominations.
func (k Keeper) GetAllDenomTraces(ctx sdk.Context) types.Traces {
traces := types.Traces{}
k.IterateDenomTraces(ctx, func(denomTrace types.DenomTrace) bool {
traces = append(traces, denomTrace)
return false
})
return traces.Sort()
}
// IterateDenomTraces iterates over the denomination traces in the store
// and performs a callback function.
func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(denomTrace types.DenomTrace) bool) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, types.DenomTraceKey)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
denomTrace := k.MustUnmarshalDenomTrace(iterator.Value())
if cb(denomTrace) {
break
}
}
}
// AuthenticateCapability wraps the scopedKeeper's AuthenticateCapability function
func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) bool {
return k.scopedKeeper.AuthenticateCapability(ctx, cap, name)
}
// ClaimCapability allows the transfer module that can claim a capability that IBC module
// passes to it
func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error {
return k.scopedKeeper.ClaimCapability(ctx, cap, name)
}

View File

@ -1,51 +0,0 @@
package keeper_test
import (
"testing"
"github.com/stretchr/testify/suite"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
type KeeperTestSuite struct {
suite.Suite
coordinator *ibctesting.Coordinator
// testing chains used for convenience and readability
chainA *ibctesting.TestChain
chainB *ibctesting.TestChain
chainC *ibctesting.TestChain
queryClient types.QueryClient
}
func (suite *KeeperTestSuite) SetupTest() {
suite.coordinator = ibctesting.NewCoordinator(suite.T(), 3)
suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(0))
suite.chainB = suite.coordinator.GetChain(ibctesting.GetChainID(1))
suite.chainC = suite.coordinator.GetChain(ibctesting.GetChainID(2))
queryHelper := baseapp.NewQueryServerTestHelper(suite.chainA.GetContext(), suite.chainA.App.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.chainA.App.TransferKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
}
func (suite *KeeperTestSuite) TestGetTransferAccount() {
expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(types.ModuleName)))
macc := suite.chainA.App.TransferKeeper.GetTransferAccount(suite.chainA.GetContext())
suite.Require().NotNil(macc)
suite.Require().Equal(types.ModuleName, macc.GetName())
suite.Require().Equal(expectedMaccAddr, macc.GetAddress())
}
func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}

View File

@ -1,378 +0,0 @@
package keeper_test
/// This file is a test driver for model-based tests generated from the TLA+ model of token transfer
/// Written by Andrey Kuprianov within the scope of IBC Audit performed by Informal Systems.
/// In case of any questions please don't hesitate to contact andrey@informal.systems.
import (
"encoding/json"
"fmt"
"io/ioutil"
"strconv"
"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/ibc/applications/transfer/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
type TlaBalance struct {
Address []string `json:"address"`
Denom []string `json:"denom"`
Amount int64 `json:"amount"`
}
type TlaFungibleTokenPacketData struct {
Sender string `json:"sender"`
Receiver string `json:"receiver"`
Amount int `json:"amount"`
Denom []string `json:"denom"`
}
type TlaFungibleTokenPacket struct {
SourceChannel string `json:"sourceChannel"`
SourcePort string `json:"sourcePort"`
DestChannel string `json:"destChannel"`
DestPort string `json:"destPort"`
Data TlaFungibleTokenPacketData `json:"data"`
}
type TlaOnRecvPacketTestCase = struct {
// The required subset of bank balances
BankBefore []TlaBalance `json:"bankBefore"`
// The packet to process
Packet TlaFungibleTokenPacket `json:"packet"`
// The handler to call
Handler string `json:"handler"`
// The expected changes in the bank
BankAfter []TlaBalance `json:"bankAfter"`
// Whether OnRecvPacket should fail or not
Error bool `json:"error"`
}
type FungibleTokenPacket struct {
SourceChannel string
SourcePort string
DestChannel string
DestPort string
Data types.FungibleTokenPacketData
}
type OnRecvPacketTestCase = struct {
description string
// The required subset of bank balances
bankBefore []Balance
// The packet to process
packet FungibleTokenPacket
// The handler to call
handler string
// The expected bank state after processing (wrt. bankBefore)
bankAfter []Balance
// Whether OnRecvPacket should pass or fail
pass bool
}
type OwnedCoin struct {
Address string
Denom string
}
type Balance struct {
Id string
Address string
Denom string
Amount sdk.Int
}
func AddressFromString(address string) string {
return sdk.AccAddress(crypto.AddressHash([]byte(address))).String()
}
func AddressFromTla(addr []string) string {
if len(addr) != 3 {
panic("failed to convert from TLA+ address: wrong number of address components")
}
s := ""
if len(addr[0]) == 0 && len(addr[1]) == 0 {
// simple address: id
s = addr[2]
} else if len(addr[2]) == 0 {
// escrow address: ics20-1\x00port/channel
s = fmt.Sprintf("%s\x00%s/%s", types.Version, addr[0], addr[1])
} else {
panic("failed to convert from TLA+ address: neither simple nor escrow address")
}
return s
}
func DenomFromTla(denom []string) string {
var i int
for i = 0; i+1 < len(denom) && len(denom[i]) == 0 && len(denom[i+1]) == 0; i += 2 {
// skip empty prefixes
}
return strings.Join(denom[i:], "/")
}
func BalanceFromTla(balance TlaBalance) Balance {
return Balance{
Id: AddressFromTla(balance.Address),
Address: AddressFromString(AddressFromTla(balance.Address)),
Denom: DenomFromTla(balance.Denom),
Amount: sdk.NewInt(balance.Amount),
}
}
func BalancesFromTla(tla []TlaBalance) []Balance {
balances := make([]Balance, 0)
for _, b := range tla {
balances = append(balances, BalanceFromTla(b))
}
return balances
}
func FungibleTokenPacketFromTla(packet TlaFungibleTokenPacket) FungibleTokenPacket {
return FungibleTokenPacket{
SourceChannel: packet.SourceChannel,
SourcePort: packet.SourcePort,
DestChannel: packet.DestChannel,
DestPort: packet.DestPort,
Data: types.NewFungibleTokenPacketData(
DenomFromTla(packet.Data.Denom),
uint64(packet.Data.Amount),
AddressFromString(packet.Data.Sender),
AddressFromString(packet.Data.Receiver)),
}
}
func OnRecvPacketTestCaseFromTla(tc TlaOnRecvPacketTestCase) OnRecvPacketTestCase {
return OnRecvPacketTestCase{
description: "auto-generated",
bankBefore: BalancesFromTla(tc.BankBefore),
packet: FungibleTokenPacketFromTla(tc.Packet),
handler: tc.Handler,
bankAfter: BalancesFromTla(tc.BankAfter), // TODO different semantics
pass: !tc.Error,
}
}
var addressMap = make(map[string]string)
type Bank struct {
balances map[OwnedCoin]sdk.Int
}
// Make an empty bank
func MakeBank() Bank {
return Bank{balances: make(map[OwnedCoin]sdk.Int)}
}
// Subtract other bank from this bank
func (bank *Bank) Sub(other *Bank) Bank {
diff := MakeBank()
for coin, amount := range bank.balances {
otherAmount, exists := other.balances[coin]
if exists {
diff.balances[coin] = amount.Sub(otherAmount)
} else {
diff.balances[coin] = amount
}
}
for coin, amount := range other.balances {
if _, exists := bank.balances[coin]; !exists {
diff.balances[coin] = amount.Neg()
}
}
return diff
}
// Set specific bank balance
func (bank *Bank) SetBalance(address string, denom string, amount sdk.Int) {
bank.balances[OwnedCoin{address, denom}] = amount
}
// Set several balances at once
func (bank *Bank) SetBalances(balances []Balance) {
for _, balance := range balances {
bank.balances[OwnedCoin{balance.Address, balance.Denom}] = balance.Amount
addressMap[balance.Address] = balance.Id
}
}
func NullCoin() OwnedCoin {
return OwnedCoin{
Address: AddressFromString(""),
Denom: "",
}
}
// Set several balances at once
func BankFromBalances(balances []Balance) Bank {
bank := MakeBank()
for _, balance := range balances {
coin := OwnedCoin{balance.Address, balance.Denom}
if coin != NullCoin() { // ignore null coin
bank.balances[coin] = balance.Amount
addressMap[balance.Address] = balance.Id
}
}
return bank
}
// String representation of all bank balances
func (bank *Bank) String() string {
str := ""
for coin, amount := range bank.balances {
str += coin.Address
if addressMap[coin.Address] != "" {
str += "(" + addressMap[coin.Address] + ")"
}
str += " : " + coin.Denom + " = " + amount.String() + "\n"
}
return str
}
// String representation of non-zero bank balances
func (bank *Bank) NonZeroString() string {
str := ""
for coin, amount := range bank.balances {
if !amount.IsZero() {
str += coin.Address + " : " + coin.Denom + " = " + amount.String() + "\n"
}
}
return str
}
// Construct a bank out of the chain bank
func BankOfChain(chain *ibctesting.TestChain) Bank {
bank := MakeBank()
chain.App.BankKeeper.IterateAllBalances(chain.GetContext(), func(address sdk.AccAddress, coin sdk.Coin) (stop bool) {
fullDenom := coin.Denom
if strings.HasPrefix(coin.Denom, "ibc/") {
fullDenom, _ = chain.App.TransferKeeper.DenomPathFromHash(chain.GetContext(), coin.Denom)
}
bank.SetBalance(address.String(), fullDenom, coin.Amount)
return false
})
return bank
}
// Check that the state of the bank is the bankBefore + expectedBankChange
func (suite *KeeperTestSuite) CheckBankBalances(chain *ibctesting.TestChain, bankBefore *Bank, expectedBankChange *Bank) error {
bankAfter := BankOfChain(chain)
bankChange := bankAfter.Sub(bankBefore)
diff := bankChange.Sub(expectedBankChange)
NonZeroString := diff.NonZeroString()
if len(NonZeroString) != 0 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "Unexpected changes in the bank: \n"+NonZeroString)
}
return nil
}
func (suite *KeeperTestSuite) TestModelBasedRelay() {
dirname := "model_based_tests/"
files, err := ioutil.ReadDir(dirname)
if err != nil {
panic(fmt.Errorf("Failed to read model-based test files: %w", err))
}
for _, file_info := range files {
var tlaTestCases = []TlaOnRecvPacketTestCase{}
if !strings.HasSuffix(file_info.Name(), ".json") {
continue
}
jsonBlob, err := ioutil.ReadFile(dirname + file_info.Name())
if err != nil {
panic(fmt.Errorf("Failed to read JSON test fixture: %w", err))
}
err = json.Unmarshal([]byte(jsonBlob), &tlaTestCases)
if err != nil {
panic(fmt.Errorf("Failed to parse JSON test fixture: %w", err))
}
suite.SetupTest()
_, _, connAB, connBA := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
_, _, connBC, connCB := suite.coordinator.SetupClientConnections(suite.chainB, suite.chainC, exported.Tendermint)
suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connAB, connBA, channeltypes.UNORDERED)
suite.coordinator.CreateTransferChannels(suite.chainB, suite.chainC, connBC, connCB, channeltypes.UNORDERED)
for i, tlaTc := range tlaTestCases {
tc := OnRecvPacketTestCaseFromTla(tlaTc)
registerDenom := func() {
denomTrace := types.ParseDenomTrace(tc.packet.Data.Denom)
traceHash := denomTrace.Hash()
if !suite.chainB.App.TransferKeeper.HasDenomTrace(suite.chainB.GetContext(), traceHash) {
suite.chainB.App.TransferKeeper.SetDenomTrace(suite.chainB.GetContext(), denomTrace)
}
}
description := file_info.Name() + " # " + strconv.Itoa(i+1)
suite.Run(fmt.Sprintf("Case %s", description), func() {
seq := uint64(1)
packet := channeltypes.NewPacket(tc.packet.Data.GetBytes(), seq, tc.packet.SourcePort, tc.packet.SourceChannel, tc.packet.DestPort, tc.packet.DestChannel, clienttypes.NewHeight(0, 100), 0)
bankBefore := BankFromBalances(tc.bankBefore)
realBankBefore := BankOfChain(suite.chainB)
// First validate the packet itself (mimics what happens when the packet is being sent and/or received)
err := packet.ValidateBasic()
if err != nil {
suite.Require().False(tc.pass, err.Error())
return
}
switch tc.handler {
case "SendTransfer":
var sender sdk.AccAddress
sender, err = sdk.AccAddressFromBech32(tc.packet.Data.Sender)
if err != nil {
panic("MBT failed to convert sender address")
}
registerDenom()
denomTrace := types.ParseDenomTrace(tc.packet.Data.Denom)
denom := denomTrace.IBCDenom()
err = sdk.ValidateDenom(denom)
if err == nil {
err = suite.chainB.App.TransferKeeper.SendTransfer(
suite.chainB.GetContext(),
tc.packet.SourcePort,
tc.packet.SourceChannel,
sdk.NewCoin(denom, sdk.NewIntFromUint64(tc.packet.Data.Amount)),
sender,
tc.packet.Data.Receiver,
clienttypes.NewHeight(0, 110),
0)
}
case "OnRecvPacket":
err = suite.chainB.App.TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, tc.packet.Data)
case "OnTimeoutPacket":
registerDenom()
err = suite.chainB.App.TransferKeeper.OnTimeoutPacket(suite.chainB.GetContext(), packet, tc.packet.Data)
case "OnRecvAcknowledgementResult":
err = suite.chainB.App.TransferKeeper.OnAcknowledgementPacket(
suite.chainB.GetContext(), packet, tc.packet.Data,
channeltypes.NewResultAcknowledgement(nil))
case "OnRecvAcknowledgementError":
registerDenom()
err = suite.chainB.App.TransferKeeper.OnAcknowledgementPacket(
suite.chainB.GetContext(), packet, tc.packet.Data,
channeltypes.NewErrorAcknowledgement("MBT Error Acknowledgement"))
default:
err = fmt.Errorf("Unknown handler: %s", tc.handler)
}
if err != nil {
suite.Require().False(tc.pass, err.Error())
return
}
bankAfter := BankFromBalances(tc.bankAfter)
expectedBankChange := bankAfter.Sub(&bankBefore)
if err := suite.CheckBankBalances(suite.chainB, &realBankBefore, &expectedBankChange); err != nil {
suite.Require().False(tc.pass, err.Error())
return
}
suite.Require().True(tc.pass)
})
}
}
}

View File

@ -1,492 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "a3",
"receiver": "a3",
"amount": 2,
"denom": [
"",
"",
"",
"",
"btc"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"error": false
},
{
"packet": {
"sourceChannel": "ethereum-hub",
"sourcePort": "channel-0",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "a1",
"receiver": "a3",
"amount": 1,
"denom": [
"cosmos-hub",
"",
"",
"",
"btc"
]
}
},
"handler": "SendTransfer",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"error": true
},
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "a2",
"receiver": "a2",
"amount": 4,
"denom": [
"",
"",
"ethereum-hub",
"cosmos-hub",
"atom"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"ethereum-hub",
"cosmos-hub",
"atom"
],
"amount": 4
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "",
"receiver": "a2",
"amount": 4,
"denom": [
"",
"",
"ethereum-hub",
"cosmos-hub",
"atom"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"ethereum-hub",
"cosmos-hub",
"atom"
],
"amount": 4
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"ethereum-hub",
"cosmos-hub",
"atom"
],
"amount": 8
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"error": false
},
{
"packet": {
"sourceChannel": "cosmos-hub",
"sourcePort": "bitcoin-hub",
"destChannel": "channel-0",
"destPort": "channel-1",
"data": {
"sender": "a1",
"receiver": "",
"amount": 1,
"denom": [
"transfer",
"channel-0",
"transfer",
"channel-0",
"atom"
]
}
},
"handler": "SendTransfer",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"ethereum-hub",
"cosmos-hub",
"atom"
],
"amount": 8
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"ethereum-hub",
"cosmos-hub",
"atom"
],
"amount": 8
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-1",
"btc"
],
"amount": 2
}
],
"error": true
}
]

View File

@ -1,612 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a3",
"receiver": "a2",
"amount": 3,
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
]
}
},
"handler": "OnTimeoutPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-1",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a2",
"receiver": "a1",
"amount": 3,
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
]
}
},
"handler": "OnRecvAcknowledgementError",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "a1",
"receiver": "a2",
"amount": 3,
"denom": [
"",
"",
"cosmos-hub",
"cosmos-hub",
"atom"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"atom"
],
"amount": 3
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"error": false
},
{
"packet": {
"sourceChannel": "cosmos-hub",
"sourcePort": "bitcoin-hub",
"destChannel": "transfer",
"destPort": "cosmos-hub",
"data": {
"sender": "a1",
"receiver": "",
"amount": 2,
"denom": [
"",
"channel-0",
"channel-1",
"channel-1",
""
]
}
},
"handler": "OnRecvAcknowledgementResult",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"atom"
],
"amount": 3
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"atom"
],
"amount": 3
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-1",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a3",
"receiver": "a3",
"amount": 1,
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
]
}
},
"handler": "SendTransfer",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"atom"
],
"amount": 3
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 3
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"atom"
],
"amount": 3
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-1",
"cosmos-hub",
"cosmos-hub",
"btc"
],
"amount": 3
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 2
},
{
"address": [
"transfer",
"channel-1",
""
],
"denom": [
"",
"",
"transfer",
"channel-0",
"eth"
],
"amount": 1
}
],
"error": false
}
]

View File

@ -1,58 +0,0 @@
[
{
"packet": {
"sourceChannel": "",
"sourcePort": "",
"destChannel": "",
"destPort": "",
"data": {
"sender": "a1",
"receiver": "a2",
"amount": 1,
"denom": [
"cosmos-hub",
"transfer",
"channel-0",
"cosmos-hub",
"btc"
]
}
},
"handler": "OnRecvAcknowledgementError",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"error": true
}
]

View File

@ -1,159 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* Transition 7 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 1
/\ error = TRUE
/\ handler = "OnRecvAcknowledgementError"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> TRUE,
handler |-> "OnRecvAcknowledgementError",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnRecvAcknowledgementError"
/\ history[s$2]["error"] = TRUE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:15:18 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,159 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "",
"receiver": "a1",
"amount": 1,
"denom": [
"",
"",
"channel-0",
"ethereum-hub",
"btc"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"transfer",
"channel-1",
"channel-0",
"ethereum-hub",
"btc"
],
"amount": 1
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-1",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a1",
"receiver": "a2",
"amount": 1,
"denom": [
"transfer",
"channel-1",
"channel-0",
"ethereum-hub",
"btc"
]
}
},
"handler": "OnRecvAcknowledgementError",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"transfer",
"channel-1",
"channel-0",
"ethereum-hub",
"btc"
],
"amount": 1
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"transfer",
"channel-1",
"channel-0",
"ethereum-hub",
"btc"
],
"amount": 2
}
],
"error": false
}
]

View File

@ -1,310 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 2 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1
/\ count = 1
/\ error = FALSE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]
(* Transition 11 to State4 *)
State4 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 2
/\ count = 2
/\ error = FALSE
/\ handler = "OnRecvAcknowledgementError"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 2
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 2,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1,
error |-> FALSE,
handler |-> "OnRecvAcknowledgementError",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "ethereum-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnRecvAcknowledgementError"
/\ history[s$2]["error"] = FALSE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:14:33 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,58 +0,0 @@
[
{
"packet": {
"sourceChannel": "",
"sourcePort": "",
"destChannel": "",
"destPort": "",
"data": {
"sender": "a1",
"receiver": "a2",
"amount": 1,
"denom": [
"cosmos-hub",
"transfer",
"channel-0",
"cosmos-hub",
"btc"
]
}
},
"handler": "OnRecvAcknowledgementResult",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"error": true
}
]

View File

@ -1,159 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* Transition 13 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 1
/\ error = TRUE
/\ handler = "OnRecvAcknowledgementResult"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> TRUE,
handler |-> "OnRecvAcknowledgementResult",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnRecvAcknowledgementResult"
/\ history[s$2]["error"] = TRUE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:13:42 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,58 +0,0 @@
[
{
"packet": {
"sourceChannel": "ethereum-hub",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "ethereum-hub",
"data": {
"sender": "a1",
"receiver": "a2",
"amount": 1,
"denom": [
"cosmos-hub",
"transfer",
"channel-0",
"cosmos-hub",
"btc"
]
}
},
"handler": "OnRecvAcknowledgementResult",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"error": false
}
]

View File

@ -1,159 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "ethereum-hub",
sourceChannel |-> "ethereum-hub",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "ethereum-hub",
sourceChannel |-> "ethereum-hub",
sourcePort |-> "transfer"]
(* Transition 12 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 1
/\ error = FALSE
/\ handler = "OnRecvAcknowledgementResult"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "ethereum-hub",
sourceChannel |-> "ethereum-hub",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvAcknowledgementResult",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "ethereum-hub",
sourceChannel |-> "ethereum-hub",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnRecvAcknowledgementResult"
/\ history[s$2]["error"] = FALSE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:12:59 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,58 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "",
"receiver": "",
"amount": 1,
"denom": [
"",
"",
"transfer",
"channel-0",
""
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"error": true
}
]

View File

@ -1,159 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 3 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 1
/\ error = TRUE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> TRUE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnRecvPacket"
/\ history[s$2]["error"] = TRUE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:02:31 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,73 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "",
"receiver": "a2",
"amount": 1,
"denom": [
"",
"",
"ethereum-hub",
"cosmos-hub",
"btc"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-0",
"ethereum-hub",
"cosmos-hub",
"btc"
],
"amount": 1
}
],
"error": false
}
]

View File

@ -1,174 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |->
[channel |-> "cosmos-hub", port |-> "ethereum-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "ethereum-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 5 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "ethereum-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1
/\ count = 1
/\ error = FALSE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |->
[channel |-> "cosmos-hub", port |-> "ethereum-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "ethereum-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |->
[channel |-> "cosmos-hub", port |-> "ethereum-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnRecvPacket"
/\ history[s$2]["error"] = FALSE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:01:28 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,58 +0,0 @@
[
{
"packet": {
"sourceChannel": "",
"sourcePort": "",
"destChannel": "",
"destPort": "",
"data": {
"sender": "a1",
"receiver": "a2",
"amount": 1,
"denom": [
"cosmos-hub",
"transfer",
"channel-0",
"cosmos-hub",
"btc"
]
}
},
"handler": "OnTimeoutPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"error": true
}
]

View File

@ -1,159 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* Transition 6 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 1
/\ error = TRUE
/\ handler = "OnTimeoutPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> TRUE,
handler |-> "OnTimeoutPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "channel-0"],
prefix1 |-> [channel |-> "transfer", port |-> "cosmos-hub"]],
receiver |-> "a2",
sender |-> "a1"],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnTimeoutPacket"
/\ history[s$2]["error"] = TRUE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:09:25 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,159 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "a3",
"receiver": "a1",
"amount": 1,
"denom": [
"",
"",
"bitcoin-hub",
"transfer",
"btc"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"transfer",
"channel-1",
"bitcoin-hub",
"transfer",
"btc"
],
"amount": 1
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-1",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a1",
"receiver": "",
"amount": 1,
"denom": [
"transfer",
"channel-1",
"bitcoin-hub",
"transfer",
"btc"
]
}
},
"handler": "OnTimeoutPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"transfer",
"channel-1",
"bitcoin-hub",
"transfer",
"btc"
],
"amount": 1
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"transfer",
"channel-1",
"bitcoin-hub",
"transfer",
"btc"
],
"amount": 2
}
],
"error": false
}
]

View File

@ -1,310 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 2 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1
/\ count = 1
/\ error = FALSE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]],
receiver |-> "",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]
(* Transition 10 to State4 *)
State4 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 2
/\ count = 2
/\ error = FALSE
/\ handler = "OnTimeoutPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 2
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 2,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]]
>>
:> 1,
error |-> FALSE,
handler |-> "OnTimeoutPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-1", port |-> "transfer"]],
receiver |-> "",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "OnTimeoutPacket"
/\ history[s$2]["error"] = FALSE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:07:37 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,58 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "",
"receiver": "",
"amount": 1,
"denom": [
"",
"",
"",
"",
""
]
}
},
"handler": "SendTransfer",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"error": true
}
]

View File

@ -1,159 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 0 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 1
/\ error = TRUE
/\ handler = "SendTransfer"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> TRUE,
handler |-> "SendTransfer",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "SendTransfer"
/\ history[s$2]["error"] = TRUE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 11:00:34 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,174 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a3",
"receiver": "a2",
"amount": 1,
"denom": [
"",
"",
"cosmos-hub",
"cosmos-hub",
"eth"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-0",
"cosmos-hub",
"cosmos-hub",
"eth"
],
"amount": 1
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-1",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a2",
"receiver": "a1",
"amount": 1,
"denom": [
"transfer",
"channel-0",
"cosmos-hub",
"cosmos-hub",
"eth"
]
}
},
"handler": "SendTransfer",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-0",
"cosmos-hub",
"cosmos-hub",
"eth"
],
"amount": 1
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a2"
],
"denom": [
"transfer",
"channel-0",
"cosmos-hub",
"cosmos-hub",
"eth"
],
"amount": 0
},
{
"address": [
"transfer",
"channel-1",
""
],
"denom": [
"transfer",
"channel-0",
"cosmos-hub",
"cosmos-hub",
"eth"
],
"amount": 1
}
],
"error": false
}
]

View File

@ -1,323 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 2 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1
/\ count = 1
/\ error = FALSE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]],
receiver |-> "a1",
sender |-> "a2"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]
(* Transition 1 to State4 *)
State4 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 0
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1
/\ count = 2
/\ error = FALSE
/\ handler = "SendTransfer"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a2",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 2
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 0
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |->
"eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a2", port |-> ""], [denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]]
>>
:> 1,
error |-> FALSE,
handler |-> "SendTransfer",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "eth",
prefix0 |-> [channel |-> "cosmos-hub", port |-> "cosmos-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]],
receiver |-> "a1",
sender |-> "a2"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "",
sender |-> ""],
destChannel |-> "",
destPort |-> "",
sourceChannel |-> "",
sourcePort |-> ""]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
BMC!Skolem((\E s$2 \in DOMAIN history:
history[s$2]["handler"] = "SendTransfer"
/\ history[s$2]["error"] = FALSE
/\ history[s$2]["packet"]["data"]["amount"] > 0))
================================================================================
\* Created by Apalache on Thu Dec 10 10:58:54 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,305 +0,0 @@
[
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a1",
"receiver": "a3",
"amount": 5,
"denom": [
"",
"",
"",
"",
"atom"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 5
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-1",
"sourcePort": "transfer",
"destChannel": "channel-0",
"destPort": "transfer",
"data": {
"sender": "a3",
"receiver": "a1",
"amount": 3,
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
]
}
},
"handler": "SendTransfer",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 5
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 2
},
{
"address": [
"transfer",
"channel-1",
""
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 3
}
],
"error": false
},
{
"packet": {
"sourceChannel": "channel-0",
"sourcePort": "transfer",
"destChannel": "channel-1",
"destPort": "transfer",
"data": {
"sender": "a1",
"receiver": "a1",
"amount": 1,
"denom": [
"transfer",
"channel-0",
"transfer",
"channel-0",
"atom"
]
}
},
"handler": "OnRecvPacket",
"bankBefore": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 2
},
{
"address": [
"transfer",
"channel-1",
""
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 3
}
],
"bankAfter": [
{
"address": [
"",
"",
""
],
"denom": [
"",
"",
"",
"",
""
],
"amount": 0
},
{
"address": [
"",
"",
"a1"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 1
},
{
"address": [
"",
"",
"a3"
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 2
},
{
"address": [
"transfer",
"channel-1",
""
],
"denom": [
"",
"",
"transfer",
"channel-0",
"atom"
],
"amount": 2
}
],
"error": false
}
]

View File

@ -1,563 +0,0 @@
------------------------- MODULE counterexample -------------------------
EXTENDS relay_tests
(* Initial state *)
State1 ==
TRUE
(* Transition 0 to State2 *)
State2 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
/\ count = 0
/\ error = FALSE
/\ handler = ""
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 3 to State3 *)
State3 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 5
/\ count = 1
/\ error = FALSE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 5,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 3,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]
(* Transition 1 to State4 *)
State4 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 3
/\ count = 2
/\ error = FALSE
/\ handler = "SendTransfer"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 5,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 2
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |->
"atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 3,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 5,
error |-> FALSE,
handler |-> "SendTransfer",
packet |->
[data |->
[amount |-> 3,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 1,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]],
receiver |-> "a1",
sender |-> "a1"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* Transition 4 to State5 *)
State5 ==
/\ bank = <<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 1
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
/\ count = 3
/\ error = FALSE
/\ handler = "OnRecvPacket"
/\ history = 0
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 1
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 5,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 5,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a3",
sender |-> "a1"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
@@ 2
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |->
"atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 3,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 5,
error |-> FALSE,
handler |-> "SendTransfer",
packet |->
[data |->
[amount |-> 3,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]],
receiver |-> "a1",
sender |-> "a3"],
destChannel |-> "channel-0",
destPort |-> "transfer",
sourceChannel |-> "channel-1",
sourcePort |-> "transfer"]]
@@ 3
:> [bankAfter |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a1", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 1
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |->
"atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2,
bankBefore |->
<<
[channel |-> "", id |-> "", port |-> ""], [denom |-> "",
prefix0 |-> [channel |-> "", port |-> ""],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 0
@@ <<
[channel |-> "", id |-> "a3", port |-> ""], [denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 2
@@ <<
[channel |-> "channel-1", id |-> "", port |-> "transfer"], [denom |->
"atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "", port |-> ""]]
>>
:> 3,
error |-> FALSE,
handler |-> "OnRecvPacket",
packet |->
[data |->
[amount |-> 1,
denomTrace |->
[denom |-> "atom",
prefix0 |-> [channel |-> "channel-0", port |-> "transfer"],
prefix1 |-> [channel |-> "channel-0", port |-> "transfer"]],
receiver |-> "a1",
sender |-> "a1"],
destChannel |-> "channel-1",
destPort |-> "transfer",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]]
/\ p = [data |->
[amount |-> 0,
denomTrace |->
[denom |-> "btc",
prefix0 |-> [channel |-> "transfer", port |-> "bitcoin-hub"],
prefix1 |-> [channel |-> "channel-0", port |-> "channel-1"]],
receiver |-> "a1",
sender |-> ""],
destChannel |-> "ethereum-hub",
destPort |-> "cosmos-hub",
sourceChannel |-> "channel-0",
sourcePort |-> "transfer"]
(* The following formula holds true in the last state and violates the invariant *)
InvariantViolation ==
history[1]["handler"] = "OnRecvPacket"
/\ BMC!Skolem((\E s$2 \in DOMAIN history:
((IF history[s$2]["packet"]["data"]["denomTrace"]["prefix0"]
= [port |-> "", channel |-> ""]
THEN [port |-> "", channel |-> ""]
ELSE IF history[s$2]["packet"]["data"]["denomTrace"]["prefix1"]
= [port |-> "", channel |-> ""]
THEN history[s$2]["packet"]["data"]["denomTrace"]["prefix0"]
ELSE history[s$2]["packet"]["data"]["denomTrace"]["prefix1"])[
"port"
]
= history[s$2]["packet"]["sourcePort"]
/\ (IF history[s$2]["packet"]["data"]["denomTrace"]["prefix0"]
= [port |-> "", channel |-> ""]
THEN [port |-> "", channel |-> ""]
ELSE IF history[s$2]["packet"]["data"]["denomTrace"]["prefix1"]
= [port |-> "", channel |-> ""]
THEN history[s$2]["packet"]["data"]["denomTrace"]["prefix0"]
ELSE history[s$2]["packet"]["data"]["denomTrace"]["prefix1"])[
"channel"
]
= history[s$2]["packet"]["sourceChannel"])
/\ history[s$2]["handler"] = "OnRecvPacket"
/\ history[s$2]["error"] = FALSE))
================================================================================
\* Created by Apalache on Thu Dec 10 13:38:11 CET 2020
\* https://github.com/informalsystems/apalache

View File

@ -1,43 +0,0 @@
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
var _ types.MsgServer = Keeper{}
// See createOutgoingPacket in spec:https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay
// Transfer defines a rpc handler method for MsgTransfer.
func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return nil, err
}
if err := k.SendTransfer(
ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp,
); err != nil {
return nil, err
}
k.Logger(ctx).Info("IBC fungible token transfer", "token", msg.Token.Denom, "amount", msg.Token.Amount.String(), "sender", msg.Sender, "receiver", msg.Receiver)
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeTransfer,
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
sdk.NewAttribute(types.AttributeKeyReceiver, msg.Receiver),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
),
})
return &types.MsgTransferResponse{}, nil
}

View File

@ -1,30 +0,0 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// GetSendEnabled retrieves the send enabled boolean from the paramstore
func (k Keeper) GetSendEnabled(ctx sdk.Context) bool {
var res bool
k.paramSpace.Get(ctx, types.KeySendEnabled, &res)
return res
}
// GetReceiveEnabled retrieves the receive enabled boolean from the paramstore
func (k Keeper) GetReceiveEnabled(ctx sdk.Context) bool {
var res bool
k.paramSpace.Get(ctx, types.KeyReceiveEnabled, &res)
return res
}
// GetParams returns the total set of ibc-transfer parameters.
func (k Keeper) GetParams(ctx sdk.Context) types.Params {
return types.NewParams(k.GetSendEnabled(ctx), k.GetReceiveEnabled(ctx))
}
// SetParams sets the total set of ibc-transfer parameters.
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
k.paramSpace.SetParamSet(ctx, &params)
}

View File

@ -1,15 +0,0 @@
package keeper_test
import "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
func (suite *KeeperTestSuite) TestParams() {
expParams := types.DefaultParams()
params := suite.chainA.App.TransferKeeper.GetParams(suite.chainA.GetContext())
suite.Require().Equal(expParams, params)
expParams.SendEnabled = false
suite.chainA.App.TransferKeeper.SetParams(suite.chainA.GetContext(), expParams)
params = suite.chainA.App.TransferKeeper.GetParams(suite.chainA.GetContext())
suite.Require().Equal(expParams, params)
}

View File

@ -1,406 +0,0 @@
package keeper
import (
"fmt"
"strings"
"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
)
// SendTransfer handles transfer sending logic. There are 2 possible cases:
//
// 1. Sender chain is acting as the source zone. The coins are transferred
// to an escrow address (i.e locked) on the sender chain and then transferred
// to the receiving chain through IBC TAO logic. It is expected that the
// receiving chain will mint vouchers to the receiving address.
//
// 2. Sender chain is acting as the sink zone. The coins (vouchers) are burned
// on the sender chain and then transferred to the receiving chain though IBC
// TAO logic. It is expected that the receiving chain, which had previously
// sent the original denomination, will unescrow the fungible token and send
// it to the receiving address.
//
// Another way of thinking of source and sink zones is through the token's
// timeline. Each send to any chain other than the one it was previously
// received from is a movement forwards in the token's timeline. This causes
// trace to be added to the token's history and the destination port and
// destination channel to be prefixed to the denomination. In these instances
// the sender chain is acting as the source zone. When the token is sent back
// to the chain it previously received from, the prefix is removed. This is
// a backwards movement in the token's timeline and the sender chain
// is acting as the sink zone.
//
// Example:
// These steps of transfer occur: A -> B -> C -> A -> C -> B -> A
//
// 1. A -> B : sender chain is source zone. Denom upon receiving: 'B/denom'
// 2. B -> C : sender chain is source zone. Denom upon receiving: 'C/B/denom'
// 3. C -> A : sender chain is source zone. Denom upon receiving: 'A/C/B/denom'
// 4. A -> C : sender chain is sink zone. Denom upon receiving: 'C/B/denom'
// 5. C -> B : sender chain is sink zone. Denom upon receiving: 'B/denom'
// 6. B -> A : sender chain is sink zone. Denom upon receiving: 'denom'
func (k Keeper) SendTransfer(
ctx sdk.Context,
sourcePort,
sourceChannel string,
token sdk.Coin,
sender sdk.AccAddress,
receiver string,
timeoutHeight clienttypes.Height,
timeoutTimestamp uint64,
) error {
if !k.GetSendEnabled(ctx) {
return types.ErrSendDisabled
}
sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel)
if !found {
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", sourcePort, sourceChannel)
}
destinationPort := sourceChannelEnd.GetCounterparty().GetPortID()
destinationChannel := sourceChannelEnd.GetCounterparty().GetChannelID()
// get the next sequence
sequence, found := k.channelKeeper.GetNextSequenceSend(ctx, sourcePort, sourceChannel)
if !found {
return sdkerrors.Wrapf(
channeltypes.ErrSequenceSendNotFound,
"source port: %s, source channel: %s", sourcePort, sourceChannel,
)
}
// begin createOutgoingPacket logic
// See spec for this logic: https://github.com/cosmos/ics/tree/master/spec/ics-020-fungible-token-transfer#packet-relay
channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(sourcePort, sourceChannel))
if !ok {
return sdkerrors.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability")
}
// NOTE: denomination and hex hash correctness checked during msg.ValidateBasic
fullDenomPath := token.Denom
var err error
// deconstruct the token denomination into the denomination trace info
// to determine if the sender is the source chain
if strings.HasPrefix(token.Denom, "ibc/") {
fullDenomPath, err = k.DenomPathFromHash(ctx, token.Denom)
if err != nil {
return err
}
}
labels := []metrics.Label{
telemetry.NewLabel("destination-port", destinationPort),
telemetry.NewLabel("destination-channel", destinationChannel),
}
// NOTE: SendTransfer simply sends the denomination as it exists on its own
// chain inside the packet data. The receiving chain will perform denom
// prefixing as necessary.
if types.SenderChainIsSource(sourcePort, sourceChannel, fullDenomPath) {
labels = append(labels, telemetry.NewLabel("source", "true"))
// create the escrow address for the tokens
escrowAddress := types.GetEscrowAddress(sourcePort, sourceChannel)
// escrow source tokens. It fails if balance insufficient.
if err := k.bankKeeper.SendCoins(
ctx, sender, escrowAddress, sdk.NewCoins(token),
); err != nil {
return err
}
} else {
labels = append(labels, telemetry.NewLabel("source", "false"))
// transfer the coins to the module account and burn them
if err := k.bankKeeper.SendCoinsFromAccountToModule(
ctx, sender, types.ModuleName, sdk.NewCoins(token),
); err != nil {
return err
}
if err := k.bankKeeper.BurnCoins(
ctx, types.ModuleName, sdk.NewCoins(token),
); err != nil {
// NOTE: should not happen as the module account was
// retrieved on the step above and it has enough balace
// to burn.
panic(fmt.Sprintf("cannot burn coins after a successful send to a module account: %v", err))
}
}
packetData := types.NewFungibleTokenPacketData(
fullDenomPath, token.Amount.Uint64(), sender.String(), receiver,
)
packet := channeltypes.NewPacket(
packetData.GetBytes(),
sequence,
sourcePort,
sourceChannel,
destinationPort,
destinationChannel,
timeoutHeight,
timeoutTimestamp,
)
if err := k.channelKeeper.SendPacket(ctx, channelCap, packet); err != nil {
return err
}
defer func() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "ibc", "transfer"},
float32(token.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", fullDenomPath)},
)
telemetry.IncrCounterWithLabels(
[]string{"ibc", types.ModuleName, "send"},
1,
labels,
)
}()
return nil
}
// OnRecvPacket processes a cross chain fungible token transfer. If the
// sender chain is the source of minted tokens then vouchers will be minted
// and sent to the receiving address. Otherwise if the sender chain is sending
// back tokens this chain originally transferred to it, the tokens are
// unescrowed and sent to the receiving address.
func (k Keeper) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error {
// validate packet data upon receiving
if err := data.ValidateBasic(); err != nil {
return err
}
if !k.GetReceiveEnabled(ctx) {
return types.ErrReceiveDisabled
}
// decode the receiver address
receiver, err := sdk.AccAddressFromBech32(data.Receiver)
if err != nil {
return err
}
labels := []metrics.Label{
telemetry.NewLabel("source-port", packet.GetSourcePort()),
telemetry.NewLabel("source-channel", packet.GetSourceChannel()),
}
// This is the prefix that would have been prefixed to the denomination
// on sender chain IF and only if the token originally came from the
// receiving chain.
//
// NOTE: We use SourcePort and SourceChannel here, because the counterparty
// chain would have prefixed with DestPort and DestChannel when originally
// receiving this coin as seen in the "sender chain is the source" condition.
if types.ReceiverChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) {
// sender chain is not the source, unescrow tokens
// remove prefix added by sender chain
voucherPrefix := types.GetDenomPrefix(packet.GetSourcePort(), packet.GetSourceChannel())
unprefixedDenom := data.Denom[len(voucherPrefix):]
// coin denomination used in sending from the escrow address
denom := unprefixedDenom
// The denomination used to send the coins is either the native denom or the hash of the path
// if the denomination is not native.
denomTrace := types.ParseDenomTrace(unprefixedDenom)
if denomTrace.Path != "" {
denom = denomTrace.IBCDenom()
}
token := sdk.NewCoin(denom, sdk.NewIntFromUint64(data.Amount))
// unescrow tokens
escrowAddress := types.GetEscrowAddress(packet.GetDestPort(), packet.GetDestChannel())
if err := k.bankKeeper.SendCoins(ctx, escrowAddress, receiver, sdk.NewCoins(token)); err != nil {
// NOTE: this error is only expected to occur given an unexpected bug or a malicious
// counterparty module. The bug may occur in bank or any part of the code that allows
// the escrow address to be drained. A malicious counterparty module could drain the
// escrow address by allowing more tokens to be sent back then were escrowed.
return sdkerrors.Wrap(err, "unable to unescrow tokens, this may be caused by a malicious counterparty module or a bug: please open an issue on counterparty module")
}
defer func() {
telemetry.SetGaugeWithLabels(
[]string{"ibc", types.ModuleName, "packet", "receive"},
float32(data.Amount),
[]metrics.Label{telemetry.NewLabel("denom", unprefixedDenom)},
)
telemetry.IncrCounterWithLabels(
[]string{"ibc", types.ModuleName, "receive"},
1,
append(
labels, telemetry.NewLabel("source", "true"),
),
)
}()
return nil
}
// sender chain is the source, mint vouchers
// since SendPacket did not prefix the denomination, we must prefix denomination here
sourcePrefix := types.GetDenomPrefix(packet.GetDestPort(), packet.GetDestChannel())
// NOTE: sourcePrefix contains the trailing "/"
prefixedDenom := sourcePrefix + data.Denom
// construct the denomination trace from the full raw denomination
denomTrace := types.ParseDenomTrace(prefixedDenom)
traceHash := denomTrace.Hash()
if !k.HasDenomTrace(ctx, traceHash) {
k.SetDenomTrace(ctx, denomTrace)
}
voucherDenom := denomTrace.IBCDenom()
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeDenomTrace,
sdk.NewAttribute(types.AttributeKeyTraceHash, traceHash.String()),
sdk.NewAttribute(types.AttributeKeyDenom, voucherDenom),
),
)
voucher := sdk.NewCoin(voucherDenom, sdk.NewIntFromUint64(data.Amount))
// mint new tokens if the source of the transfer is the same chain
if err := k.bankKeeper.MintCoins(
ctx, types.ModuleName, sdk.NewCoins(voucher),
); err != nil {
return err
}
// send to receiver
if err := k.bankKeeper.SendCoinsFromModuleToAccount(
ctx, types.ModuleName, receiver, sdk.NewCoins(voucher),
); err != nil {
panic(fmt.Sprintf("unable to send coins from module to account despite previously minting coins to module account: %v", err))
}
defer func() {
telemetry.SetGaugeWithLabels(
[]string{"ibc", types.ModuleName, "packet", "receive"},
float32(data.Amount),
[]metrics.Label{telemetry.NewLabel("denom", data.Denom)},
)
telemetry.IncrCounterWithLabels(
[]string{"ibc", types.ModuleName, "receive"},
1,
append(
labels, telemetry.NewLabel("source", "false"),
),
)
}()
return nil
}
// OnAcknowledgementPacket responds to the the success or failure of a packet
// acknowledgement written on the receiving chain. If the acknowledgement
// was a success then nothing occurs. If the acknowledgement failed, then
// the sender is refunded their tokens using the refundPacketToken function.
func (k Keeper) OnAcknowledgementPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData, ack channeltypes.Acknowledgement) error {
switch ack.Response.(type) {
case *channeltypes.Acknowledgement_Error:
return k.refundPacketToken(ctx, packet, data)
default:
// the acknowledgement succeeded on the receiving chain so nothing
// needs to be executed and no error needs to be returned
return nil
}
}
// OnTimeoutPacket refunds the sender since the original packet sent was
// never received and has been timed out.
func (k Keeper) OnTimeoutPacket(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error {
return k.refundPacketToken(ctx, packet, data)
}
// refundPacketToken will unescrow and send back the tokens back to sender
// if the sending chain was the source chain. Otherwise, the sent tokens
// were burnt in the original send so new tokens are minted and sent to
// the sending address.
func (k Keeper) refundPacketToken(ctx sdk.Context, packet channeltypes.Packet, data types.FungibleTokenPacketData) error {
// NOTE: packet data type already checked in handler.go
// parse the denomination from the full denom path
trace := types.ParseDenomTrace(data.Denom)
token := sdk.NewCoin(trace.IBCDenom(), sdk.NewIntFromUint64(data.Amount))
// decode the sender address
sender, err := sdk.AccAddressFromBech32(data.Sender)
if err != nil {
return err
}
if types.SenderChainIsSource(packet.GetSourcePort(), packet.GetSourceChannel(), data.Denom) {
// unescrow tokens back to sender
escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel())
if err := k.bankKeeper.SendCoins(ctx, escrowAddress, sender, sdk.NewCoins(token)); err != nil {
// NOTE: this error is only expected to occur given an unexpected bug or a malicious
// counterparty module. The bug may occur in bank or any part of the code that allows
// the escrow address to be drained. A malicious counterparty module could drain the
// escrow address by allowing more tokens to be sent back then were escrowed.
return sdkerrors.Wrap(err, "unable to unescrow tokens, this may be caused by a malicious counterparty module or a bug: please open an issue on counterparty module")
}
return nil
}
// mint vouchers back to sender
if err := k.bankKeeper.MintCoins(
ctx, types.ModuleName, sdk.NewCoins(token),
); err != nil {
return err
}
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, sdk.NewCoins(token)); err != nil {
panic(fmt.Sprintf("unable to send coins from module to account despite previously minting coins to module account: %v", err))
}
return nil
}
// DenomPathFromHash returns the full denomination path prefix from an ibc denom with a hash
// component.
func (k Keeper) DenomPathFromHash(ctx sdk.Context, denom string) (string, error) {
// trim the denomination prefix, by default "ibc/"
hexHash := denom[len(types.DenomPrefix+"/"):]
hash, err := types.ParseHexHash(hexHash)
if err != nil {
return "", sdkerrors.Wrap(types.ErrInvalidDenomForTransfer, err.Error())
}
denomTrace, found := k.GetDenomTrace(ctx, hash)
if !found {
return "", sdkerrors.Wrap(types.ErrTraceNotFound, hexHash)
}
fullDenomPath := denomTrace.GetFullDenomPath()
return fullDenomPath, nil
}

View File

@ -1,36 +0,0 @@
-------------------------- MODULE account ----------------------------
(**
The accounts interface; please ignore the definition bodies.
*)
EXTENDS identifiers
CONSTANT
AccountIds
\* a non-account
NullAccount == "NullAccount"
\* All accounts
Accounts == { NullAccount }
\* Make an escrow account for the given port and channel
MakeEscrowAccount(port, channel) == NullAccount
\* Make an account from the accound id
MakeAccount(accountId) == NullAccount
\* Type constraints for accounts
AccountTypeOK ==
/\ NullAccount \in Accounts
/\ \A p \in Identifiers, c \in Identifiers:
MakeEscrowAccount(p, c) \in Accounts
/\ \A a \in Identifiers:
MakeAccount(a) \in Accounts
=============================================================================
\* Modification History
\* Last modified Thu Nov 19 18:21:10 CET 2020 by c
\* Last modified Thu Nov 05 14:44:18 CET 2020 by andrey
\* Created Thu Nov 05 13:22:40 CET 2020 by andrey

View File

@ -1,46 +0,0 @@
-------------------------- MODULE account_record ----------------------------
(**
The most basic implementation of accounts, which is a union of normal and escrow accounts
Represented via records.
*)
EXTENDS identifiers
CONSTANT
AccountIds
NullAccount == [
port |-> NullId,
channel |-> NullId,
id |-> NullId
]
Accounts == [
port: Identifiers,
channel: Identifiers,
id: AccountIds
]
MakeEscrowAccount(port, channel) == [
port |-> port,
channel |-> channel,
id |-> NullId
]
MakeAccount(accountId) == [
port |-> NullId,
channel |-> NullId,
id |-> accountId
]
ACCOUNT == INSTANCE account
AccountTypeOK == ACCOUNT!AccountTypeOK
=============================================================================
\* Modification History
\* Last modified Thu Nov 19 18:21:46 CET 2020 by c
\* Last modified Thu Nov 05 14:49:10 CET 2020 by andrey
\* Created Thu Nov 05 13:22:40 CET 2020 by andrey

View File

@ -1,100 +0,0 @@
{
"description": "Transforms an Apalache counterexample into the test for ICS20 Token Transfer OnRecvPacket",
"usage": "jsonatr --use apalache-to-recv-test.json --in counterexample.json --out recv-test.json",
"input": [
{
"name": "history",
"description": "extract history from the last state of Apalache CE",
"kind": "INLINE",
"source": "$.declarations[-2].body.and..[?(@.eq == 'history')].arg.atat..arg.record"
},
{
"name": "bankRecordToBalance",
"description": "",
"kind": "INLINE",
"source": {
"address": [
"$.colonGreater.tuple[0]..[?(@.key.str == 'port')].value.str | unwrap",
"$.colonGreater.tuple[0]..[?(@.key.str == 'channel')].value.str | unwrap",
"$.colonGreater.tuple[0]..[?(@.key.str == 'id')].value.str | unwrap"
],
"denom": [
"$.colonGreater.tuple[1]..[?(@.key.str == 'port')].value.str | unwrap",
"$.colonGreater.tuple[1]..[?(@.key.str == 'channel')].value.str | unwrap",
"$.colonGreater.tuple[1]..[?(@.key.str == 'denom')].value.str | unwrap"
],
"amount": "$.arg | unwrap"
}
},
{
"name": "bankBefore",
"description": "extract bankBefore from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'bankBefore')].value.atat | unwrap | map(bankRecordToBalance)"
},
{
"name": "bankAfter",
"description": "extract bankAfter from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'bankAfter')].value.atat | unwrap | map(bankRecordToBalance)"
},
{
"name": "packet",
"description": "extract packet from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'packet')].value.record"
},
{
"name": "packetData",
"description": "extract bankAfter from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'data')].value.record"
},
{
"name": "packetDataDenom",
"description": "extract bankAfter from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'data')].value.record.[?(@.key.str == 'denomTrace')].value.record"
},
{
"name": "packetRecord",
"description": "decompose packet",
"kind": "INLINE",
"source": {
"sourceChannel" : "$.[?(@.key.str == 'sourceChannel')].value.str | unwrap",
"sourcePort" : "$.[?(@.key.str == 'sourcePort')].value.str | unwrap",
"destChannel" : "$.[?(@.key.str == 'destChannel')].value.str | unwrap",
"destPort" : "$.[?(@.key.str == 'destPort')].value.str | unwrap",
"data": {
"sender": "$packetData.[?(@.key.str == 'sender')].value.str | unwrap",
"receiver": "$packetData.[?(@.key.str == 'receiver')].value.str | unwrap",
"amount": "$packetData.[?(@.key.str == 'amount')].value | unwrap",
"denom": [
"$packetDataDenom.[?(@.key.str == 'port')].value.str | unwrap",
"$packetDataDenom.[?(@.key.str == 'channel')].value.str | unwrap",
"$packetDataDenom.[?(@.key.str == 'denom')].value.str | unwrap"
]
}
}
},
{
"name": "handler",
"description": "extract handler from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'handler')].value.str"
},
{
"name": "historyState",
"description": "decompose single history state",
"kind": "INLINE",
"source": {
"packet": "$packet | unwrap | packetRecord",
"handler": "$handler | unwrap",
"bankBefore": "$bankBefore",
"bankAfter": "$bankAfter",
"error": "$..[?(@.key.str == 'error')].value | unwrap"
}
}
],
"output": "$history[1:] | map(historyState)"
}

View File

@ -1,104 +0,0 @@
{
"description": "Transforms an Apalache counterexample into the test for ICS20 Token Transfer OnRecvPacket",
"usage": "jsonatr --use apalache-to-recv-test.json --in counterexample.json --out recv-test.json",
"input": [
{
"name": "history",
"description": "extract history from the last state of Apalache CE",
"kind": "INLINE",
"source": "$.declarations[-2].body.and..[?(@.eq == 'history')].arg.atat..arg.record"
},
{
"name": "bankRecordToBalance",
"description": "",
"kind": "INLINE",
"source": {
"address": [
"$.colonGreater.tuple[0]..[?(@.key.str == 'port')].value.str | unwrap",
"$.colonGreater.tuple[0]..[?(@.key.str == 'channel')].value.str | unwrap",
"$.colonGreater.tuple[0]..[?(@.key.str == 'id')].value.str | unwrap"
],
"denom": [
"$.colonGreater.tuple[1]..[?(@.key.str == 'prefix1')].value..[?(@.key.str == 'port')].value.str | unwrap",
"$.colonGreater.tuple[1]..[?(@.key.str == 'prefix1')].value..[?(@.key.str == 'channel')].value.str | unwrap",
"$.colonGreater.tuple[1]..[?(@.key.str == 'prefix0')].value..[?(@.key.str == 'port')].value.str | unwrap",
"$.colonGreater.tuple[1]..[?(@.key.str == 'prefix0')].value..[?(@.key.str == 'channel')].value.str | unwrap",
"$.colonGreater.tuple[1]..[?(@.key.str == 'denom')].value.str | unwrap"
],
"amount": "$.arg | unwrap"
}
},
{
"name": "bankBefore",
"description": "extract bankBefore from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'bankBefore')].value.atat | unwrap | map(bankRecordToBalance)"
},
{
"name": "bankAfter",
"description": "extract bankAfter from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'bankAfter')].value.atat | unwrap | map(bankRecordToBalance)"
},
{
"name": "packet",
"description": "extract packet from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'packet')].value.record"
},
{
"name": "packetData",
"description": "extract bankAfter from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'data')].value.record"
},
{
"name": "packetDataDenom",
"description": "extract bankAfter from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'data')].value.record.[?(@.key.str == 'denomTrace')].value.record"
},
{
"name": "packetRecord",
"description": "decompose packet",
"kind": "INLINE",
"source": {
"sourceChannel" : "$.[?(@.key.str == 'sourceChannel')].value.str | unwrap",
"sourcePort" : "$.[?(@.key.str == 'sourcePort')].value.str | unwrap",
"destChannel" : "$.[?(@.key.str == 'destChannel')].value.str | unwrap",
"destPort" : "$.[?(@.key.str == 'destPort')].value.str | unwrap",
"data": {
"sender": "$packetData.[?(@.key.str == 'sender')].value.str | unwrap",
"receiver": "$packetData.[?(@.key.str == 'receiver')].value.str | unwrap",
"amount": "$packetData.[?(@.key.str == 'amount')].value | unwrap",
"denom": [
"$packetDataDenom.[?(@.key.str == 'prefix1')].value..[?(@.key.str == 'port')].value.str | unwrap",
"$packetDataDenom.[?(@.key.str == 'prefix1')].value..[?(@.key.str == 'channel')].value.str | unwrap",
"$packetDataDenom.[?(@.key.str == 'prefix0')].value..[?(@.key.str == 'port')].value.str | unwrap",
"$packetDataDenom.[?(@.key.str == 'prefix0')].value..[?(@.key.str == 'channel')].value.str | unwrap",
"$packetDataDenom.[?(@.key.str == 'denom')].value.str | unwrap"
]
}
}
},
{
"name": "handler",
"description": "extract handler from the history state",
"kind": "INLINE",
"source": "$..[?(@.key.str == 'handler')].value.str"
},
{
"name": "historyState",
"description": "decompose single history state",
"kind": "INLINE",
"source": {
"packet": "$packet | unwrap | packetRecord",
"handler": "$handler | unwrap",
"bankBefore": "$bankBefore",
"bankAfter": "$bankAfter",
"error": "$..[?(@.key.str == 'error')].value | unwrap"
}
}
],
"output": "$history[1:] | map(historyState)"
}

View File

@ -1,50 +0,0 @@
-------------------------- MODULE denom ----------------------------
(**
The denomination traces interface; please ignore the definition bodies.
*)
EXTENDS identifiers
CONSTANT
Denoms
\* A non-account
NullDenomTrace == "NullDenomTrace"
\* All denomination traces
DenomTraces == {NullDenomTrace}
\* Make a new denomination trace from the port/channel prefix and the basic denom
MakeDenomTrace(port, channel, denom) == NullDenomTrace
\* Get the denomination trace port
GetPort(trace) == NullId
\* Get the denomination trace port
GetChannel(trace) == NullId
\* Get the denomination trace basic denomination
GetDenom(trace) == NullDenomTrace
\* Is this denomination trace a native denomination, or is it a prefixed trace
\* Note that those cases are exclusive, but not exhaustive
IsNativeDenomTrace(trace) == GetPort(trace) = NullId /\ GetChannel(trace) = NullId
IsPrefixedDenomTrace(trace) == GetPort(trace) /= NullId /\ GetChannel(trace) /= NullId
DenomTypeOK ==
/\ NullDenomTrace \in DenomTraces
/\ \A p \in Identifiers, c \in Identifiers, d \in Denoms:
MakeDenomTrace(p, c, d) \in DenomTraces
/\ \A t \in DenomTraces:
/\ GetPort(t) \in Identifiers
/\ GetChannel(t) \in Identifiers
/\ GetDenom(t) \in DenomTraces
=============================================================================
\* Modification History
\* Last modified Thu Nov 05 15:49:23 CET 2020 by andrey
\* Created Thu Nov 05 13:22:40 CET 2020 by andrey

View File

@ -1,53 +0,0 @@
-------------------------- MODULE denom_record ----------------------------
(**
The most basic implementation of denomination traces that allows only one-step sequences
Represented via records
*)
EXTENDS identifiers
CONSTANT
Denoms
MaxDenomLength == 3
DenomTraces == [
port: Identifiers,
channel: Identifiers,
denom: Denoms
]
NullDenomTrace == [
port |-> NullId,
channel |-> NullId,
denom |-> NullId
]
GetPort(trace) == trace.port
GetChannel(trace) == trace.channel
GetDenom(trace) == trace.denom
IsNativeDenomTrace(trace) == GetPort(trace) = NullId /\ GetChannel(trace) = NullId /\ GetDenom(trace) /= NullId
IsPrefixedDenomTrace(trace) == GetPort(trace) /= NullId /\ GetChannel(trace) /= NullId /\ GetDenom(trace) /= NullId
ExtendDenomTrace(port, channel, trace) ==
IF GetPort(trace) = NullId /\ GetChannel(trace) = NullId
THEN
[
port |-> port,
channel |-> channel,
denom |-> trace.denom
]
ELSE
NullDenomTrace
DENOM == INSTANCE denom
DenomTypeOK == DENOM!DenomTypeOK
=============================================================================
\* Modification History
\* Last modified Thu Nov 05 16:41:47 CET 2020 by andrey
\* Created Thu Nov 05 13:22:40 CET 2020 by andrey

View File

@ -1,114 +0,0 @@
-------------------------- MODULE denom_record2 ----------------------------
(**
The implementation of denomination traces that allows one- or two-step sequences
Represented via records
*)
EXTENDS identifiers
CONSTANT
Denoms
MaxDenomLength == 5
DenomPrefixes == [
port: Identifiers,
channel: Identifiers
]
NullDenomPrefix == [
port |-> NullId,
channel |-> NullId
]
MakeDenomPrefix(port, channel) == [
port |-> port,
channel |-> channel
]
IsValidDenomPrefix(prefix) ==
/\ prefix.port /= NullId
/\ prefix.channel /= NullId
DenomTraces == [
prefix1: DenomPrefixes, \* the most recent prefix
prefix0: DenomPrefixes, \* the deepest prefix
denom: Denoms
]
NullDenomTrace == [
prefix1 |-> NullDenomPrefix,
prefix0 |-> NullDenomPrefix,
denom |-> NullId
]
TraceLen(trace) ==
IF trace.prefix0 = NullDenomPrefix
THEN 1
ELSE IF trace.prefix1 = NullDenomPrefix
THEN 3
ELSE 5
LatestPrefix(trace) ==
IF trace.prefix0 = NullDenomPrefix
THEN NullDenomPrefix
ELSE IF trace.prefix1 = NullDenomPrefix
THEN trace.prefix0
ELSE trace.prefix1
ExtendDenomTrace(port, channel, trace) ==
IF trace.prefix0 = NullDenomPrefix
THEN [
prefix1 |-> NullDenomPrefix,
prefix0 |-> MakeDenomPrefix(port, channel),
denom |-> trace.denom
]
ELSE IF trace.prefix1 = NullDenomPrefix
THEN [
prefix1 |-> MakeDenomPrefix(port, channel),
prefix0 |-> trace.prefix0,
denom |-> trace.denom
]
ELSE NullDenomTrace \* can extend only for two steps
ReduceDenomTrace(trace) ==
IF trace.prefix1 /= NullDenomPrefix
THEN [
prefix1 |-> NullDenomPrefix,
prefix0 |-> trace.prefix0,
denom |-> trace.denom
]
ELSE IF trace.prefix0 /= NullDenomPrefix
THEN [
prefix1 |-> NullDenomPrefix,
prefix0 |-> NullDenomPrefix,
denom |-> trace.denom
]
ELSE NullDenomTrace \* cannot reduce further
GetPort(trace) == LatestPrefix(trace).port
GetChannel(trace) == LatestPrefix(trace).channel
GetDenom(trace) == trace.denom
IsValidDenomTrace(trace) ==
/\ GetDenom(trace) /= NullId
/\ IF IsValidDenomPrefix(trace.prefix1)
THEN IsValidDenomPrefix(trace.prefix0)
ELSE
/\ trace.prefix1 = NullDenomPrefix
/\ (IsValidDenomPrefix(trace.prefix0) \/ trace.prefix0 = NullDenomPrefix)
IsNativeDenomTrace(trace) == LatestPrefix(trace) = NullDenomPrefix /\ GetDenom(trace) /= NullId
IsPrefixedDenomTrace(trace) == LatestPrefix(trace) /= NullDenomPrefix /\ GetDenom(trace) /= NullId
DENOM == INSTANCE denom
DenomTypeOK == DENOM!DenomTypeOK
=============================================================================
\* Modification History
\* Last modified Fri Dec 04 10:38:10 CET 2020 by andrey
\* Created Fri Dec 04 10:22:10 CET 2020 by andrey

View File

@ -1,47 +0,0 @@
-------------------------- MODULE denom_sequence ----------------------------
(**
The implementation of denomination traces via sequences
*)
EXTENDS Integers, Sequences, identifiers
CONSTANT
Denoms,
MaxDenomLength
a <: b == a
AsAddress(seq) == seq <: Seq(STRING)
UNROLL_DEFAULT_GenSeq == { AsAddress(<< >>) }
UNROLL_TIMES_GenSeq == 5
\* This produces denomination sequences up to the given bound
RECURSIVE GenSeq(_)
GenSeq(n) ==
IF n = 0 THEN { AsAddress(<< >>) }
ELSE LET Shorter == GenSeq(n-1) IN
{ Append(s,x): x \in Identifiers, s \in Shorter } \union Shorter
DenomTraces == GenSeq(MaxDenomLength)
ExtendDenomTrace(port, channel, denom) == AsAddress(<<port, channel>>) \o denom
GetPort(trace) == trace[1]
GetChannel(trace) == trace[2]
GetDenom(trace) == SubSeq(trace, 3, Len(trace))
NullDenomTrace == AsAddress(<< >>)
IsNativeDenomTrace(trace) == GetPort(trace) = NullId /\ GetChannel(trace) = NullId /\ GetDenom(trace) /= NullDenomTrace
IsPrefixedDenomTrace(trace) == GetPort(trace) /= NullId /\ GetChannel(trace) /= NullId /\ GetDenom(trace) /= NullDenomTrace
DENOM == INSTANCE denom
DenomTypeOK == DENOM!DenomTypeOK
=============================================================================
\* Modification History
\* Last modified Thu Nov 05 15:29:21 CET 2020 by andrey
\* Created Thu Nov 05 13:22:40 CET 2020 by andrey

View File

@ -1,10 +0,0 @@
-------------------------- MODULE identifiers ----------------------------
CONSTANT
Identifiers,
NullId
=============================================================================
\* Modification History
\* Last modified Thu Nov 05 13:23:12 CET 2020 by andrey
\* Created Thu Nov 05 13:22:40 CET 2020 by andrey

View File

@ -1,278 +0,0 @@
-------------------------- MODULE relay ----------------------------
(**
* A primitive model for account arithmetics and token movement
* of the Cosmos SDK ICS20 Token Transfer
* We completely abstract away many details,
* and want to focus on a minimal spec useful for testing
*
* We also try to make the model modular in that it uses
* denomination traces and accounts via abstract interfaces,
* outlined in denom.tla and account.tla
*)
EXTENDS Integers, FiniteSets, Sequences, identifiers, denom_record2, account_record
CONSTANT
MaxAmount
VARIABLE
error,
bank,
p, \* we want to start with generating single packets,
handler,
history,
count
Amounts == 0..MaxAmount
GetSourceEscrowAccount(packet) == MakeEscrowAccount(packet.sourcePort, packet.sourceChannel)
GetDestEscrowAccount(packet) == MakeEscrowAccount(packet.destPort, packet.destChannel)
FungibleTokenPacketData == [
sender: AccountIds,
receiver: AccountIds,
denomTrace: DenomTraces,
amount: Amounts
]
Packets == [
\* We abstract those packet fields away
\* sequence: uint64
\* timeoutHeight: Height
\* timeoutTimestamp: uint64
sourcePort: Identifiers,
sourceChannel: Identifiers,
destPort: Identifiers,
destChannel: Identifiers,
data: FungibleTokenPacketData
]
IsSource(packet) ==
/\ GetPort(packet.data.denomTrace) = packet.sourcePort
/\ GetChannel(packet.data.denomTrace) = packet.sourceChannel
\* This function models the port and channel checks that happen when the packet is sent
IsValidSendChannel(packet) ==
/\ packet.sourcePort = "transfer"
/\ (packet.sourceChannel = "channel-0" \/ packet.sourceChannel = "channel-1")
/\ packet.destPort = "transfer"
/\ packet.destChannel = "channel-0"
\* This function models the port and channel checks that happen when relay gets the packet
IsValidRecvChannel(packet) ==
/\ packet.sourcePort = "transfer"
/\ packet.sourceChannel = "channel-0"
/\ packet.destPort = "transfer"
/\ (packet.destChannel = "channel-0" \/ packet.destChannel = "channel-1")
WellFormedPacket(packet) ==
/\ packet.sourcePort /= NullId
/\ packet.sourceChannel /= NullId
/\ packet.destPort /= NullId
/\ packet.destChannel /= NullId
BankWithAccount(abank, account, denom) ==
IF <<account, denom>> \in DOMAIN abank
THEN abank
ELSE [x \in DOMAIN bank \union { <<account, denom>> }
|-> IF x = <<account, denom>>
THEN 0
ELSE bank[x] ]
IsKnownDenomTrace(trace) ==
\E account \in Accounts :
<<account, trace>> \in DOMAIN bank
SendTransferPre(packet, pbank) ==
LET data == packet.data
trace == data.denomTrace
sender == data.sender
amount == data.amount
escrow == GetSourceEscrowAccount(packet)
IN
/\ WellFormedPacket(packet)
/\ IsValidSendChannel(packet)
/\ IsNativeDenomTrace(trace) \/ (IsValidDenomTrace(trace) /\ IsKnownDenomTrace(trace))
/\ data.sender /= NullId
/\ <<escrow, data.denomTrace>> \in DOMAIN pbank
/\ \/ amount = 0 \* SendTrasfer actually allows for 0 amount
\/ <<MakeAccount(sender), trace>> \in DOMAIN pbank /\ bank[MakeAccount(sender), trace] >= amount
SendTransferNext(packet) ==
LET data == packet.data IN
LET denom == GetDenom(data.denomTrace) IN
LET amount == data.amount IN
LET sender == data.sender IN
LET escrow == GetSourceEscrowAccount(packet) IN
LET bankwithescrow == BankWithAccount(bank, escrow, data.denomTrace) IN
IF SendTransferPre(packet,bankwithescrow)
THEN
/\ error' = FALSE
\*/\ IBCsend(chain, packet)
/\ IF ~IsSource(packet)
\* This is how the check is encoded in ICS20 and the implementation.
\* The meaning is "IF denom = AsAddress(NativeDenom)" because of the following argument:
\* observe that due to the disjunction in SendTransferPre(packet), we have
\* ~IsSource(packet) /\ SendTransferPre(packet) => denom = AsAddress(NativeDenom)
THEN
\* tokens are from this chain
\* transfer tokens from sender into escrow account
bank' = [bankwithescrow EXCEPT ![MakeAccount(sender), data.denomTrace] = @ - amount,
![escrow, data.denomTrace] = @ + amount]
ELSE
\* tokens are from other chain. We forward them.
\* burn sender's money
bank' = [bankwithescrow EXCEPT ![MakeAccount(sender), data.denomTrace] = @ - amount]
ELSE
/\ error' = TRUE
/\ UNCHANGED bank
OnRecvPacketPre(packet) ==
LET data == packet.data
trace == data.denomTrace
denom == GetDenom(trace)
amount == data.amount
IN
/\ WellFormedPacket(packet)
/\ IsValidRecvChannel(packet)
/\ IsValidDenomTrace(trace)
/\ amount > 0
\* if there is no receiver account, it is created by the bank
/\ data.receiver /= NullId
/\ IsSource(packet) =>
LET escrow == GetDestEscrowAccount(packet) IN
LET denomTrace == ReduceDenomTrace(trace) IN
/\ <<escrow, denomTrace>> \in DOMAIN bank
/\ bank[escrow, denomTrace] >= amount
OnRecvPacketNext(packet) ==
LET data == packet.data IN
LET trace == data.denomTrace IN
LET denom == GetDenom(trace) IN
LET amount == data.amount IN
LET receiver == data.receiver IN
/\ IF OnRecvPacketPre(packet)
THEN
\* This condition is necessary so that denomination traces do not exceed the maximum length
/\ (IsSource(packet) \/ TraceLen(trace) < MaxDenomLength)
/\ error' = FALSE
/\ IF IsSource(packet)
THEN
\* transfer from the escrow account to the receiver account
LET denomTrace == ReduceDenomTrace(trace) IN
LET escrow == GetDestEscrowAccount(packet) IN
LET bankwithreceiver == BankWithAccount(bank, MakeAccount(receiver), denomTrace) IN
bank' = [bankwithreceiver
EXCEPT ![MakeAccount(receiver), denomTrace] = @ + amount,
![escrow, denomTrace] = @ - amount]
ELSE
\* create new tokens with new denomination and transfer it to the receiver account
LET denomTrace == ExtendDenomTrace(packet.destPort, packet.destChannel, trace) IN
LET bankwithreceiver ==
BankWithAccount(bank, MakeAccount(receiver), denomTrace) IN
bank' = [bankwithreceiver
EXCEPT ![MakeAccount(receiver), denomTrace] = @ + amount]
ELSE
/\ error' = TRUE
/\ UNCHANGED bank
OnTimeoutPacketPre(packet) ==
LET data == packet.data
trace == data.denomTrace
denom == GetDenom(trace)
amount == data.amount
IN
/\ WellFormedPacket(packet)
/\ IsValidSendChannel(packet)
/\ IsValidDenomTrace(trace)
/\ data.sender /= NullId
/\ ~IsSource(packet) =>
LET escrow == GetSourceEscrowAccount(packet)
IN /\ <<escrow, trace>> \in DOMAIN bank
/\ bank[escrow, trace] >= amount
OnTimeoutPacketNext(packet) ==
LET data == packet.data IN
LET trace == data.denomTrace IN
LET denom == GetDenom(data.denomTrace) IN
LET amount == data.amount IN
LET sender == data.sender IN
LET bankwithsender == BankWithAccount(bank, MakeAccount(sender), trace) IN
IF OnTimeoutPacketPre(packet)
THEN
/\ error' = FALSE
/\ IF ~IsSource(packet)
THEN
\* transfer from the escrow acount to the sender account
\* LET denomsuffix == SubSeq(denom, 3, Len(denom)) IN
LET escrow == GetSourceEscrowAccount(packet) IN
bank' = [bankwithsender
EXCEPT ![MakeAccount(sender), trace] = @ + amount,
![escrow, trace] = @ - amount]
ELSE
\* mint back the money
bank' = [bankwithsender EXCEPT ![MakeAccount(sender), trace] = @ + amount]
ELSE
/\ error' = TRUE
/\ UNCHANGED bank
OnAcknowledgementPacketResultNext(packet) ==
IF WellFormedPacket(packet)
THEN
/\ error' = FALSE
/\ UNCHANGED bank
ELSE
/\ error' = TRUE
/\ UNCHANGED bank
OnAcknowledgementPacketErrorNext(packet) ==
OnTimeoutPacketNext(packet)
Init ==
/\ p \in Packets
/\ bank = [ x \in {<<NullAccount, NullDenomTrace>>} |-> 0 ]
/\ count = 0
/\ history = [
n \in {0} |-> [
error |-> FALSE,
packet |-> p,
handler |-> "",
bankBefore |-> bank,
bankAfter |-> bank
]
]
/\ error = FALSE
/\ handler = ""
Next ==
/\ p' \in Packets
/\ count'= count + 1
/\
\/ (SendTransferNext(p) /\ handler' = "SendTransfer")
\/ (OnRecvPacketNext(p) /\ handler' = "OnRecvPacket")
\/ (OnTimeoutPacketNext(p) /\ handler' = "OnTimeoutPacket")
\/ (OnAcknowledgementPacketResultNext(p) /\ handler' = "OnRecvAcknowledgementResult")
\/ (OnAcknowledgementPacketErrorNext(p) /\ handler' = "OnRecvAcknowledgementError")
/\ history' = [ n \in DOMAIN history \union {count'} |->
IF n = count' THEN
[ packet |-> p, handler |-> handler', error |-> error', bankBefore |-> bank, bankAfter |-> bank' ]
ELSE history[n]
]
=============================================================================
\* Modification History
\* Last modified Wed Dec 2 10:15:45 CET 2020 by andrey
\* Last modified Fri Nov 20 12:37:38 CET 2020 by c
\* Last modified Thu Nov 05 20:56:37 CET 2020 by andrey
\* Last modified Fri Oct 30 21:52:38 CET 2020 by widder
\* Created Thu Oct 29 20:45:55 CET 2020 by andrey

View File

@ -1,96 +0,0 @@
-------------------------- MODULE relay_tests ----------------------------
EXTENDS Integers, FiniteSets
Identifiers == {"", "transfer", "channel-0", "channel-1", "cosmos-hub", "ethereum-hub", "bitcoin-hub"}
NullId == ""
MaxAmount == 5
Denoms == {"", "atom", "eth", "btc" }
AccountIds == {"", "a1", "a2", "a3" }
VARIABLES error, bank, p, count, history, handler
INSTANCE relay
\************************** Tests ******************************
\* Generic test for handler pass
TestHandlerPass(handlerName) ==
\E s \in DOMAIN history :
/\ history[s].handler = handlerName
/\ history[s].error = FALSE
/\ history[s].packet.data.amount > 0
\* Generic test for handler fail
TestHandlerFail(handlerName) ==
\E s \in DOMAIN history :
/\ history[s].handler = handlerName
/\ history[s].error = TRUE
/\ history[s].packet.data.amount > 0
TestSendTransferPass == TestHandlerPass("SendTransfer")
TestSendTransferPassInv == ~TestSendTransferPass
TestSendTransferFail == TestHandlerFail("SendTransfer")
TestSendTransferFailInv == ~TestSendTransferFail
TestOnRecvPacketPass == TestHandlerPass("OnRecvPacket")
TestOnRecvPacketPassInv == ~TestOnRecvPacketPass
TestOnRecvPacketFail == TestHandlerFail("OnRecvPacket")
TestOnRecvPacketFailInv == ~TestOnRecvPacketFail
TestOnTimeoutPass == TestHandlerPass("OnTimeoutPacket")
TestOnTimeoutPassInv == ~TestOnTimeoutPass
TestOnTimeoutFail == TestHandlerFail("OnTimeoutPacket")
TestOnTimeoutFailInv == ~TestOnTimeoutFail
TestOnRecvAcknowledgementResultPass == TestHandlerPass("OnRecvAcknowledgementResult")
TestOnRecvAcknowledgementResultPassInv == ~TestOnRecvAcknowledgementResultPass
TestOnRecvAcknowledgementResultFail == TestHandlerFail("OnRecvAcknowledgementResult")
TestOnRecvAcknowledgementResultFailInv == ~TestOnRecvAcknowledgementResultFail
TestOnRecvAcknowledgementErrorPass == TestHandlerPass("OnRecvAcknowledgementError")
TestOnRecvAcknowledgementErrorPassInv == ~TestOnRecvAcknowledgementErrorPass
TestOnRecvAcknowledgementErrorFail == TestHandlerFail("OnRecvAcknowledgementError")
TestOnRecvAcknowledgementErrorFailInv == ~TestOnRecvAcknowledgementErrorFail
Test5Packets ==
count >= 5
Test5PacketsInv == ~Test5Packets
Test5Packets2Different ==
/\ count >= 5
/\ \E s1, s2 \in DOMAIN history :
history[s1].handler /= history[s2].handler
Test5Packets2DifferentInv == ~Test5Packets2Different
Test5PacketsAllDifferent ==
/\ count >= 5
/\ \A s1, s2 \in DOMAIN history :
s1 /= s2 => history[s1].handler /= history[s2].handler
Test5PacketsAllDifferentInv == ~Test5PacketsAllDifferent
Test5PacketsAllDifferentPass ==
/\ Test5PacketsAllDifferent
/\ \A s \in DOMAIN history :
s > 0 =>
/\ history[s].error = FALSE
/\ history[s].packet.data.amount > 0
Test5PacketsAllDifferentPassInv == ~Test5PacketsAllDifferentPass
TestUnescrowTokens ==
\E s \in DOMAIN history :
/\ IsSource(history[s].packet)
/\ history[s].handler = "OnRecvPacket"
/\ history[s].error = FALSE
TestUnescrowTokensInv == ~TestUnescrowTokens
=============================================================================

View File

@ -1,392 +0,0 @@
package keeper_test
import (
"fmt"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
// test sending from chainA to chainB using both coin that orignate on
// chainA and coin that orignate on chainB
func (suite *KeeperTestSuite) TestSendTransfer() {
var (
amount sdk.Coin
channelA, channelB ibctesting.TestChannel
err error
)
testCases := []struct {
msg string
malleate func()
sendFromSource bool
expPass bool
}{
{"successful transfer from source chain",
func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
}, true, true},
{"successful transfer with coin from counterparty chain",
func() {
// send coin from chainA back to chainB
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
amount = types.GetTransferCoin(channelA.PortID, channelA.ID, sdk.DefaultBondDenom, 100)
}, false, true},
{"source channel not found",
func() {
// channel references wrong ID
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
channelA.ID = ibctesting.InvalidID
amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
}, true, false},
{"next seq send not found",
func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA = suite.chainA.NextTestChannel(connA, ibctesting.TransferPort)
channelB = suite.chainB.NextTestChannel(connB, ibctesting.TransferPort)
// manually create channel so next seq send is never set
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(
suite.chainA.GetContext(),
channelA.PortID, channelA.ID,
channeltypes.NewChannel(channeltypes.OPEN, channeltypes.ORDERED, channeltypes.NewCounterparty(channelB.PortID, channelB.ID), []string{connA.ID}, ibctesting.DefaultChannelVersion),
)
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
}, true, false},
// createOutgoingPacket tests
// - source chain
{"send coin failed",
func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
amount = sdk.NewCoin("randomdenom", sdk.NewInt(100))
}, true, false},
// - receiving chain
{"send from module account failed",
func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
amount = types.GetTransferCoin(channelA.PortID, channelA.ID, " randomdenom", 100)
}, false, false},
{"channel capability not found",
func() {
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
cap := suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
// Release channel capability
suite.chainA.App.ScopedTransferKeeper.ReleaseCapability(suite.chainA.GetContext(), cap)
amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
}, true, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
if !tc.sendFromSource {
// send coin from chainB to chainA
coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
transferMsg := types.NewMsgTransfer(channelB.PortID, channelB.ID, coinFromBToA, suite.chainB.SenderAccount.GetAddress(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0)
err = suite.coordinator.SendMsg(suite.chainB, suite.chainA, channelA.ClientID, transferMsg)
suite.Require().NoError(err) // message committed
// receive coin on chainA from chainB
fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, channelB.PortID, channelB.ID, channelA.PortID, channelA.ID, clienttypes.NewHeight(0, 110), 0)
// get proof of packet commitment from chainB
packetKey := host.PacketCommitmentKey(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
proof, proofHeight := suite.chainB.QueryProof(packetKey)
recvMsg := channeltypes.NewMsgRecvPacket(packet, proof, proofHeight, suite.chainA.SenderAccount.GetAddress())
err = suite.coordinator.SendMsg(suite.chainA, suite.chainB, channelB.ClientID, recvMsg)
suite.Require().NoError(err) // message committed
}
err = suite.chainA.App.TransferKeeper.SendTransfer(
suite.chainA.GetContext(), channelA.PortID, channelA.ID, amount,
suite.chainA.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// test receiving coin on chainB with coin that orignate on chainA and
// coin that orignated on chainB (source). The bulk of the testing occurs
// in the test case for loop since setup is intensive for all cases. The
// malleate function allows for testing invalid cases.
func (suite *KeeperTestSuite) TestOnRecvPacket() {
var (
channelA, channelB ibctesting.TestChannel
trace types.DenomTrace
amount sdk.Int
receiver string
)
testCases := []struct {
msg string
malleate func()
recvIsSource bool // the receiving chain is the source of the coin originally
expPass bool
}{
{"success receive on source chain", func() {}, true, true},
{"success receive with coin from another chain as source", func() {}, false, true},
{"empty coin", func() {
trace = types.DenomTrace{}
amount = sdk.ZeroInt()
}, true, false},
{"invalid receiver address", func() {
receiver = "gaia1scqhwpgsmr6vmztaa7suurfl52my6nd2kmrudl"
}, true, false},
// onRecvPacket
// - coin from chain chainA
{"failure: mint zero coin", func() {
amount = sdk.ZeroInt()
}, false, false},
// - coin being sent back to original chain (chainB)
{"tries to unescrow more tokens than allowed", func() {
amount = sdk.NewInt(1000000)
}, true, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
clientA, clientB, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
receiver = suite.chainB.SenderAccount.GetAddress().String() // must be explicitly changed in malleate
amount = sdk.NewInt(100) // must be explicitly changed in malleate
seq := uint64(1)
if tc.recvIsSource {
// send coin from chainB to chainA, receive them, acknowledge them, and send back to chainB
coinFromBToA := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
transferMsg := types.NewMsgTransfer(channelB.PortID, channelB.ID, coinFromBToA, suite.chainB.SenderAccount.GetAddress(), suite.chainA.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0)
err := suite.coordinator.SendMsg(suite.chainB, suite.chainA, channelA.ClientID, transferMsg)
suite.Require().NoError(err) // message committed
// relay send packet
fungibleTokenPacket := types.NewFungibleTokenPacketData(coinFromBToA.Denom, coinFromBToA.Amount.Uint64(), suite.chainB.SenderAccount.GetAddress().String(), suite.chainA.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(fungibleTokenPacket.GetBytes(), 1, channelB.PortID, channelB.ID, channelA.PortID, channelA.ID, clienttypes.NewHeight(0, 110), 0)
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
err = suite.coordinator.RelayPacket(suite.chainB, suite.chainA, clientB, clientA, packet, ack.GetBytes())
suite.Require().NoError(err) // relay committed
seq++
// NOTE: trace must be explicitly changed in malleate to test invalid cases
trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelA.PortID, channelA.ID, sdk.DefaultBondDenom))
} else {
trace = types.ParseDenomTrace(sdk.DefaultBondDenom)
}
// send coin from chainA to chainB
transferMsg := types.NewMsgTransfer(channelA.PortID, channelA.ID, sdk.NewCoin(trace.IBCDenom(), amount), suite.chainA.SenderAccount.GetAddress(), receiver, clienttypes.NewHeight(0, 110), 0)
err := suite.coordinator.SendMsg(suite.chainA, suite.chainB, channelB.ClientID, transferMsg)
suite.Require().NoError(err) // message committed
tc.malleate()
data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.Uint64(), suite.chainA.SenderAccount.GetAddress().String(), receiver)
packet := channeltypes.NewPacket(data.GetBytes(), seq, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, clienttypes.NewHeight(0, 100), 0)
err = suite.chainB.App.TransferKeeper.OnRecvPacket(suite.chainB.GetContext(), packet, data)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// TestOnAcknowledgementPacket tests that successful acknowledgement is a no-op
// and failure acknowledment leads to refund when attempting to send from chainA
// to chainB. If sender is source than the denomination being refunded has no
// trace.
func (suite *KeeperTestSuite) TestOnAcknowledgementPacket() {
var (
successAck = channeltypes.NewResultAcknowledgement([]byte{byte(1)})
failedAck = channeltypes.NewErrorAcknowledgement("failed packet transfer")
channelA, channelB ibctesting.TestChannel
trace types.DenomTrace
amount sdk.Int
)
testCases := []struct {
msg string
ack channeltypes.Acknowledgement
malleate func()
success bool // success of ack
expPass bool
}{
{"success ack causes no-op", successAck, func() {
trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelB.PortID, channelB.ID, sdk.DefaultBondDenom))
}, true, true},
{"successful refund from source chain", failedAck, func() {
escrow := types.GetEscrowAddress(channelA.PortID, channelA.ID)
trace = types.ParseDenomTrace(sdk.DefaultBondDenom)
coin := sdk.NewCoin(sdk.DefaultBondDenom, amount)
suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)))
}, false, true},
{"unsuccessful refund from source", failedAck,
func() {
trace = types.ParseDenomTrace(sdk.DefaultBondDenom)
}, false, false},
{"successful refund from with coin from external chain", failedAck,
func() {
escrow := types.GetEscrowAddress(channelA.PortID, channelA.ID)
trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelA.PortID, channelA.ID, sdk.DefaultBondDenom))
coin := sdk.NewCoin(trace.IBCDenom(), amount)
suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)))
}, false, true},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
_, _, _, _, channelA, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB, channeltypes.UNORDERED)
amount = sdk.NewInt(100) // must be explicitly changed
tc.malleate()
data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.Uint64(), suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(data.GetBytes(), 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, clienttypes.NewHeight(0, 100), 0)
preCoin := suite.chainA.App.BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom())
err := suite.chainA.App.TransferKeeper.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, data, tc.ack)
if tc.expPass {
suite.Require().NoError(err)
postCoin := suite.chainA.App.BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom())
deltaAmount := postCoin.Amount.Sub(preCoin.Amount)
if tc.success {
suite.Require().Equal(int64(0), deltaAmount.Int64(), "successful ack changed balance")
} else {
suite.Require().Equal(amount, deltaAmount, "failed ack did not trigger refund")
}
} else {
suite.Require().Error(err)
}
})
}
}
// TestOnTimeoutPacket test private refundPacket function since it is a simple
// wrapper over it. The actual timeout does not matter since IBC core logic
// is not being tested. The test is timing out a send from chainA to chainB
// so the refunds are occurring on chainA.
func (suite *KeeperTestSuite) TestOnTimeoutPacket() {
var (
channelA, channelB ibctesting.TestChannel
trace types.DenomTrace
amount sdk.Int
sender string
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"successful timeout from sender as source chain",
func() {
escrow := types.GetEscrowAddress(channelA.PortID, channelA.ID)
trace = types.ParseDenomTrace(sdk.DefaultBondDenom)
coin := sdk.NewCoin(trace.IBCDenom(), amount)
suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)))
}, true},
{"successful timeout from external chain",
func() {
escrow := types.GetEscrowAddress(channelA.PortID, channelA.ID)
trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelA.PortID, channelA.ID, sdk.DefaultBondDenom))
coin := sdk.NewCoin(trace.IBCDenom(), amount)
suite.Require().NoError(simapp.FundAccount(suite.chainA.App, suite.chainA.GetContext(), escrow, sdk.NewCoins(coin)))
}, true},
{"no balance for coin denom",
func() {
trace = types.ParseDenomTrace("bitcoin")
}, false},
{"unescrow failed",
func() {
trace = types.ParseDenomTrace(sdk.DefaultBondDenom)
}, false},
{"mint failed",
func() {
trace = types.ParseDenomTrace(types.GetPrefixedDenom(channelA.PortID, channelA.ID, sdk.DefaultBondDenom))
amount = sdk.OneInt()
sender = "invalid address"
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
_, _, connA, connB := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
channelA, channelB = suite.coordinator.CreateTransferChannels(suite.chainA, suite.chainB, connA, connB, channeltypes.UNORDERED)
amount = sdk.NewInt(100) // must be explicitly changed
sender = suite.chainA.SenderAccount.GetAddress().String()
tc.malleate()
data := types.NewFungibleTokenPacketData(trace.GetFullDenomPath(), amount.Uint64(), sender, suite.chainB.SenderAccount.GetAddress().String())
packet := channeltypes.NewPacket(data.GetBytes(), 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, clienttypes.NewHeight(0, 100), 0)
preCoin := suite.chainA.App.BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom())
err := suite.chainA.App.TransferKeeper.OnTimeoutPacket(suite.chainA.GetContext(), packet, data)
postCoin := suite.chainA.App.BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), trace.IBCDenom())
deltaAmount := postCoin.Amount.Sub(preCoin.Amount)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().Equal(amount.Int64(), deltaAmount.Int64(), "successful timeout did not trigger refund")
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -1,434 +0,0 @@
package transfer
import (
"context"
"encoding/json"
"fmt"
"math"
"math/rand"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/keeper"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
porttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/05-port/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
)
var (
_ module.AppModule = AppModule{}
_ porttypes.IBCModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
)
// AppModuleBasic is the IBC Transfer AppModuleBasic
type AppModuleBasic struct{}
// Name implements AppModuleBasic interface
func (AppModuleBasic) Name() string {
return types.ModuleName
}
// RegisterLegacyAminoCodec implements AppModuleBasic interface
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
types.RegisterLegacyAminoCodec(cdc)
}
// RegisterInterfaces registers module concrete types into protobuf Any.
func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
types.RegisterInterfaces(registry)
}
// DefaultGenesis returns default genesis state as raw bytes for the ibc
// transfer module.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage {
return cdc.MustMarshalJSON(types.DefaultGenesisState())
}
// ValidateGenesis performs genesis state validation for the ibc transfer module.
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error {
var gs types.GenesisState
if err := cdc.UnmarshalJSON(bz, &gs); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}
return gs.Validate()
}
// RegisterRESTRoutes implements AppModuleBasic interface
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
}
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the ibc-transfer module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx))
}
// GetTxCmd implements AppModuleBasic interface
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.NewTxCmd()
}
// GetQueryCmd implements AppModuleBasic interface
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()
}
// AppModule represents the AppModule for this module
type AppModule struct {
AppModuleBasic
keeper keeper.Keeper
}
// NewAppModule creates a new 20-transfer module
func NewAppModule(k keeper.Keeper) AppModule {
return AppModule{
keeper: k,
}
}
// RegisterInvariants implements the AppModule interface
func (AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
// TODO
}
// Route implements the AppModule interface
func (am AppModule) Route() sdk.Route {
return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper))
}
// QuerierRoute implements the AppModule interface
func (AppModule) QuerierRoute() string {
return types.QuerierRoute
}
// LegacyQuerierHandler implements the AppModule interface
func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier {
return nil
}
// RegisterServices registers module services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}
// InitGenesis performs genesis initialization for the ibc-transfer module. It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
am.keeper.InitGenesis(ctx, genesisState)
return []abci.ValidatorUpdate{}
}
// ExportGenesis returns the exported genesis state as raw bytes for the ibc-transfer
// module.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage {
gs := am.keeper.ExportGenesis(ctx)
return cdc.MustMarshalJSON(gs)
}
// ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 1 }
// BeginBlock implements the AppModule interface
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
}
// EndBlock implements the AppModule interface
func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}
// AppModuleSimulation functions
// GenerateGenesisState creates a randomized GenState of the transfer module.
func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// ProposalContents doesn't return any content functions for governance proposals.
func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent {
return nil
}
// RandomizedParams creates randomized ibc-transfer param changes for the simulator.
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return simulation.ParamChanges(r)
}
// RegisterStoreDecoder registers a decoder for transfer module's types
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper)
}
// WeightedOperations returns the all the transfer module operations with their respective weights.
func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation {
return nil
}
// ValidateTransferChannelParams does validation of a newly created transfer channel. A transfer
// channel must be UNORDERED, use the correct port (by default 'transfer'), and use the current
// supported version. Only 2^32 channels are allowed to be created.
func ValidateTransferChannelParams(
ctx sdk.Context,
keeper keeper.Keeper,
order channeltypes.Order,
portID string,
channelID string,
version string,
) error {
// NOTE: for escrow address security only 2^32 channels are allowed to be created
// Issue: https://github.com/cosmos/cosmos-sdk/issues/7737
channelSequence, err := channeltypes.ParseChannelSequence(channelID)
if err != nil {
return err
}
if channelSequence > uint64(math.MaxUint32) {
return sdkerrors.Wrapf(types.ErrMaxTransferChannels, "channel sequence %d is greater than max allowed transfer channels %d", channelSequence, uint64(math.MaxUint32))
}
if order != channeltypes.UNORDERED {
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "expected %s channel, got %s ", channeltypes.UNORDERED, order)
}
// Require portID is the portID transfer module is bound to
boundPort := keeper.GetPort(ctx)
if boundPort != portID {
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "invalid port: %s, expected %s", portID, boundPort)
}
if version != types.Version {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "got %s, expected %s", version, types.Version)
}
return nil
}
// OnChanOpenInit implements the IBCModule interface
func (am AppModule) OnChanOpenInit(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
portID string,
channelID string,
chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
version string,
) error {
if err := ValidateTransferChannelParams(ctx, am.keeper, order, portID, channelID, version); err != nil {
return err
}
// Claim channel capability passed back by IBC module
if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
return err
}
return nil
}
// OnChanOpenTry implements the IBCModule interface
func (am AppModule) OnChanOpenTry(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
portID,
channelID string,
chanCap *capabilitytypes.Capability,
counterparty channeltypes.Counterparty,
version,
counterpartyVersion string,
) error {
if err := ValidateTransferChannelParams(ctx, am.keeper, order, portID, channelID, version); err != nil {
return err
}
if counterpartyVersion != types.Version {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: got: %s, expected %s", counterpartyVersion, types.Version)
}
// Module may have already claimed capability in OnChanOpenInit in the case of crossing hellos
// (ie chainA and chainB both call ChanOpenInit before one of them calls ChanOpenTry)
// If module can already authenticate the capability then module already owns it so we don't need to claim
// Otherwise, module does not have channel capability and we must claim it from IBC
if !am.keeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
// Only claim channel capability passed back by IBC module if we do not already own it
if err := am.keeper.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
return err
}
}
return nil
}
// OnChanOpenAck implements the IBCModule interface
func (am AppModule) OnChanOpenAck(
ctx sdk.Context,
portID,
channelID string,
counterpartyVersion string,
) error {
if counterpartyVersion != types.Version {
return sdkerrors.Wrapf(types.ErrInvalidVersion, "invalid counterparty version: %s, expected %s", counterpartyVersion, types.Version)
}
return nil
}
// OnChanOpenConfirm implements the IBCModule interface
func (am AppModule) OnChanOpenConfirm(
ctx sdk.Context,
portID,
channelID string,
) error {
return nil
}
// OnChanCloseInit implements the IBCModule interface
func (am AppModule) OnChanCloseInit(
ctx sdk.Context,
portID,
channelID string,
) error {
// Disallow user-initiated channel closing for transfer channels
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "user cannot close channel")
}
// OnChanCloseConfirm implements the IBCModule interface
func (am AppModule) OnChanCloseConfirm(
ctx sdk.Context,
portID,
channelID string,
) error {
return nil
}
// OnRecvPacket implements the IBCModule interface
func (am AppModule) OnRecvPacket(
ctx sdk.Context,
packet channeltypes.Packet,
) (*sdk.Result, []byte, error) {
var data types.FungibleTokenPacketData
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
return nil, nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
}
acknowledgement := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
err := am.keeper.OnRecvPacket(ctx, packet, data)
if err != nil {
acknowledgement = channeltypes.NewErrorAcknowledgement(err.Error())
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacket,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
sdk.NewAttribute(types.AttributeKeyAmount, fmt.Sprintf("%d", data.Amount)),
sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", err != nil)),
),
)
// NOTE: acknowledgement will be written synchronously during IBC handler execution.
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, acknowledgement.GetBytes(), nil
}
// OnAcknowledgementPacket implements the IBCModule interface
func (am AppModule) OnAcknowledgementPacket(
ctx sdk.Context,
packet channeltypes.Packet,
acknowledgement []byte,
) (*sdk.Result, error) {
var ack channeltypes.Acknowledgement
if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err)
}
var data types.FungibleTokenPacketData
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
}
if err := am.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacket,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
sdk.NewAttribute(types.AttributeKeyAmount, fmt.Sprintf("%d", data.Amount)),
sdk.NewAttribute(types.AttributeKeyAck, ack.String()),
),
)
switch resp := ack.Response.(type) {
case *channeltypes.Acknowledgement_Result:
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacket,
sdk.NewAttribute(types.AttributeKeyAckSuccess, string(resp.Result)),
),
)
case *channeltypes.Acknowledgement_Error:
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacket,
sdk.NewAttribute(types.AttributeKeyAckError, resp.Error),
),
)
}
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}
// OnTimeoutPacket implements the IBCModule interface
func (am AppModule) OnTimeoutPacket(
ctx sdk.Context,
packet channeltypes.Packet,
) (*sdk.Result, error) {
var data types.FungibleTokenPacketData
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
}
// refund tokens
if err := am.keeper.OnTimeoutPacket(ctx, packet, data); err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeTimeout,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender),
sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom),
sdk.NewAttribute(types.AttributeKeyRefundAmount, fmt.Sprintf("%d", data.Amount)),
),
)
return &sdk.Result{
Events: ctx.EventManager().Events().ToABCIEvents(),
}, nil
}

View File

@ -1,246 +0,0 @@
package transfer_test
import (
"math"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
func (suite *TransferTestSuite) TestOnChanOpenInit() {
var (
channel *channeltypes.Channel
testChannel ibctesting.TestChannel
connA *ibctesting.TestConnection
chanCap *capabilitytypes.Capability
)
testCases := []struct {
name string
malleate func()
expPass bool
}{
{
"success", func() {}, true,
},
{
"max channels reached", func() {
testChannel.ID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1)
}, false,
},
{
"invalid order - ORDERED", func() {
channel.Ordering = channeltypes.ORDERED
}, false,
},
{
"invalid port ID", func() {
testChannel = suite.chainA.NextTestChannel(connA, ibctesting.MockPort)
}, false,
},
{
"invalid version", func() {
channel.Version = "version"
}, false,
},
{
"capability already claimed", func() {
err := suite.chainA.App.ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(testChannel.PortID, testChannel.ID))
suite.Require().NoError(err)
}, false,
},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupTest() // reset
_, _, connA, _ = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
testChannel = suite.chainA.NextTestChannel(connA, ibctesting.TransferPort)
counterparty := channeltypes.NewCounterparty(testChannel.PortID, testChannel.ID)
channel = &channeltypes.Channel{
State: channeltypes.INIT,
Ordering: channeltypes.UNORDERED,
Counterparty: counterparty,
ConnectionHops: []string{connA.ID},
Version: types.Version,
}
module, _, err := suite.chainA.App.IBCKeeper.PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort)
suite.Require().NoError(err)
chanCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, testChannel.ID))
suite.Require().NoError(err)
cbs, ok := suite.chainA.App.IBCKeeper.Router.GetRoute(module)
suite.Require().True(ok)
tc.malleate() // explicitly change fields in channel and testChannel
err = cbs.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
testChannel.PortID, testChannel.ID, chanCap, channel.Counterparty, channel.GetVersion(),
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *TransferTestSuite) TestOnChanOpenTry() {
var (
channel *channeltypes.Channel
testChannel ibctesting.TestChannel
connA *ibctesting.TestConnection
chanCap *capabilitytypes.Capability
counterpartyVersion string
)
testCases := []struct {
name string
malleate func()
expPass bool
}{
{
"success", func() {}, true,
},
{
"max channels reached", func() {
testChannel.ID = channeltypes.FormatChannelIdentifier(math.MaxUint32 + 1)
}, false,
},
{
"capability already claimed in INIT should pass", func() {
err := suite.chainA.App.ScopedTransferKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(testChannel.PortID, testChannel.ID))
suite.Require().NoError(err)
}, true,
},
{
"invalid order - ORDERED", func() {
channel.Ordering = channeltypes.ORDERED
}, false,
},
{
"invalid port ID", func() {
testChannel = suite.chainA.NextTestChannel(connA, ibctesting.MockPort)
}, false,
},
{
"invalid version", func() {
channel.Version = "version"
}, false,
},
{
"invalid counterparty version", func() {
counterpartyVersion = "version"
}, false,
},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupTest() // reset
_, _, connA, _ = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
testChannel = suite.chainA.NextTestChannel(connA, ibctesting.TransferPort)
counterparty := channeltypes.NewCounterparty(testChannel.PortID, testChannel.ID)
channel = &channeltypes.Channel{
State: channeltypes.TRYOPEN,
Ordering: channeltypes.UNORDERED,
Counterparty: counterparty,
ConnectionHops: []string{connA.ID},
Version: types.Version,
}
counterpartyVersion = types.Version
module, _, err := suite.chainA.App.IBCKeeper.PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort)
suite.Require().NoError(err)
chanCap, err = suite.chainA.App.ScopedIBCKeeper.NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(ibctesting.TransferPort, testChannel.ID))
suite.Require().NoError(err)
cbs, ok := suite.chainA.App.IBCKeeper.Router.GetRoute(module)
suite.Require().True(ok)
tc.malleate() // explicitly change fields in channel and testChannel
err = cbs.OnChanOpenTry(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
testChannel.PortID, testChannel.ID, chanCap, channel.Counterparty, channel.GetVersion(), counterpartyVersion,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *TransferTestSuite) TestOnChanOpenAck() {
var (
testChannel ibctesting.TestChannel
connA *ibctesting.TestConnection
counterpartyVersion string
)
testCases := []struct {
name string
malleate func()
expPass bool
}{
{
"success", func() {}, true,
},
{
"invalid counterparty version", func() {
counterpartyVersion = "version"
}, false,
},
}
for _, tc := range testCases {
tc := tc
suite.Run(tc.name, func() {
suite.SetupTest() // reset
_, _, connA, _ = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, exported.Tendermint)
testChannel = suite.chainA.NextTestChannel(connA, ibctesting.TransferPort)
counterpartyVersion = types.Version
module, _, err := suite.chainA.App.IBCKeeper.PortKeeper.LookupModuleByPort(suite.chainA.GetContext(), ibctesting.TransferPort)
suite.Require().NoError(err)
cbs, ok := suite.chainA.App.IBCKeeper.Router.GetRoute(module)
suite.Require().True(ok)
tc.malleate() // explicitly change fields in channel and testChannel
err = cbs.OnChanOpenAck(suite.chainA.GetContext(), testChannel.PortID, testChannel.ID, counterpartyVersion)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -1,33 +0,0 @@
package simulation
import (
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// TransferUnmarshaler defines the expected encoding store functions.
type TransferUnmarshaler interface {
MustUnmarshalDenomTrace([]byte) types.DenomTrace
}
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding DenomTrace type.
func NewDecodeStore(cdc TransferUnmarshaler) func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.PortKey):
return fmt.Sprintf("Port A: %s\nPort B: %s", string(kvA.Value), string(kvB.Value))
case bytes.Equal(kvA.Key[:1], types.DenomTraceKey):
denomTraceA := cdc.MustUnmarshalDenomTrace(kvA.Value)
denomTraceB := cdc.MustUnmarshalDenomTrace(kvB.Value)
return fmt.Sprintf("DenomTrace A: %s\nDenomTrace B: %s", denomTraceA.IBCDenom(), denomTraceB.IBCDenom())
default:
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
}
}
}

View File

@ -1,59 +0,0 @@
package simulation_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
func TestDecodeStore(t *testing.T) {
app := simapp.Setup(false)
dec := simulation.NewDecodeStore(app.TransferKeeper)
trace := types.DenomTrace{
BaseDenom: "uatom",
Path: "transfer/channelToA",
}
kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{
Key: types.PortKey,
Value: []byte(types.PortID),
},
{
Key: types.DenomTraceKey,
Value: app.TransferKeeper.MustMarshalDenomTrace(trace),
},
{
Key: []byte{0x99},
Value: []byte{0x99},
},
},
}
tests := []struct {
name string
expectedLog string
}{
{"PortID", fmt.Sprintf("Port A: %s\nPort B: %s", types.PortID, types.PortID)},
{"DenomTrace", fmt.Sprintf("DenomTrace A: %s\nDenomTrace B: %s", trace.IBCDenom(), trace.IBCDenom())},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
if i == len(tests)-1 {
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
} else {
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
}
})
}
}

View File

@ -1,54 +0,0 @@
package simulation
import (
"encoding/json"
"fmt"
"math/rand"
"strings"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// Simulation parameter constants
const port = "port_id"
// RadomEnabled randomized send or receive enabled param with 75% prob of being true.
func RadomEnabled(r *rand.Rand) bool {
return r.Int63n(101) <= 75
}
// RandomizedGenState generates a random GenesisState for transfer.
func RandomizedGenState(simState *module.SimulationState) {
var portID string
simState.AppParams.GetOrGenerate(
simState.Cdc, port, &portID, simState.Rand,
func(r *rand.Rand) { portID = strings.ToLower(simtypes.RandStringOfLength(r, 20)) },
)
var sendEnabled bool
simState.AppParams.GetOrGenerate(
simState.Cdc, string(types.KeySendEnabled), &sendEnabled, simState.Rand,
func(r *rand.Rand) { sendEnabled = RadomEnabled(r) },
)
var receiveEnabled bool
simState.AppParams.GetOrGenerate(
simState.Cdc, string(types.KeyReceiveEnabled), &receiveEnabled, simState.Rand,
func(r *rand.Rand) { receiveEnabled = RadomEnabled(r) },
)
transferGenesis := types.GenesisState{
PortId: portID,
DenomTraces: types.Traces{},
Params: types.NewParams(sendEnabled, receiveEnabled),
}
bz, err := json.MarshalIndent(&transferGenesis, "", " ")
if err != nil {
panic(err)
}
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, bz)
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&transferGenesis)
}

View File

@ -1,74 +0,0 @@
package simulation_test
import (
"encoding/json"
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// TestRandomizedGenState tests the normal scenario of applying RandomizedGenState.
// Abonormal scenarios are not tested here.
func TestRandomizedGenState(t *testing.T) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
s := rand.NewSource(1)
r := rand.New(s)
simState := module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
NumBonded: 3,
Accounts: simtypes.RandomAccounts(r, 3),
InitialStake: 1000,
GenState: make(map[string]json.RawMessage),
}
simulation.RandomizedGenState(&simState)
var ibcTransferGenesis types.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &ibcTransferGenesis)
require.Equal(t, "euzxpfgkqegqiqwixnku", ibcTransferGenesis.PortId)
require.True(t, ibcTransferGenesis.Params.SendEnabled)
require.True(t, ibcTransferGenesis.Params.ReceiveEnabled)
require.Len(t, ibcTransferGenesis.DenomTraces, 0)
}
// TestRandomizedGenState tests abnormal scenarios of applying RandomizedGenState.
func TestRandomizedGenState1(t *testing.T) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
s := rand.NewSource(1)
r := rand.New(s)
// all these tests will panic
tests := []struct {
simState module.SimulationState
panicMsg string
}{
{ // panic => reason: incomplete initialization of the simState
module.SimulationState{}, "invalid memory address or nil pointer dereference"},
{ // panic => reason: incomplete initialization of the simState
module.SimulationState{
AppParams: make(simtypes.AppParams),
Cdc: cdc,
Rand: r,
}, "assignment to entry in nil map"},
}
for _, tt := range tests {
require.Panicsf(t, func() { simulation.RandomizedGenState(&tt.simState) }, tt.panicMsg)
}
}

View File

@ -1,32 +0,0 @@
package simulation
import (
"fmt"
"math/rand"
gogotypes "github.com/gogo/protobuf/types"
"github.com/cosmos/cosmos-sdk/x/simulation"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types"
)
// ParamChanges defines the parameters that can be modified by param change proposals
// on the simulation
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
return []simtypes.ParamChange{
simulation.NewSimParamChange(types.ModuleName, string(types.KeySendEnabled),
func(r *rand.Rand) string {
sendEnabled := RadomEnabled(r)
return fmt.Sprintf("%s", types.ModuleCdc.MustMarshalJSON(&gogotypes.BoolValue{Value: sendEnabled}))
},
),
simulation.NewSimParamChange(types.ModuleName, string(types.KeyReceiveEnabled),
func(r *rand.Rand) string {
receiveEnabled := RadomEnabled(r)
return fmt.Sprintf("%s", types.ModuleCdc.MustMarshalJSON(&gogotypes.BoolValue{Value: receiveEnabled}))
},
),
}
}

View File

@ -1,36 +0,0 @@
package simulation_test
import (
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/simulation"
)
func TestParamChanges(t *testing.T) {
s := rand.NewSource(1)
r := rand.New(s)
expected := []struct {
composedKey string
key string
simValue string
subspace string
}{
{"transfer/SendEnabled", "SendEnabled", "false", "transfer"},
{"transfer/ReceiveEnabled", "ReceiveEnabled", "true", "transfer"},
}
paramChanges := simulation.ParamChanges(r)
require.Len(t, paramChanges, 2)
for i, p := range paramChanges {
require.Equal(t, expected[i].composedKey, p.ComposedKey())
require.Equal(t, expected[i].key, p.Key())
require.Equal(t, expected[i].simValue, p.SimValue()(r), p.Key())
require.Equal(t, expected[i].subspace, p.Subspace())
}
}

View File

@ -1,117 +0,0 @@
<!--
order: 1
-->
# Concepts
## Acknowledgements
ICS20 uses the recommended acknowledgement format as specified by [ICS 04](https://github.com/cosmos/ics/tree/master/spec/ics-004-channel-and-packet-semantics#acknowledgement-envelope).
A successful receive of a transfer packet will result in a Result Acknowledgement being written
with the value `[]byte(byte(1))` in the `Response` field.
An unsuccessful receive of a transfer packet will result in an Error Acknowledgement being written
with the error message in the `Response` field.
## Denomination Trace
The denomination trace corresponds to the information that allows a token to be traced back to its
origin chain. It contains a sequence of port and channel identifiers ordered from the most recent to
the oldest in the timeline of transfers.
This information is included on the token denomination field in the form of a hash to prevent an
unbounded denomination length. For example, the token `transfer/channelToA/uatom` will be displayed
as `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2`.
Each send to any chain other than the one it was previously received from is a movement forwards in
the token's timeline. This causes trace to be added to the token's history and the destination port
and destination channel to be prefixed to the denomination. In these instances the sender chain is
acting as the "source zone". When the token is sent back to the chain it previously received from, the
prefix is removed. This is a backwards movement in the token's timeline and the sender chain is
acting as the "sink zone".
It is strongly recommended to read the full details of [ADR 001: Coin Source Tracing](./../../../../../docs/architecture/adr-001-coin-source-tracing.md) to understand the implications and context of the IBC token representations.
### UX suggestions for clients
For clients (wallets, exchanges, applications, block explorers, etc) that want to display the source of the token, it is recommended to use the following
alternatives for each of the cases below:
#### Direct connection
If the denomination trace contains a single identifier prefix pair (as in the example above), then
the easiest way to retrieve the chain and light client identifier is to map the trace information
directly. In summary, this requires querying the channel from the denomination trace identifiers,
and then the counterparty client state using the counterparty port and channel identifiers from the
retrieved channel.
A general pseudo algorithm would look like the following:
1. Query the full denomination trace.
2. Query the channel with the `portID/channelID` pair, which corresponds to the first destination of the
token.
3. Query the client state using the identifiers pair. Note that this query will return a `"Not
Found"` response if the current chain is not connected to this channel.
4. Retrieve the the client identifier or chain identifier from the client state (eg: on
Tendermint clients) and store it locally.
Using the gRPC gataway client service the steps above would be, with a given IBC token `ibc/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` stored on `chainB`:
1. `GET /ibc_transfer/v1beta1/denom_traces/7F1D3FCF4AE79E1554D670D1AD949A9BA4E4A3C76C63093E17E446A46061A7A2` -> `{"path": "transfer/channelToA", "base_denom": "uatom"}`
2. `GET /ibc/channel/v1beta1/channels/channelToA/ports/transfer/client_state"` -> `{"client_id": "clientA", "chain-id": "chainA", ...}`
3. `GET /ibc/channel/v1beta1/channels/channelToA/ports/transfer"` -> `{"channel_id": "channelToA", port_id": "transfer", counterparty: {"channel_id": "channelToB", port_id": "transfer"}, ...}`
4. `GET /ibc/channel/v1beta1/channels/channelToB/ports/transfer/client_state" -> {"client_id": "clientB", "chain-id": "chainB", ...}`
Then, the token transfer chain path for the `uatom` denomination would be: `chainA` -> `chainB`.
### Multiple hops
The multiple channel hops case applies when the token has passed through multiple chains between the original source and final destination chains.
The IBC protocol doesn't know the topology of the overall network (i.e connections between chains and identifier names between them). For this reason, in the the multiple hops case, a particular chain in the timeline of the individual transfers can't query the chain and client identifiers of the other chains.
Take for example the following sequence of transfers `A -> B -> C` for an IBC token, with a final prefix path (trace info) of `transfer/channelChainC/transfer/channelChainB`. What the paragraph above means is that is that even in the case that chain `C` is directly connected to chain `A`, querying the port and channel identifiers that chain `B` uses to connect to chain `A` (eg: `transfer/channelChainA`) can be completely different from the one that chain `C` uses to connect to chain `A` (eg: `transfer/channelToChainA`).
Thus the proposed solution for clients that the IBC team recommends are the following:
- **Connect to all chains**: Connecting to all the chains in the timeline would allow clients to
perform the queries outlined in the [direct connection](#direct-connection) section to each
relevant chain. By repeatedly following the port and channel denomination trace transfer timeline,
clients should always be able to find all the relevant identifiers. This comes at the tradeoff
that the client must connect to nodes on each of the chains in order to perform the queries.
- **Relayer as a Service (RaaS)**: A longer term solution is to use/create a relayer service that
could map the denomination trace to the chain path timeline for each token (i.e `origin chain ->
chain #1 -> ... -> chain #(n-1) -> final chain`). These services could provide merkle proofs in
order to allow clients to optionally verify the path timeline correctness for themselves by
running light clients. If the proofs are not verified, they should be considered as trusted third
parties services. Additionally, client would be advised in the future to use RaaS that support the
largest number of connections between chains in the ecosystem. Unfortunately, none of the existing
public relayers (in [Golang](https://github.com/cosmos/relayer) and
[Rust](https://github.com/informalsystems/ibc-rs)), provide this service to clients.
::: tip
The only viable alternative for clients (at the time of writing) to tokens with multiple connection hops, is to connect to all chains directly and perform relevant queries to each of them in the sequence.
:::
## Locked Funds
In some [exceptional cases](./../../../../../docs/architecture/adr-026-ibc-client-recovery-mechanisms.md#exceptional-cases), a client state associated with a given channel cannot be updated. This causes that funds from fungible tokens in that channel will be permanently locked and thus can no longer be transferred.
To mitigate this, a client update governance proposal can be submitted to update the frozen client
with a new valid header. Once the proposal passes the client state will be unfrozen and the funds
from the associated channels will then be unlocked. This mechanism only applies to clients that
allow updates via governance, such as Tendermint clients.
In addition to this, it's important to mention that a token must be sent back along the exact route
that it took originally un order to return it to its original form on the source chain (eg: the
Cosmos Hub for the `uatom`). Sending a token back to the same chain across a different channel will
**not** move the token back across its timeline. If a channel in the chain history closes before the
token can be sent back across that channel, then the token will not be returnable to its original
form.
## Security Considerations
For safety, no other module must be capable of minting tokens with the `ibc/` prefix. The IBC
transfer module needs a subset of the denomination space that only it can create tokens in.

View File

@ -1,10 +0,0 @@
<!--
order: 2
-->
# State
The transfer IBC application module keeps state of the port to which the module is binded and the denomination trace information as outlined in [ADR 01](./../../../../../docs/architecture/adr-001-coin-source-tracing.md).
- `Port`: `0x01 -> ProtocolBuffer(string)`
- `DenomTrace`: `0x02 | []bytes(traceHash) -> ProtocolBuffer(DenomTrace)`

View File

@ -1,36 +0,0 @@
<!--
order: 3
-->
# State Transitions
## Send Fungible Tokens
A successful fungible token send has two state transitions depending if the
transfer is a movement forward or backwards in the token's timeline:
1. Sender chain is the source chain, *i.e* a transfer to any chain other than the one it was previously received from is a movement forwards in the token's timeline. This results in the following state transitions:
- The coins are transferred to an escrow address (i.e locked) on the sender chain
- The coins are transferred to the receiving chain through IBC TAO logic.
2. Sender chain is the sink chain, *i.e* the token is sent back to the chain it previously received from. This is a backwards movement in the token's timeline. This results in the following state transitions:
- The coins (vouchers) are burned on the sender chain
- The coins transferred to the receiving chain though IBC TAO logic.
## Receive Fungible Tokens
A successful fungible token receive has two state transitions depending if the
transfer is a movement forward or backwards in the token's timeline:
1. Receiver chain is the source chain. This is a backwards movement in the token's timeline. This results in the following state transitions:
- The leftmost port and channel identifier pair is removed from the token denomination prefix.
- The tokens are unescrowed and sent to the receiving address.
2. Receiver chain is the sink chain. This is a movement forwards in the token's timeline. This results in the following state transitions:
- Token vouchers are minted by prefixing the destination port and channel identifiers to the trace information.
- The receiving chain stores the new trace information in the store (if not set already).
- The vouchers are sent to the receiving address.

View File

@ -1,40 +0,0 @@
<!--
order: 4
-->
# Messages
## MsgTransfer
A fungible token cross chain transfer is achieved by using the `MsgTransfer`:
```go
type MsgTransfer struct {
SourcePort string
SourceChannel string
Token sdk.Coin
Sender string
Receiver string
TimeoutHeight ibcexported.Height
TimeoutTimestamp uint64
}
```
This message is expected to fail if:
- `SourcePort` is invalid (see 24-host naming requirements)
- `SourceChannel` is invalid (see 24-host naming requirements)
- `Token` is invalid (denom is invalid or amount is negative)
- `Token.Amount` is not positive
- `Sender` is empty
- `Receiver` is empty
- `TimeoutHeight` and `TimeoutTimestamp` are both zero
- `Token.Denom` is not a valid IBC denomination as per [ADR 001 - Coin Source Tracing](./../../../../../docs/architecture/adr-001-coin-source-tracing.md).
This message will send a fungible token to the counterparty chain represented
by the counterparty Channel End connected to the Channel End with the identifiers
`SourcePort` and `SourceChannel`.
The denomination provided for transfer should correspond to the same denomination
represented on this chain. The prefixes will be added as necessary upon by the
receiving chain.

View File

@ -1,44 +0,0 @@
<!--
order: 5
-->
# Events
## MsgTransfer
| Type | Attribute Key | Attribute Value |
|--------------|---------------|-----------------|
| ibc_transfer | sender | {sender} |
| ibc_transfer | receiver | {receiver} |
| message | action | transfer |
| message | module | transfer |
## OnRecvPacket callback
| Type | Attribute Key | Attribute Value |
|-----------------------|---------------|-----------------|
| fungible_token_packet | module | transfer |
| fungible_token_packet | receiver | {receiver} |
| fungible_token_packet | denom | {denom} |
| fungible_token_packet | amount | {amount} |
| fungible_token_packet | success | {ackSuccess} |
| denomination_trace | trace_hash | {hex_hash} |
## OnAcknowledgePacket callback
| Type | Attribute Key | Attribute Value |
|-----------------------|-----------------|-------------------|
| fungible_token_packet | module | transfer |
| fungible_token_packet | receiver | {receiver} |
| fungible_token_packet | denom | {denom} |
| fungible_token_packet | amount | {amount} |
| fungible_token_packet | success | error | {ack.Response} |
## OnTimeoutPacket callback
| Type | Attribute Key | Attribute Value |
|-----------------------|-----------------|-----------------|
| fungible_token_packet | module | transfer |
| fungible_token_packet | refund_receiver | {receiver} |
| fungible_token_packet | denom | {denom} |
| fungible_token_packet | amount | {amount} |

Some files were not shown because too many files have changed in this diff Show More