chainside / btcnodejs

A Nodejs SegWit-compliant library which provides tools to handle Bitcoin data structures in a simple fashion.
https://www.chainside.net
GNU Lesser General Public License v3.0
37 stars 13 forks source link
bitcoin javascript nodejs

chainside

developed with :heart: by chainside

btcnodejs

btcnodejs is a Segwit-compliant bitcoin library which provides tools for managing bitcoin data structures. It is the NodeJS version of btcpy.

This library is a work in progress and its usage in a production environment is highly discouraged. Also, as long as the version is 0.*, API breaking changes might occur

Some of the functionalities are a wrapping around bitcoinjs-lib, and their development is still in progress.

It makes usage of bytebuffer.js for representing most of the data structures

Table of Contents

Installation

To install the library, run npm install btcnodejs

Browserify

This library can be used in the browser with browserify. If you are familiar with browserify, you can skip this.

Assuming the entry point of the project is a file main.js like:

const btcnodejs = require("btcnodejs");
const net = btcnodejs.network;
net.setup("testnet");
var k = new btcnodejs.HDPrivateKey();
console.log(k.privkey.toWIF());

Go into the main.js folder and run:

browserify main.js > browser_main.js

Now you can load the 'browserified' main.js into your html:

<!DOCTYPE html>
<html>
  <head>
    <title>Example Browserify</title>
    </head>
  <body>
      <script src="https://github.com/chainside/btcnodejs/raw/master/browser_main.js"></script>
  </body>
</html>

What it does

This library aims to manage bitcoin data structures. It offers functionalities for

What it does not do

This library does not implement the following functionalities:

Tests

In order to run tests, cd in the package directory and run

npm test

To run tests in the browser, you first need brfs installed. Then you can run browserify on the tests file, by doing (within the package directory):

browserify -t brfs test/test.js > test/browser_tests.js

Now you can create the .html file with the test script:

<!DOCTYPE html>
<html>
  <head>
    <title>Mocha Tests</title>
    <link rel="stylesheet" href="https://github.com/chainside/btcnodejs/blob/master/node_modules/mocha/mocha.css">
  </head>
  <body>
    <div id="mocha"></div>
    <script src="https://github.com/chainside/btcnodejs/raw/master/node_modules/mocha/mocha.js"></script>

    <script>mocha.setup('bdd')</script>
    <script src="https://github.com/chainside/btcnodejs/raw/master/test/browser_tests.js"></script>
    <script>
    mocha.run();
    </script>
  </body>
</html>

Usage

On the first import, network setup must be executed. This is achieved by doing:

const network = require('btcnodejs').network
network.setup('testnet') //network can be either 'testnet' or 'mainnet'

Once the network setup is executed, every subsequent setup will throw an exception.

The network module also exposes functionalities to get the current setup network

 const network = require('btcnodejs').network
 network.setup('testnet')
 network.net_name()               //outputs 'testnet'
 network.is_mainnet()             //returns 'false'

API

Transactions

btcnodejs.Transaction

Transactions are immutable objects representing bitcoin transactions.

Attributes

new Transaction(version, inputs, outputs, locktime, segwit=false)

toJSON()

Returns the JSON representation of the transaction

hash()

Computes the double sha256 on the serialized transaction. Returns the hex string representing the hash

segwitId()

Computes the txid of a segwit transaction Returns the hex string representing the id of the transaction.

static fromHex(hex)

Returns a Transaction object

const btcnodejs = require('btcnodejs')
const Transaction = btcnodejs.Transaction
btcnodejs.network.setup('testnet')

const tx = Transaction.fromHex("0100000001e4da173fbefe5e60ff63dfd38566ade407532294db655463b77a783f379ce605000000006b4" +
                               "83045022100af246c27890c2bc07a0b7450d3d82509702a44a4defdff766355240b114ee2ac02207bb67b" +
                               "468452fa1b325dd5583879f5c1412e0bb4dae1c2c96c7a408796ab76f1012102ab9e8575536a1e99604a1" +
                               "58fc60fe2ebd1cb1839e919b4ca42b8d050cfad71b2ffffffff0100c2eb0b000000001976a914df76c017" +
                               "354ac39bde796abe4294d31de8b5788a88ac00000000")

console.log(tx.txid)           //'e977c07090c2a1dcaefd3f3c4ebf4e231f4116cb272f805b0b22a85e7eece09c'

toHex()

Returns the hexadecimal representation of the transactions

serialize(segwit = this.segwit)

Returns a ByteBuffer containing the serialized transaction. If called with no parameter, the serialization is performed based on the transaction type. To perform a non-segwit serialization of a segwit transaction(i.e. to compute the segwit txid), false can be passed to the function.

static deserialize(bytebuffer)

Returns a Transaction object from a ByteBuffer object representing the serialized transaction

toMutable()

Returns a MutableTransaction object

btcnodejs.MutableTransaction

Mutable Transaction objects

Attributes

new MutableTransaction(version, inputs, outputs, locktime, segwit=false)

Returns a MutableTransaction object

toImmutable()

Returns an immutable Transaction object

spend(txouts, solvers)

Returns a Transaction object where the scriptSigs of its inputs are computed.

const btcnodejs = require('./lib/index')
btcnodejs.network.setup(network)
var t = new btcnodejs.Transaction(...)
var tospend = btcnodejs.Transaction.fromHex('...')
var key = btcnodejs.Privatekey.fromWIF(wif_key)
var solver = new btcnodejs.P2pkhSolver(key)
var unsigned = t.toMutable()
var spent = unsigned.spend([tospend.outputs[1]], [solver])

btcnodejs.Sighash

Sighash object

Attributes

new Sighash(sighash, anyonecanpay = false)

Returns a Sighash object

btcnodejs.Input

Transaction Input object

Attributes

new Input(txid, out, scriptSig, sequence, witness = undefined)

Returns an Input object

toJSON()

Returns the JSON representation of the Input

btcnodejs.Output

Transaction Output object

Attributes

new Output(amount, scriptPubKey)

Returns an Output object

toJSON()

Returns the JSON representation of the Output

btcnodejs.Witness

Input Witness Object

Attributes

new Witness(data)

Returns a Witness Object where data represents the required data to sign a transaction Input

serialize()

Returns a ByteBuffer representing the Witness serialization as it appears in a bitcoin transaction

toScriptSig()

Returns a ScriptSig object

toHex()

Returns the hexadecimal representation of the Witness object

static fromHexArray([hex_wit_sig, hex_wit_pk])

Returns a Witness object from an array of hexadecimal strings representing the siganture and the public key

btcnodejs.Sequence

Sequence object representing the sequence number of a transaction Input

Attributes

new Sequence(n)

Returns a Sequence object

isTime()

Returns a Boolean which tells if the Sequence is measured in time

isBlocks()

Returns a Boolean which tells if the Sequence is measured in blocks

isActive()

Returns a Boolean which tells if a Sequence restriction is active

btcnodejs.Locktime

Locktime object representing the locktime on a transaction

Attributes

new Locktime(n)

Returns a Locktime object

isTime()

Returns a Boolean which tells if the Locktime is measured in time

isBlocks()

Returns a Boolean which tells if the Locktime is measured in blocks

isActive()

Returns a Boolean which tells if a Locktime restriction is active

Scripts

btcnodejs.Script

Base Script object representing a general script as a ByteBuffer. Every Script class extends Script.

Attributes

new Script(body)

Returns a Script object initialized from a bytebuffer representing the script

serialize()

Returns the body of the script_code

btcnodejs.ScriptSig

ScriptSig object

toAsm()

Returns a string representing the ASM of the script

static fromAsm(asm)

Returns a ScriptSig from an ASM string

toHex()

Returns the hexadecimal representation of the ScriptSig

static fromHex(hex)

Returns a ScriptSig object from an hexadecimal string representing the body of the script

toWitness()

Returns a Witness object where its data is retrieved from the ScriptSig body removing the push operations

const btcnodejs = require('btcnodejs')
const ScriptSig = btcnodejs.ScriptSig
btcnodejs.network.setup('testnet')

const sig = ScriptSig.fromHex("483045022100b7bf286e5f6ac6fa308e8876a8a59b289094851a26cf62c20abd174917eb7762022069b5269e584e4c7" +
                              "6f207d1b789bff7171a663d795e49751c12cf07dceb2a94c70121024a0dcb0527c2751ea4dda3aa98f6eface16e978d" +
                              "ba8062bcbed623f158c07691")

sig.toWitness().toHex()                           
// "02483045022100b7bf286e5f6ac6fa308e8876a8a59b289094851a26cf62c20abd174917eb7762022069b5269e584e4c76f207d1b789bff7171a663d795e49751c12c    f07dceb2a94c70121024a0dcb0527c2751ea4dda3aa98f6eface16e978dba8062bcbed623f158c07691"

btcnodejs.ScriptPubKey

ScriptPubkey object representing a general script pubkey. It extends Script and is extended by specific ScriptPubkey types.

toHex()

Returns the hexadecimal representation of the ScriptPubKey

static fromHex(hex)

Returns a ScriptPubKey object from an hexadecimal string representing the body of the script. If the hex is representing an identifiable script, the fromHex() will return an instance of the specific ScriptPubKey. At the moment, identifiables scripts are P2pkh, P2sh, P2wpkhV0, P2wshV0, MultiSig

const btcnodejs = require('btcnodejs')
const ScriptPubKey = btcnodejs.ScriptPubKey
btcnodejs.network.setup('testnet')

const spk = ScriptPubKey.fromHex('76a9148b4912ec0496b5f759f3af5ab24d6f4779a52f9e88ac')
spk instanceof btcnodejs.P2pkhScript         //true                             

toAddress(network = undefined, segwitV = undefined)

Returns the p2sh/p2wsh address of the Script.

const btcnodejs = require('btcnodejs')
const ScriptPubKey = btcnodejs.ScriptPubKey
btcnodejs.network.setup('testnet')

const spk = ScriptPubKey.fromHex('76a9148b4912ec0496b5f759f3af5ab24d6f4779a52f9e88ac')
const p2pkh_address = spk.toAddress()
p2pkh_address.hash          // "029c09b86e1e4c3822bc71859af3300520d577c2"
p2pkh_address.toBase58()    // "2MsV2GNkfjxPjsp9ux2vwxW5HYaZh1HDtXJ

btcnodejs.P2pkhScript

P2pkhScript object

new P2pkhScript(source)

Returns a P2pkhScript object. This can be obtained from an Address, a Publickey or a ByteBuffer representing a pubkeyhash

Attributes

getAddress()

Returns an Address object representing the script Address

btcnodejs.P2wpkhV0Script

Segwit version of P2pkhScript. It has the same interface of P2pkhScript but the source Address must be a Segwit Address object

getScriptCode()

Returns the ScriptCode of the P2wpkhV0Script

btcnodejs.P2shScript

P2shScript object

Attributes

new P2shScript(source)

Returns a P2pkhScript object. This can be obtained from an Address, a ScriptPubKey or a ByteBuffer representing a scripthash

getAddress()

Returns an Address object representing the script Address

btcnodejs.P2wshV0Script

Segwit version of P2shScript. It has the same interface of P2shScript but the source Address must be a Segwit Address object

btcnodejs.IfElseScript

IfElseScript object

new IfElseScript(source)

Attributes

const btcnodejs = require('btcnodejs')
btcnodejs.network.setup('testnet')

const p2pkh = new btcnodejs.P2pkhScript(btcnodejs.Publickey.fromHex("026263992eda6538202047f1514e0f6155a229c3d61b066807664e9ef73d406d95"))
const multisig = new btcnodejs.MultiSigScript([
        2,
        btcnodejs.Publickey.fromHex(
          "02c08786d63f78bd0a6777ffe9c978cf5899756cfc32bfad09a89e211aeb926242"
        ),
        btcnodejs.Publickey.fromHex(
          "033e81519ecf373ea3a5c7e1c051b71a898fb3438c9550e274d980f147eb4d069d"
        ),
        btcnodejs.Publickey.fromHex(
          "036d568125a969dc78b963b494fa7ed5f20ee9c2f2fc2c57f86c5df63089f2ed3a"
        ),
        3
      ])
const ie_script = new btcnodejs.IfElseScript([p2pkh, multisig])

btcnodejs.RelativeTimelockScript

RelativeTimelockScript object

new RelativeTimelockScript(source)

Returns a RelativeTimelockScript object

Attributes

btcnodejs.MultiSigScript

MultisigScript object

new MultiSigScript(source)

Returns a MultiSigScript object

Attributes

const btcnodejs = require('btcnodejs')
btcnodejs.network.setup('testnet')

//Creating a 2-of-3 Multisig Script
const multisig = new btcnodejs.MultiSigScript([
        2,
        btcnodejs.Publickey.fromHex(
          "02c08786d63f78bd0a6777ffe9c978cf5899756cfc32bfad09a89e211aeb926242"
        ),
        btcnodejs.Publickey.fromHex(
          "033e81519ecf373ea3a5c7e1c051b71a898fb3438c9550e274d980f147eb4d069d"
        ),
        btcnodejs.Publickey.fromHex(
          "036d568125a969dc78b963b494fa7ed5f20ee9c2f2fc2c57f86c5df63089f2ed3a"
        ),
        3
      ])

Solvers

Solvers are objects which are able to compute the scriptSig and Witness from a given array of digests. They are an easy way to compute transaction input's signatures.

They all provide the method:

solve(digests)

which returns an object :

{scriptSig : ScriptSig object , witness: Witness object}

const btcnodejs = require('btcnodejs')
btcnodejs.network.setup('testnet')

const private_key = btcnodejs.Privatekey.fromHex('9b1b400e3b1211c6a56695cf1742f0a94ea38b995c1e1fb910458baa8a0874c4')
const p2pkh_solver = new btcnodejs.P2pkhSolver(private_key)

p2pkh_solver.solve(["0e12bda8a692aefa29651e87af9f47127ab098be1c189284e41d8e17a0516add"]).scriptSig.toHex()
//
'47304402202409f1f966c382f02e023ac828d7653e9268777bd1030e7101338f36a383fde302207ced2d14ff131d3b349bb00d3010a16f08831548e68750223cb8117cab553cab01210330e8ca46b7e5aa07d975ee152214431e419fac34e50becaf7e46db9a9c97d244'

btcnodejs.P2pkhSolver

Solver for P2pkh Scripts

Attributes

new P2pkhSolver(privkey, sighash = new Sighash('ALL'))

Returns a P2pkhSolver object

const btcnodejs = require('btcnodejs')
btcnodejs.network.setup('testnet')

const private_key = btcnodejs.Privatekey.fromHex('9b1b400e3b1211c6a56695cf1742f0a94ea38b995c1e1fb910458baa8a0874c4')
const p2pkh_solver = new btcnodejs.P2pkhSolver(private_key)

btcnodejs.P2wpkhV0Solver

Solver for P2wpkh version 0 scripts. It extends P2pkhSolver

btcnodejs.P2shSolver

Solver for P2sh scripts

Attributes

new P2shSolver(redeemScript, redeemScriptSolver)

btcnodejs.P2wshV0Solver

Solver for P2wsh version 0 Scripts

Attributes

new P2wshV0Solver(witnessScript, witnessScriptSolver)

btcnodejs.MultiSigSolver

Solver for MultiSig Scripts

Attributes

new MultiSigSolver(privkeys, sighashes = [new Sighash('ALL')])

The number of sigashes must be equal to the number of privatekeys.

btcnodejs.IfElseSolver

Solver for If Else Scripts

Attributes

new IfElseSolver(branch, innerSolver)

btcnodejs.RelativeTimelockSolver

Attributes

new RelativeTimelockSolver(innerSolver)

Crypto

The library provides structures and methods to handle Private and Public key objects

btcnodejs.Privatekey

Attributes

new Privatekey(bytebuffer)

Returns a Privatekey object where the body is a bytebuffer representing the private key

static fromHex(hex)

Returns a Privatekey object from an hexadecimal string representing a private key

toHex()

Returns the Hexadecimal representation of the Privatekey

serialize()

Returns the body of the Privatekey

getPublic(compressed = true)

Returns a Publickey object representing the public key associated with this Privatekey. By passing compressed = false, the public key will be of uncompressed type.

sign(message)

Computes the signature of a message, using the elliptic nodejs library using the secp256k1 curve.

signDER(message)

Returns the signature of the message in DER encoding

toWIF(compressed = false)

Returns the Wallet import format string representing the private key. If true is passed in input, the WIF string will represent a private key associated with a compressed Publickey.

fromWIF(wif_string)

Return a Privatekey object from its Wallet import format string.

fromBip32(bip32_string)

Returns a Privatekey object from its Bip32 format string.

btcnodejs.Publickey

Publickey object

Attributes

new Publickey(bytebuffer)

Returns a Publickey object. Its type will be odd, even, uncompressed based on the the input bytebuffer data. It will keep both the uncompressed and compressed versions as its body, but its type will decide which version to use for any operation.

hash()

Returns the hash of the Publickey body.

static fromHex(hex)

Returns a Publickey object from its hexadecimal representation

toHex(compressed = true)

Returns the hexadecimal representation of its body. If false is passed as input it will return the hexadecimal representing its uncompressed version.

toAddress(network = undefined, segwit = false)

Returns an Address object created from the Publickey hash.

serialize()

Returns the Publickey body

HD

This library exposes functionalities to manage Hierarchical deterministic keys. It makes usage of bitcoinjs-lib for some functionalities

btcnodejs.HDPrivateKey

Hierarchical deterministic PrivateKey object

Attributes

new HDPrivateKey(source)

Returns an HDPrivateKey object. If no parameter is given as input, a random HDPrivateKey is returned. Otherwise, a bip32 representation of an hd key can be passed

derive(path)

Returns a child HDPrivateKey derived as specified in BIP32. The path must be a string starting with 'm/'. To derive an hardened child, its index in the path is followed by ' i.e derive('m/0'')

getPublic()

Returns the corresponding HDPublicKey

static fromSeed(seed)

Returns a master HDPrivateKey generated from the hexadecimal string representing a seed

btcnodejs.HDPublicKey

Hierarchical deterministic Public key object

Attributes

new HDPublicKey(source)

Returns an HDPublicKey object. If no parameter is given as input, a random HDPublicKey is returned. Otherwise, a bip32 representation of an hd key can be passed.

derive(path)

Returns a child HDPublicKey derived as specified in BIP32.

Address

This library exposes functionalities to manage bitcoin addresses. It wraps bitcoinjs-lib for addresses encodings.

btcnodejs.Address

Attributes

new Address(type, hash, network = undefined)

Returns an Address object. If network is not specified, the first setup network name will be used.

static fromBase58(base58string)

Returns an Address object from its base58 encoding

toBase58()

Returns a Base58 encoded string representing the bitcoin address

btcnodejs.SegwitAddress

SegwitAddress object extending Address. It has an extra version attribute specifying the segwit version.

Attributes

static fromBech32(bech32string)

Returns a Segwit Address object from its bech32 encoding

toBech32()

Returns a Bech32 encoded string representing the bitcoin Segwit address

Block

btcnodejs.BlockHeader

BlockHeader object

Attributes

new BlockHeader(version, prev_block, merkle_root, timestamp, bits, nonce)

Returns a BlockHeader objects

static fromHex(hex)

Returns a BlockHeader object from an hexadecimal string representing the associated BlockHeader

serialize()

Returns a ByteBuffer representing the serialized BlockHeader

blockHash()

Returns an hexadecimal string representing the hash of the associated Block

TODO