Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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/

like image 617
Jack Avatar asked Aug 13 '21 13:08

Jack


People also ask

Is RSK EVM compatible?

RSK currently supports all the opcodes and precompiles contracts of Ethereum, and therefore it can support any language that compiles to the EVM. This includes Solidity, Julia, and new or experimental programming languages such as Vyper.

What is RSK smart Bitcoin?

RSK is an open-source sidechain platform that hosts smart contracts. Smart contracts execute the terms of agreements between two parties without an intermediary. A side chain that runs smart contracts is essential in cryptocurrency due to the high costs and sluggishness of confirming Bitcoin transactions.

What is bitcoin on RSK?

Bitcoin on RSK is the token used to pay for the execution of transactions in RSK. You can the faucet in Testnet, or exchanges in Mainnet.

How do smart contracts store data in blockchain?

1) Smart-contract stores data in a block of blockchain if that data (variable) was declared as "storage". 2) I think smart contract finds the latest value by seeking for address of that variable and fetch it 3) -

How to build your own RSK platform?

RSK is an open-source platform for Ethereum compatible smart contracts based on the Bitcoin network. Below is a summary of the steps to be taken to build our front end: Create, compile and deploy a smart contract on RSK Testnet using Remix; Interact with the smart contract. Steps 1 to 4 are explained in detail in the tutorial link below:

How to copy the address of a smart contract in remix?

When a smart contract is deployed with Remix, we can see it in the left panel under deploy and run transactions. Click on the copy button at the right side of the smart contract to copy the address of the smart contract. We will need it for use on the front end.


2 Answers

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();
    }
}
like image 153
Sergio Lerner Avatar answered Oct 03 '22 07:10

Sergio Lerner


RSKIP220 has indeed been been included in the IRIS 3.0.0 release of RSKj, and you can see part of the implementation:

Here in RepositoryBtcBlockStoreWithCache

    public StoredBlock getStoredBlockAtMainChainHeight(int height) throws BlockStoreException {

... and here in BridgeMethods

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

Note that these methods are not exposed externally through a special RPC or something similar to that. Instead they are available on the RSK Bridge, via precompiled functions. Precompiled functions are functions that are included within the implementation of the RSK node itself, but exposed as if they were a smart contract.

This means that you can interact with them both

  • off-chain, for example in a DApp, using web3.js, ethers.js, etc
  • on-chain, for example within your own smart contract

To do so, you can use the ABI for the RSK Bridge:

  {
    "name": "getBtcBlockchainParentBlockHeaderByHash",
    "type": "function",
    "constant": true,
    "inputs": [
      {
        "name": "btcBlockHash", 
        "type": "bytes32" 
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "bytes"
      }
    ]
  },
like image 21
bguiz Avatar answered Oct 03 '22 07:10

bguiz