diff --git a/.gitignore b/.gitignore index 9894b7b68fea..5888bb5aa552 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ examples/build/* docs/_build docs/tutorial docs/node_modules +docs/modules dist tools-stamp proto-tools-stamp diff --git a/docs/Screen Shot 2019-10-17 at 15.07.22.png b/docs/Screen Shot 2019-10-17 at 15.07.22.png deleted file mode 100644 index fc823b91ed22..000000000000 Binary files a/docs/Screen Shot 2019-10-17 at 15.07.22.png and /dev/null differ diff --git a/docs/building-modules/README.md b/docs/building-modules/README.md index 15a2f0c4640f..12dd140f89ad 100644 --- a/docs/building-modules/README.md +++ b/docs/building-modules/README.md @@ -1,7 +1,7 @@ # Building Modules diff --git a/docs/core/README.md b/docs/core/README.md index 98620ca416c9..9cb69b4c716d 100644 --- a/docs/core/README.md +++ b/docs/core/README.md @@ -16,8 +16,8 @@ This repository contains reference documentation on the core concepts of the Cos 6. [Encoding](./encoding.md) 7. [Events](./events.md) 8. [Telemetry](./telemetry.md) -9 [IBC](./ibc.md) -10.[Object-Capabilities](./ocap.md) -11.[RunTx recovery middleware](./runtx_middleware.md) +9. [Object-Capabilities](./ocap.md) +10. [RunTx recovery middleware](./runtx_middleware.md) -After reading about the core concepts, head on to the [Building Modules documentation](../building-modules/README.md) to learn more about the process of building modules. +After reading about the core concepts, check the [IBC documentation](../ibc/README.md) to learn more +about the IBC core concepts and how to integrate it to you application. diff --git a/docs/core/events.md b/docs/core/events.md index 7493b86a584f..f2407bcf2e08 100644 --- a/docs/core/events.md +++ b/docs/core/events.md @@ -109,8 +109,8 @@ The `type` and `attribute` value of the `query` allow you to filter the specific } ``` -where `senderAddress` is an address following the [`AccAddress`](../basics/accounts.md#addresses) format. +where `senderAddress` is an address following the [`AccAddress`](../basics/accounts.md#addresses) format. ## Next {hide} -Learn about [object-capabilities](./ocap.md) {hide} +Learn about SDK [telemetry](./telemetry.md) {hide} diff --git a/docs/core/ibc.md b/docs/core/ibc.md deleted file mode 100644 index c0483f527aef..000000000000 --- a/docs/core/ibc.md +++ /dev/null @@ -1,346 +0,0 @@ - - -# IBC - -This document serves as a guide for developers who want to write their own IBC applications. Due to the modular design of the IBC protocol, IBC application developers do not need to concern themselves with the low-level details of clients, connections, and proof verification. Nevertheless a brief explanation of the lower levels of the stack is given so that application developers may have a high-level understanding of the IBC protocol. Then the document goes into detail on the abstraction layer most relevant for application developers (channels and ports), and describes how to define your own custom packets, and `IBCModule` callbacks. - -To have your module interact over IBC you must: bind to a port(s), define your own packet data (and optionally acknowledgement) structs as well as how to encode/decode them, and implement the `IBCModule` interface. Below is a more detailed explanation of how to write an IBC application module correctly. - -## Pre-requisites Readings - -- [IBC SDK specification](../../modules/ibc) {prereq} - -## Core IBC Overview - -**[Clients](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/02-client)**: IBC Clients are light clients (identified by a unique client-id) that track the consensus states of other blockchains, along with the proof spec necessary to properly verify proofs against the client's consensus state. A client may be associated with any number of connections. - -**[Connections](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/03-connection)**: Connections encapsulate two `ConnectionEnd` objects on two seperate blockchains. Each `ConnectionEnd` is associated with a client of the other blockchain (ie counterparty blockchain). The connection handshake is responsible for verifying that the light clients on each chain are correct for their respective counterparties. Connections, once established, are responsible for facilitating all cross-chain verification of IBC state. A connection may be associated with any number of channels. - -**[Proofs](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/23-commitment) and [Paths](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/24-host)**: In IBC, blockchains do not directly pass messages to each other over the network. Instead, to communicate, a blockchain will commit some state to a specifically defined path reserved for a specific message type and a specific counterparty (perhaps storing a specific connectionEnd as part of a handshake, or a packet intended to be relayed to a module on the counterparty chain). A relayer process monitors for updates to these paths, and will relay messages, by submitting the data stored under the path along with a proof to the counterparty chain. The paths that all IBC implementations must use for committing IBC messages is defined in [ICS-24](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) and the proof format that all implementations must be able to produce and verify is defined in this [ICS-23 implementation](https://github.com/confio/ics23). - -**[Capabilities](https://github.com/cosmos/cosmos-sdk/tree/master/x/capability)**: IBC is intended to work in execution environements where modules do not necessarily trust each other. Thus IBC must authenticate module actions on ports and channels so that only modules with the appropriate permissions can use them. This is accomplished using dynamic capabilities ([ADR](../architecture/adr-003-dynamic-capability-store.md)). Upon binding to a port or creating a channel for a module, IBC will return a dynamic capability that the module must claim in order to use that port or channel. This prevents other modules from using that port or channel since they will not own the appropriate capability. For information on the object capability model, look [here](./ocap.md) - -### Channels and Ports - -While the above is useful background information, IBC modules do not need to interact at all with these lower-level abstractions. The relevant abstraction layer for IBC application developers is that of channels and ports. IBC applications should be written as self-contained **modules**. A module on one blockchain can thus communicate with other modules on other blockchains by sending, receiving and acknowledging packets through channels, which are uniquely identified by the `(channelID, portID)` tuple. A useful analogy is to consider IBC modules as internet applications on a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being analogous to a IP port and the IBC channelID being analogous to an IP address. Thus, a single instance of an IBC module may communicate on the same port with any number of other modules and IBC will correctly route all packets to the relevant module using the `(channelID, portID)` tuple. An IBC module may also communicate with another IBC module over multiple ports, with each `(portID<->portID)` packet stream being sent on a different unique channel. - -#### [Ports](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/05-port) - -An IBC module may bind to any number of ports. Each port must be identified by a unique `portID`. Since IBC is designed to be secure with mutually-distrusted modules operating on the same ledger, binding a port will return a dynamic object capability. In order to take action on a particular port (eg open a channel with its portID), a module must provide the dynamic object capability to the IBC handler. This prevents a malicious module from opening channels with ports it does not own. Thus, IBC modules are responsible for claiming the capability that is returned on `BindPort`. Currently, ports must be bound on app initialization. A module may bind to ports in `InitGenesis` like so: - -```go -func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { - // ... other initialization logic - - // Only try to bind to port if it is not already bound, since we may already own - // port capability from capability InitGenesis - if !isBound(ctx, state.PortID) { - // module binds to desired ports on InitChain - // and claims returned capabilities - cap1 := keeper.IBCPortKeeper.BindPort(ctx, port1) - cap2 := keeper.IBCPortKeeper.BindPort(ctx, port2) - cap3 := keeper.IBCPortKeeper.BindPort(ctx, port3) - - // NOTE: The module's scoped capability keeper must be private - keeper.scopedKeeper.ClaimCapability(cap1) - keeper.scopedKeeper.ClaimCapability(cap2) - keeper.scopedKeeper.ClaimCapability(cap3) - } - - // ... more initialization logic -} -``` - -#### [Channels](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/04-channel) - -An IBC channel can be established between 2 IBC ports. Currently, a port is exclusively owned by a single module. IBC packets are sent over channels. Just as IP packets contain the destination IP address and IP port as well as the source IP address and source IP port, IBC packets will contain the destination portID and channelID as well as the source portID and channelID. This enables IBC to correctly route packets to the destination module, while also allowing modules receiving packets to know the sender module. - -A channel may be `ORDERED`, in which case, packets from a sending module must be processed by the receiving module in the order they were sent. Or a channel may be `UNORDERED`, in which case packets from a sending module are processed in the order they arrive (may not be the order they were sent). - -Modules may choose which channels they wish to communicate over with, thus IBC expects modules to implement callbacks that are called during the channel handshake. These callbacks may do custom channel initialization logic, if any return an error, the channel handshake will fail. Thus, by returning errors on callbacks, modules can programatically reject and accept channels. - -The SDK expects all IBC modules to implement the interface `IBCModule`, defined [here](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/05-port/types/module.go). This interface contains all of the callbacks IBC expects modules to implement. This section will describe the callbacks that are called during channel handshake execution. - -The channel handshake is a 4 step handshake. Briefly, if chainA wants to open a channel with chainB using an already established connection, chainA will do `ChanOpenInit`, chainB will do `chanOpenTry`, chainA will do `ChanOpenAck`, chainB will do `chanOpenConfirm`. If all this happens successfully, the channel will be open on both sides. At each step in the handshake, the module associated with the `channelEnd` will have it's callback executed for that step of the handshake. So on `chanOpenInit`, the module on chainA will have its callback `OnChanOpenInit` executed. - -Just as ports came with dynamic capabilites, channel initialization will return a dynamic capability that the module **must** claim so that they can pass in a capability to authenticate channel actions like sending packets. The channel capability is passed into the callback on the first parts of the handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. - -Here are the channel handshake callbacks that modules are expected to implement: - -```go -// Called by IBC Handler on MsgOpenInit -func (k Keeper) OnChanOpenInit(ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - channelCap *capabilitytypes.Capability, - counterParty channeltypes.Counterparty, - version string, -) error { - // OpenInit must claim the channelCapability that IBC passes into the callback - k.scopedKeeper.ClaimCapability(ctx, channelCap) - - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - // Examples: Abort if order == UNORDERED, - // Abort if version is unsupported - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgOpenTry -OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, - channelID string, - channelCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version, - counterpartyVersion string, -) error { - // OpenInit must claim the channelCapability that IBC passes into the callback - k.scopedKeeper.ClaimCapability(ctx, channelCap) - - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgOpenAck -OnChanOpenAck( - ctx sdk.Context, - portID, - channelID string, - counterpartyVersion string, -) error { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgOpenConfirm -OnChanOpenConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom initialization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -The channel closing handshake will also invoke module callbacks that can return errors to abort the closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls `ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. - -```go -// Called by IBC Handler on MsgCloseInit -OnChanCloseInit( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} - -// Called by IBC Handler on MsgCloseConfirm -OnChanCloseConfirm( - ctx sdk.Context, - portID, - channelID string, -) error { - // ... do custom finalization logic - - // Use above arguments to determine if we want to abort handshake - err := checkArguments(args) - return err -} -``` - -#### Packets - -Modules communicate with each other by sending packets over IBC channels. As mentioned above, all IBC packets contain the destination `portID` and `channelID` along with the source `portID` and `channelID`, this allows modules to know the sender module of a given packet. IBC packets also contain a sequence to optionally enforce ordering. IBC packets also contain a `TimeoutTimestamp` and `TimeoutHeight`, which when non-zero, will determine the deadline before which the receiving module must process a packet. If the timeout passes without the packet being successfully received, the sending module can timeout the packet and take appropriate actions. - -Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. Thus, packet data is completely opaque to IBC handlers. It is incumbent on a sender module to encode their application-specific packet information into the `Data` field of packets, and the receiver module to decode that `Data` back to the original application data. - -Thus, modules connected by a channel must agree on what application data they are sending over the channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up to each application module to determine how to implement this agreement. However, for most applications this will happen as a version negotiation during the channel handshake. While more complex version negotiation is possible to implement inside the channel opening handshake, a very simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc-transfer/module.go). - -Thus a module must define a custom packet data structure, along with a well-defined way to encode and decode it to and from `[]byte`. - -```go -// Custom packet data defined in application module -type CustomPacketData struct { - // Custom fields ... -} - -EncodePacketData(packetData CustomPacketData) []byte { - // encode packetData to bytes -} - -DecodePacketData(encoded []byte) (CustomPacketData) { - // decode from bytes to packet data -} -``` - -Then a module must encode its packet data before sending it through IBC. - -```go -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -IBCChannelKeeper.SendPacket(ctx, packet) -``` - -A module receiving a packet must decode the `PacketData` into a structure it expects so that it can act on it. - -```go -// Receiving custom application packet data (in OnRecvPacket) -packetData := DecodePacketData(packet.Data) -// handle received custom packet data -``` - -#### Acknowledgements - -Modules may optionally commit an acknowledgement upon receiving and processing a packet. This acknowledgement can then be relayed back to the original sender chain, which can take action depending on the contents of the acknowledgement. - -Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and receive acknowledegments with the IBC modules as byte strings. - -Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an acknowledgement struct along with encoding and decoding it, is very similar to the packet data example above. - -#### Packet Flow Handling - -Just as IBC expected modules to implement callbacks for channel handshakes, IBC also expects modules to implement callbacks for handling the packet flow through a channel. - -Once a module A and module B are connected to each other, relayers can start relaying packets and acknowledgements back and forth on the channel. The packet flow diagram is [here](https://github.com/cosmos/ics/blob/master/spec/ics-004-channel-and-packet-semantics/packet-state-machine.png). Briefly, a successful packet flow works as follows: module A sends a packet through the IBC module, the packet is received by module B, if module B writes an acknowledgement of the packet then module A will process the acknowledgement. If the packet is not successfully received before the timeout, then module A processes the packet's timeout. - -**Sending Packets**: Modules do not send packets through callbacks, since the modules initiate the action of sending packets to the IBC module, as opposed to other parts of the packet flow where msgs sent to the IBC module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. - -```go -// retrieve the dynamic capability for this channel -channelCap := scopedKeeper.GetCapability(ctx, channelCapName) -// Sending custom application packet data -data := EncodePacketData(customPacketData) -packet.Data = data -// Send packet to IBC, authenticating with channelCap -IBCChannelKeeper.SendPacket(ctx, channelCap, packet) -``` - -Note: In order to prevent modules from sending packets on channels they do not own, IBC expects modules to pass in the correct channel capability for the packet's source channel. - -**Receiving Packets**: To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state changes given the packet data without worrying about whether the packet is valid or not. - -Modules may optionally return an acknowledgement as a byte string and return it to the IBC handler. The IBC handler will then commit this acknowledgment of the packet so that a relayer may relay the acknowledgement back to the sender module. - -```go -OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (res *sdk.Result, ack []byte, abort error) { - // Decode the packet data - packetData := DecodePacketData(packet.Data) - - // do application state changes based on packet data - // and return result, acknowledgement and abortErr - // Note: abortErr is only not nil if we need to abort the entire receive packet, and allow a replay of the receive. - // If the application state change failed but we do not want to replay the packet, - // simply encode this failure with relevant information in ack and return nil error - res, ack, abortErr := processPacket(ctx, packet, packetData) - - // if we need to abort the entire receive packet, return error - if abortErr != nil { - return nil, nil, abortErr - } - - // Encode the ack since IBC expects acknowledgement bytes - ackBytes := EncodeAcknowledgement(ack) - - return res, ackBytes, nil -} -``` - -::: warning -`OnRecvPacket` should **only** return an error if we want the entire receive packet execution (including the IBC handling) to be reverted. This will allow the packet to be replayed in the case that some mistake in the relaying caused the packet processing to fail. - -If some application-level error happened while processing the packet data, in most cases, we will not want the packet processing to revert. Instead, we may want to encode this failure into the acknowledgement and finish processing the packet. This will ensure the packet cannot be replayed, and will also allow the sender module to potentially remediate the situation upon receiving the acknowledgement. An example of this technique is in the ibc-transfer module's [OnRecvPacket](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc-transfer/module.go). -::: - -**Acknowledging Packets**: If the receiving module writes an ackowledgement while processing the packet, a relayer can relay back the acknowledgement to the sender module. The sender module can then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the acknowledgement is entirely upto the modules on the channel (just like the packet data); however, it may often contain information on whether the packet was successfully received and processed along with some additional data that could be useful for remediation if the packet processing failed. - -Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback is responsible for decoding the acknowledgment and processing it. - -```go -OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, -) (*sdk.Result, error) { - // Decode acknowledgement - ack := DecodeAcknowledgement(acknowledgement) - - // process ack - res, err := processAck(ack) - return res, err -} -``` - -**Timeout Packets**: If the timout for a packet is reached before the packet is successfully received, the receiving chain can no longer process it. Thus, the sending chain must process the timout using `OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is indeed valid, so our module only needs to implement the state machine logic for what to do once a timeout is reached and the packet can no longer be received. - -```go -OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, -) (*sdk.Result, error) { - // do custom timeout logic -} -``` - -#### Registering Module with the IBC Router - -IBC needs to know which module is bound to which port so that it can route packets to the appropriate module and call the appropriate callback. The port to module name mapping is handled by IBC's portKeeper. However, the mapping from module name to the relevant callbacks is accomplished by the [port.Router](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc//05-port/types/router.go). - -As mentioned above, modules must implement the IBC module interface (which contains both channel handshake callbacks and packet handling callbacks). The concrete implementation of this interface must be registered with the module name as a route on the IBC Router. - -Currently, the Router is static so it must be initialized and set correctly on **app initialization. Once the Router has been set, no new routes can be added. - -```go -// app.go - -// Create static IBC router, add module routes, then set and seal it -ibcRouter := port.NewRouter() - -// Note: moduleCallbacks must implement IBCModule interface -ibcRouter.AddRoute(moduleName, moduleCallbacks) - -// Setting Router will finalize all routes by sealing router -// No more routes can be added -app.IBCKeeper.SetRouter(ibcRouter) -``` - -Adding the module routes allows the IBC handler to call the appropriate callback when processing a channel handshake or a packet. - -#### Working Example - -For a real working example of an IBC application, you can look through the `ibc-transfer` module which implements everything discussed above. - -Here are the useful parts of the module to look at: - -[Binding to transfer port](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc-transfer/genesis.go) - -[Sending transfer packets](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc-transfer/keeper/relay.go) - -[Implementing IBC callbacks](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc-transfer/module.go) diff --git a/docs/core/ocap.md b/docs/core/ocap.md index 82dfd61ab18d..1634af280808 100644 --- a/docs/core/ocap.md +++ b/docs/core/ocap.md @@ -1,5 +1,5 @@ # Object-Capability Model @@ -39,7 +39,7 @@ foundation of an object capability system. > to another object only through a preexisting chain of references. > In short, "Only connectivity begets connectivity." -For an introduction to object-capabilities, see [this article](https://en.wikipedia.org/wiki/Object-capability_model). +For an introduction to object-capabilities, see this [Wikipedia article](https://en.wikipedia.org/wiki/Object-capability_model). ## Ocaps in practice @@ -50,11 +50,11 @@ principle: ```go type AppAccount struct {...} -var account := &AppAccount{ +account := &AppAccount{ Address: pub.Address(), Coins: sdk.Coins{sdk.NewInt64Coin("ATM", 100)}, } -var sumValue := externalModule.ComputeSumValue(account) +sumValue := externalModule.ComputeSumValue(account) ``` The method `ComputeSumValue` implies a pure function, yet the implied @@ -62,7 +62,7 @@ capability of accepting a pointer value is the capability to modify that value. The preferred method signature should take a copy instead. ```go -var sumValue := externalModule.ComputeSumValue(*account) +sumValue := externalModule.ComputeSumValue(*account) ``` In the Cosmos SDK, you can see the application of this principle in the @@ -70,6 +70,6 @@ gaia app. +++ https://github.com/cosmos/gaia/blob/master/app/app.go#L197-L209 -## Next +## Next {hide} -Learn about [building modules](../building-modules/intro.md) {hide} +Learn about the [`runTx` middleware](./runtx_middleware.md) {hide} diff --git a/docs/core/runtx_middleware.md b/docs/core/runtx_middleware.md index 4699e66d7053..a2eaaa735c69 100644 --- a/docs/core/runtx_middleware.md +++ b/docs/core/runtx_middleware.md @@ -1,5 +1,5 @@ # RunTx recovery middleware @@ -10,7 +10,7 @@ Recovery middleware is used to add custom panic recovery for SDK application dev More context could be found in the corresponding [ADR-022](../architecture/adr-022-custom-panic-handling.md). -Implementation could be found in the [recovery.go](../../baseapp/recovery.go) file. +Implementation could be found in the [recovery.go](../../baseapp/recovery.go) file. ## Interface @@ -21,6 +21,7 @@ type RecoveryHandler func(recoveryObj interface{}) error `recoveryObj` is a return value for `recover()` function from the `buildin` Golang package. **Contract:** + * RecoveryHandler returns `nil` if `recoveryObj` wasn't handled and should be passed to the next recovery middleware; * RecoveryHandler returns a non-nil `error` if `recoveryObj` was handled; @@ -28,13 +29,14 @@ type RecoveryHandler func(recoveryObj interface{}) error ``BaseApp.AddRunTxRecoveryHandler(handlers ...RecoveryHandler)`` -BaseApp method adds recovery middleware to the default recovery chain. +BaseApp method adds recovery middleware to the default recovery chain. ## Example Lets assume we want to emit the "Consensus failure" chain state if some particular error occurred. We have a module keeper that panics: + ```go func (k FooKeeper) Do(obj interface{}) { if obj == nil { @@ -42,10 +44,11 @@ func (k FooKeeper) Do(obj interface{}) { err := sdkErrors.Wrap(fooTypes.InternalError, "obj is nil") panic(err) } -} +} ``` By default that panic would be recovered and an error message will be printed to log. To override that behaviour we should register a custom RecoveryHandler: + ```go // SDK application constructor customHandler := func(recoveryObj interface{}) error { @@ -53,14 +56,18 @@ customHandler := func(recoveryObj interface{}) error { if !ok { return nil } - + if fooTypes.InternalError.Is(err) { - panic(fmt.Errorf("FooKeeper did panic with error: %w", err)) + panic(fmt.Errorf("FooKeeper did panic with error: %w", err)) } - + return nil } baseApp := baseapp.NewBaseApp(...) baseApp.AddRunTxRecoveryHandler(customHandler) ``` + +## Next {hide} + +Learn about the [IBC](./../ibc/README.md) protocol {hide} diff --git a/docs/core/telemetry.md b/docs/core/telemetry.md index f2986e30f802..951ba86c54f4 100644 --- a/docs/core/telemetry.md +++ b/docs/core/telemetry.md @@ -4,6 +4,8 @@ order: 8 # Telemetry +Gather relevant insights about your application and modules with custom metrics and telemetry. {synopsis} + The Cosmos SDK enables operators and developers to gain insight into the performance and behavior of their application through the use of the `telemetry` package. The Cosmos SDK currently supports enabling in-memory and prometheus as telemetry sinks. This allows the ability to query for and scrape @@ -75,7 +77,7 @@ The following examples expose too much cardinality and may not even prove to be ## Supported Metrics | Metric | Description | Unit | Type | -| :------------------------------ | :------------------------------------------------------------------------------------- | :----------- | :------ | +|:--------------------------------|:---------------------------------------------------------------------------------------|:-------------|:--------| | `tx_count` | Total number of txs processed via `DeliverTx` | tx | counter | | `tx_successful` | Total number of successful txs processed via `DeliverTx` | tx | counter | | `tx_failed` | Total number of failed txs processed via `DeliverTx` | tx | counter | @@ -116,3 +118,7 @@ The following examples expose too much cardinality and may not even prove to be | `store_cachekv_set` | Duration of a CacheKV `Store#Set` call | ms | summary | | `store_cachekv_write` | Duration of a CacheKV `Store#Write` call | ms | summary | | `store_cachekv_delete` | Duration of a CacheKV `Store#Delete` call | ms | summary | + +## Next {hide} + +Learn about the [object-capability](./ocap.md) model {hide} diff --git a/docs/core/transactions.md b/docs/core/transactions.md index ede39cf1a627..b5ae3bc57fb1 100644 --- a/docs/core/transactions.md +++ b/docs/core/transactions.md @@ -45,13 +45,13 @@ When users interact with the application's interfaces, they invoke the underlyin ### Messages -**`Message`s** are module-specific objects that trigger state transitions within the scope of the module they belong to. Module developers define the `message`s for their module by implementing the `Msg` interface, and also define a [`Handler`](../building-modules/handler.md) to process them. +**`Message`s** are module-specific objects that trigger state transitions within the scope of the module they belong to. Module developers define the `message`s for their module by implementing the `Msg` interface, and also define a [`Handler`](../building-modules/handler.md) to process them. +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/types/tx_msg.go#L8-L29 `Message`s in a module are typically defined in a `msgs.go` file (though not always), and one handler with multiple functions to handle each of the module's `message`s is defined in a `handler.go` file. -Note: module `messages` are not to be confused with [ABCI Messages](https://tendermint.com/docs/spec/abci/abci.html#messages) which define interactions between the Tendermint and application layers. +Note: module `messages` are not to be confused with [ABCI Messages](https://tendermint.com/docs/spec/abci/abci.html#messages) which define interactions between the Tendermint and application layers. To learn more about `message`s, click [here](../building-modules/messages-and-queries.md#messages). @@ -67,17 +67,17 @@ The `TxBuilder` contains data closely related with the processing of transaction +++ https://github.com/cosmos/cosmos-sdk/blob/7d7821b9af132b0f6131640195326aa02b6751db/x/auth/types/txbuilder.go#L18-L31 -- `TxEncoder` defined by the developer for this type of transaction. Used to encode messages before being processed by nodes running Tendermint. -- `Keybase` that manages the user's keys and is used to perform signing operations. -- `AccountNumber` from which this transaction originated. -- `Sequence`, the number of transactions that the user has sent out, used to prevent replay attacks. -- `Gas` option chosen by the users for how to calculate how much gas they will need to pay. A common option is "auto" which generates an automatic estimate. -- `GasAdjustment` to adjust the estimate of gas by a scalar value, used to avoid underestimating the amount of gas required. -- `SimulateAndExecute` option to simply simulate the transaction execution without broadcasting. -- `ChainID` representing which blockchain this transaction pertains to. -- `Memo` to send with the transaction. -- `Fees`, the maximum amount the user is willing to pay in fees. Alternative to specifying gas prices. -- `GasPrices`, the amount per unit of gas the user is willing to pay in fees. Alternative to specifying fees. +* `TxEncoder` defined by the developer for this type of transaction. Used to encode messages before being processed by nodes running Tendermint. +* `Keybase` that manages the user's keys and is used to perform signing operations. +* `AccountNumber` from which this transaction originated. +* `Sequence`, the number of transactions that the user has sent out, used to prevent replay attacks. +* `Gas` option chosen by the users for how to calculate how much gas they will need to pay. A common option is "auto" which generates an automatic estimate. +* `GasAdjustment` to adjust the estimate of gas by a scalar value, used to avoid underestimating the amount of gas required. +* `SimulateAndExecute` option to simply simulate the transaction execution without broadcasting. +* `ChainID` representing which blockchain this transaction pertains to. +* `Memo` to send with the transaction. +* `Fees`, the maximum amount the user is willing to pay in fees. Alternative to specifying gas prices. +* `GasPrices`, the amount per unit of gas the user is willing to pay in fees. Alternative to specifying fees. The `Context` is initialized using the application's `codec` and data more closely related to the user interaction with the interface, holding data such as the output to the user and the broadcast mode. Read more about `Context` [here](../interfaces/query-lifecycle.md#context). @@ -89,4 +89,4 @@ Since `message`s are module-specific types, each module needs a [`handler`](../b ## Next {hide} -Learn about the [context](./context.md) {hide} \ No newline at end of file +Learn about the [context](./context.md) {hide} diff --git a/docs/ibc/README.md b/docs/ibc/README.md new file mode 100644 index 000000000000..a33648d43b15 --- /dev/null +++ b/docs/ibc/README.md @@ -0,0 +1,16 @@ + + +# IBC + +This repository contains reference documentation for the IBC protocol integration and concepts: + +1. [Overview](./overview.md) +2. [Integration](./integration.md) +3. [Customization](./custom.md) + +After reading about IBC, head on to the [Building Modules +documentation](../building-modules/README.md) to learn more about the process of building modules. diff --git a/docs/ibc/custom.md b/docs/ibc/custom.md new file mode 100644 index 000000000000..e14c14ee7d51 --- /dev/null +++ b/docs/ibc/custom.md @@ -0,0 +1,408 @@ + + +# Customization + +Learn how to configure your application to use IBC and send data packets to other chains. {synopsis} + +This document serves as a guide for developers who want to write their own Inter-blockchain +Communication Protocol (IBC) applications for custom [use-cases](https://github.com/cosmos/ics/blob/master/ibc/4_IBC_USECASES.md). + +Due to the modular design of the IBC protocol, IBC +application developers do not need to concern themselves with the low-level details of clients, +connections, and proof verification. Nevertheless a brief explanation of the lower levels of the +stack is given so that application developers may have a high-level understanding of the IBC +protocol. Then the document goes into detail on the abstraction layer most relevant for application +developers (channels and ports), and describes how to define your own custom packets, and +`IBCModule` callbacks. + +To have your module interact over IBC you must: bind to a port(s), define your own packet data and acknolwedgement structs as well as how to encode/decode them, and implement the +`IBCModule` interface. Below is a more detailed explanation of how to write an IBC application +module correctly. + +## Pre-requisites Readings + +- [IBC Overview](./overview.md)) {prereq} +- [IBC default integration](./integration.md) {prereq} + +## Create a custom IBC application module + +### Implement `IBCModule` Interface and callbacks + +The Cosmos SDK expects all IBC modules to implement the [`IBCModule` +interface](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/05-port/types/module.go). This +interface contains all of the callbacks IBC expects modules to implement. This section will describe +the callbacks that are called during channel handshake execution. + +Here are the channel handshake callbacks that modules are expected to implement: + +```go +// Called by IBC Handler on MsgOpenInit +func (k Keeper) OnChanOpenInit(ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID string, + channelID string, + channelCap *capabilitytypes.Capability, + counterParty channeltypes.Counterparty, + version string, +) error { + // OpenInit must claim the channelCapability that IBC passes into the callback + k.scopedKeeper.ClaimCapability(ctx, channelCap) + + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + // Examples: Abort if order == UNORDERED, + // Abort if version is unsupported + err := checkArguments(args) + return err +} + +// Called by IBC Handler on MsgOpenTry +OnChanOpenTry( + ctx sdk.Context, + order channeltypes.Order, + connectionHops []string, + portID, + channelID string, + channelCap *capabilitytypes.Capability, + counterparty channeltypes.Counterparty, + version, + counterpartyVersion string, +) error { + // OpenInit must claim the channelCapability that IBC passes into the callback + k.scopedKeeper.ClaimCapability(ctx, channelCap) + + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} + +// Called by IBC Handler on MsgOpenAck +OnChanOpenAck( + ctx sdk.Context, + portID, + channelID string, + counterpartyVersion string, +) error { + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} + +// Called by IBC Handler on MsgOpenConfirm +OnChanOpenConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // ... do custom initialization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} +``` + +The channel closing handshake will also invoke module callbacks that can return errors to abort the +closing handshake. Closing a channel is a 2-step handshake, the initiating chain calls +`ChanCloseInit` and the finalizing chain calls `ChanCloseConfirm`. + +```go +// Called by IBC Handler on MsgCloseInit +OnChanCloseInit( + ctx sdk.Context, + portID, + channelID string, +) error { + // ... do custom finalization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} + +// Called by IBC Handler on MsgCloseConfirm +OnChanCloseConfirm( + ctx sdk.Context, + portID, + channelID string, +) error { + // ... do custom finalization logic + + // Use above arguments to determine if we want to abort handshake + err := checkArguments(args) + return err +} +``` + +### Bind Ports + +Currently, ports must be bound on app initialization. A module may bind to ports in `InitGenesis` +like so: + +```go +func InitGenesis(ctx sdk.Context, keeper keeper.Keeper, state types.GenesisState) { + // ... other initialization logic + + // Only try to bind to port if it is not already bound, since we may already own + // port capability from capability InitGenesis + if !isBound(ctx, state.PortID) { + // module binds to desired ports on InitChain + // and claims returned capabilities + cap1 := keeper.IBCPortKeeper.BindPort(ctx, port1) + cap2 := keeper.IBCPortKeeper.BindPort(ctx, port2) + cap3 := keeper.IBCPortKeeper.BindPort(ctx, port3) + + // NOTE: The module's scoped capability keeper must be private + keeper.scopedKeeper.ClaimCapability(cap1) + keeper.scopedKeeper.ClaimCapability(cap2) + keeper.scopedKeeper.ClaimCapability(cap3) + } + + // ... more initialization logic +} +``` + +### Custom Packets + +Modules connected by a channel must agree on what application data they are sending over the +channel, as well as how they will encode/decode it. This process is not specified by IBC as it is up +to each application module to determine how to implement this agreement. However, for most +applications this will happen as a version negotiation during the channel handshake. While more +complex version negotiation is possible to implement inside the channel opening handshake, a very +simple version negotation is implemented in the [ibc-transfer module](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc-transfer/module.go). + +Thus, a module must define its a custom packet data structure, along with a well-defined way to +encode and decode it to and from `[]byte`. + +```go +// Custom packet data defined in application module +type CustomPacketData struct { + // Custom fields ... +} + +EncodePacketData(packetData CustomPacketData) []byte { + // encode packetData to bytes +} + +DecodePacketData(encoded []byte) (CustomPacketData) { + // decode from bytes to packet data +} +``` + +Then a module must encode its packet data before sending it through IBC. + +```go +// Sending custom application packet data +data := EncodePacketData(customPacketData) +packet.Data = data +IBCChannelKeeper.SendPacket(ctx, packet) +``` + +A module receiving a packet must decode the `PacketData` into a structure it expects so that it can +act on it. + +```go +// Receiving custom application packet data (in OnRecvPacket) +packetData := DecodePacketData(packet.Data) +// handle received custom packet data +``` + +#### Packet Flow Handling + +Just as IBC expected modules to implement callbacks for channel handshakes, IBC also expects modules +to implement callbacks for handling the packet flow through a channel. + +Once a module A and module B are connected to each other, relayers can start relaying packets and +acknowledgements back and forth on the channel. + +![IBC packet flow diagram](https://media.githubusercontent.com/media/cosmos/ics/master/spec/ics-004-channel-and-packet-semantics/packet-state-machine.png) + +Briefly, a successful packet flow works as follows: + +1. module A sends a packet through the IBC module +2. the packet is received by module B +3. if module B writes an acknowledgement of the packet then module A will process the + acknowledgement +4. if the packet is not successfully received before the timeout, then module A processes the + packet's timeout. + +##### Sending Packets + +Modules do not send packets through callbacks, since the modules initiate the action of sending +packets to the IBC module, as opposed to other parts of the packet flow where msgs sent to the IBC +module must trigger execution on the port-bound module through the use of callbacks. Thus, to send a +packet a module simply needs to call `SendPacket` on the `IBCChannelKeeper`. + +```go +// retrieve the dynamic capability for this channel +channelCap := scopedKeeper.GetCapability(ctx, channelCapName) +// Sending custom application packet data +data := EncodePacketData(customPacketData) +packet.Data = data +// Send packet to IBC, authenticating with channelCap +IBCChannelKeeper.SendPacket(ctx, channelCap, packet) +``` + +::: warning +In order to prevent modules from sending packets on channels they do not own, IBC expects +modules to pass in the correct channel capability for the packet's source channel. +::: + +##### Receiving Packets + +To handle receiving packets, the module must implement the `OnRecvPacket` callback. This gets +invoked by the IBC module after the packet has been proved valid and correctly processed by the IBC +keepers. Thus, the `OnRecvPacket` callback only needs to worry about making the appropriate state +changes given the packet data without worrying about whether the packet is valid or not. + +Modules must return an acknowledgement as a byte string and return it to the IBC handler. +The IBC handler will then commit this acknowledgment of the packet so that a relayer may relay the +acknowledgement back to the sender module. + +```go +OnRecvPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (res *sdk.Result, ack []byte, abort error) { + // Decode the packet data + packetData := DecodePacketData(packet.Data) + + // do application state changes based on packet data + // and return result, acknowledgement and abortErr + // Note: abortErr is only not nil if we need to abort the entire receive packet, and allow a replay of the receive. + // If the application state change failed but we do not want to replay the packet, + // simply encode this failure with relevant information in ack and return nil error + res, ack, abortErr := processPacket(ctx, packet, packetData) + + // if we need to abort the entire receive packet, return error + if abortErr != nil { + return nil, nil, abortErr + } + + // Encode the ack since IBC expects acknowledgement bytes + ackBytes := EncodeAcknowledgement(ack) + + return res, ackBytes, nil +} +``` + +::: warning +`OnRecvPacket` should **only** return an error if we want the entire receive packet execution +(including the IBC handling) to be reverted. This will allow the packet to be replayed in the case +that some mistake in the relaying caused the packet processing to fail. + +If some application-level error happened while processing the packet data, in most cases, we will +not want the packet processing to revert. Instead, we may want to encode this failure into the +acknowledgement and finish processing the packet. This will ensure the packet cannot be replayed, +and will also allow the sender module to potentially remediate the situation upon receiving the +acknowledgement. An example of this technique is in the `ibc-transfer` module's +[`OnRecvPacket`](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc-transfer/module.go). +::: + +### Acknowledgements + +Modules must commit an acknowledgement upon receiving and processing a packet. This +acknowledgement can then be relayed back to the original sender chain, which can take action +depending on the contents of the acknowledgement. + +Just as packet data was opaque to IBC, acknowledgements are similarly opaque. Modules must pass and +receive acknowledegments with the IBC modules as byte strings. + +Thus, modules must agree on how to encode/decode acknowledgements. The process of creating an +acknowledgement struct along with encoding and decoding it, is very similar to the packet data +example above. + +#### Acknowledging Packets + +After a module writes an acknowledgement while receiving a packet. a relayer can relay back the acknowledgement to the sender module. The sender module can +then process the acknowledgement using the `OnAcknowledgementPacket` callback. The contents of the +acknowledgement is entirely upto the modules on the channel (just like the packet data); however, it +may often contain information on whether the packet was successfully received and processed along +with some additional data that could be useful for remediation if the packet processing failed. + +Since the modules are responsible for agreeing on an encoding/decoding standard for packet data and +acknowledgements, IBC will pass in the acknowledgements as `[]byte` to this callback. The callback +is responsible for decoding the acknowledgment and processing it. + +```go +OnAcknowledgementPacket( + ctx sdk.Context, + packet channeltypes.Packet, + acknowledgement []byte, +) (*sdk.Result, error) { + // Decode acknowledgement + ack := DecodeAcknowledgement(acknowledgement) + + // process ack + res, err := processAck(ack) + return res, err +} +``` + +#### Timeout Packets + +If the timout for a packet is reached before the packet is successfully received, the receiving +chain can no longer process it. Thus, the sending chain must process the timout using +`OnTimeoutPacket` to handle this situation. Again the IBC module will verify that the timeout is +indeed valid, so our module only needs to implement the state machine logic for what to do once a +timeout is reached and the packet can no longer be received. + +```go +OnTimeoutPacket( + ctx sdk.Context, + packet channeltypes.Packet, +) (*sdk.Result, error) { + // do custom timeout logic +} +``` + +### Routing + +As mentioned above, modules must implement the IBC module interface (which contains both channel +handshake callbacks and packet handling callbacks). The concrete implementation of this interface +must be registered with the module name as a route on the IBC `Router`. + +```go +// app.go +func NewApp(...args) *App { +// ... + +// Create static IBC router, add module routes, then set and seal it +ibcRouter := port.NewRouter() + +ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) +// Note: moduleCallbacks must implement IBCModule interface +ibcRouter.AddRoute(moduleName, moduleCallbacks) + +// Setting Router will finalize all routes by sealing router +// No more routes can be added +app.IBCKeeper.SetRouter(ibcRouter) +``` + +## Working Example + +For a real working example of an IBC application, you can look through the `ibc-transfer` module +which implements everything discussed above. + +Here are the useful parts of the module to look at: + +[Binding to transfer +port](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc-transfer/genesis.go) + +[Sending transfer +packets](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc-transfer/keeper/relay.go) + +[Implementing IBC +callbacks](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc-transfer/module.go) + +## Next {hide} + +Learn about [building modules](../building-modules/intro.md) {hide} diff --git a/docs/ibc/integration.md b/docs/ibc/integration.md new file mode 100644 index 000000000000..595a566b1c4a --- /dev/null +++ b/docs/ibc/integration.md @@ -0,0 +1,275 @@ + + +# Integration + +Learn how to integrate IBC to your application and send data packets to other chains. {synopsis} + +This document outlines the required steps to integrate and configure the [IBC +module](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc) to your Cosmos SDK application and +send fungible token transfers to other chains. + +## Integrating the IBC module + +Integrating the IBC module to your SDK-based application is straighforward. The general changes can be summarized in the following steps: + +- Add required modules to the `module.BasicManager` +- Define additional `Keeper` fields for the new modules on the `App` type +- Add the module's `StoreKeys` and initialize their `Keepers` +- Set up corresponding routers and routes for the `ibc` and `evidence` modules +- Add the modules to the module `Manager` +- Add modules to `Begin/EndBlockers` and `InitGenesis` +- Update the module `SimulationManager` to enable simulations +- Add IBC `Keeper` to the `AnteHandler` + +### Module `BasicManager` and `ModuleAccount` permissions + +The first step is to add the following modules to the `BasicManager`: `x/capability`, `x/ibc`, +`x/evidence` and `x/ibc-transfer`. After that, we need to grant `Minter` and `Burner` permissions to +the `ibc-transfer` `ModuleAccount` to mint and burn relayed tokens. + +```go +// app.go +var ( + + ModuleBasics = module.NewBasicManager( + // ... + capability.AppModuleBasic{}, + ibc.AppModuleBasic{}, + evidence.AppModuleBasic{}, + transfer.AppModuleBasic{}, // i.e ibc-transfer module + ) + + // module account permissions + maccPerms = map[string][]string{ + // other module accounts permissions + // ... + ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, +) +``` + +### Application fields + +Then, we need to register the `Keepers` as follows: + +```go +// app.go +type App struct { + // baseapp, keys and subspaces definitions + + // other keepers + // ... + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + EvidenceKeeper evidencekeeper.Keeper // required to set up the client misbehaviour route + TransferKeeper ibctransferkeeper.Keeper // for cross-chain fungible token transfers + + // make scoped keepers public for test purposes + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedTransferKeeper capabilitykeeper.ScopedKeeper + + /// ... + /// module and simulation manager definitions +} +``` + +### Configure the `Keepers` + +During initialization, besides initializing the IBC `Keepers` (for the `x/ibc`, and +`x/ibc-transfer` modules), we need to grant specific capabilities through the capability module +`ScopedKeepers` so that we can authenticate the object-capability permissions for each of the IBC +channels. + +```go +func NewApp(...args) *App { + // define codecs and baseapp + + // add capability keeper and ScopeToModule for ibc module + app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey]) + + // grant capabilities for the ibc and ibc-transfer modules + scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) + scopedTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) + + // ... other modules keepers + + // Create IBC Keeper + app.IBCKeeper = ibckeeper.NewKeeper( + appCodec, keys[ibchost.StoreKey], app.StakingKeeper, scopedIBCKeeper, + ) + + // Create Transfer Keepers + app.TransferKeeper = ibctransferkeeper.NewKeeper( + appCodec, keys[ibctransfertypes.StoreKey], + app.IBCKeeper.ChannelKeeper, &app.IBCKeeper.PortKeeper, + app.AccountKeeper, app.BankKeeper, scopedTransferKeeper, + ) + transferModule := transfer.NewAppModule(app.TransferKeeper) + + // Create evidence Keeper for to register the IBC light client misbehaviour evidence route + evidenceKeeper := evidencekeeper.NewKeeper( + appCodec, keys[evidencetypes.StoreKey], &app.StakingKeeper, app.SlashingKeeper, + ) + + // .. continues +} +``` + +### Register `Routers` + +IBC needs to know which module is bound to which port so that it can route packets to the +appropriate module and call the appropriate callbacks. The port to module name mapping is handled by +IBC's port `Keeper`. However, the mapping from module name to the relevant callbacks is accomplished +by the port +[`Router`](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc//05-port/types/router.go) on the +IBC module. + +Adding the module routes allows the IBC handler to call the appropriate callback when processing a +channel handshake or a packet. + +The second `Router` that is required is the evidence module router. This router handles genenal +evidence submission and routes the business logic to each registered evidence handler. In the case +of IBC, it is required to submit evidence for [light client +misbehaviour](https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour) +in order to freeze a client and prevent further data packets from being sent/received. + +Currently, a `Router` is static so it must be initialized and set correctly on app initialization. +Once the `Router` has been set, no new routes can be added. + +```go +// app.go +func NewApp(...args) *App { + // .. continuation from above + + // Create static IBC router, add ibc-tranfer module route, then set and seal it + ibcRouter := port.NewRouter() + ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferModule) + // Setting Router will finalize all routes by sealing router + // No more routes can be added + app.IBCKeeper.SetRouter(ibcRouter) + + // create static Evidence routers + + evidenceRouter := evidencetypes.NewRouter(). + // add IBC ClientMisbehaviour evidence handler + AddRoute(ibcclient.RouterKey, ibcclient.HandlerClientMisbehaviour(app.IBCKeeper.ClientKeeper)) + + // Setting Router will finalize all routes by sealing router + // No more routes can be added + evidenceKeeper.SetRouter(evidenceRouter) + + // set the evidence keeper from the section above + app.EvidenceKeeper = *evidenceKeeper + + // .. continues +``` + +### Module Managers + +In order to use IBC, we need to add the new modules to the module `Manager` and to the `SimulationManager` in case your application supports [simulations](./../building-modules/simulator.md). + +```go +// app.go +func NewApp(...args) *App { + // .. continuation from above + + app.mm = module.NewManager( + // other modules + // ... + capability.NewAppModule(appCodec, *app.CapabilityKeeper), + evidence.NewAppModule(app.EvidenceKeeper), + ibc.NewAppModule(app.IBCKeeper), + transferModule, + ) + + // ... + + app.sm = module.NewSimulationManager( + // other modules + // ... + capability.NewAppModule(appCodec, *app.CapabilityKeeper), + evidence.NewAppModule(app.EvidenceKeeper), + ibc.NewAppModule(app.IBCKeeper), + transferModule, + ) + + // .. continues +``` + +### Application ABCI Ordering + +One addition from IBC is the concept of `HistoricalEntries` which are stored on the staking module. +Each entry contains the historical information for the `Header` and `ValidatorSet` of this chain which is stored +at each height during the `BeginBlock` call. The historical info is required to introspect the +past historical info at any given height in order to verify the light client `ConsensusState` during the +connection handhake. + +The IBC module also has +[`BeginBlock`](https://github.com/cosmos/cosmos-sdk/blob/master/x/ibc/02-client/abci.go) logic as +well. This is optional as it is only required if your application uses the [localhost +client](https://github.com/cosmos/ics/blob/master/spec/ics-009-loopback-client) to connect two +different modules from the same chain. + +::: tip +Only register the ibc module to the `SetOrderBeginBlockers` if your application will use the +localhost (_aka_ loopback) client. +::: + +```go +// app.go +func NewApp(...args) *App { + // .. continuation from above + + // add evidence, staking and ibc modules to BeginBlockers + app.mm.SetOrderBeginBlockers( + // other modules ... + evidencetypes.ModuleName, stakingtypes.ModuleName, ibchost.ModuleName, + ) + + // ... + + // NOTE: Capability module must occur first so that it can initialize any capabilities + // so that other modules that want to create or claim capabilities afterwards in InitChain + // can do so safely. + app.mm.SetOrderInitGenesis( + capabilitytypes.ModuleName, + // other modules ... + ibchost.ModuleName, evidencetypes.ModuleName, ibctransfertypes.ModuleName, + ) + + // .. continues +``` + +::: warning +**IMPORTANT**: The capability module **must** be declared first in `SetOrderInitGenesis` +::: + +### IBC AnteHandler + +The IBC module defines `ProofVerificationDecorator` that handles messages that contains application +specific packet types. This is mostly to perform stateful packet execution. For more context, please +refer to [ADR 15 - IBC Packet Receiver](./../architecture/adr-015-ibc-packet-receiver.md). + +```go +// app.go +func NewApp(...args) *App { + // .. continuation from above + + app.SetAnteHandler( + ante.NewAnteHandler( + app.AccountKeeper, app.BankKeeper, *app.IBCKeeper, ante.DefaultSigVerificationGasConsumer, + ), + ) + + // ... + return app +} +``` + +That's it! You have now wired up the IBC module and are now able to send fungible tokens across +different chains. If you want to have a broader view of the changes take a look into the SDK's +[`SimApp`](https://github.com/cosmos/cosmos-sdk/blob/master/simapp/app.go). + +## Next {hide} + +Learn about how to create [custom IBC modules](./custom.md) for your application {hide} diff --git a/docs/ibc/overview.md b/docs/ibc/overview.md new file mode 100644 index 000000000000..8bcd2f6ad41c --- /dev/null +++ b/docs/ibc/overview.md @@ -0,0 +1,152 @@ + + +# Overview + +Learn what IBC is, its components and use cases. {synopsis} + +## What is the Interblockchain Communication Protocol (IBC)? + +This document serves as a guide for developers who want to write their own Inter-blockchain +Communication Protocol (IBC) applications for custom [use-cases](https://github.com/cosmos/ics/blob/master/ibc/4_IBC_USECASES.md). + +Due to the modular design of the IBC protocol, IBC +application developers do not need to concern themselves with the low-level details of clients, +connections, and proof verification. Nevertheless a brief explanation of the lower levels of the +stack is given so that application developers may have a high-level understanding of the IBC +protocol. Then the document goes into detail on the abstraction layer most relevant for application +developers (channels and ports), and describes how to define your own custom packets, and +`IBCModule` callbacks. + +To have your module interact over IBC you must: bind to a port(s), define your own packet data (and +optionally acknowledgement) structs as well as how to encode/decode them, and implement the +`IBCModule` interface. Below is a more detailed explanation of how to write an IBC application +module correctly. + +## Components Overview + +### [Clients](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/02-client) + +IBC Clients are light clients (identified by a unique client-id) that track the consensus states of +other blockchains, along with the proof spec necessary to properly verify proofs against the +client's consensus state. A client may be associated with any number of connections to multiple +chains. The supported IBC clients are: + +* [Tendermint light client](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/07-tendermint): The default for SDK-based chains, +* [Localhost (loopback) client](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/09-localhost): Useful for +testing, simulation and relaying packets to modules on the same application. + +### [Connections](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/03-connection) + +Connections encapsulate two `ConnectionEnd` objects on two seperate blockchains. Each +`ConnectionEnd` is associated with a client of the other blockchain (ie counterparty blockchain). +The connection handshake is responsible for verifying that the light clients on each chain are +correct for their respective counterparties. Connections, once established, are responsible for +facilitation all cross-chain verification of IBC state. A connection may be associated with any +number of channels. + +### [Proofs](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/23-commitment) and [Paths](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/24-host) + +In IBC, blockchains do not directly pass messages to each other over the network. Instead, to +communicate, a blockchain will commit some state to a specifically defined path reserved for a +specific message type and a specific counterparty (perhaps storing a specific connectionEnd as part +of a handshake, or a packet intended to be relayed to a module on the counterparty chain). A relayer +process monitors for updates to these paths, and will relay messages, by submitting the data stored +under the path along with a proof to the counterparty chain. The paths that all IBC implementations +must use for committing IBC messages is defined in +[ICS-24](https://github.com/cosmos/ics/tree/master/spec/ics-024-host-requirements) and the proof +format that all implementations must be able to produce and verify is defined in this [ICS-23 implementation](https://github.com/confio/ics23). + +### [Capabilities](./ocap.md) + +IBC is intended to work in execution environements where modules do not necessarily trust each +other. Thus IBC must authenticate module actions on ports and channels so that only modules with the +appropriate permissions can use them. This is accomplished using [dynamic +capabilities](../architecture/adr-003-dynamic-capability-store.md). Upon binding to a port or +creating a channel for a module, IBC will return a dynamic capability that the module must claim in +order to use that port or channel. This prevents other modules from using that port or channel since +they will not own the appropriate capability. + +While the above is useful background information, IBC modules do not need to interact at all with +these lower-level abstractions. The relevant abstraction layer for IBC application developers is +that of channels and ports. IBC applications should be written as self-contained **modules**. A +module on one blockchain can thus communicate with other modules on other blockchains by sending, +receiving and acknowledging packets through channels, which are uniquely identified by the +`(channelID, portID)` tuple. A useful analogy is to consider IBC modules as internet applications on +a computer. A channel can then be conceptualized as an IP connection, with the IBC portID being +analogous to a IP port and the IBC channelID being analogous to an IP address. Thus, a single +instance of an IBC module may communicate on the same port with any number of other modules and and +IBC will correctly route all packets to the relevant module using the (channelID, portID tuple). An +IBC module may also communicate with another IBC module over multiple ports, with each +`(portID<->portID)` packet stream being sent on a different unique channel. + +### [Ports](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/05-port) + +An IBC module may bind to any number of ports. Each port must be identified by a unique `portID`. +Since IBC is designed to be secure with mutually-distrusted modules operating on the same ledger, +binding a port will return a dynamic object capability. In order to take action on a particular port +(eg open a channel with its portID), a module must provide the dynamic object capability to the IBC +handler. This prevents a malicious module from opening channels with ports it does not own. Thus, +IBC modules are responsible for claiming the capability that is returned on `BindPort`. + +### [Channels](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/04-channel) + +An IBC channel can be established between 2 IBC ports. Currently, a port is exclusively owned by a +single module. IBC packets are sent over channels. Just as IP packets contain the destination IP +address and IP port as well as the source IP address and source IP port, IBC packets will contain +the destination portID and channelID as well as the source portID and channelID. This enables IBC to +correctly route packets to the destination module, while also allowing modules receiving packets to +know the sender module. + +A channel may be `ORDERED`, in which case, packets from a sending module must be processed by the +receiving module in the order they were sent. Or a channel may be `UNORDERED`, in which case packets +from a sending module are processed in the order they arrive (may not be the order they were sent). + +Modules may choose which channels they wish to communicate over with, thus IBC expects modules to +implement callbacks that are called during the channel handshake. These callbacks may do custom +channel initialization logic, if any return an error, the channel handshake will fail. Thus, by +returning errors on callbacks, modules can programatically reject and accept channels. + +The channel handshake is a 4 step handshake. Briefly, if a given chain A wants to open a channel with +chain B using an already established connection: + +1. chain A sends a `ChanOpenInit` message to signal a channel initialization attempt with chain B. +2. chain B sends a `ChanOpenTry` message to try opening the channel on chain A. +3. chain A sends a `ChanOpenAck` message to mark its channel end status as open. +4. chain B sends a `ChanOpenConfirm` message to mark its channel end status as open. + +If all this happens successfully, the channel will be open on both sides. At each step in the handshake, the module +associated with the `ChannelEnd` will have it's callback executed for that step of the handshake. So +on `ChanOpenInit`, the module on chain A will have its callback `OnChanOpenInit` executed. + +Just as ports came with dynamic capabilites, channel initialization will return a dynamic capability +that the module **must** claim so that they can pass in a capability to authenticate channel actions +like sending packets. The channel capability is passed into the callback on the first parts of the +handshake; either `OnChanOpenInit` on the initializing chain or `OnChanOpenTry` on the other chain. + +### [Packets](https://github.com/cosmos/cosmos-sdk/tree/master/x/ibc/04-channel) + +Modules communicate with each other by sending packets over IBC channels. As mentioned above, all +IBC packets contain the destination `portID` and `channelID` along with the source `portID` and +`channelID`, this allows modules to know the sender module of a given packet. IBC packets also +contain a sequence to optionally enforce ordering. IBC packets also contain a `TimeoutTimestamp` and +`TimeoutHeight`, which when non-zero, will determine the deadline before which the receiving module +must process a packet. If the timeout passes without the packet being successfully received, the +sending module can timeout the packet and take appropriate actions. + +Modules send custom application data to each other inside the `Data []byte` field of the IBC packet. +Thus, packet data is completely opaque to IBC handlers. It is incumbent on a sender module to encode +their application-specific packet information into the `Data` field of packets, and the receiver +module to decode that `Data` back to the original application data. + +## Further Readings and Specs + +If you want to learn more about IBC, check the following specifications: + +* [IBC specification overview](https://github.com/cosmos/ics/blob/master/ibc/README.md) +* [IBC SDK specification](../../modules/ibc) + +## Next {hide} + +Learn about how to [integrate](./integration.md) IBC to your application {hide} diff --git a/docs/package-lock.json b/docs/package-lock.json index a4d6471584d8..2d30980556f0 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -6903,8 +6903,7 @@ "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "optional": true + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pify": { "version": "4.0.1", diff --git a/x/README.md b/x/README.md index 5cc373173df7..3be56a3de605 100644 --- a/x/README.md +++ b/x/README.md @@ -9,7 +9,7 @@ Here are some production-grade modules that can be used in Cosmos SDK applicatio - [Auth](auth/spec/README.md) - Authentication of accounts and transactions for Cosmos SDK application. - [Bank](bank/spec/README.md) - Token transfer functionalities. -- [Capability](capability/docs/README.md) - Object capability implementation. +- [Capability](capability/spec/README.md) - Object capability implementation. - [Crisis](crisis/spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). - [Distribution](distribution/spec/README.md) - Fee distribution, and staking token provision distribution. - [Evidence](evidence/spec/README.md) - Evidence handling for double signing, misbehaviour, etc. diff --git a/x/capability/spec/01_concepts.md b/x/capability/spec/01_concepts.md new file mode 100644 index 000000000000..7751df4c0817 --- /dev/null +++ b/x/capability/spec/01_concepts.md @@ -0,0 +1,34 @@ + + +# Concepts + +## Capabilities + +Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability` +which creates a new unique, unforgeable object-capability reference. The newly +created capability is automatically persisted; the calling module need not call +`ClaimCapability`. Calling `NewCapability` will create the capability with the +calling module and name as a tuple to be treated the capabilities first owner. + +Capabilities can be claimed by other modules which add them as owners. `ClaimCapability` +allows a module to claim a capability key which it has received from another +module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST +be called if a module which receives a capability wishes to access it by name in +the future. Again, capabilities are multi-owner, so if multiple modules have a +single Capability reference, they will all own it. If a module receives a capability +from another module but does not call `ClaimCapability`, it may use it in the executing +transaction but will not be able to access it afterwards. + +`AuthenticateCapability` can be called by any module to check that a capability +does in fact correspond to a particular name (the name can be un-trusted user input) +with which the calling module previously associated it. + +`GetCapability` allows a module to fetch a capability which it has previously +claimed by name. The module is not allowed to retrieve capabilities which it does +not own. + +## Stores + +- MemStore diff --git a/x/capability/spec/02_state.md b/x/capability/spec/02_state.md new file mode 100644 index 000000000000..b93de4bf4ab7 --- /dev/null +++ b/x/capability/spec/02_state.md @@ -0,0 +1,11 @@ + + +# State + +## Index + +## CapabilityOwners + +## Capability diff --git a/x/capability/docs/README.md b/x/capability/spec/README.md similarity index 62% rename from x/capability/docs/README.md rename to x/capability/spec/README.md index a280743d7edf..b5a2db2f8afe 100644 --- a/x/capability/docs/README.md +++ b/x/capability/spec/README.md @@ -1,6 +1,13 @@ -# x/capability + -## Abstract +# `capability` + +## Overview `x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](./../../../docs/architecture/adr-003-dynamic-capability-store.md), that allows for provisioning, tracking, and authenticating multi-owner capabilities @@ -27,7 +34,7 @@ like queriers, REST and CLI handlers, and genesis state. ## Initialization During application initialization, the keeper must be instantiated with a persistent -store key and an in-memory store key. +store key and an in-memory store key. ```go type App struct { @@ -63,27 +70,7 @@ func NewApp(...) *App { } ``` -## Capabilities - -Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability` -which creates a new unique, unforgeable object-capability reference. The newly -created capability is automatically persisted; the calling module need not call -`ClaimCapability`. Calling `NewCapability` will create the capability with the -calling module and name as a tuple to be treated the capabilities first owner. - -Capabilities can be claimed by other modules which add them as owners. `ClaimCapability` -allows a module to claim a capability key which it has received from another -module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST -be called if a module which receives a capability wishes to access it by name in -the future. Again, capabilities are multi-owner, so if multiple modules have a -single Capability reference, they will all own it. If a module receives a capability -from another module but does not call `ClaimCapability`, it may use it in the executing -transaction but will not be able to access it afterwards. - -`AuthenticateCapability` can be called by any module to check that a capability -does in fact correspond to a particular name (the name can be un-trusted user input) -with which the calling module previously associated it. - -`GetCapability` allows a module to fetch a capability which it has previously -claimed by name. The module is not allowed to retrieve capabilities which it does -not own. +## Contents + +1. **[Concepts](01_concepts.md)** +1. **[State](02_state.md)**