RSK 上的智能合约是否有一种方法可以在不使用预言机的情况下从比特币网络获取链上数据?

Is there a way for smart contract on RSK to fetch on-chain data from Bitcoin network without using oracles?

是否有一种方法可以让 RSK 上的智能合约不依赖于受信任的预言机来获取比特币上的链上数据?

我刚刚找到一个名为 Open Bitcoin blockchain oracle (RSKIP220) 的提案,它将通过 IRIS 升级实施,但找不到任何资源。有人知道我在哪里可以找到它吗?

Blog post mentioning RSKIP220: https://blog.rsk.co/noticia/iris-v3-0-0-is-here-what-you-need-to-know-about-rsk-upcoming-network-upgrade/

RSKIP220 确实已经包含在 RSKj 的 IRIS 3.0.0 版本中, 你可以看到部分实现:

Here in RepositoryBtcBlockStoreWithCache

    public StoredBlock getStoredBlockAtMainChainHeight(int height) throws BlockStoreException {

... 和 here in BridgeMethods

    GET_BTC_BLOCKCHAIN_PARENT_BLOCK_HEADER_BY_HASH(
            CallTransaction.Function.fromSignature(
                    "getBtcBlockchainParentBlockHeaderByHash",
                    new String[]{"bytes32"},
                    new String[]{"bytes"}

请注意,这些方法不会通过特殊的 RPC 或类似的东西暴露在外部。相反,它们可通过预编译函数在 RSK Bridge 上使用。预编译函数是包含在 RSK 节点本身的实现中的函数,但就像它们是智能合约一样公开。

这意味着您可以同时与他们互动

  • 链下,例如在 DApp 中,使用 web3.js、ethers.js 等
  • 在链上,例如在您自己的智能合约中

为此,您可以使用 ABI for the RSK Bridge:

  {
    "name": "getBtcBlockchainParentBlockHeaderByHash",
    "type": "function",
    "constant": true,
    "inputs": [
      {
        "name": "btcBlockHash", 
        "type": "bytes32" 
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes"
      }
    ]
  },

这里是一个工作示例,说明如何使用 Bridge 方法访问比特币块。此代码已在 RSK 测试网中进行测试。

Bridge.sol:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

interface Bridge {
  function getBtcBlockchainBestChainHeight (  ) external view returns ( int );
  function getStateForBtcReleaseClient (  ) external view returns ( bytes memory);
  function getStateForDebugging (  ) external view returns ( bytes memory  );
  function getBtcBlockchainInitialBlockHeight (  ) external view returns ( int );
  function getBtcBlockchainBlockHashAtDepth ( int256 depth ) external view returns ( bytes memory );
  function getBtcTxHashProcessedHeight ( string calldata hash ) external view returns ( int64 );
  function isBtcTxHashAlreadyProcessed ( string calldata hash ) external view returns ( bool );
  function getFederationAddress (  ) external view returns ( string memory );
  function registerBtcTransaction ( bytes calldata atx, int256 height, bytes calldata pmt ) external;
  function addSignature ( bytes calldata pubkey, bytes[] calldata signatures, bytes calldata txhash ) external;
  function receiveHeaders ( bytes[] calldata blocks ) external;
  function receiveHeader ( bytes calldata ablock ) external returns ( int256 );
  function getFederationSize (  ) external view returns ( int256 );
  function getFederationThreshold (  ) external view returns ( int256 );
  function getFederatorPublicKey ( int256 index ) external view returns ( bytes memory);
  function getFederatorPublicKeyOfType ( int256 index, string calldata atype ) external returns ( bytes memory);
  function getFederationCreationTime (  ) external view returns ( int256 );
  function getFederationCreationBlockNumber (  ) external view returns ( int256 );
  function getRetiringFederationAddress (  ) external view returns ( string memory );
  function getRetiringFederationSize (  ) external view returns ( int256 );
  function getRetiringFederationThreshold (  ) external view returns ( int256 );
  function getRetiringFederatorPublicKey ( int256 index ) external view returns ( bytes memory);
  function getRetiringFederatorPublicKeyOfType ( int256 index,string calldata atype ) external view returns ( bytes memory);
  function getRetiringFederationCreationTime (  ) external view returns ( int256 );
  function getRetiringFederationCreationBlockNumber (  ) external view returns ( int256 );
  function createFederation (  ) external returns ( int256 );
  function addFederatorPublicKey ( bytes calldata  key ) external returns ( int256 );
  function addFederatorPublicKeyMultikey ( bytes calldata btcKey, bytes calldata rskKey, bytes calldata mstKey ) external returns ( int256 );
  function commitFederation ( bytes calldata hash ) external returns ( int256 );
  function rollbackFederation (  ) external returns ( int256 );
  function getPendingFederationHash (  ) external view returns ( bytes memory);
  function getPendingFederationSize (  ) external view  returns ( int256 );
  function getPendingFederatorPublicKey ( int256 index ) external view returns ( bytes memory);
  function getPendingFederatorPublicKeyOfType ( int256 index, string calldata atype ) external view returns ( bytes memory);
  function getLockWhitelistSize (  ) external view returns ( int256 );
  function getLockWhitelistAddress ( int256 index ) external view returns ( string memory);
  function getLockWhitelistEntryByAddress ( string calldata aaddress ) external view  returns ( int256 );
  function addLockWhitelistAddress ( string calldata aaddress, int256 maxTransferValue ) external returns ( int256 );
  function addOneOffLockWhitelistAddress ( string calldata aaddress, int256 maxTransferValue ) external returns ( int256 );
  function addUnlimitedLockWhitelistAddress ( string calldata aaddress ) external returns ( int256 ); 
  function removeLockWhitelistAddress ( string calldata aaddress ) external returns ( int256 );
  function setLockWhitelistDisableBlockDelay ( int256 disableDelay ) external returns ( int256 );
  function getFeePerKb (  ) external view returns ( int256 );
  function voteFeePerKbChange ( int256 feePerKb ) external returns ( int256 );
  function updateCollections (  ) external;
  function getMinimumLockTxValue (  ) external view returns ( int256 );
  function getBtcTransactionConfirmations ( bytes32  txHash, bytes32 blockHash, uint256 merkleBranchPath, bytes32[] calldata merkleBranchHashes ) external view returns ( int256 );
  function getLockingCap (  ) external view returns ( int256 );
  function increaseLockingCap ( int256 newLockingCap ) external returns ( bool );
  function registerBtcCoinbaseTransaction ( bytes calldata btcTxSerialized, bytes32 blockHash, bytes calldata pmtSerialized, bytes32 witnessMerkleRoot, bytes32 witnessReservedValue ) external;
  function hasBtcBlockCoinbaseTransactionInformation ( bytes32 blockHash ) external returns ( bool );
  function registerFastBridgeBtcTransaction ( bytes calldata btcTxSerialized, uint256 height, bytes calldata pmtSerialized, bytes32 derivationArgumentsHash, bytes calldata userRefundBtcAddress, address liquidityBridgeContractAddress, bytes calldata liquidityProviderBtcAddress, bool shouldTransferToContract ) external returns ( int256 );
  function getActiveFederationCreationBlockHeight (  ) external view  returns ( uint256 );
  function getBtcBlockchainBestBlockHeader (  ) external view  returns ( bytes memory );
  function getBtcBlockchainBlockHeaderByHash ( bytes32 btcBlockHash ) external view returns ( bytes memory );
  function getBtcBlockchainBlockHeaderByHeight ( uint256 btcBlockHeight ) external view  returns ( bytes memory );
  function getBtcBlockchainParentBlockHeaderByHash ( bytes32 btcBlockHash ) external view  returns ( bytes memory);
}

QueryDemo.sol:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

import "./Bridge.sol";

contract QueryDemo {
    int public bestChainHeight;
    bytes public returned;
    bytes32 public headerHash;
    
    function reverse(uint256 input) internal pure returns (uint256 v) {
        v = input;
    
        // swap bytes
        v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |
            ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
    
        // swap 2-byte long pairs
        v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |
            ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
    
        // swap 4-byte long pairs
        v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) |
            ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
    
        // swap 8-byte long pairs
        v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) |
            ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
    
        // swap 16-byte long pairs
        v = (v >> 128) | (v << 128);
    }

    function clear() public   {
        headerHash =0;
        returned = "";
    } 
    
    function getBridge() private pure returns (Bridge) {
        return Bridge(address(0x01000006));
    }
    
    function getBtcBlockchainBestChainHeight() public {
        bestChainHeight = getBridge().getBtcBlockchainBestChainHeight();
    }
    
    // getBtcBlockchainBlockHashAtDepth:
    // This method throws an OOG because getBtcBlockchainBlockHashAtDepth() cannot be called
    // from a contract. Use getBtcBlockchainBestChainHeigh() and getBtcBlockchainBlockHeaderByHeight()
    // 
    function storeBtcBlockchainBlockHashAtDepth(int256 depth) public  {
      returned  = getBridge().getBtcBlockchainBlockHashAtDepth(depth); 
    }
    
    function getHeaderHash(bytes memory x) private pure returns(bytes32) {
        bytes32 h = sha256(x);
        bytes32 h2 = sha256(abi.encodePacked(h));
        return bytes32(reverse(uint256(h2))); // to show it like Bitcoin does on the debugger 
    }
    
    function computeHeaderHash() private {
        headerHash = getHeaderHash(returned);
    }
    
    function storeBtcBlockchainBestBlockHeader (  ) external {
        returned = getBridge().getBtcBlockchainBestBlockHeader();
        computeHeaderHash();
    }
    
    function getBtcBlockchainBestBlockHeader (  ) external view returns (bytes memory) {
        return getBridge().getBtcBlockchainBestBlockHeader();
   
    }
    
    function storeBtcBlockchainBlockHeaderByHash ( bytes32 btcBlockHash ) external {
        returned = getBridge().getBtcBlockchainBlockHeaderByHash ( btcBlockHash );
        computeHeaderHash();
    }
    
    function getBtcBlockchainBlockHeaderByHash ( bytes32 btcBlockHash ) external view returns (bytes memory) {
        return  getBridge().getBtcBlockchainBlockHeaderByHash ( btcBlockHash );
    }
    
    function storeBtcBlockchainBlockHeaderByHeight ( uint256 btcBlockHeight ) external {
        returned = getBridge().getBtcBlockchainBlockHeaderByHeight (btcBlockHeight);
        computeHeaderHash();
    }
    
    function getBtcBlockchainBlockHeaderByHeight ( uint256 btcBlockHeight ) external view returns(bytes memory ret) {
        return getBridge().getBtcBlockchainBlockHeaderByHeight (btcBlockHeight);
    }
    
    function storeBtcBlockchainParentBlockHeaderByHash ( bytes32 btcBlockHash ) external {
        returned = getBridge().getBtcBlockchainParentBlockHeaderByHash ( btcBlockHash);
        computeHeaderHash();
    }
    
    function getBtcBlockchainParentBlockHeaderByHash ( bytes32 btcBlockHash ) external view returns(bytes memory ret) {
        return  getBridge().getBtcBlockchainParentBlockHeaderByHash ( btcBlockHash);
    }
    
    function testGetParentParentHeader() public view returns(bytes memory ret) {
        bytes memory x = getBridge().getBtcBlockchainBlockHeaderByHeight (2064695);
        bytes32  h =getHeaderHash(x);    
        
        // now the has has been computed. Use the has to get the parent block header
        ret=getBridge().getBtcBlockchainParentBlockHeaderByHash ( h);
    }
    
    function testStoreGetParentHeader() public {
        returned = getBridge().getBtcBlockchainBlockHeaderByHeight (2064695);
        computeHeaderHash();    
        
        // now the has has been computed. Use the has to get the parent block header
        returned = getBridge().getBtcBlockchainParentBlockHeaderByHash ( headerHash);
        computeHeaderHash();
    }
}