Skip to content

Commit a3a2b5c

Browse files
authored
[IBC] Make the IBC Host a submodule with access to the bus (#868)
## Description <!-- reviewpad:summarize:start --> ### Summary generated by Reviewpad on 13 Jul 23 10:41 UTC This pull request includes several changes across multiple files. Here is a summary of the changes: 1. In the file `ibc/handle_message_test.go`, the file was renamed to `ibc/ibc_msg_mempool_test.go` with a similarity index of 85%. 2. In the same file, the imports were modified, and the `strings` package was added. 3. The test function `TestHandleMessage_ErrorAlreadyInMempool` was renamed to `TestEmitMessage_MessageAddedToLocalMempool`. Some code within the renamed test function was also modified, including changes in the preparation of test data and the addition of a transaction to the mempool. 4. The test function `TestHandleMessage_BasicValidation_Message` was renamed to `TestIBCMessage_BasicValidation_Message`. 5. The test function `TestHandleMessage_BasicValidation_Transaction` was renamed to `TestIBCMessage_BasicValidation_Transaction`. 6. A new test function `TestHandleMessage_ErrorAlreadyInMempool` was added to check for the error of having a duplicate transaction in the mempool. 7. A new test function `TestHandleMessage_ErrorAlreadyCommitted` was added to check for the error of having an already committed transaction. 8. The test function `TestHandleMessage_GetIndexedMessage` was modified to include changes in the preparation of the environment. 9. The test function `TestHandleMessage_AddToMempool` was removed. Additionally, other files such as `treestore_module.go`, `emitter.go`, `submodule.go`, `config.validator4.json`, `persistence/ibc.go`, `defaults.go`, `bus_module.go`, `ibc_store_module.go`, `bulk_store_cache.go`, `ibc_host_module.go`, `config.validator4.json`, `persistence/test/benchmark_state_test.go`, `p2p/README.md`, `runtime/manager_test.go`, `shared/node.go`, `persistence/test/manager_test.go`, `shared/modules/bulk_store_cache.go`, `ibc.go`, `shared/node.go`, `ics24.md`, `main_test.go` have also been modified. Please let me know if you need more information or details about any specific change. <!-- reviewpad:summarize:end --> ## Issue Fixes #854 ## Type of change Please mark the relevant option(s): - [x] New feature, functionality or library - [ ] Bug fix - [ ] Code health or cleanup - [ ] Major breaking change - [ ] Documentation - [ ] Other <!-- add details here if it a different type of change --> ## List of changes - Move IBC host into its own submodule - Enable local ProvableStore instances to emit events to alter the IBC state tree ## Testing - [x] `make develop_test`; if any code changes were made - [x] `make test_e2e` on [k8s LocalNet](https://github.com/pokt-network/pocket/blob/main/build/localnet/README.md); if any code changes were made - [x] `e2e-devnet-test` passes tests on [DevNet](https://pocketnetwork.notion.site/How-to-DevNet-ff1598f27efe44c09f34e2aa0051f0dd); if any code was changed - [x] [Docker Compose LocalNet](https://github.com/pokt-network/pocket/blob/main/docs/development/README.md); if any major functionality was changed or introduced - [x] [k8s LocalNet](https://github.com/pokt-network/pocket/blob/main/build/localnet/README.md); if any infrastructure or configuration changes were made ## Required Checklist - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added, or updated, [`godoc` format comments](https://go.dev/blog/godoc) on touched members (see: [tip.golang.org/doc/comment](https://tip.golang.org/doc/comment)) - [x] I have tested my changes using the available tooling - [ ] I have updated the corresponding CHANGELOG ### If Applicable Checklist - [ ] I have updated the corresponding README(s); local and/or global - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] I have added, or updated, [mermaid.js](https://mermaid-js.github.io) diagrams in the corresponding README(s) - [ ] I have added, or updated, documentation and [mermaid.js](https://mermaid-js.github.io) diagrams in `shared/docs/*` if I updated `shared/*`README(s)
1 parent 1742f81 commit a3a2b5c

39 files changed

Lines changed: 1979 additions & 676 deletions

build/config/config.validator1.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@
6060
},
6161
"ibc": {
6262
"enabled": true,
63-
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e",
64-
"stores_dir": "/var/ibc"
63+
"stores_dir": "/var/ibc",
64+
"host": {
65+
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e"
66+
}
6567
}
6668
}

build/config/config.validator2.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
},
5454
"ibc": {
5555
"enabled": true,
56-
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e",
57-
"stores_dir": "/var/ibc"
56+
"stores_dir": "/var/ibc",
57+
"host": {
58+
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e"
59+
}
5860
}
5961
}

build/config/config.validator3.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
},
5454
"ibc": {
5555
"enabled": true,
56-
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e",
57-
"stores_dir": "/var/ibc"
56+
"stores_dir": "/var/ibc",
57+
"host": {
58+
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e"
59+
}
5860
}
5961
}

build/config/config.validator4.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
},
5454
"ibc": {
5555
"enabled": true,
56-
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e",
57-
"stores_dir": "/var/ibc"
56+
"stores_dir": "/var/ibc",
57+
"host": {
58+
"private_key": "0ca1a40ddecdab4f5b04fa0bfed1d235beaa2b8082e7554425607516f0862075dfe357de55649e6d2ce889acf15eb77e94ab3c5756fe46d3c7538d37f27f115e"
59+
}
5860
}
5961
}

consensus/e2e_tests/utils_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ func CreateTestConsensusPocketNode(
122122
telemetryMock := baseTelemetryMock(t, eventsChannel)
123123
loggerMock := baseLoggerMock(t, eventsChannel)
124124
rpcMock := baseRpcMock(t, eventsChannel)
125-
ibcMock := ibcUtils.IBCMockWithHost(t, eventsChannel)
125+
ibcMock, hostMock := ibcUtils.IBCMockWithHost(t, bus)
126+
bus.RegisterModule(hostMock)
126127

127128
for _, module := range []modules.Module{
128129
p2pMock,

ibc/docs/ics24.md

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
- [IBC State Tree](#ibc-state-tree)
1111
- [Data Retrieval](#data-retrieval)
1212
- [IBC Messages](#ibc-messages)
13-
- [IBC Message Handling](#ibc-message-handling)
13+
- [IBC Message Broadcasting](#ibc-message-broadcasting)
1414
- [Mempool](#mempool)
1515
- [State Transition](#state-transition)
1616
- [Provable Stores](#provable-stores)
17+
- [Bulk Store Cacher](#bulk-store-cacher)
1718
- [Caching](#caching)
1819

1920
## Overview
@@ -26,11 +27,18 @@ As token transfers as defined in [ICS-20][ics20] work on a lock and mint pattern
2627

2728
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.
2829

30+
An example of the JSON configuration for the IBC module is as follows:
31+
2932
```json
3033
"ibc": {
31-
"enabled": bool,
32-
"private_key": string,
33-
"stores_dir": string
34+
"enabled": true,
35+
"stores_dir": "/var/ibc",
36+
"host": {
37+
"private_key": "private key hex string",
38+
"bulk_store_cacher": {
39+
"max_height_stored": 5
40+
}
41+
}
3442
}
3543
```
3644

@@ -116,7 +124,7 @@ When attempting to generate a proof for a specific `key` in the IBC state tree t
116124

117125
### IBC Messages
118126

119-
Hosts maintain uncommitted changes in a local ephemeral IBC store while messages propagate through the mempool.
127+
Hosts propagate any local changes they propose to the IBC store throughout the network's existing `Transaction` flow, and they handle them locally.
120128

121129
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:
122130

@@ -127,42 +135,51 @@ _Note: In both types described above the `key` field **must** already be prefixe
127135

128136
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.
129137

130-
### IBC Message Handling
138+
### IBC Message Broadcasting
131139

132-
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:
140+
Upon making a local change to the IBC store the host will:
133141

134-
1. Wrap the `IBCMessage` within a `Transaction`
135-
2. Sign the `Transaction` using the `IBCModule`'s private key
136-
3. Broadcast the `Transaction` throughout the mempool
142+
1. Create the relevent `IBCMessage` type
143+
- `UpdateIBCStore`: for creation/update events
144+
- `PruneIBCStore`: for deletion events
145+
2. Wrap the `IBCMessage` within a `Transaction`
146+
3. Sign the `Transaction` using the IBC Host's private key
147+
4. Add the `Transaction` to the local mempool
148+
5. Broadcast the `Transaction` via the `P2P` module for the other nodes to include it in their mempools
137149

138150
```mermaid
139-
graph LR
140-
subgraph Bus
141-
A[Events]
151+
graph TD
152+
subgraph Update
153+
A[Key]
154+
B[Value]
155+
end
156+
subgraph UpdateIBCStore
157+
C[Signer]
158+
D[Key]
159+
E[Value]
142160
end
143-
subgraph I[IBC Host]
144-
I1["HandleMessage(Message)"]
161+
subgraph IBCMessage
162+
F[Event]
145163
end
146-
subgraph Handler
147-
H1["ConvertIBCMessageToTransaction(IBCMessage)"]
148-
subgraph Transaction
149-
T1["coreTypes.Transaction{Msg: IBCMessage}"]
150-
end
151-
H2["SignTransaction(Transaction)"]
164+
subgraph Transaction
165+
G[Msg]
166+
H[Nonce]
167+
I[Signature]
152168
end
153169
subgraph Mempool
154-
M1["ValidateTransaction(Transaction)"]
155-
M2["AddToMempool(Transaction)"]
170+
J[Txs]
171+
end
172+
subgraph P2P
173+
K[Broadcast]
156174
end
157-
Bus--Message-->I
158-
I--IBCMessage-->Handler
159-
H1--IBCMessage-->Transaction
160-
Transaction--Transaction-->H2
161-
Handler--Transaction-->Mempool
162-
M1--Transaction-->M2
175+
Update -- "Update(Key, Value)" --> UpdateIBCStore
176+
UpdateIBCStore -- UpdateIBCStore --> IBCMessage
177+
IBCMessage -- Message --> Transaction
178+
Transaction -- Tx --> Mempool
179+
Transaction -- Tx --> P2P
163180
```
164181

165-
See: [ibc/module.go](../module.go) for the specific implementation details.
182+
See: [emitter.go](../store/emitter.go) for the specific implementation details.
166183

167184
### Mempool
168185

@@ -177,15 +194,29 @@ See: [PROTOCOL_STATE_HASH.md](../../persistence/docs/PROTOCOL_STATE_HASH.md#ibc-
177194

178195
## Provable Stores
179196

180-
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).
197+
The `ProvableStore` interface defined in [ibc_store_module.go](../../shared/modules/ibc_store_module.go) is implemented by the [`provableStore`](../store/provable_store.go) type and managed by the [`BulkStoreCacher`](../store/bulk_store_cache.go).
181198

182-
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.
199+
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 (if not already present) to generate the `CommitmentPath` to the element in the IBC state tree. The `CommitmentPrefix` for any provable store can be obtained through the following method:
200+
201+
```go
202+
type ProvableStore interface {
203+
...
204+
GetCommitmentPrefix() CommitmentPrefix
205+
...
206+
}
207+
```
183208

184209
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.
185210

211+
## Bulk Store Cacher
212+
213+
The [`BulkStoreCacher`](../store/bulk_store_cache.go) manages all the different provable store instances. It keeps an in-memory map of the current active provable stores, and also manages their caches in bulk.
214+
186215
### Caching
187216

188-
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).
217+
Every local change made to the IBC store (`update`/`delete`) is stored in an in-memory cache. These caches are written to disk (i.e. flushed) by the `BulkStoreCacher`, upon the receipt of a new height event from consensus. This means that the cache for any given height is always written to disk all at once.
218+
219+
The `BulkStoreCacher` also keeps track of the maximum height stored in the cache. The `max_height_stored` value (default `5`) is used when a new height event comes in to prune old entries in the cache stored on disk in a "circular buffer" like fashion.
189220

190221
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.
191222

ibc/host.go

Lines changed: 0 additions & 36 deletions
This file was deleted.

ibc/host/submodule.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package host
2+
3+
import (
4+
"errors"
5+
"time"
6+
7+
"github.com/pokt-network/pocket/ibc/store"
8+
"github.com/pokt-network/pocket/runtime/configs"
9+
coreTypes "github.com/pokt-network/pocket/shared/core/types"
10+
"github.com/pokt-network/pocket/shared/modules"
11+
"github.com/pokt-network/pocket/shared/modules/base_modules"
12+
)
13+
14+
var _ modules.IBCHostSubmodule = &ibcHost{}
15+
16+
type ibcHost struct {
17+
base_modules.IntegrableModule
18+
19+
cfg *configs.IBCHostConfig
20+
logger *modules.Logger
21+
storesDir string
22+
}
23+
24+
func Create(bus modules.Bus, config *configs.IBCHostConfig, options ...modules.IBCHostOption) (modules.IBCHostSubmodule, error) {
25+
return new(ibcHost).Create(bus, config, options...)
26+
}
27+
28+
// WithLogger assigns a logger for the IBC host
29+
func WithLogger(logger *modules.Logger) modules.IBCHostOption {
30+
return func(m modules.IBCHostSubmodule) {
31+
if mod, ok := m.(*ibcHost); ok {
32+
mod.logger = logger
33+
}
34+
}
35+
}
36+
37+
// WithStoresDir assigns a stores directory for the IBC host
38+
func WithStoresDir(dir string) modules.IBCHostOption {
39+
return func(m modules.IBCHostSubmodule) {
40+
if mod, ok := m.(*ibcHost); ok {
41+
mod.storesDir = dir
42+
}
43+
}
44+
}
45+
46+
func (*ibcHost) Create(bus modules.Bus, config *configs.IBCHostConfig, options ...modules.IBCHostOption) (modules.IBCHostSubmodule, error) {
47+
h := &ibcHost{
48+
cfg: config,
49+
}
50+
for _, option := range options {
51+
option(h)
52+
}
53+
h.logger.Info().Msg("🛰️ Creating IBC host 🛰️")
54+
bus.RegisterModule(h)
55+
_, err := store.Create(h.GetBus(),
56+
h.cfg.BulkStoreCacher,
57+
store.WithLogger(h.logger),
58+
store.WithStoresDir(h.storesDir),
59+
store.WithPrivateKey(h.cfg.PrivateKey),
60+
)
61+
if err != nil {
62+
return nil, err
63+
}
64+
return h, nil
65+
}
66+
67+
func (h *ibcHost) GetModuleName() string { return modules.IBCHostSubmoduleName }
68+
69+
// GetTimestamp returns the current unix timestamp
70+
func (h *ibcHost) GetTimestamp() uint64 {
71+
return uint64(time.Now().Unix())
72+
}
73+
74+
// GetProvableStore returns an instance of a provable store with the given name with the
75+
// CommitmentPrefix set to []byte(name). The store is created if it does not exist.
76+
//
77+
// Any changes made using the store are handled locally and propagated through the bus,
78+
// added to all nodes' mempools ready for inclusion in the next block to transition the IBC store state tree.
79+
// Any operations will ensure the CommitmentPrefix is prepended to the key if not present already.
80+
func (h *ibcHost) GetProvableStore(name string) (modules.ProvableStore, error) {
81+
if err := h.GetBus().GetBulkStoreCacher().AddStore(name); err != nil && !errors.Is(err, coreTypes.ErrIBCStoreAlreadyExists(name)) {
82+
return nil, err
83+
}
84+
return h.GetBus().GetBulkStoreCacher().GetStore(name)
85+
}

0 commit comments

Comments
 (0)