智能合约源码解析之Bridge Contract

源代码

算法描述参见我的博客文章- 有效的在基于以太坊EVM的链之间跨链,下面主要分析智能合约代码: 

Bridge.sol

数据结构

Validator的奖励:

reward = base + a*n (n是Header中提议的块数 = end-start)

struct Reward {
    uint256 base;
    uint256 a;
}

Reward reward;
uint256 public maxReward;

Epoch随机数种子

bytes32 public epochSeed = keccak256(block.difficulty + block.number + now);

 筹码/保证金(Stake)

struct Stake {           // Validator预付的保证金金额及validator的地址
    uint256 amount;
    address staker;
}
mapping(address => uint256) stakers;   // Validator Map
Stake[] stakes;                        // 保证金数组
uint256 public stakeSum;               // 保证金总额
address public stakeToken;             // 保证金的币种

全局变量


// 连续块头的默克尔树的根
mapping(address => bytes32[]) roots;

// 每一个桥接链的最后一块的块号
mapping(address => uint256) lastBlock;

// 只有Admin才能创建和建立侧链和主链的映射
// fromChainId => (oldTokenAddr => newTokenAddr)
mapping(address => mapping(address => address)) tokens;Block


// 对一个给定的链,一个特定的EPOCH,记录开始块和终块并提供Headerroot
event RootStorage(address indexed chain, uint256 indexed start,
    uint256 indexed end, bytes32 headerRoot, uint256 i, address proposer);
event Deposit(address indexed user, address indexed toChain,
    address indexed depositToken, address fromChain, uint256 amount);
event Withdraw(address indexed user, address indexed fromChain,
    address indexed withdrawToken, uint256 amount);
event TokenAdded(address indexed fromChain, address indexed origToken,
    address indexed newToken);
event TokenAssociated(address indexed toChain, address indexed fromToken,
    address indexed toToken);

提币

  // Pending withdrawals. The user prepares a withdrawal with tx data and then
  // releases it with a withdraw. It can be overwritten by the user and gets wiped
  // upon withdrawal.
  struct Withdrawal {
    address withdrawToken;          // Token to withdraw (i.e. the one mapped to deposit)
    address fromChain;
    uint256 amount;         // Number of atomic units to withdraw
    bytes32 txRoot;         // Transactions root for the block housing this tx
    bytes32 txHash;         // Hash of this tx
    bytes32 receiptsRoot;   // Receipts root for the block housing this tx
  }
  mapping(address => Withdrawal) pendingWithdrawals;

主要函数

保证金/Stake

stake(uint256 amount)

以特定的币种充值保证金。设置充值币种,充值数额/总额,存入Validator数组

destake(uint256 amount)

撤销保证金。调整充值数额/总额

function proposeRoot(bytes32 headerRoot, address chainId, uint256 end, bytes sigs)

将Headerroot存入roots数组

计算奖励金额并发送

生成EpochSeed=keccak256(block.difficulty + block.number + now);

发送RootStorage Event

记录本Epoch的Last Block

Helper函数

function toBytes(address a) constant returns (bytes b) 

function toBytes(uint256 x) returns (bytes b) 

function encodeAddress(address a) returns(bytes) 


function getStake(address a) public constant returns (uint256) 

function getStakeIndex(address a) public constant returns (uint256) 

function getLastBlock(address fromChain) public constant returns (uint256) 

// 挑选提议者。被挑中的概率取决于保证金额大小
function getProposer() public constant returns (address) 

function getTokenMapping(address chain, address token) public constant returns (address) 

// 取32 bytes强制类型转换成byes32
function getBytes32(uint64 start, bytes data) pure returns (bytes32) 
// 取32 bytes强制类型转换成uint256
function getUint256(uint64 start, bytes data) pure returns (uint256)

// 取8 bytes强制类型转换成uint64
function getUint64(uint64 start, bytes data) pure returns (uint64) 

// 'proof' is a concatenated set of [right][hash], i.e. 33 byte chunks
function merkleProof(bytes32 leaf, bytes32 targetHash, bytes proof) private constant returns (bool) 


// Change the number of validators required to allow a passed header root
function updateValidatorThreshold(uint256 newThreshold) public onlyAdmin()

// The admin can update the reward at any time.
function updateReward(uint256 base, uint256 a, uint256 max) public onlyAdmin() 

// 保证金币种只能在实例初始化的时候设定
function Bridge(address token) 

modifier onlyAdmin() 

部署

参考 这个源代码

client --add http://localhost:7545,0x27fa13e74d1aff21d18119053fbbe1b7e10ba0d0,http://localhost:8545,0xb85cae815b3f05b0c8c8f277312dba1f747d3171
  1. 将2个一模一样的Bridge合约部署到两个基于EVM的链上。(一个称为主链,一个为侧链)
  2. 参与者通过调用Bridge.stake()预缴保证金(stake),进入Proposer候补池
  3. 每当数据送到了Bridge contract,就依据保证金大小,选择一个新的Proposer
  4. 这个Proposer聆听侧链的消息,收集块头。

猜你喜欢

转载自my.oschina.net/gavinzheng731/blog/1798721
今日推荐