BSV
$53.75
Vol 37.71m
-6.73%
BTC
$96316
Vol 39918.75m
-2.68%
BCH
$452.48
Vol 395.58m
-3.92%
LTC
$100.58
Vol 914.17m
-3.65%
DOGE
$0.31
Vol 5958.21m
-8.82%
Getting your Trinity Audio player ready...

This post was first published on Medium.

Smart contracts have no knowledge of the outside world and have to rely on oracles to import external data in general. We have shown two ways to import data from oracles before, based on Rabin signature and ECDSA. In this article, we show it is possible to access a specific type of external data, i.e., data on the blockchain (such as block headers and transactions), in the absence of oracles, while still maintaining data integrity. By allowing smart contracts to access on-chain data with minimal trust, it opens endless opportunities for all new kinds of smart contracts on Bitcoin.

Access block headers

The Bitcoin blockchain consists of a chain of blocks, as the name suggest. A block has two parts: a block header and transactions.

A block and its header
Caption: A Block and Its Header

A block header contains the metadata of the block, with six fields as shown below.

The bitcoin block header
Caption: The Bitcoin Block Header

It is worth noting that bitcoin headers are part of Bitcoin’s proof-of-work consensus algorithm. More specifically, the hash of a serialized block header should not exceed the difficulty target (i.e., the number of leading zeros). Thanks to trustless nature of proof of work, it is extremely costly to produce a valid block header, especially when the difficulty is high. But it is very easy to check if a given block header is valid. This is exactly how we import a block header into a smart contract shown below, without relying on any oracles.

Caption: Blockchain Contract

isBlockHeaderValid() at Line 22 checks if a block header is valid. bits2Target() at Line 31 calculates the difficulty target from a compact form (a 4-byte field typically referred to as nBits). We simply hash the block header at Line 23 and make sure it meets the difficulty target at Line 27.

Fake block headers

We also check the difficulty target is no larger than the blockchainTarget parameter at Line 27, to control the difficulty of producing a fake block header. Otherwise, an attacker can easily create a block header, whose hash meets the target of difficulty within (e.g., only has 2 leading zeros). As with many other aspects of Bitcoin such as 0-conf, the security of importing block headers this way is economic, not merely technical. This means in practice, it is imperative that a smart contract relying on a real block header should not lock more coins than it costs to produce a fake header.

Access transactions

Once a block header is available, we can easily access any transaction in the block. This is because the block header contains the root of the Merkle tree of all the transactions. Similar to SPV, we pass the transaction and its Merkle path into a smart contract and verify it matches the root hash in the block header. txInBlock() at Line 17 demonstrates this.

A Merkle Tree and Merkle Proof
Caption: A Merkle Tree and Merkle Proof

A Case Study: Using blockchain to generate random numbers

In general, it is considered a hard problem to generate pseudo-random numbers in a blockchain securely and fairly, since the blockchain is both deterministic and transparent. We leverage blockchain data, specifically the nonce field of a block header, as the source of entropy.

Alice and Bob both lock same amount of bitcoins into the following contract. Once the transaction containing the contract is broadcasted, it will be mined into a future block. Depending on the nonce of the block, which is hard to predict and can be regarded as random, a winner is determined and takes all locked bitcoins.

BlochainPRNG image
Caption: BlockchainPRNG Contract

Line 17 and 20 use the OP_PUSH_TX technique to get the txid of the transaction containing the contract. Line 23 verifies the block header is legitimate and Line 26 verifies the previous transaction is in it. If the nonce field is odd, Alice wins; otherwise, Bob wins.

Summary

We have shown how to access blockchain data in Bitcoin smart contracts with minimal trust. Since a serialized bitcoin header is only 80-bytes long and Merkle proof scales logarithmically, this technique is extremely efficient (same as SPV).

We have also shown an example to use the blockchain data to generate pseudo-random numbers. This is only the beginning of what is possible, which we will explore in future posts. Stay tuned.

Update

There are other ways of changing block hash, besides manipulating nonce. That is, a miner can set the nonce to a given value (e.g., odd in the PRNG contract) and change extraNonce or timestamp till block hash reaches target. The miner can thus manipulate the result without losing successfully found blocks, at no extra cost. Use block hash, instead of nonce, if minimizing the risk of miner collusion is desired.

Acknowledgements

This work is inspired by the work of Ying Chen now at Cambridge Cryptographic.

Watch: CoinGeek New York presentation, Smart Contracts & Computation on Bitcoin

Recommended for you

Google unveils ‘Willow’; Bernstein downplays quantum threat to Bitcoin
Google claims that Willow can eliminate common errors associated with quantum computing, while Bernstein analysts noted that Willow’s 105 qubits...
December 18, 2024
WhatsOnChain adds support for 1Sat Ordinals with new API set
WhatsOnChain now supports the 1Sat Ordinals with a set of APIs in beta testing; with this new development, developers can...
December 13, 2024
Advertisement
Advertisement
Advertisement