Home

Awesome

bitcoin-block: A Bitcoin block interface for JavaScript

CI

bitcoin-block implements the basic block primitives: BitcoinBlock, BitcoinTransaction, BitcoinTransactionIn, BitcoinTransactionOut and BitcoinOutPoint. These primitives are able to decode raw block binary form and present the same data available via the Bitcoin Core RPC (and via the bitcoin-cli utility) and many online block explorers minus contextual chain data that is not available in individual blocks (e.g. height, confirmations, next block). These primitives can also re-encode binary block form given the minimum required block and data.

Transactions are SegWit-aware and can decode and re-encode both full and no-witness forms and their associated merkle trees: including the standard no-witness transaction merkle tree found in the block header and the full witness transaction data merkle plus the witness confirmation hash.

Top-level primitives also implement a toPorcelain() method that converts the block form to a pure, undecorated JavaScript object that, when passed through JSON.stringify() presents identical data to the Bitcoin Core RPC getblock (i.e. bitcoin-cli getblock ...) interface (minus contextual chain data). The reverse operation is also possible, whereby this JSON form can be re-instantiated into the block primitives and even re-encoded into binary form.

Full compatibility, including round-trip to from binary, to JSON, back to binary form, has been tested across the entire Bitcoin blockchain (to date of writing).

Example

Make your own block explorer from raw block data:

const fs = require('fs')
const {
  BitcoinBlock,
  toHashHex,
  COIN
} = require('./')

// read in hex data from a file, as you get from `bitcoin-cli getblock <hash> 0`
const rawBlockData = Buffer.from(fs.readFileSync(process.argv[2], 'ascii'), 'hex')

const block = BitcoinBlock.decode(rawBlockData)

console.log(`Block: ${toHashHex(block.hash)}
  Previous block: ${toHashHex(block.previousblockhash)}
  Timestamp: ${new Date(block.time * 1000).toUTCString()}
  Difficulty: ${block.difficulty}
  TX merkle root: ${toHashHex(block.merkleroot)}
  Version: ${block.version}
  Bits: ${block.bits}
  Weight: ${block.weight} WU
  Size: ${block.size} bytes
  Nonce: ${block.nonce}
  Transaction volume: ${block.tx.slice(1).reduce((p, c) => p + c.vout.reduce((p, c) => p + c.value, 0), 0) / COIN}
  Block reward: ${block.tx[0].vout[0].value / COIN}
  Transactions ${block.tx.length}:`)
block.tx.slice(1).forEach((tx, i) => {
  tx.vout.forEach((vout, j) => {
    const is = `${i + 1}`
    if (j === 0) {
      console.log(`    #${is} for ${vout.value / COIN} BTC`)
    } else {
      console.log(`     ${''.padStart(is.length, ' ')} and ${vout.value / COIN} BTC`)
    }
  })
})
> node example.js test/fixtures/000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506.hex
Block: 000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506
  Previous block: 000000000002d01c1fccc21636b607dfd930d31d01c3a62104612a1719011250
  Timestamp: Wed, 29 Dec 2010 11:57:43 GMT
  Difficulty: 14484.162361225399
  TX merkle root: f3e94742aca4b5ef85488dc37c06c3282295ffec960994b2c0d5ac2a25a95766
  Version: 1
  Bits: 453281356
  Weight: 3828 WU
  Size: 957 bytes
  Nonce: 274148111
  Transaction volume: 53.01
  Block reward: 50
  Transactions 4:
    #1 for 5.56 BTC
       and 44.44 BTC
    #2 for 0.01 BTC
       and 2.99 BTC
    #3 for 0.01 BTC

Native vs Porcelain APIs: toPorcelain() and fromPorcelain()

BitcoinBlock, BitcoinTransaction, BitcoinTransactionIn and BitcoinTransactionOut each implement a toPorcelain() method. When called, this method will return a plain, undecorated, JavaScript object which contains only the properties that can be found on the Bitcoin RPC (and via bitcoin-cli) in the JSON form of these objects. Performing a JSON.stringify() on these objects would produce the same output provided by the Bitcoin RPC minus certain properties that are only derivable with full chain context.

BitcoinBlock#toPorcelain() on a block that has complete transactions will also call BitcoinTransaction#toPorcelain() on those transactions and present those as well in the returned result. In this way, a JSON.stringify(block.toPorcelain()) can replicate the Bitcoin RPC output when the transactions are present.

All byte arrays are presented as hex strings in the porcelain API. All hashes and merkle roots are presented as hexidecimal big-endian uint256 form, i.e. a reversed 32-byte-array printed in hex. This is where we get the standard leading-zeros bitcoin block addresses (even though the zeros are trailing in serialized form).

Unavailable properties

For blocks, the following properties are not derivable from isolated block data:

Additionally, the difficulty property may different slightly in precision of output but will be the same to two decimal places.

Schema

Using IPlD Schemas we can approximately describe the structure of Bitcoin blocks and transactions in both their native and porcelain forms.

Round-trip conversion

BitcoinBlock, BitcoinTransaction, BitcoinTransactionIn and BitcoinTransactionOut each also implement a fromPorcelain() method which performs the reverse operation by instantiating the native classes from basic plain object representations.

fromPorcelain() should be preferred to using constructors for instantiating these objects in a stand-alone manner (i.e. not from parsing raw block data). This is because fromPorcelain() is also able to reconstruct hashes and identifiers properly from the provided data.

Only the non-redundant parts of a porcelain form of the objects are required to perform this operation. See the API documentation below for details.

API

Contents

<a name="COIN"></a>

COIN

The COIN constant is the number of satoshis in 1 BTC, i.e. 100,000,000. Transaction store values in satoshis so must be divided by COIN to find the amount in BTC.

<a name="HASH_NO_WITNESS"></a>

HASH_NO_WITNESS

HASH_NO_WITNESS is available on BitcoinBlock and BitcoinTransaction and is used as an optional argument to their respective encode() methods to signal that encoded transactions should not include witness data (i.e. their pre SegWit form and the form used to generate the txid and transaction merkle root).

<a name="toHashHex"></a>

toHashHex(hash)

Takes a hash, in byte form, and returns it as a big-endian uint256 in hex encoded form. This format is typically used by Bitcoin in its hash identifiers, particularly its block hashes and transaction identifiers and hashes.

This method simply reverses the bytes and produces a hex string from the resulting bytes.

See fromHashHex for the reverse operation.

Parameters:

Return value (string)

<a name="fromHashHex"></a>

fromHashHex(hashStr)

Takes a string containing a big-endian uint256 in hex encoded form and converts it to a standard byte array.

This method simply reverses the string and produces a Uint8Array from the hex bytes.

See toHashHex for the reverse operation.

Parameters:

Return value (Uint8Array)

<a name="dblSha2256"></a>

dblSha2256(bytes)

Perform a standard Bitcoin double SHA2-256 hash on a binary blob. SHA2-256(SHA2-256(bytes))

Parameters:

Return value (Uint8Array): a 32-byte digest

<a name="merkleRoot"></a>

merkleRoot(hashes)

Generate a merkle root using dblSha2256 on each node. The merkle tree uses Bitcoin's algorithm whereby a level with an odd number of nodes has the last node duplicated.

Parameters:

Return value (Bufer): the merkle root hash

<a name="merkle"></a>

merkle(hashes)

Generate a merkle tree using dblSha2256 on each node. The merkle tree uses Bitcoin's algorithm whereby a level with an odd number of nodes has the last node duplicated.

This generator function will yield { hash, data } elements for each node of the merkle tree where data is a two-element array containing hash Uint8Arrays of the previous level and hash is a Uint8Array containing the hash of those concatenated hashes.

It is possible for a result to not contain a data element if the input hashes array contains only one element, in this case, that single element will be the merkle root and the only result yielded, as { hash }.

The final yielded result is the merkle root.

Parameters:

<a name="BitcoinBlock"></a>

class BitcoinBlock

Properties:

<a name="BitcoinBlock_new"></a>

Constructor: BitcoinBlock()

A class representation of a Bitcoin Block. Parent for all of the data included in the raw block data in addition to some information that can be calculated based on that data. Properties are intended to match the names that are provided by the Bitcoin API (hence the casing and some strange names).

<a name="BitcoinBlock"></a>

class BitcoinBlock

<a name="BitcoinBlock_new"></a>

Constructor: BitcoinBlock(version, previousblockhash, merkleroot, time, bits, nonce[, hash][, tx][, size])

Instantiate a new BitcoinBlock.

See the class properties for expanded information on these parameters. The difficulty property will be calculated from bits. The stripedsize and weight properties will be calculated from the transactions if they are available.

To represent a header only, the hash, tx and size parameters are optional.

Parameters:

<a name="BitcoinBlock_toPorcelain"></a>

BitcoinBlock#toPorcelain()

Convert to a serializable form that has nice stringified hashes and other simplified forms. May be useful for simplified inspection.

The object returned by this method matches the shape of the JSON structure provided by the getblock RPC call of Bitcoin Core minus some chain-contextual fields that are not calculable from isolated block data. Performing a JSON.stringify() on this object will yield the same data as the RPC minus these fields.

See block-porcelain.ipldsch for a description of the layout of the object returned from this method.

Return value (object)

<a name="BitcoinBlock_calculateMerkleRoot"></a>

BitcoinBlock#calculateMerkleRoot(noWitness)

Calculate the merkle root of the transactions in this block. This method should reproduce the native merkleroot field if this block was decoded from raw block data.

This operation can be performed with or without witness data using the noWitness flag parameter. Without witness data will yield the merkleroot, with witness data will yield the witness merkle root which is hashed with the witness nonce (from the single coinbase vin) to produce the witness commitment that is stored in the coinbase (from one of the vouts).

This method assumes this object has transactions attached to it and is not the header data alone.

Parameters:

Return value (Uint8Array): the merkle root

<a name="BitcoinBlock_calculateWitnessCommitment"></a>

BitcoinBlock#calculateWitnessCommitment()

Calculate the witness commitment for this block. Uses the full transaction merkle root (with witness data), appended to the witness nonce (stored in the coinbase vin) and hashed.

This method assumes this object has transactions attached to it and is not the header data alone. It also assumes a valid witness nonce stored in the single element of the scriptWitness in the coinbase's single vin.

Return value (Uint8Array): the witness commitment

<a name="BitcoinBlock_getWitnessCommitment"></a>

BitcoinBlock#getWitnessCommitment()

Get the witness commitment as decoded from the block data. This is a shortcut method that assumes transaction data is associated with this block and reaches into the coinbase and finds the witness commitment within one of the vout elements.

See BitcoinTransaction#getWitnessCommitment()

Return value (Uint8Array): the witness commitment

<a name="BitcoinBlock_getWitnessCommitmentNonce"></a>

BitcoinBlock#getWitnessCommitmentNonce()

Get the witness commitment nonce from the scriptWitness in the coinbase. This is a shortcut that assumes transaction data (with witness data) is associated with this block and reaches into the coinbase to find the nonce in the scriptWitness.

See BitcoinTransaction#getWitnessCommitmentNonce()

Return value (Uint8Array): the witness commitment nonce

<a name="BitcoinBlock_isSegWit"></a>

BitcoinBlock#isSegWit()

Does this block contain SegWit (BIP141) transactions. This method assumes this block has transaction data associated with it as it checks whether those transactions were encoded as SegWit.

Return value (boolean)

<a name="BitcoinBlock_encode"></a>

BitcoinBlock#encode(args)

Encode this block into its raw binary form. Assuming you have the complete block data in this instantiated form.

It is possible to perform a decode().encode() round-trip for any given valid block data and produce the same binary output.

Parameters:

Return value (Uint8Array)

<a name="BitcoinBlock__HASH_NO_WITNESS"></a>

BitcoinBlock.HASH_NO_WITNESS

Symbol used as a flag for Block#calculateMerkleRoot to calculate the merkle root without transaction witness data included in the transaction hashes.

<a name="BitcoinBlock__fromPorcelain"></a>

BitcoinBlock.fromPorcelain(porcelain)

Instantiate a BitcoinBlock from porcelain data. This is the inverse of BitcoinBlock#toPorcelain. It does not require the entirety of the porcelain data as much of it is either duplicate data or derivable from other fields.

If a full tx array is provided on the porcelain object BitcoinTransaction.fromPorcelain is called on each of these in turn to re-instantiate the native transaction array.

Fields required to instantiate a basic header form are:

A tx array indicates that full block data is present and it should attempt to decode the entire structure.

Parameters:

Return value (BitcoinBlock)

<a name="BitcoinBlock__decode"></a>

BitcoinBlock.decode(bytes, strictLengthUsage)

Decode a BitcoinBlock from the raw bytes of the block. Such data in hex form is available directly from the bitcoin cli: bitcoin-cli getblock <hash> 0 (where 0 requests hex form).

Use this if you have the full block hash, otherwise use BitcoinBlock.decodeBlockHeaderOnly to parse just the 80-byte header data.

Parameters:

Return value (BitcoinBlock)

<a name="BitcoinBlock__decodeBlockHeaderOnly"></a>

BitcoinBlock.decodeBlockHeaderOnly(bytes)

Decode only the header section of a BitcoinBlock from the raw bytes of the block. This method will exclude the transactions but will properly present the header data including the correct hash.

To decode the entire block data, use BitcoinBlock.decodeBlock.

This method returns a BitcoinBlockHeaderOnly which is a subclass of BitcoinBlock and may be used as such. Just don't expect it to give you any transaction data beyond the merkle root.

Parameters:

Return value (BitcoinBlock)

<a name="BitcoinTransaction"></a>

class BitcoinTransaction

Properties:

<a name="BitcoinTransaction_new"></a>

Constructor: BitcoinTransaction()

A class representation of a Bitcoin Transaction, multiple of which are contained within each BitcoinBlock.

<a name="BitcoinTransaction"></a>

class BitcoinTransaction

<a name="BitcoinTransaction_new"></a>

Constructor: BitcoinTransaction(version, segWit, vin, vout, lockTime[, rawBytes][, hash][, txid][, sizeNoWitness][, size])

Instantiate a new BitcoinTransaction.

See the class properties for expanded information on these parameters.

Parameters:

<a name="BitcoinTransaction_toPorcelain"></a>

BitcoinTransaction#toPorcelain()

Convert to a serializable form that has nice stringified hashes and other simplified forms. May be useful for simplified inspection.

The object returned by this method matches the shape of the JSON structure provided by the getblock (or gettransaction) RPC call of Bitcoin Core. Performing a JSON.stringify() on this object will yield the same data as the RPC.

See block-porcelain.ipldsch for a description of the layout of the object returned from this method.

Return value (object)

<a name="BitcoinTransaction_getWitnessCommitmentIndex"></a>

BitcoinTransaction#getWitnessCommitmentIndex()

Find the witness commitment index in the vout array. This method should only work on SegWit coinbase transactions. The vout array is scanned and each scriptPubKey field is inspected. If one is 38 bytes long and begins with 0x6a24aa21a9ed, this is the witness commitment vout, and the index of this vout is returned.

Return value (number)

<a name="BitcoinTransaction_getWitnessCommitment"></a>

BitcoinTransaction#getWitnessCommitment()

Get the witness commitment from this transaction. This method should only work on SegWit coinbase transactions. See BitcoinTransaction#getWitnessCommitmentIndex for details on how this is found in the vout array. The leading 6 byte flag is removed from the scriptPubKey of the vout before being returned by this method.

Return value (Uint8Array): the witness commitment

<a name="BitcoinTransaction_getWitnessCommitmentNonce"></a>

BitcoinTransaction#getWitnessCommitmentNonce()

Get the witness commitment nonce from the scriptWitness in this transaction. This method should only work on coinbase transacitons in SegWit blocks where the transaction data we're working with has full witness data attached (i.e. not the trimmed no-witness form) since the nonce is stored in the scrptWitness.

The scriptWitness of a SegWit coinbase contains a stack with a single 32-byte array which is the nonce that combines with the witness merkle root to be hashed together and form the witness commitment.

Return value (Uint8Array): the witness commitment

<a name="BitcoinTransaction_isCoinbase"></a>

BitcoinTransaction#isCoinbase()

Determine if this is the coinbase. This involves checking the vout array, if this array has a single entry and the prevout field is a null hash (0x00*32), this is assumed to be the coinbase.

Return value (boolean)

<a name="BitcoinTransaction_encode"></a>

BitcoinTransaction#encode(args)

Encode this transaction into its raw binary form. Assuming you have the complete transaction data in this instantiated form.

It is possible to perform a decode().encode() round-trip for any given valid transaction data and produce the same binary output.

Parameters:

Return value (Uint8Array)

<a name="BitcoinTransaction__isPorcelainSegWit"></a>

BitcoinTransaction.isPorcelainSegWit(porcelain)

Check if the porcelain form of a transaction is has witness data and is therefore post-SegWit.

Parameters:

Return value (boolean)

<a name="BitcoinTransaction__fromPorcelain"></a>

BitcoinTransaction.fromPorcelain(porcelain)

Instantiate a BitcoinTransaction from porcelain data. This is the inverse of BitcoinTransaction#toPorcelain. It does not require the entirety of the porcelain data as much of it is either duplicate data or derivable from other fields.

This function is normally called from BitcoinBlock.fromPorcelain to instantiate the each element of the tx array.

Fields required to instantiate a transaction are:

Some indication of whether this is a SegWit transaction is also required to properly instantiate a correct BitcoinTransaction. This could be one of:

Parameters:

Return value (BitcoinTransaction)

<a name="BitcoinTransaction__decode"></a>

BitcoinTransaction.decode(bytes, strictLengthUsage)

Decode a BitcoinTransaction from the raw bytes of the transaction. Normally raw transaction data isn't available in detached form, although the hex is available in the JSON output provided by the bitcoin cli attached to each element of the tx array. It may also come from the BitcoinTransaction#encode method.

Parameters:

Return value (BitcoinTransaction)

<a name="BitcoinTransactionIn"></a>

class BitcoinTransactionIn

A class representation of a Bitcoin TransactionIn, multiple of which are contained within each BitcoinTransaction in its vin array.

Properties:

<a name="BitcoinTransactionIn_new"></a>

Constructor: BitcoinTransactionIn(prevout, scriptSig, sequence)

Instantiate a new BitcoinTransactionIn.

See the class properties for expanded information on these parameters.

<a name="BitcoinTransactionIn_toPorcelain"></a>

BitcoinTransactionIn#toPorcelain()

Convert to a serializable form that has nice stringified hashes and other simplified forms. May be useful for simplified inspection.

The object returned by this method matches the shape of the JSON structure provided by the getblock (or gettransaction) RPC call of Bitcoin Core. Performing a JSON.stringify() on this object will yield the same data as the RPC.

See block-porcelain.ipldsch for a description of the layout of the object returned from this method.

Return value (object)

<a name="BitcoinTransactionIn__fromPorcelain"></a>

BitcoinTransactionIn.fromPorcelain(porcelain)

Instantiate a BitcoinTransactionIn from porcelain data. This is the inverse of BitcoinTransactionIn#toPorcelain.

This function is normally called from BitcoinTransaction.fromPorcelain to instantiate the each element of the vin array.

Fields required to instantiate a transaction are:

Then, if this TransactionIn is attached to the coinbase:

Otherwise:

Parameters:

Return value (BitcoinTransactionIn)

<a name="BitcoinTransactionOut"></a>

class BitcoinTransactionOut

A class representation of a Bitcoin TransactionOut, multiple of which are contained within each BitcoinTransaction in its vout array.

Properties:

<a name="BitcoinTransactionOut_new"></a>

Constructor: BitcoinTransactionOut(value, scriptPubKey)

Instantiate a new BitcoinTransactionOut.

See the class properties for expanded information on these parameters.

<a name="BitcoinTransactionOut_toPorcelain"></a>

BitcoinTransactionOut#toPorcelain()

Convert to a serializable form that has nice stringified hashes and other simplified forms. May be useful for simplified inspection.

The object returned by this method matches the shape of the JSON structure provided by the getblock (or gettransaction) RPC call of Bitcoin Core. Performing a JSON.stringify() on this object will yield the same data as the RPC.

See block-porcelain.ipldsch for a description of the layout of the object returned from this method.

Return value (object)

<a name="BitcoinTransactionOut__fromPorcelain"></a>

BitcoinTransactionOut.fromPorcelain(porcelain)

Instantiate a BitcoinTransactionIn from porcelain data. This is the inverse of BitcoinTransactionOut#toPorcelain.

This function is normally called from BitcoinTransaction.fromPorcelain to instantiate the each element of the vin array.

Fields required to instantiate a transaction are:

Parameters:

Return value (BitcoinTransactionOut)

License and Copyright

Copyright 2020 Rod Vagg

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.