Because smart contracts have no awareness of the outside world, they must depend on oracles to external input data. We’ve previously shown two methods for importing data from Oracles, based on Rabin signature and ECDSA. In this article, we demonstrate that in the absence of oracles, it is feasible to access a particular form of external data, namely data on the blockchain (such as block headers and transactions), while retaining data integrity. It gives up limitless possibilities for all new types of smart contracts on Bitcoin by enabling smart contracts to access on-chain data with minimum trust.
Headers Of Access Blocks
As the name implies, the Bitcoin blockchain comprises a series of blocks. There are two pieces to a partnership: a block header and transactions.
Bitcoin headers are an element of the proof-of-work consensus method used by Bitcoin. The difficulty goal should not exceed a serialized block header (i.e., the number of leading zeros). Producing a valid block header is exceedingly expensive, mainly when the complexity is high, due to the trustless nature of proof of work. It is, however, relatively simple to determine if a particular block header is genuine. This is how we import a block header into a smart contract without using oracles, as illustrated below.
Block Headers That Are Not Real
To manage the difficulty of creating a false block header, we ensure that the difficulty goal is no more significant than the blockchain target parameter at Line 27. Otherwise, an attacker may generate a block header whose hash satisfies the objective of difficulty inside (e.g., only has two leading zeros) (e.g., only has two leading zeros). The security of importing block headers this way is economical, not just technological, as it is with many other features of Bitcoin, such as 0-conf. This implies that, in reality, a smart contract that relies on a genuine block header must not lock more bitcoin than it takes to create a false title.
Blocks in a chain
Is Block Header Valid , as demonstrated below, verifies a chain of blocks rather than a single block, as we did in the last article. At Line 8, we reuse the method isBlockHeaderValid() from the previous code to verify each block. In addition, on Line 12, we hash a block header and compare it to the prevBlockHash field in the following block header on Line 14. In other words, these two blocks are linked.
A Case Study: Block Time Betting
On average, mining a block on Bitcoin takes 10 minutes. Alice and Bob want to gauge how long it will take to mine a particular block. They put some bitcoins into the smart contract that follows in a transaction. The transaction will be drilled into a snag when it has been broadcasted. Alice wins and takes all the money locked up if the block is mined in fewer than 10 minutes; else, Bob wins. The block time1 is calculated as the difference between the block’s timestamp (the 4th field in the header) and its timestamp before it.
A Chain of 3 Blocks
We utilize the OP PUSH TX method to acquire the transaction’s txid containing the betting contract, as we did with the BlockchainPRNG contract from the previous article. Line 20 checks to see whether the chain of block headers is valid, and Line 23 checks to see if the betting transaction is present. The block time is calculated on Line 26 and utilized to select the winner on Line 29.
False blocks should be avoided.
The blockchain target parameter was added in the previous post to regulate the difficulty of an accepted block header. To make it even more difficult to import a false block outside of the Bitcoin public blockchain, we may demand additional blocks stacked on top of a partnership. The more blocks stacked on top of the league, the more costly it is to imitate it. This is comparable to the six confirmations required when purchasing products using Bitcoin. We need to alter N to 7 in the betting contract above to guarantee that the transaction receives six assurances.
Bitcoin block timestamping isn’t exact. Thus it can’t be used to measure time intervals of more than 10 minutes. The betting contract is good as long as it is random and difficult to anticipate since it is based on the unpredictability of block time rather than its accuracy.
Transactions Of Access
We can retrieve any transaction in a block once the block header is provided. The block header includes the Merkle tree’s root for all transactions. We feed the marketing and its Merkle path into a smart contract, much like SPV, and check that they match the root hash in the block header. This is shown in thin block on Line 17.
A case study: generating random numbers using blockchain
Because the blockchain is both predictable and visible, it isn’t easy to create pseudorandom numbers safely and fairly. As a source of entropy, we use blockchain data, notably the nonce field of a block header.
Alice and Bob lock in an equal number of bitcoins in the next contract. The contract will be mined into a future block after the broadcast transaction. A winner is decided based on the nonce of the league, which is difficult to anticipate and may be considered random and takes all locked bitcoins.
The OP PUSH TX method is used on lines 17 and 20 to acquire the txid of the transaction containing the contract. Line 23 checks that the block header is valid, and Line 26 reviews that the prior marketing is present. Alice wins if the nonce field is odd; else, Bob wins.
We’ve shown how to use Bitcoin smart contracts to access blockchain data while maintaining a low level of trust. This approach is incredibly efficient since a serialized bitcoin header is just 80 bytes long, and Merkle proof scales logarithmically (same as SPV).
We’ve also shown how to produce pseudorandom integers using blockchain data. This is only the start of what’s possible, which we’ll go over in more detail in future blogs. Keep an eye out for updates.
Ying Chen, currently at Cambridge Cryptographic, was an inspiration for this project.