tronprotocol / tips

TRON Improvement Proposals
218 stars 187 forks source link

TRC-261: The Design of Cross-Chain Smart Contract #261

Closed tomatoishealthy closed 1 year ago

tomatoishealthy commented 3 years ago
tip: 261
title: The Design of Cross-Chain Smart Contract
author: ray<ray.wu@tron.network>
discussions to: https://github.com/tronprotocol/tips/issues/261
category: TRC
status: DRAFT
created: 2021-04-09

The Design of Cross-Chain Smart Contract

Simple Summary

This TIP describes the implementation of the cross-chain contract call model.

Abstract

Developing cross-chain mechanisms is an essential part of advancing blockchain technology. They can break down barriers and facilitate value exchanges among the ecosystems of different chains. Currently, the mainstream cross-chain scenarios include token cross-chain and message cross-chain, the latter has a higher degree of abstraction than the former. TRON offers both solutions: cross-chain TRC10 token transfer and cross-chain contract call. This article details the implementation of the cross-chain contract call model.

Motivation

While TRON has already implemented cross-chain transfers based on TRC10 tokens, such a pure token-based cross-chain mechanism has certain limitations. Although TRON's TVM provides developers with a flexible, secure and programmable environment where they can develop contracts with Solidity language, the cross-chain contract call feature is still not available so far. That's why a cross-chain contract call solution that expands TRON's functionality and flexibility is urgently needed.

Specification

CrossContract: the transaction that carries the interoperate message of chain CrossDataType: token | contract, identify the type of the CrossContract ContractTrigger: the contract data structure of the cross-chain message ProxyAddress: the owner of the contract on the dest chain, used to identify the contract as a cross-chain contract

Rationale

Some factors to consider when it comes to cross-chain contract call:

Message body

A cross-chain message must differentiate between TRC10 token transfer and contract call to ensure the universality of the cross-chain message body. To that end, a field is needed to identify the type of transaction. Also, since TRC10 token transfer and contract call have widely different message bodies, and there's barely any overlap between the two data formats, it is important to use an original coding method to store cross-chain transactions. Also, unlike TRC10 token transfer, which is easier to understand, cross-chain contracts are much more flexible. Thus, it is important for a cross-chain contract to specify the contract method to be triggered on each of the two chains. Therefore, there should be two transactions for triggering the contract in the message body of the cross-chain contract.

Triggering and transmission

Users will feel no difference in triggering a cross-chain contract call and a common contract call. However, they have to ensure that they follow the correct contract specifications mentioned above when triggering a cross-chain contract. For example, Client 1 initiates a cross-chain contract call expecting to trigger the test() method of Contract A on Chain A. If the call of Chain A succeeds, then the test() method of Contract A on Chain B will be triggered. Chain A will parse and split the transaction after receiving the cross-chain message and execute its part of the transaction on itself. If execution succeeds, it will send the remaining cross-chain contract message to Chain B.

Constraints of cross-chain contracts

As mentioned above, cross-chain contracts are remarkably flexible, which brings about an issue: how to constrain the relationship between contract calls on two chains? In other words, if a cross-chain contract transaction triggers the contract method Method A on Chain A first, how to ensure which contract method can this transaction call on Chain B? Without constraints, users may execute a low-value contract call on Chain A, and then trigger a high-value contract call on Chain B and transfer that value back to them, in this way stealing the assets on Chain B. ​ Hence the following rules: ​

Failure

Failures can be divided into the following two scenarios:

Cross-chain contract verification process

When the cross-chain smart contract transaction executes successfully, chain A needs to send the smart contract transaction to chain B. To ensure the authenticity of the transaction sent by chain A, chain B needs to verify the transaction. The verification is divided into two parts:

There are the Merkle roots of the transaction and the transaction result in TRON's block structure, respectively. When chain A sends the transaction, it needs to carry the proof of the transaction and the transaction result, and chain B uses the proof to verify the correctness of the transaction sent by chainA.

Fee

Refer to Tip 256

Flowchart

image

Implementation

Cross-chain message format:

message CrossContract {
 bytes owner_address = 1;
 bytes owner_chainId = 2;
 bytes to_address = 3;
 bytes to_chainId = 4;
 bytes data = 5;
 CrossDataType type = 6;
 enum CrossDataType {
   TOKEN = 0;
   CONTRACT = 1;
 }
}

CrossDataType is used to differentiate message types. data field uses byte array to make all types of transactions more compatible. For contracts, the format of the data field is:

message ContractTrigger {
 TriggerSmartContract source = 2;
 TriggerSmartContract dest = 3;
}

Users need to generate two transactions to create a CrossContract message. While creating the dest transaction, users need to set the owner of the contract as the proxy address and skip signature, as the proxy is an address without a private key and is unable to sign a transaction. At the same time, parameters of both the source and dest need to be consistent. After successfully creating the transaction, users broadcast it. Upon receiving the transaction, Chain A executes it in the routine transaction logic (this step is skipped as this is cross-chain contract transaction), then parses and splits the source and dest transactions through preProcessTransaction:

if (crossContract.getType() == CrossDataType.CONTRACT) {
    1. parse source and dest contract
    2. check the source contract data is equal to the dest 
    3. check the proxy account is right
    4. set the `crossTriggerTx` = source when crossContract on the source chain and set to dest on the dest chain
    5. complete the metadata of the crossTriggerTx
    6. process the crossTriggerTx
    7. set the result of crossTriggerTx to the original cross contract 
    8. send the cross contract to the dest if on the source chain, or send the ACK to the source
}

Transaction processing

if (isCrossChainTx) {
    1. skip validate Tapos
    2. skip common logic validate
    3. skip validate signature
}

The following conditions must be met while users are creating a cross-chain contract transaction: The data field for the source contract should be fully consistent with that of the dest contract, including the functions and parameters.
The first parameter should be the contract address of the source chain. Set the owner of the dest contract as the proxy address, which can be obtained from the registered metadata on the parachain.
demo:

bytes _data;   // the contract data

contract source {
  data = _data;
}

contract dest {
  owner_address = proxy;
  data = _data;
  ...
}

Because the cross-chain contract call splits the transaction and executing it separately, if it is processed according to the normal process, the transaction database will store 3 transactions: one cross-chain transaction and two contract calls. However, the cross-chain transaction has already includes these two contract transactions, and when using the transactionStore to replay the blockchain, the extra transactions will be replay twice. Therefore the two internal contract don't need to be stored.

function processTransaction(final TransactionCapsule trxCap, BlockCapsule blockCap, boolean save) {
  ...
  if (save) {
     // put this transaction into transactionStore
  }
  ....
}

the above logic is: If the transaction is not an internal transaction in a cross-chain contract, the transaction is stored in the transactionStore, otherwise skipped.

cest-bon-bon commented 3 years ago

To ensure that only cross-chain transactions can call the cross-chain contract on Chain B, when constructing a cross-chain transaction on Chain A, the transaction owner that is going to trigger the Chain B contract should be set to a proxy address (which is registered in the metadata of the chain through cross-chain slot auction).

I got a question regarding the proxy address, as you mentioned it is set during the slot auction, here comes the questions.

  1. Can the proxy address changed in the next round of Auction?
  2. In Chain B, are the proxy address allowed to trigger all the contracts? or only limited smart contracts?
tomatoishealthy commented 3 years ago

To ensure that only cross-chain transactions can call the cross-chain contract on Chain B, when constructing a cross-chain transaction on Chain A, the transaction owner that is going to trigger the Chain B contract should be set to a proxy address (which is registered in the metadata of the chain through cross-chain slot auction).

I got a question regarding the proxy address, as you mentioned it is set during the slot auction, here comes the questions.

  1. Can the proxy address changed in the next round of Auction?
  2. In Chain B, are the proxy address allowed to trigger all the contracts? or only limited smart contracts?

Good questions.

  1. For security purposes, the proxy address can't be changed as the cross-contract must check the proxy account whether equal with the owner, if proxy address changed, the check logic can't work well.

  2. Actually, every account can trigger all the contracts, so the same with the proxy address. but as the proxy address don't have a private key, so actually we can't trigger a contract using proxy address because we don't know how to sign this transaction. Only cross-chain transaction will skip the signature validation and trigger the specified contract, and TRON also define that: every cross-contract must implement the check logic to make sure that only the proxy account can trigger their contract to avoid some illegal access.

dancespiele commented 3 years ago

Is it only possible or will be possible to implement cross-chain between native token and TRON-10? not TRON-20? Is not possible cross-chain currently? In case that yes, where can I find the documentation?

tomatoishealthy commented 3 years ago

Is it only possible or will be possible to implement cross-chain between native token and TRON-10? not TRON-20? Is not possible cross-chain currently? In case that yes, where can I find the documentation?

TRON-20 transfer is contained in Cross-Chain Smart Contract. But it is still under design, all docs now are in this TIP, we could discuss here and get a feasible solution.

dancespiele commented 3 years ago

Ok I'm one of the Okcash contributor and we are interesting in implement a cross-chain between $OK native and $OK TRON-20 and I have the next question, How will be possible to pair 1:1 with the $OK TRON-20, I guess we will need to implement a communication between blockchains where both sides knows when someone buy/sell $OK coins in native or TRON-20 token, also for keeping both the same price, right?

tomatoishealthy commented 3 years ago

Ok I'm one of the Okcash contributor and we are interesting in implement a cross-chain between $OK native and $OK TRON-20 and I have the next question, How will be possible to pair 1:1 with the $OK TRON-20, I guess we will need to implement a communication between blockchains where both sides knows when someone buy/sell $OK coins in native or TRON-20 token, also for keeping both the same price, right?

Now we only design the Isomorphic cross-chain, heterogeneous cross-chain is still being explored. If Okcash and TRON are heterogeneous, I think the token can't be transferred for now.

a cross-chain between $OK native and $OK TRON-20

I am not sure what this means, do you want to transfer the OK coin from your chain to TRC20 on TRON? Now isomorphic cross-chain on TRON only supports TRC10 to TRC10, TRC20 TO TRC20, does not support native token to TRC20 token.

dancespiele commented 3 years ago

I guess I'm speaking about heterogeneous cross-chain. If you said that native to TRC20 token is not supported how was possible BTC and TUSD in TRON? if for now is not possible to swap from native to TRC20 token is there any possibility to create a token in TRON and link the price mcap etc... with the native token? I mean for example if change the price of $OK native it changes also in $OK from TRC20 $OK -> 0,06$ $OK = TRC20 -> 0,06$ increase $OK -> 0,07$ = TRC20 -> 0,07$

tomatoishealthy commented 3 years ago

I guess I'm speaking about heterogeneous cross-chain. If you said that native to TRC20 token is not supported how was possible BTC and TUSD in TRON? if for now is not possible to swap from native to TRC20 token is there any possibility to create a token in TRON and link the price mcap etc... with the native token? I mean for example if change the price of $OK native it changes also in $OK from TRC20 $OK -> 0,06$ $OK = TRC20 -> 0,06$ increase $OK -> 0,07$ = TRC20 -> 0,07$

I think we are not talking about the same things, now some cross-chain token transfer designs already exist, like side-chain, stake model... Like what you say, now BTC&ETH can be traded on TRON, actually, they are not really ETH, people stake the ETH in one place(it may be a contract or something else, just make sure that everyone can check and know the corresponding number of BTC&ETH are in there), then people can mint the same amount token on TRON, the token may be named WBTC&WETH which is a TRC20 token, this is how the cross-chain token transfer on TRON for now.

But the premise is you must trust the "place" which was made by some people, not built by the code. Engineers prefer to trust the code. So this TIP only discusses the design of the Isomorphism cross-chain without staking.

I think you should check the detail that how WBTC works on TRON, that may help you.

Meanwhile, the price is decided by the market, you should not worry about the price, leave them to trade freely, the market will choose the reasonable price.