rskip | title | description | status | purpose | author | layer | complexity | created |
---|---|---|---|---|---|---|---|---|
119 |
Precompiled contract for inspecting block headers |
Draft |
Usa |
DM (@diego) |
Core |
1 |
2019-04-01 |
RSKIP | 119 |
---|---|
Title | Precompiled contract for inspecting block headers |
Created | 01-APR-19 |
Author | DM |
Purpose | Usa |
Layer | Core |
Complexity | 1 |
Status | Draft |
A new precompiled contract (i.e., native, hardwired onto the RSK consensus layer) is introduced. This contract contains operations to allow inspection of several block header fields that can be useful for smart contract developers.
Exploring the headers of specific blocks from solidity code (or assembly WOLOG) executing on the RVM could be too expensive. Doing this directly in solidity would require to write it and test it multiple times. Furthermore, different implementations can lead to errors potentially protruding to loss of funds. A well-written, tested and precompiled function set of operations to access the block header fields will tackle these problems while at the same time it will enforce certain level of security by implementing these as part of the RSK consensus.
A new precompiled contract will be accessible at the 0x0000000000000000000000000000000001000010
address. It will implement the following functions (signatures and return values are as follows):
getBitcoinHeader(uint256 blockDepth) returns (bytes)
getBlockHash(uint256 blockDepth) returns (bytes)
getCoinbaseAddress(uint256 blockDepth) returns (bytes)
getGasLimit(uint256 blockDepth) returns (bytes)
getGasUsed(uint256 blockDepth) returns (bytes)
getMergedMiningTags(uint256 blockDepth) returns (bytes)
getMinGasPrice(uint256 blockDepth) returns (bytes)
getRSKDifficulty(uint256 blockDepth) returns (bytes)
getUncleCoinbaseAddress(uint256 blockDepth, uint256 uncleIndex) returns (bytes)
There is a limitation on how deep the block to inspect can be from the executing block. It is possible to recover fields of the past 4000 blocks, meaning that the blockDepth must be a value between 0 and 3999 inclusive, where blockDepth 0 references the parent block of the executing block, blockDepth 1 references the grandparent of the executing block and so on. If there is no block at the specified depth, an empty byte array is returned.
In case of error, each of these methods behaves as if a solidity assert
statement was being used. That is, contract state is reverted and all the gas is consumed.
The method getBitcoinHeader(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the associated Bitcoin merged mining header.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the Bitcoin merged mining header for the parent block of the executing block.
getBitcoinHeader(0)
We want to recover the Bitcoin merged mining header for the 2500th block starting at the executing block.
getBitcoinHeader(2500)
We try to recover the Bitcoin merged mining header for a block beyond the 4000 depth limit. An empty byte array is returned.
getBitcoinHeader(5000) => []
We try to recover the Bitcoin merged mining header for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getBitcoinHeader(3500) => []
The method getBlockHash(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the block hash.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the block hash for the parent block of the executing block.
getBlockHash(0)
We want to recover the block hash for the 2500th block starting at the executing block.
getBlockHash(2500)
We try to recover the block hash for a block beyond the 4000 depth limit. An empty byte array is returned.
getBlockHash(5000) => []
We try to recover the block hash for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getBlockHash(3500) => []
The method getCoinbaseAddress(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the block's coinbase address.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the coinbase address for the parent block of the executing block.
getCoinbaseAddress(0)
We want to recover the coinbase address for the 2500th block starting at the executing block.
getCoinbaseAddress(2500)
We try to recover the coinbase address for a block beyond the 4000 depth limit. An empty byte array is returned.
getCoinbaseAddress(5000) => []
We try to recover the coinbase address for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getCoinbaseAddress(3500) => []
The method getGasLimit(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the block's gas limit.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the gas limit for the parent block of the executing block.
getGasLimit(0)
We want to recover the gas limit for the 2500th block starting at the executing block.
getGasLimit(2500)
We try to recover the gas limit for a block beyond the 4000 depth limit. An empty byte array is returned.
getGasLimit(5000) => []
We try to recover the gas limit for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getGasLimit(3500) => []
The method getGasUsed(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the block's gas used.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the gas used by the parent block of the executing block.
getGasUsed(0)
We want to recover the gas used by the 2500th block starting at the executing block.
getGasUsed(2500)
We try to recover the gas used by a block beyond the 4000 depth limit. An empty byte array is returned.
getGasUsed(5000) => []
We try to recover the gas used by a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getGasUsed(3500) => []
The method getMergedMiningTags(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the block's merged mining tags.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the merged mining tags for the parent block of the executing block.
getMergedMiningTags(0)
We want to recover the merged mining tags for the 2500th block starting at the executing block.
getMergedMiningTags(2500)
We try to recover the merged mining tags for a block beyond the 4000 depth limit. An empty byte array is returned.
getMergedMiningTags(5000) => []
We try to recover the merged mining tags for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getMergedMiningTags(3500) => []
The method getMinGasPrice(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the minimum gas price.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the minimum gas price for the parent block of the executing block.
getMinGasPrice(0)
We want to recover the minimum gas price for the 2500th block starting at the executing block.
getMinGasPrice(2500)
We try to recover the minimum gas price for a block beyond the 4000 depth limit. An empty byte array is returned.
getMinGasPrice(5000) => []
We try to recover the minimum gas price for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getMinGasPrice(3500) => []
The method getRSKDifficulty(uint256 blockDepth) returns (bytes)
takes as input the depth of the block to query block header fields from and returns a byte array representation of the block's RSK difficulty.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the RSK's difficulty for the parent block of the executing block.
getRSKDifficulty(0)
We want to recover the RSK's difficulty for the 2500th block starting at the executing block.
getRSKDifficulty(2500)
We try to recover the RSK's difficulty for a block beyond the 4000 depth limit. An empty byte array is returned.
getRSKDifficulty(5000) => []
We try to recover the RSK's difficulty for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getRSKDifficulty(3500) => []
The method getUncleCoinbaseAddress(uint256 blockDepth, uint256 uncleIndex) returns (bytes)
takes as input the depth of the block to query block header fields from, the index of the uncle to query for and returns a byte array representation of the coinbase address for the indexed uncle.
blockDepth
must be an unsigned value ranging from 0 to 3999.
This method has a fixed cost of 1,000 gas units. On top of that, normal transaction gas costs apply.
We want to recover the coinbase address of the first uncle of the executing block's parent block.
getUncleCoinbaseAddress(0, 0)
We want to recover the coinbase address of the third uncle of the 2500th block starting at the executing block.
getUncleCoinbaseAddress(2500, 2)
We want to recover the coinbase address of the an unexistent uncle of the 2500th block starting at the executing block. An empty byte array is returned.
getUncleCoinbaseAddress(2500, 12) => []
We try to recover the coinbase address of an uncle for a block beyond the 4000 depth limit. An empty byte array is returned.
getUncleCoinbaseAddress(5000, 0) => []
We try to recover the coinbase address of an uncle for a block that is not beyond the 4000 depth limit but still does not exist. An empty byte array is returned.
getUncleCoinbaseAddress(3500, 0) => []
TODO (if any)
Copyright and related rights waived via CC0.