GithubHelp home page GithubHelp logo

ibc-demo's Introduction

IBC Demo

This project is to demonstrate the use of pallet-ibc.

The runtime in this project is mainly composed of two special pallets.

One is pallet-ibc and the other is a template pallet that is defined in the pallets/template directory.

pallet-ibc provides IBC support and the template pallet contains the demo logic of the chain.

And here is a glue package that allows an RPC client based on substrate-subxt to interact with the demo chain through RPC.

The repository also includes implementation of relayer process defined in ICS 018 and a cli tool to make the cross-chain work.

Local Development

Follow these steps to prepare a local Substrate development environment ๐Ÿ› ๏ธ

Setup

Setup instructions can be found at the Substrate Developer Hub.

Build

Once the development environment is set up, build the node template. This command will build the Wasm and native code:

git clone https://github.com/cdot-network/ibc-demo.git
cd ibc-demo
git submodule update --init
cargo build --release

Run

Start demo chains and send packet via IBC protocol:

Open a terminal and run the following command to start a test chain called appia.

./target/release/node-template --base-path /tmp/chain-appia --dev

Open another terminal and start the flaminia test chain.

./target/release/node-template --base-path /tmp/chain-flaminia --dev --port 20333 --ws-port 8844

Create a client of flaminia chain on appia chain, and then create a client of appia chain on flaminia.

./target/release/cli appia-client-id create-client flaminia-client-id
./target/release/cli flaminia-client-id create-client appia-client-id

Bind ports for two chains.

./target/release/cli appia bind-port bank
./target/release/cli flaminia bind-port bank
# ./target/release/cli appia release-port bank // don't

Open a new terminal and run relayer.

export RUST_LOG=relayer=info
./target/release/relayer -c relayer/config.toml

Use the cli tool to initiate a connection. The 2 client IDs below "53a9...fa10 779c...8e03" are from "relayer/config.toml"

./target/release/cli appia conn-open-init 53a954d6a7b1c595e025226e5f2a1782fdea30cd8b0d207ed4cdb040af3bfa10 779ca65108d1d515c3e4bc2e9f6d2f90e27b33b147864d1cd422d9f92ce08e03

When the log shows that the connection status of both chains is open, initiate a channel handshake. The connection ID below "d93f...bd11" is from the stdout of the command above

./target/release/cli appia chan-open-init d93fc49e1b2087234a1e2fc204b500da5d16874e631e761bdab932b37907bd11 bank bank

When the log shows that the channel status of both chains is open, you can send cross-chain messages as the following command. The 2 channel IDs below "00e2...86ac a161...601e" are from stdout of the command above, "01020304" is the data to send by channel, in Hex format.

./target/release/cli appia send-packet 1 1000 bank 00e2e14470ed9a017f586dfe6b76bb0871a8c91c3151778de110db3dfcc286ac bank a1611bcd0ba368e921b1bd3eb4aa66534429b14837725e8cef28182c25db601e 01020304

After some blocks, you can see that the flamenia log shows that the packet has been received.

How the Demo Commands Implemented in Source Code

  • In cli, substrate-subxt invokes the pallet's callable functions by the macro substrate_subxt_proc_macro::Call. Please refer to document substrate_subxt_proc_macro::Call for details.

Creating a Client

USAGE:
    cli <CHAIN> create-client <chain-name>

After the command is triggered, the following functions are executed in sequence.

// https://github.com/cdot-network/ibc-demo/tree/master/cli/src/main.rs
async fn create_client(
    ...
) -> Result<(), Box<dyn Error>> {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/template/src/lib.rs
pub fn test_create_client(
    ...
) -> dispatch::DispatchResult {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/ibc/src/lib.rs
pub fn create_client(
	...
) -> dispatch::DispatchResult {
	...
}	

Binding a Port

USAGE:
    cli <CHAIN> bind-port <identifier>

After the command is triggered, the following functions are executed in sequence.

// https://github.com/cdot-network/ibc-demo/tree/master/cli/src/main.rs
async fn bind_port(addr: &str, identifier: Vec<u8>) -> Result<(), Box<dyn Error>> {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/template/src/lib.rs
pub fn test_bind_port(origin, identifier: Vec<u8>) -> dispatch::DispatchResult {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/ibc/src/lib.rs
pub fn bind_port(identifier: Vec<u8>, module_index: u8) -> dispatch::DispatchResult {
	...
}

Relaying

USAGE:
    relayer --config <FILE>

After the command is triggered, the following function keep scanning the 2 chains(A & B) for the jobs:

  • Block header synchronization
  • Connection handshakes
  • Channel handshakes
  • Packet flow
async fn relay(
    ...
) -> Result<(), Box<dyn Error>> {
    ...

    // Block header synchronization
    // For the 2 parties on inter-blockchain communication, if one chain(counterparty_client) doesn't have latest block header of the other chain(client).
    if counterparty_client_state.latest_height < block_number {
        ...
    }
    ...
    
    // Scanning the 2 chains' connection state
    // If it detects any party of the 2 can move connection opening handshakes state forward, it sends a request to the corresponding party. 
    for connection in client_state.connections.iter() {
        ...
        // If current handshake state is (A,B)->(INIT, none), it sends a request to chain B, which converts the handshake state to (INIT, TRYOPEN)  
        if connection_end.state == ConnectionState::Init
            && remote_connection_end.state == ConnectionState::None {
            ...    
        }
        // If current handshake state is (A,B)->(INIT, TRYOPEN), it sends a request to chain B, which converts the handshake state to (OPEN, TRYOPEN)  
        else if connection_end.state == ConnectionState::TryOpen
            && remote_connection_end.state == ConnectionState::Init
        {
            ...
        }
        // If current handshake state is (A,B)->(OPEN, TRYOPEN), it sends a request to chain B, which converts the handshake state to (OPEN, OPEN)  
        else if connection_end.state == ConnectionState::Open
            && remote_connection_end.state == ConnectionState::TryOpen {
            ...    
        }
    }

    ...

    // Scanning the 2 chains' channel state
    // If it detects any party of the 2 can move channel opening handshakes state forward, it sends a request to the corresponding party.     
    for channel in client_state.channels.iter() {
        ...
        // If current handshake state is (A,B)->(INIT, none), it sends a request to chain B, which converts the handshake state to (INIT, TRYOPEN)  
        if channel_end.state == ChannelState::Init && remote_channel_end.state == ChannelState::None {
            ...    
        }
        // If current handshake state is (A,B)->(INIT, TRYOPEN), it sends a request to chain B, which converts the handshake state to (OPEN, TRYOPEN)  
        else if channel_end.state == ChannelState::TryOpen
            && remote_channel_end.state == ChannelState::Init
        {
            ...
        }
        // If current handshake state is (A,B)->(OPEN, TRYOPEN), it sends a request to chain B, which converts the handshake state to (OPEN, OPEN)  
        else if channel_end.state == ChannelState::Open
            && remote_channel_end.state == ChannelState::TryOpen {
            ...    
        }    
    }

    // Scanning the 2 events in packet flow: RawEvent::SendPacket, RawEvent::RecvPacket
    // If it detects either event from one party(chain A), it sends corresponding request to the other party(chain B) to move the packet flow forward
    for event in events.into_iter() {
        match event.event {
            node_runtime::Event::pallet_ibc(pallet_ibc::RawEvent::SendPacket(  // Detects event RawEvent::SendPacket from one party(chain A), who initializes sending packet 
                ...
            ) {
                ...
                let datagram = Datagram::PacketRecv {
                    ...
                };
                tx.send(datagram).unwrap(); // Sends the packet to the other party(chain B)
            }
            node_runtime::Event::pallet_ibc(pallet_ibc::RawEvent::RecvPacket( // Detects event RawEvent::RecvPacket, an acknowledgement, from the other party(chain B), who acknowledges after receiving the packet 
                ...
            )) => {
                ...
                let datagram = Datagram::PacketAcknowledgement {
                    ...
                }
                };
                tx.send(datagram).unwrap(); // Sends the acknowledgement to chain A
            }
        ...
    }
}

Opening a Connection

USAGE:
    cli <CHAIN> conn-open-init <client-identifier> <counterparty-client-identifier>

After the command is triggered, the following functions are executed in sequence.

// https://github.com/cdot-network/ibc-demo/tree/master/cli/src/main.rs
async fn conn_open_init(
    ...
) -> Result<(), Box<dyn Error>> {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/template/src/lib.rs
pub fn test_conn_open_init(
    ...
) -> dispatch::DispatchResult {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/ibc/src/lib.rs
pub fn conn_open_init(
    ...
) -> dispatch::DispatchResult {
	...
}

Opening a Channel

USAGE:
    cli <CHAIN> chan-open-init [FLAGS] <connection-identifier> <port-identifier> <counterparty-port-identifier>

After the command is triggered, the following functions are executed in sequence.

// https://github.com/cdot-network/ibc-demo/tree/master/cli/src/main.rs
async fn chan_open_init(
    ...
) -> Result<(), Box<dyn Error>> {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/template/src/lib.rs
pub fn test_chan_open_init(
    ...
) -> dispatch::DispatchResult {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/ibc/src/lib.rs
pub fn chan_open_init(
    ...
) -> dispatch::DispatchResult {
	...
}

Sending a Packet

USAGE:
    cli <CHAIN> send-packet <sequence> <timeout-height> <source-port> <source-channel> <dest-port> <dest-channel> <data>

After the command is triggered, the following functions are executed in sequence.

// https://github.com/cdot-network/ibc-demo/tree/master/cli/src/main.rs
async fn send_packet(
    ...
) -> Result<(), Box<dyn Error>> {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/template/src/lib.rs
pub fn test_send_packet(
    ...
) -> dispatch::DispatchResult {
    ...
}
// https://github.com/cdot-network/ibc-demo/tree/master/pallets/ibc/src/lib.rs
pub fn send_packet(
    ...
) -> dispatch::DispatchResult {
	...
}

ibc-demo's People

Contributors

apopiak avatar athei avatar bkchr avatar c410-f3r avatar danforbes avatar davirain-su avatar en avatar jeluard avatar jimmychu0807 avatar joshorndorff avatar kaichaosun avatar livelybug avatar riusricardo avatar shawntabrizi avatar tripleight avatar wheresaddie avatar xlc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

jredrado

ibc-demo's Issues

Status of pallet

Hi there,

Is this pallet working? Can you provide status update?

Do you recommend testing it as it is?

What challenges are you facing? How can I support?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.