Functions: Utils
There are several helper methods available that abstract Bitcoin internals away in the main function implementation.
sha256d
Bitcoin uses a double SHA256 hash to protect against “length-extension” attacks.
Note
Bitcoin uses little endian representations when sending hashes across the network and for storing values internally. For more details, see the documentation. The output of the SHA256 function is big endian by default.
Function Signature
sha256d(data)
Parameters
data
: bytes encoded input.
Returns
hash
: the double SHA256 hash encodes as a bytes fromdata
.
Function Sequence
Hash
data
with sha256.Hash the result of step 1 with sha256.
Return
hash
.
concatSha256d
A function that computes a parent hash from two child nodes. This function is used in the reconstruction of the Merkle tree.
Function Signature
concatSha256d(left, right)
Parameters
left
: 32 bytes of input data that are added first.right
: 32 bytes of input data that are added second.
Returns
hash
: the double sha256 hash encoded as a bytes fromleft
andright
.
Function Sequence
Concatenate
left
andright
into a 64 bytes.Call the sha256d function to hash the concatenated bytes.
Return
hash
.
nBitsToTarget
This function calculates the PoW difficulty target from a compressed nBits representation. See the Bitcoin documentation for further details. The computation for the difficulty is as follows:
Function Signature
nBitsToTarget(nBits)
Parameters
nBits
: 4 bytes compressed PoW target representation.
Returns
target
: PoW difficulty target computed from nBits.
Function Sequence
Extract the exponent by shifting the
nBits
to the right by 24.Extract the significand by taking the first three bytes of
nBits
.Calculate the
target
via the equation above and using 2 as the base (as we use the U256 type).Return
target
.
checkCorrectTarget
Verifies the currently submitted block header has the correct difficulty target.
Function Signature
checkCorrectTarget(hashPrevBlock, blockHeight, target)
Parameters
hashPrevBlock
: 32 bytes previous block hash (necessary to retrieve previous target).blockHeight
: height of the current block submission.target
: PoW difficulty target computed from nBits.
Returns
True
: if the difficulty target is set correctly.False
: otherwise.
Function Sequence
Retrieve the previous block header with the
hashPrevBlock
from theBlockHeaders
storage and the difficulty target (prevTarget
) of this (previous) block.Check if the
prevTarget
difficulty should be adjusted at thisblockHeight
.If the difficulty should not be adjusted, check if the
target
of the submitted block matches theprevTarget
of the previous block and check thatprevTarget``is not ``0
. Return false if either of these checks fails.The difficulty should be adjusted. Calculate the new expected target by calling the computeNewTarget function and passing the timestamp of the previous block (get using
hashPrevBlock
key inBlockHeaders
), the timestamp of the last re-target (get block hash fromChains
usingblockHeight - 2016
as key, then queryBlockHeaders
) and the target of the previous block (get usinghashPrevBlock
key inBlockHeaders
) as parameters. Check that the new target matches thetarget
of the current block (i.e., the block’s target was set correctly).If the newly calculated target difficulty matches
target
, returnTrue
.Otherwise, return
False
.
computeNewTarget
Computes the new difficulty target based on the given parameters, as implemented in the Bitcoin core client.
Function Signature
computeNewTarget(prevTime, startTime, prevTarget)
Parameters
prevTime
: timestamp of previous block.startTime
: timestamp of last re-target.prevTarget
: PoW difficulty target of the previous block.
Returns
newTarget
: PoW difficulty target of the current block.
Function Sequence
Compute the actual time span between
prevTime
andstartTime
.Compare if the actual time span is smaller than the target interval divided by 4 (default target interval in Bitcoin is two weeks). If true, set the actual time span to the target interval divided by 4.
Compare if the actual time span is greater than the target interval multiplied by 4. If true, set the actual time span to the target interval multiplied by 4.
Calculate the
newTarget
by multiplying the actual time span with theprevTarget
and dividing by the target time span (2 weeks for Bitcoin).If the
newTarget
is greater than the maximum target in Bitcoin, set thenewTarget
to the maximum target (Bitcoin maximum target is \(2^{224}-1\)).Return the
newTarget
.
computeMerkle
The computeMerkle function calculates the root of the Merkle tree of transactions in a Bitcoin block. Further details are included in the Bitcoin developer reference.
Function Signature
computeMerkle(txId, txIndex, merkleProof)
Parameters
txId
: the hash identifier of the transaction.txIndex
: index of transaction in the block’s transaction Merkle tree.merkleProof
: Merkle tree path (concatenated LE sha256 hashes).
Returns
merkleRoot
: the hash of the Merkle root.
Errors
ERR_INVALID_MERKLE_PROOF = "Invalid Merkle Proof structure"
: raise an exception if the Merkle proof is malformed.
Function Sequence
Check if the length of the Merkle proof is 32 bytes long.
If true, only the coinbase transaction is included in the block and the Merkle proof is the
merkleRoot
. Return themerkleRoot
.If false, continue function execution.
Check if the length of the Merkle proof is greater or equal to 64 and if it is a power of 2.
If true, continue function execution.
If false, raise
ERR_INVALID_MERKLE_PROOF
.
Calculate the
merkleRoot
. For each 32 bytes long hash in the Merkle proof:Determine the position of transaction hash (or the last resulting hash) at either
0
or1
.Slice the next 32 bytes from the Merkle proof.
Concatenate the transaction hash (or last resulting hash) with the 32 bytes of the Merkle proof in the right order (depending on the transaction/last calculated hash position).
Calculate the double SHA256 hash of the concatenated input with the concatSha256d function.
Repeat until there are no more hashes in the
merkleProof
.
The last resulting hash from step 3 is the
merkleRoot
. ReturnmerkleRoot
.
Example
Assume we have the following input:
txId:
330dbbc15169c538583073fd0a7708d8de2d3dc155d75b361cbf5c24b73f3586
txIndex:
0
merkleProof:
86353fb7245cbf1c365bd755c13d2dded808770afd73305838c56951c1bb0d33b635f586cf6c4763f3fc98b99daf8ac14ce1146dc775777c2cd2c4290578ef2e
The computeMerkle
function would go past step 1 as our proof is longer than 32 bytes. Next, step 2 would also be passed as the proof length is equal to 64 bytes and a power of 2. Last, we calculate the Merkle root in step 3 as shown below.
calculateDifficulty
Given the target
, calculates the Proof-of-Work difficulty
value, as defined in the Bitcoin wiki.
Function Signature
calculateDifficulty(target)
Parameters
target
: target as specified in a Bitcoin block header.
Returns
difficulty
: difficulty calculated from giventarget
.
Function Sequence
Return
0xffff0000000000000000000000000000000000000000000000000000
(max. possible target, also referred to as “difficulty 1”) divided bytarget
.
getForkIdByBlockHash
Helper function allowing to query the list of tracked forks (Forks
) for the identifier of a fork given its last submitted (“highest”) block hash.
Specification
Function Signature
getForkIdByBlockHash(blockHash)
Parameters
blockHash
: block hash of the last submitted block to a fork.
Returns
forkId
: if there exists a fork withblockHash
as latest submitted block inforkHashes
.ERR_FORK_ID_NOT_FOUND
: otherwise.
Errors
ERR_FORK_ID_NOT_FOUND = Fork ID not found for specified block hash."
: return this error if there exists noforkId
for the givenblockHash
.
Function Sequence
Loop over all entries in
Forks
and check ifforkHashes[forkHashes.length -1] == blockhash
If
True
: return the correspondingforkId
.
Return
ERR_FORK_ID_NOT_FOUND
otherwise.
incrementChainCounter
Increments the current ChainCounter
and returns the new value.
Specification
Function Signature
incrementChainsCounter()
Returns
chainCounter
: the new integer value of theChainCounter
.
Function Sequence
ChainCounter++
Return
ChainCounter