/* @notice This function is meant to be invoked by the user, * a certin amount teokens will be locked in the proxy contract the invoker/msg.sender immediately. * Then the same amount of tokens will be unloked from target chain proxy contract at the target chain with chainId later. * @param fromAssetHash The asset address in current chain, uniformly named as `fromAssetHash` * @param toChainId The target chain id * * @param toAddress The address in bytes format to receive same amount of tokens in target chain * @param amount The amount of tokens to be crossed from ethereum to the chain with chainId */ function lock(address fromAssetHash, uint64 toChainId, bytes memory toAddress, uint256 amount) public payable returns (bool) { require(amount != 0, "amount cannot be zero!"); //将代币合约地址锁到代理合约之中 require(_transferToContract(fromAssetHash, amount), "transfer asset from fromAddress to lock_proxy contract failed!"); bytes memory toAssetHash = assetHashMap[fromAssetHash][toChainId]; require(toAssetHash.length != 0, "empty illegal toAssetHash");
function crossChain(uint64 toChainId, bytes calldata toContract, bytes calldata method, bytes calldata txData) whenNotPaused external returns (bool) { // Only allow whitelist contract to call require(whiteListFromContract[msg.sender],"Invalid from contract"); // Load Ethereum cross chain data contract IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress); // To help differentiate two txs, the ethTxHashIndex is increasing automatically uint256 txHashIndex = eccd.getEthTxHashIndex(); // Convert the uint256 into bytes bytes memory paramTxHash = Utils.uint256ToBytes(txHashIndex); // Construct the makeTxParam, and put the hash info storage, to help provide proof of tx existence bytes memory rawParam = abi.encodePacked(ZeroCopySink.WriteVarBytes(paramTxHash), ZeroCopySink.WriteVarBytes(abi.encodePacked(sha256(abi.encodePacked(address(this), paramTxHash)))), ZeroCopySink.WriteVarBytes(Utils.addressToBytes(msg.sender)), ZeroCopySink.WriteUint64(toChainId), ZeroCopySink.WriteVarBytes(toContract), ZeroCopySink.WriteVarBytes(method), ZeroCopySink.WriteVarBytes(txData) ); // Must save it in the storage to be included in the proof to be verified. require(eccd.putEthTxHash(keccak256(rawParam)), "Save ethTxHash by index to Data contract failed!"); // Fire the cross chain event denoting there is a cross chain request from Ethereum network to other public chains through Poly chain network emit CrossChainEvent(tx.origin, paramTxHash, msg.sender, toChainId, toContract, rawParam); return true; }
height := s.ReadyBlock() for { select { case <-s.Done(): log.Info("Submitter is exiting now", "chain", s.name) returnnil default: }
select { case <-ticker.C: h := s.ReadyBlock() if h > 0 && height != h { height = h log.Info("Current ready block height", "chain", s.name, "height", height) } default: }
tx, block, err := mq.Pop(s.Context) if err != nil { log.Error("Bus pop error", "err", err) continue } if tx == nil { time.Sleep(200 * time.Millisecond) continue }
/* * @param native Native Service that carries values of information of cross-chain events * @param proof The proof submitted by the current cross-chain transaction * @param extra The cross-chain message which is used to construct MakeTxParam * @param fromChainID Source chain id * @param height The block height corresponding to the current transaction event * @param sideChain Source chain information that contains the ccm contract address */ funcverifyFromEthTx(native *native.NativeService, proof, extra []byte, fromChainID uint64, height uint32, sideChain *cmanager.SideChain) (*scom.MakeTxParam, error)
1 2 3 4 5 6
/* * @param ethProof The proof submitted by the current cross-chain transaction * @param blockData The block header stored in poly chain corresponding to the current transaction event * @param contractAddr The ccm contract address */ funcVerifyMerkleProof(ethProof *ETHProof, blockData *eth.Header, contractAddr []byte) ([]byte, error)
// CallContext performs a JSON-RPC call with the given arguments. If the context is // canceled before the call has successfully returned, CallContext returns immediately. // // The result must be a pointer so that package json can unmarshal into it. You // can also pass nil, in which case the result is ignored. func(c *Client) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error {}
/* * @param proof Poly chain transaction Merkle proof * @param rawHeader The header containing crossStateRoot to verify the above tx Merkle proof * @param headerProof The header Merkle proof used to verify rawHeader * @param curRawHeader Any header in current epoch consensus of Poly chain * @param headerSig The converted signature variable for solidity derived from Poly chain consensus nodes' signature * used to verify the validity of curRawHeader * @return true or false */ function verifyHeaderAndExecuteTx(bytes memory proof, bytes memory rawHeader, bytes memory headerProof, bytes memory curRawHeader,bytes memory headerSig) whenNotPaused public returns (bool){ ECCUtils.Header memory header = ECCUtils.deserializeHeader(rawHeader); // Load ehereum cross chain data contract IEthCrossChainData eccd = IEthCrossChainData(EthCrossChainDataAddress);
// Get stored consensus public key bytes of current Poly chain epoch and deserialize Poly chain consensus public key bytes to address[] address[] memory polyChainBKs = ECCUtils.deserializeKeepers(eccd.getCurEpochConPubKeyBytes());
uint n = polyChainBKs.length; if (header.height >= curEpochStartHeight) { // It's enough to verify rawHeader signature require(ECCUtils.verifySig(rawHeader, headerSig, polyChainBKs, n - ( n - 1) / 3), "Verify Poly chain header signature failed!"); } else { // We need to verify the signature of curHeader require(ECCUtils.verifySig(curRawHeader, headerSig, polyChainBKs, n - ( n - 1) / 3), "Verify Poly chain current epoch header signature failed!");
// Then use curHeader.StateRoot and headerProof to verify rawHeader.CrossStateRoot ECCUtils.Header memory curHeader = ECCUtils.deserializeHeader(curRawHeader); bytes memory proveValue = ECCUtils.MerkleProve(headerProof, curHeader.blockRoot); require(ECCUtils.getHeaderHash(rawHeader) == Utils.bytesToBytes32(proveValue), "verify header proof failed!"); }
// Through rawHeader.CrossStatesRoot, the toMerkleValue or cross chain msg can be verified and parsed from proof bytes memory toMerkleValueBs = ECCUtils.MerkleProve(proof, header.crossStatesRoot);
// Parse the toMerkleValue struct and make sure the tx has not been processed, then mark this tx as processed ECCUtils.ToMerkleValue memory toMerkleValue = ECCUtils.deserializeMerkleValue(toMerkleValueBs); require(!eccd.checkIfFromChainTxExist(toMerkleValue.fromChainID, Utils.bytesToBytes32(toMerkleValue.txHash)), "the transaction has been executed!"); require(eccd.markFromChainTxExist(toMerkleValue.fromChainID, Utils.bytesToBytes32(toMerkleValue.txHash)), "Save crosschain tx exist failed!");
// Ethereum ChainId is 2, we need to check the transaction is for Ethereum network require(toMerkleValue.makeTxParam.toChainId == chainId, "This Tx is not aiming at this network!");
// Obtain the target contract, so that Ethereum cross chain manager contract can trigger the executation of cross chain tx on Ethereum side address toContract = Utils.bytesToAddress(toMerkleValue.makeTxParam.toContract);
// only invoke PreWhiteListed Contract and method For Now require(whiteListContractMethodMap[toContract][toMerkleValue.makeTxParam.method],"Invalid to contract or method");
//TODO: check this part to make sure we commit the next line when doing local net UT test require(_executeCrossChainTx(toContract, toMerkleValue.makeTxParam.method, toMerkleValue.makeTxParam.args, toMerkleValue.makeTxParam.fromContract, toMerkleValue.fromChainID), "Execute CrossChain Tx failed!");
// Fire the cross chain event denoting the executation of cross chain tx is successful, // and this tx is coming from other public chains to current Ethereum network emit VerifyHeaderAndExecuteTxEvent(toMerkleValue.fromChainID, toMerkleValue.makeTxParam.toContract, toMerkleValue.txHash, toMerkleValue.makeTxParam.txHash);
return true; }
/* * @notice Dynamically invoke the target contract, trigger execution of cross-chain tx on Ethereum side * @param _toContract the Ethereum Cross Chain Manager contract will invoke the target contract * @param _method At which method will be invoked within the target contract * @param _args The parameter that will be passed into the target contract * @param _fromContractAddr From chain smart contract address * @param _fromChainId Indicate from which chain current cross-chain tx comes * @return true or false */ function _executeCrossChainTx(address _toContract, bytes memory _method, bytes memory _args, bytes memory _fromContractAddr, uint64 _fromChainId) internal returns (bool){ // Ensure the target contract gonna be invoked is indeed a contract rather than a normal account address require(Utils.isContract(_toContract), "The passed in address is not a contract!"); bytes memory returnData; bool success;
// The returnData will be bytes32, the last byte must be 01; (success, returnData) = _toContract.call(abi.encodePacked(bytes4(keccak256(abi.encodePacked(_method, "(bytes,bytes,uint64)"))), abi.encode(_args, _fromContractAddr, _fromChainId)));
// Ensure the executation is successful require(success == true, "EthCrossChain call business contract failed");
// Ensure the returned value is true require(returnData.length != 0, "No return value from business contract!"); (bool res,) = ZeroCopySource.NextBool(returnData, 31); require(res == true, "EthCrossChain call business contract return is not true");