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
datawith 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 fromleftandright.
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
nBitsto the right by 24. - Extract the significand by taking the first three bytes of
nBits. - Calculate the
targetvia 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
hashPrevBlockfrom theBlockHeadersstorage and the difficulty target (prevTarget) of this (previous) block.Check if the
prevTargetdifficulty should be adjusted at thisblockHeight.If the difficulty should not be adjusted, check if the
targetof the submitted block matches theprevTargetof 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
hashPrevBlockkey inBlockHeaders), the timestamp of the last re-target (get block hash fromChainsusingblockHeight - 2016as key, then queryBlockHeaders) and the target of the previous block (get usinghashPrevBlockkey inBlockHeaders) as parameters. Check that the new target matches thetargetof the current block (i.e., the block’s target was set correctly).- If the newly calculated target difficulty matches
target, returnTrue. - Otherwise, return
False.
- If the newly calculated target difficulty matches
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
prevTimeandstartTime. - 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
newTargetby multiplying the actual time span with theprevTargetand dividing by the target time span (2 weeks for Bitcoin). - If the
newTargetis greater than the maximum target in Bitcoin, set thenewTargetto 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.
- If true, only the coinbase transaction is included in the block and the Merkle proof is the
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
0or1. - 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.
- Determine the position of transaction hash (or the last resulting hash) at either
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.
An example of the computeMerkle function with a transaction from a block that contains two transactions in total.
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 withblockHashas 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 noforkIdfor the givenblockHash.
Function Sequence¶
Loop over all entries in
Forksand check ifforkHashes[forkHashes.length -1] == blockhash- If
True: return the correspondingforkId.
- If
Return
ERR_FORK_ID_NOT_FOUNDotherwise.