Search code examples
javascriptsoliditybitcoinrsk

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


Is there a way for smart contract on RSK to fetch on-chain data on Bitcoin not depending on trusted oracles?

I just found a proposal called Open Bitcoin blockchain oracle (RSKIP220) which will be implemented from the IRIS upgrade but couldn't find any resources on it. Does anybody know where I can find it?

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/


Solution

  • Here is a working example of how to use Bridge methods to access Bitcoin blocks. This code has been tested in RSK Testnet.

    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();
        }
    }