-
Notifications
You must be signed in to change notification settings - Fork 33
[IBC] Implement ICS-24 - Tracking IBC store transitions in the network state #847
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
76 commits
Select commit
Hold shift + click to select a range
ab9ff72
Add ics23 integration
h5law b47402d
Add SMT proof conversion to ics23 Existence and Exclusion proofs with…
h5law 20fa2fc
Add ICS23 docs
h5law 52e62e4
Fix errors
h5law 0656658
Update next error comment
h5law d631bb3
Address comments in docs
h5law 1beb4bd
Add names back to tests
h5law 9a7a578
Address comments
h5law 327ed96
Address comments
h5law bc5a878
add isLeft helper and use smt.GetPathBit()
h5law 2f67dcd
go.mod
h5law 17e2419
Fix SMT repo
h5law cf92d93
Add IBC proto types to protogen
h5law a194cef
Add provable stores and HandleMessage
h5law c7206fc
Export treestore trees
h5law 8c9f38a
Add IBC message handling
h5law 9b3d286
Add ibc message types
h5law 797ac03
Add provable stores and HandleMessage
h5law b1f9a88
Add more IBC errors
h5law 1dca7d8
Add GetProvableStore
h5law ff2d440
Implement provableStore
h5law 83fb7a1
Add private key to ibc config
h5law aa56b42
Allow conversion of IbcMessage to Transaction
h5law 454db6e
HandleEvent adds ibc message to TxMempool
h5law 0d867f3
Add signer to messages
h5law a3178e4
Implement utility Message interface for IbcMessage types
h5law 3570e52
Update IBC config to have a private key
h5law 22970b1
Add IBC nil field errors
h5law f72f513
Add IbcMessage Tx handling logic
h5law c7176e8
Add techdebt comment
h5law 5c2bbc5
Remove duplicate method
h5law c05ab8e
Add IBC store change related postgres DB sql code
h5law 3732091
Add update IBC state tree logic from postgres DB changes
h5law 5ffa511
Remove prefix field from ibc messages
h5law eee1a18
Add IBC postgres db update error
h5law cdec8ca
Add SetIBCStoreEntry method to PostgresContext
h5law ac619b4
Address linter errors
h5law ff447f7
Add HandleMessage unit tests
h5law 6e4a510
Simplify tests as covered in utility
h5law 895dfd0
Update validation testcases
h5law ac2a974
Fix importing twice
h5law dbf7f2b
Add nolint comments
h5law 0c05028
Check msg equality in test mempool test
h5law 2cf0ff2
Add new issue comments
h5law 7cbbe6e
Add mockgen flag for ProvableStore
h5law a1edf4b
Address comments
h5law 416682b
Add diagrams
h5law 953a146
Update state hashes
h5law c39ea1d
fixup: runtime key addition
h5law 89550be
fixup: remove prefixes from IbcMessages
h5law 4766802
Clear IBC table state between tests
h5law ed94086
Improve unit test cases
h5law 32964cb
Add no valuehashing to state trees
h5law 1d84d08
Add ibc.feature text file to track upcoming tests to be added
h5law f7e7c0c
Update docs
h5law be48d99
Fix proto naming
h5law e54be28
Add signer comments
h5law 9ccc197
Prefix errors with IBC
h5law fbadb8d
Update docs
h5law 65f647f
Address comments
h5law 6414094
Update IBC errors
h5law 681a328
Remove no value hashing from state trees
h5law 128cee5
Reword IBC stores
h5law ccea884
Update interfaces
h5law d27211d
Add storesDir to IBC config and pass to host and storemanger
h5law d476191
golint error
h5law 9cb2bdd
Reorganise
h5law 6b74a5f
Update docs on data retrieval
h5law 9ba683a
Update docs on provable stores and caching
h5law 5bb0adf
Prefix errors
h5law 157f3c9
Merge branch 'main' into ibc/initial_stores
h5law e94f4a9
linter error
h5law e6b53fe
Address comments
h5law 733f53b
merge: squash and merge main
h5law 7994828
Merge branch 'main' into ibc/initial_stores
h5law 57c6b92
address comments
h5law File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,32 +1,196 @@ | ||
| # ICS-24 Host Requirements <!-- omit in toc --> | ||
|
|
||
| - [Overview](#overview) | ||
| - [Host Configuration](#host-configuration) | ||
| - [Implementation](#implementation) | ||
| - [Persistence](#persistence) | ||
| - [Paths and Identifiers](#paths-and-identifiers) | ||
| - [Timestamps](#timestamps) | ||
| - [IBC State](#ibc-state) | ||
| - [IBC State Tree](#ibc-state-tree) | ||
| - [Data Retrieval](#data-retrieval) | ||
| - [IBC Messages](#ibc-messages) | ||
| - [IBC Message Handling](#ibc-message-handling) | ||
| - [Mempool](#mempool) | ||
| - [State Transition](#state-transition) | ||
| - [Provable Stores](#provable-stores) | ||
| - [Caching](#caching) | ||
|
|
||
| ## Overview | ||
|
|
||
| [ICS-24][ics24] details the requirements of the host chain, in order for it to be compatible with IBC. A host is defined as a node on a chain that runs the IBC software. A host has the ability to create connections with counterparty chains, open channels, and ports as well as commit proofs to the consensus state of its own chain for the relayer to submit to another chain. The host is responsible to managing and creating clients and all other aspects of the IBC module. | ||
| [ICS-24][ics24] details the requirements of the host chain, in order for it to be compatible with IBC. A host is defined as a node on a chain that runs the IBC software. A host has the ability to create connections with counterparty chains, open channels, expose ports, and commit proofs to the consensus state of its own chain for the relayer to submit to another chain. The host is responsible to managing and creating clients and all other aspects of the IBC module. | ||
|
|
||
| As token transfers as defined in [ICS-20][ics20] work on a lock and mint pattern, any tokens sent from **chain A** to **chain B** will have a denomination unique to the connection/channel/port combination that the packet was sent over. This means that if a host where to shutdown a connection or channel without warning any tokens yet to be returned to the host chain would be lost. For this reason, only validator nodes are able to become hosts, as they provide the most reliability out of the different node types. | ||
|
|
||
| ## Host Configuration | ||
|
|
||
| Only validators can be configured to be IBC hosts. If the IBC module, during its creation, detects the node is a validator (and the IBC `enabled` field in the config is `true`) it will automatically create a host. | ||
|
|
||
| ```json | ||
| "ibc": { | ||
| "enabled": bool, | ||
| "private_key": string, | ||
| "stores_dir": string | ||
| } | ||
| ``` | ||
|
|
||
| The `PrivateKey` field of the configuration is used to sign IBC store related messages and state transitions for inclusion in the block. | ||
|
|
||
| ## Implementation | ||
|
|
||
| **Note**: The ICS-24 implementation is still a work in progress and is not yet fully implemented. | ||
|
|
||
| ICS-24 has numerous sub components that must be implemented in order for the host to be fully functional. These range from type definitions for identifiers, paths and stores as well as the methods to interact with them. Alongside these ICS-24 also defines the Event Logging system which is used to store the packet data and timeouts for the relayers to read, as only the `CommitmentProof` objects are committed to the chain state. In addition to these numerous other features are part of ICS-24 that are closely linked to other ICS components such as consensus state introspection and client state validation. | ||
|
|
||
| ### Persistence | ||
h5law marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| The IBC stores must be included in the networks consensus state as one of the many state trees. This is to ensure the IBC light clients verifying Pocket network's state can verify the inclusion or exclusion of IBC related information from the block headers. | ||
|
|
||
| The following is a simplified sequence diagram of an IBC fungible token transfer. This requires **Chain A** to commit to its state the packet data related to the transfer, so that **Chain B** can verify the inclusion of this packet data with the light client of **Chain A** it runs. | ||
|
|
||
| ```mermaid | ||
Olshansk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| sequenceDiagram | ||
| actor UA as User A | ||
| box Transparent Chain A | ||
| participant A1 as Validator A | ||
| participant A2 as IBC Host A | ||
| participant A3 as Light Client B | ||
| end | ||
| box Transparent Relayer | ||
| actor R1 as Relayer | ||
| end | ||
| box Transparent Chain B | ||
| participant B1 as Validator B | ||
| participant B2 as IBC Host B | ||
| participant B3 as Light Client A | ||
| end | ||
| actor UB as User B | ||
| R1->>R1: Watch(Chain A) | ||
| R1->>R1: Watch(Chain B) | ||
| UA->>+A1: Send 10$POKT to User B | ||
| A1->>A1: Lock(10$POKT) | ||
| A1->>+A2: Create(FungibleTokenPacketData) | ||
| A2->>-A1: Commit(FungibleTokenPacketData) | ||
| A1->>-A1: NewBlock() | ||
| R1->>R1: CheckNewBlockForIBCPackets() | ||
| R1->>+A2: QueryAndProve(FungibleTokenPacketData) | ||
| A2->>R1: FungibleTokenPacketData | ||
| A2->>-R1: Proof(FungibleTokenPacketData) | ||
| R1->>+B2: Validate(FungibleTokenPacketData, Proof(FungibleTokenPacketData)) | ||
| B2->>+B3: Verify(Proof(FungibleTokenPacketData)) | ||
| B3->>-B2: FoundInState(FungibleTokenPacketData) | ||
| B2->>-B1: Send 10$POKT to User B | ||
| B1->>B1: Mint(10$POKT) | ||
| B1->>UB: Receive 10$POKT from User A | ||
| ``` | ||
|
|
||
| As the IBC host will make changes to the IBC store locally, in response to functions being called by relayers, they require these changes to be propagated throughout the network (i.e. the mempool) and included in all other node's IBC stores so that during block production these changes are reflected in the state transition. This is done by utilizing the existing transaction workflow, adding the IBC store change messages to the mempool and then handling them as a new message type in block production/application logic. | ||
h5law marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| See: [IBC State](#ibc-state) below for more details on the IBC state transition process. | ||
|
|
||
| ### Paths and Identifiers | ||
|
|
||
| Paths are defined as bytestrings that are used to access the elements in the different stores. They are built with the function `ApplyPrefix()` which takes a store key as a prefix and a path string and will return the key to access an element in the specific store. The logic for paths can be found in [host/keys.go](../host/keys.go) and [host/prefix.go](../host/prefix.go) | ||
| Paths are defined as bytestrings that are used to access the elements in the different stores. They are built with the function `ApplyPrefix()` which takes a store key as a prefix and a path string and will return the key to access an element in the specific store. The logic for paths can be found in [path/keys.go](../path/keys.go) and [path/prefix.go](../path/prefix.go) | ||
|
|
||
| Identifiers are bytestrings constrained to specific characters and lengths depending on their usages. They are used to identify: channels, clients, connections and ports. Although the minimum length of the identifiers is much less we use a minimum length of 32 bytes and a maximum length that varies depending on the use case to randomly generate identifiers. This allows for an extremely low chance of collision between identifiers. Identifiers have no significance beyond their use to store different elements in the IBC stores and as such there is no need for non-random identifiers. The logic for identifiers can be found in [host/identifiers.go](../host/identifiers.go). | ||
| Identifiers are bytestrings constrained to specific characters and lengths depending on their usages. They are used to identify: channels, clients, connections and ports. Although the minimum length of the identifiers is much less we use a minimum length of 32 bytes and a maximum length that varies depending on the use case to randomly generate identifiers. This allows for an extremely low chance of collision between identifiers. Identifiers have no significance beyond their use to store different elements in the IBC stores and as such there is no need for non-random identifiers. The logic for identifiers can be found in [path/identifiers.go](../path/identifiers.go). | ||
|
|
||
| ### Timestamps | ||
|
|
||
| The `GetTimestamp()` function returns the current unix timestamp of the host machine and is used to calculate timeout periods for packets | ||
|
|
||
| ## IBC State | ||
|
|
||
| As mentioned [above](#persistence) the IBC store **MUST** be included in the consensus state of the network. As such the IBC store as defined in [ICS-24][ics24] has been implemented as a single IBC state tree. | ||
|
|
||
| ### IBC State Tree | ||
|
|
||
| The IBC state tree is an `SMT` backed by a persistent `KVStore`, this is used for proof generation/verification. Data retrieval uses the `peristence` layer, see the [data retrieval](#data-retrieval) section below for more details. | ||
|
|
||
| The root hash of the IBC state tree is included in the `rootTree` which computes the network's state hash for any given block. This allows verifiers to not only verify the inclusion/exclusion of any element in the IBC state tree itself but also that the IBC state tree was used to compute the network's state hash, by utilising the `CommitmentProof` object defined in [ICS-23][ics23]. | ||
|
|
||
| ### Data Retrieval | ||
|
|
||
| In order to query the IBC store the `persistence` layer is leveraged. All local changes to the IBC store are broadcasted as [IBC messages](#ibc-messages) and ultimately stored in each node's `peristence` layer. This allows for the efficient querying of the IBC store instead of having to query the IBC state tree directly. | ||
|
|
||
| When attempting to generate a proof for a specific `key` in the IBC state tree the IBC host will import a local copy of the IBC state tree and use this to generate the proof. Otherwise all queries are handled by the `peristence` layer's underlying database. | ||
|
|
||
h5law marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ### IBC Messages | ||
|
|
||
| Hosts maintain uncommitted changes in a local ephemeral IBC store while messages propagate through the mempool. | ||
|
|
||
| These messages enable a variety of IBC related state changes such as creating light clients, opening connections, sending packets, etc... This is enabled by propagating `IBCMessage` types defined in [ibc/types/proto/messages.proto](../types/proto/messages.proto). This type acts as an enum representing two possible state transition events: | ||
|
|
||
| - `UpdateIBCStore`: Updating the store with a key-value pair; adding a new or updating an existing element | ||
| - `PruneIBCStore`: Pruning the store via its key; removal of an existing element | ||
|
|
||
| _Note: In both types described above the `key` field **must** already be prefixed with the `CommitmentPrefix` and should be a valid path in the store._ | ||
|
|
||
| When changes are made locally they are not committed to the IBC store itself but are instead used to create an `IBCMessage` which is broadcasted to the network. This is akin to a simple send transaction that has been propagated throughout the mempool but has not been committed to the on-chain state. | ||
|
|
||
| ### IBC Message Handling | ||
|
|
||
| Upon a node receiving an `IBCMessage` from the event bus it will use the `HandleMessage()` method of the `IBCModule` to add this message to the transactions mempool via the following steps: | ||
|
|
||
| 1. Wrap the `IBCMessage` within a `Transaction` | ||
| 2. Sign the `Transaction` using the `IBCModule`'s private key | ||
| 3. Broadcast the `Transaction` throughout the mempool | ||
|
|
||
| ```mermaid | ||
| graph LR | ||
| subgraph Bus | ||
| A[Events] | ||
| end | ||
| subgraph I[IBC Host] | ||
| I1["HandleMessage(Message)"] | ||
| end | ||
| subgraph Handler | ||
| H1["ConvertIBCMessageToTransaction(IBCMessage)"] | ||
| subgraph Transaction | ||
| T1["coreTypes.Transaction{Msg: IBCMessage}"] | ||
| end | ||
| H2["SignTransaction(Transaction)"] | ||
| end | ||
| subgraph Mempool | ||
| M1["ValidateTransaction(Transaction)"] | ||
| M2["AddToMempool(Transaction)"] | ||
| end | ||
| Bus--Message-->I | ||
| I--IBCMessage-->Handler | ||
| H1--IBCMessage-->Transaction | ||
| Transaction--Transaction-->H2 | ||
| Handler--Transaction-->Mempool | ||
| M1--Transaction-->M2 | ||
| ``` | ||
|
|
||
| See: [ibc/module.go](../module.go) for the specific implementation details. | ||
|
|
||
| ### Mempool | ||
|
|
||
| With the `IBCMessage` now propagated through the network's mempool, when it is reaped (by the block proposer) the message's validity will be handled by first determining the type of the `IBCMessage`: | ||
|
|
||
| - `UpdateIBCStore`: The `key` and `value` fields are tracked by persistence and used to update the `ibc` store state tree | ||
| - `PruneIBCStore`: The `key` field is tracked by persistence and marked for removal in the `ibc` store state tree | ||
|
|
||
| ### State Transition | ||
|
|
||
| See: [PROTOCOL_STATE_HASH.md](../../persistence/docs/PROTOCOL_STATE_HASH.md#ibc-state-tree) for more information on how the persistence module uses the data it has tracked from the `IBCMessage` objects, in order to update the actual state trees and in turn the root hash. | ||
|
|
||
| ## Provable Stores | ||
|
|
||
| The `ProvableStore` interface defined in [shared/modules/ibc_module.go](../../shared/modules/ibc_module.go) is implemented by the [`provableStore`](../store/provable_store.go) type and managed by the [`StoreManager`](../store/store_manager.go). | ||
|
|
||
| The provable stores are each assigned a `prefix`. This represents the specific sub-store that they are able to access and interact with in the IBC state tree. When doing any operation `get`/`set`/`delete` the `prefix` is applied to the `key` provided to generate the `CommitmentPath` to the element in the IBC state tree. | ||
|
|
||
| The provable stores do not directly interface with the IBC state tree but instead utliise the `peristence` layer to query the data locally. This allows for the efficient querying of the IBC store instead of having to query the IBC state tree directly. Any changes made by the `ProvableStore` instance are broadcasted to the network for inclusion in the next block, being stored in their mempools. | ||
|
|
||
| ### Caching | ||
|
|
||
| Every local change made to the IBC store (`update`/`delete`) is stored in an in-memory cache. These caches are written to disk by the [`StoreManager`](../store/store_manager.go). | ||
|
|
||
| In the event of a node failure, or local changes not being propagated correctly. Any changes stored in the cache can be "replayed" by the node and broadcasted to the network for inclusion in the next block. | ||
|
|
||
| _TODO: Implement this functionality_ | ||
|
|
||
| [ics24]: https://github.com/cosmos/ibc/blob/main/spec/core/ics-024-host-requirements/README.md | ||
| [ics20]: https://github.com/cosmos/ibc/blob/main/spec/app/ics-020-fungible-token-transfer/README.md | ||
| [smt]: https://github.com/pokt-network/smt | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.