Skip to content

Commit

Permalink
Adding Cross Chain
Browse files Browse the repository at this point in the history
  • Loading branch information
AelfHarsh committed Jun 20, 2024
1 parent 026713a commit 4efa16d
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 0 deletions.
61 changes: 61 additions & 0 deletions docs/Architecture/Cross Chain/Architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Side Chain and Main Chain Node Documentation

## Overview

Conceptually, a side chain node and a main chain node are similar. Both are independent blockchains with their own peer-to-peer networks and possibly their own ecosystems. This setup can be implemented at multiple levels. In terms of peer-to-peer networks, all side chains operate in parallel to each other but are linked to a main chain node through a cross-chain communication mechanism.

Through this link, messages are exchanged, and indexing is performed to ensure that transactions from the main chain or other side chains are verifiable in the side chain. Implementers can use AElf libraries and frameworks to build these chains.

**Key Role of the Main Chain:**

- The main chain's primary purpose is to index the side chains.
- Only the main chain indexes data about all the side chains.
- Side chains are independent and do not have knowledge about each other.
- When side chains need to verify transactions from other chains, they use the main chain as a bridge to provide cross-chain verification information.

## Node Level Architecture

In the current architecture, both the side chain node and the main chain node have one server and exactly one client. This forms the basis for AElf's two-way communication between the main chain and side chains. Both the server and the client are implemented as node plugins (a node has a collection of plugins). Interaction (listening and requesting) can start once both nodes are running.

![Node Level Architecture](side-chain-nodes.png)

The diagram above illustrates two nodes run by an entity: one main chain node and one side chain node. Note that the nodes don't have to be in the same physical location.

### Side Chain Lifetime

The lifetime of a side chain involves the following steps:

- **Request side chain creation.**
- **Wait for acceptance on the main chain.**
- **Start and initialize the side chain.** It will be indexed by the main chain automatically.
- **Cross-chain verification** is allowed only if the side chain is indexed correctly.

### Communication

When the side chain node starts, it will initiate various communications. Here are the main points of the protocol:

- **Initial Request:** When the side chain node starts for the first time, it will request the main chain node for a chain initialization context.
- **Handshake:** After initialization, the side chain is launched and will perform a handshake with the main chain node to signal that it is ready to be indexed.
- **Indexing Process:** During indexing, information about irreversible blocks will be exchanged between the side chain and the main chain. The main chain will write the final result in a block, which is calculated using the cross-chain data from all side chains. The side chain will also record the data in a contract from the main chain.

AElf provides cross-chain communication implementation using gRPC.

```protobuf
rpc RequestIndexingFromParentChain (CrossChainRequest) returns (stream acs7.ParentChainBlockData) {}
rpc RequestIndexingFromSideChain (CrossChainRequest) returns (stream acs7.SideChainBlockData) {}
```

### Cache

For effective indexing, a cache layer is used to store cross-chain data received from remote nodes, ensuring the data is available and correct. The cross-chain data is cached by chain ID and block height with a count limit. The cache layer provides the data if it is cached when the node needs it, thus decoupling the communication part and node running logic.

### Cross-Chain Contract

Apart from the data in blocks, most cross-chain data will be stored by the cross-chain contract. Cross-chain data cached by the node is packed into transactions during the mining process, and the calculated result is stored by the contract. The cross-chain data in the block is the result of side chain indexing calculations from this contract. Cross-chain verification can only work correctly with data from this contract.

### Data Flow

Conceptually, the node operates as described in the following diagram. The main/side chain node receives cross-chain data from the other side and stores it in local memory. The indexing transaction is packed by the miner, and the cross-chain data is written into the `State` through the `Crosschain Contract`.

![Data Flow](architecture-node.png)
140 changes: 140 additions & 0 deletions docs/Architecture/Cross Chain/Cross Chain Transfer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Cross Chain Transfer

Cross chain transfer is one of the most commonly used cases when it comes to cross chain verification. AElf already supports cross chain transfer functionality in its contract. This section will explain how to transfer tokens across chains. It assumes a side chain is already deployed and has been indexed by the main chain.

The transfer process will always use the same contract methods and follow these two steps:
- **Initiate the transfer**
- **Receive the tokens**

## Prepare

There are a few preparation steps required before a cross chain transfer, which need to be done only once for each chain. If these steps are already completed, you can skip this part.

Let's say you want to transfer token **FOO** from chain **A** to chain **B**. Before you start, make sure you understand how cross chain transaction verification works. Any input containing `MerklePath` in the following steps means that cross chain verification is needed. Refer to the [cross chain verification documentation](crosschain-verification) for more details.

- **Validate `Token Contract` address on chain A**

Send transaction `tx_1` to the `Genesis Contract` with the method `ValidateSystemContractAddress`. You need to provide `system_contract_hash_name` and the address of the `Token Contract`. `tx_1` should be successfully packed in the block.

```protobuf
rpc ValidateSystemContractAddress(ValidateSystemContractAddressInput) returns (google.protobuf.Empty){}
message ValidateSystemContractAddressInput {
aelf.Hash system_contract_hash_name = 1;
aelf.Address address = 2;
}
```

- **Register the token contract address of chain A on chain B**

Create a proposal for the `RegisterCrossChainTokenContractAddress` for the default parliament organization on chain B. Refer to the [Parliament contract documentation](../../reference/smart-contract-api/parliament) for more details. Apart from cross chain verification context, you also need to provide the origin data of `tx_1` and the `Token Contract` address on chain A.

```protobuf
rpc RegisterCrossChainTokenContractAddress (RegisterCrossChainTokenContractAddressInput) returns (google.protobuf.Empty) {}
message RegisterCrossChainTokenContractAddressInput {
int32 from_chain_id = 1;
int64 parent_chain_height = 2;
bytes transaction_bytes = 3;
aelf.MerklePath merkle_path = 4;
aelf.Address token_contract_address = 5;
}
```

- **Validate `TokenInfo` of FOO on chain A**

Send transaction `tx_2` to the `Token Contract` with the method `ValidateTokenInfoExists` on chain A. You need to provide `TokenInfo` of FOO. `tx_2` should be successfully packed in the block.

```protobuf
rpc ValidateTokenInfoExists(ValidateTokenInfoExistsInput) returns (google.protobuf.Empty){}
message ValidateTokenInfoExistsInput {
string symbol = 1;
string token_name = 2;
int64 total_supply = 3;
int32 decimals = 4;
aelf.Address issuer = 5;
bool is_burnable = 6;
int32 issue_chain_id = 7;
}
```

- **Create token FOO on chain B**

Send transaction `tx_3` to the `Token Contract` with the method `CrossChainCreateToken` on chain B. You need to provide the origin data of `tx_2` and the cross chain verification context of `tx_2`.

```protobuf
rpc CrossChainCreateToken(CrossChainCreateTokenInput) returns (google.protobuf.Empty) {}
message CrossChainCreateTokenInput {
int32 from_chain_id = 1;
int64 parent_chain_height = 2;
bytes transaction_bytes = 3;
aelf.MerklePath merkle_path = 4;
}
```

## Initiate the Transfer

On the token contract of the source chain, the `CrossChainTransfer` method is used to trigger the transfer:

```protobuf
rpc CrossChainTransfer (CrossChainTransferInput) returns (google.protobuf.Empty) { }
message CrossChainTransferInput {
aelf.Address to = 1;
string symbol = 2;
sint64 amount = 3;
string memo = 4;
int32 to_chain_id = 5;
int32 issue_chain_id = 6;
}
```

### The fields of the input:

- **to**: the target address to receive the token
- **symbol**: the symbol of the token to be transferred
- **amount**: the amount of the token to be transferred
- **memo**: a memo field for this transfer
- **to_chain_id**: the destination chain ID where the tokens will be received
- **issue_chain_id**: the chain ID where the token was issued

## Receive on the Destination Chain

On the destination chain where the tokens need to be received, the `CrossChainReceiveToken` method is used to trigger the reception:

```protobuf
rpc CrossChainReceiveToken (CrossChainReceiveTokenInput) returns (google.protobuf.Empty) { }
message CrossChainReceiveTokenInput {
int32 from_chain_id = 1;
int64 parent_chain_height = 2;
bytes transfer_transaction_bytes = 3;
aelf.MerklePath merkle_path = 4;
}
rpc GetBoundParentChainHeightAndMerklePathByHeight (aelf.Int64Value) returns (CrossChainMerkleProofContext) {
option (aelf.is_view) = true;
}
message CrossChainMerkleProofContext {
int64 bound_parent_chain_height = 1;
aelf.MerklePath merkle_path_from_parent_chain = 2;
}
```

### The fields of the input:

- **from_chain_id**: the source chain ID from which the cross chain transfer was launched

- **parent_chain_height**: the height of the block on the main chain that contains the `CrossChainTransfer` transaction (for main chain to side chain transfer). For side chain to side chain or side chain to main chain transfer, it is the result of `GetBoundParentChainHeightAndMerklePathByHeight` (input is the height of the `CrossChainTransfer`), accessible in the `bound_parent_chain_height` field.

- **transfer_transaction_bytes**: the serialized form of the `CrossChainTransfer` transaction.

- **merkle_path**: obtained from the source chain. The construction of merkle path data differs among cases:
- **Main chain to side chain transfer**: merkle path from the main chain’s web API `GetMerklePathByTransactionIdAsync` (with `CrossChainTransfer` transaction ID as input).
- **Side chain to side chain or side chain to main chain transfer**:
- merkle path from the source chain’s web API `GetMerklePathByTransactionIdAsync` (with `CrossChainTransfer` transaction ID as input).
- output of `GetBoundParentChainHeightAndMerklePathByHeight` method in the `CrossChain Contract` (with `CrossChainTransfer` transaction’s block height as input). Path nodes are in the `merkle_path_from_parent_chain` field of the `CrossChainMerkleProofContext` object.
- Concatenate the above two merkle paths.
Empty file.
20 changes: 20 additions & 0 deletions docs/Architecture/Cross Chain/Introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Introduction

One of the major issues with current blockchain systems is scalability. This is mainly due to **congestion problems** in existing blockchains. The core problem is that when a single chain needs to sequentially order and process transactions, a popular dApp consuming a lot of resources can negatively impact other dApps.

To address this issue, AElf introduced side chains in its initial design. The concept is that each side-chain handles one or more similar business scenarios, distributing different tasks across multiple chains to improve overall processing efficiency.

## Key Points:
- **Independent and Specialized**: Side-chains are designed to be independent and specialized, ensuring that the dApps running on them perform efficiently and smoothly.
- **Network Link**: There is a network link between the main-chain node and side-chain nodes, with communication indirectly facilitated through a Merkle root.

![image](introduction-topology.png)

*The diagram above illustrates the conceptual idea behind side chains.*

Side chains are isolated but still need a way to interact with each other. To enable cross-chain verification scenarios, AElf introduces a communication mechanism through **Merkle roots** and **indexing**.

## Overview
The following sections of this documentation will provide:
- An overview of the architecture of AElf's side chains.
- A guide explaining how to set up a main-chain and a side chain node.
Empty file.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Architecture/Cross Chain/merkle-path.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/Architecture/Cross Chain/merkle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 4efa16d

Please sign in to comment.