bitcore Documentation

A full stack for bitcoin and blockchain-based applications

4,985 stars TypeScript TypeScript 1 file ยท ~10,173 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy bitcore on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name bitcore --restart always mongo:3.6.23
Configured Services & Ports
โš™๏ธ db
image: mongo:3.6.23
โš™๏ธ bitcoin
image: ruimarinho/bitcoin-core:24
โš™๏ธ erigon
image: chainstack/erigon:2.60.8
โš™๏ธ geth
image: ethereum/client-go:v1.16.7
โš™๏ธ rippled
image: build locally
docker-compose.yml
yaml (docker-compose.yml)
services:

  db:
    image: mongo:3.6.23

  bitcoin:
    image: ruimarinho/bitcoin-core:24
    command:
      -printtoconsole
      -regtest=1
      -txindex=0
      -listen=1
      -server=1
      -dnsseed=0
      -upnp=0
      -port=8332
      -rpcport=8333
      -rpcallowip=0.0.0.0/0
      -rpcbind=0.0.0.0
      -rpcuser=bitcorenodetest
      -rpcpassword=local321
      -fallbackfee=0.00001

  erigon:
    image: chainstack/erigon:2.60.8
    command:
      --chain=dev
      --datadir=/home/erigon/data
      --private.api.addr=0.0.0.0:9090
      --http.addr=0.0.0.0
      --http.api=eth,erigon,web3,net,debug,trace,txpool
      --http.port=8545
      --mine
      --ws

  geth:
    image: ethereum/client-go:v1.16.7
    volumes:
      - ./.docker/geth-keystore:/keystore
      - geth-data:/geth-data
    command:
      --dev
      --datadir /geth-data
      --keystore /keystore
      --txlookuplimit=0
      --snapshot=false
      --cache=1024
      --http
      --http.api web3,eth,debug,net,txpool
      --http.corsdomain '*'
      --http.vhosts '*'
      --http.addr 0.0.0.0
      --http.port 8545
      --ws
      --ws.origins '*'
      --ws.api web3,eth,debug,net,txpool
      --ws.addr 0.0.0.0
      --ws.port 8546

  rippled:
    build:
      context: .
      dockerfile: ./.docker/rippled.Dockerfile

networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/16

volumes:
  geth-data:

File: README.md

Bitcore Monorepo

Infrastructure to build Bitcoin and blockchain-based applications for the next generation of financial technology.

Applications

Libraries

Extras

  • Bitcore Build - A helper to add tasks to gulp
  • Bitcore Client - A helper to create a wallet using the bitcore-node infrastructure
  • Bitpay/Bitpay App - An easy-to-use, multiplatform, multisignature, secure wallet for bitcoin, ethereum, and more

Versioning

This repo follows the even-odd versioning convention. Major versions that are even (e.g. v8.x.x) are stable releases, odd are beta releases (e.g. v9.x.x). Beta versions may contain breaking changes or major feature additions that are still in testing.

Contributing

See CONTRIBUTING.md on the main bitcore repo for information about how to contribute.

License

Code released under the MIT license.

Copyright 2013-2025 BitPay, Inc. Bitcore is a trademark maintained by BitPay, Inc.

[^1]: The Bitcore P2P Doge library is no longer maintained as all the core functionality is contained in Bitcore P2P


File: packages/bitcore-wallet-service/README.md

Bitcore Wallet Service



A Multisig HD Bitcore Wallet Service.

Description

Bitcore Wallet Service facilitates multisig HD wallets creation and operation through a (hopefully) simple and intuitive REST API.

BWS can usually be installed within minutes and accommodates all the needed infrastructure for peers in a multisig wallet to communicate and operate โ€“ with minimum server trust.

See bitcore-wallet-client for the official client library that communicates to BWS and verifies its response. Also check bitcore-cli for a simple CLI wallet implementation that relies on BWS.

BWS is been used in production enviroments for Copay Wallet, Bitpay App wallet and others.

More about BWS at https://blog.bitpay.com/announcing-the-bitcore-wallet-suite/

Getting Started

sh
git clone https://github.com/bitpay/bitcore.git
cd bitcore
npm install
npm run bws

This will launch the BWS service (with default settings) at http://localhost:3232/bws/api.

BWS needs mongoDB. You can configure the connection inside the "bitcoreWalletService" section of your bitcore.config.json. See the Configuration section of Installation.md.

BWS uses by default a Request Rate Limitation to CreateWallet endpoint. If you need to modify it, check defaults.js' Defaults.RateLimit

Security Considerations

  • Private keys are never sent to BWS. Copayers store them locally.
  • Extended public keys are stored on BWS. This allows BWS to easily check wallet balance, send offline notifications to copayers, etc.
  • During wallet creation, the initial copayer creates a wallet secret that contains a private key. All copayers need to prove they have the secret by signing their information with this private key when joining the wallet. The secret should be shared using secured channels.
  • A copayer could join the wallet more than once, and there is no mechanism to prevent this. See wallet's confirm command, for a method for confirming copayers.
  • All BWS responses are verified:
    • Addresses and change addresses are derived independently and locally by the copayers from their local data.
    • TX Proposals templates are signed by copayers and verified by others, so the BWS cannot create or tamper with them.

Using SSL

You can add your certificates at the bws.config.js using:

json
https: true,
  privateKeyFile: 'private.pem',
  certificateFile: 'cert.pem',
  ////// The following is only for certs which are not
  ////// trusted by nodejs 'https' by default
  ////// CAs like Verisign do not require this
  // CAinter1: '', // ex. 'COMODORSADomainValidationSecureServerCA.crt'
  // CAinter2: '', // ex. 'COMODORSAAddTrustCA.crt'
  // CAroot: '', // ex. 'AddTrustExternalCARoot.crt'

@dabura667 made a report about how to use letsencrypt with BWS: https://github.com/bitpay/bitcore-wallet-service/issues/423

TX proposal life cycle

Tx proposal need to be:

  1. First created via /v?/txproposal
    -> This will create a 'temporary' TX proposal, returning the object, but not locking the inputs
  2. Then published via /v?/txproposal/:id/publish
    -> This publish the tx proposal to all copayers, looking the inputs. The TX proposal can be deleted also, after been published.
  3. Then signed via /v?/txproposal/:id/signature for each copayer
  4. Then broadcasted to the p2p network via /v?/txproposal/:id/broadcast

There are plenty examples of creating and sending proposals in the /test/integration code.

Enabling Regtest Mode for BWS and Copay

Requirements

mongo topology crashes sometimes due to notifications being incompatible in a web browser
bitcore-wallet-service/lib/notificationbroadcaster.js
Note: If testing on a PC browser, comment out notificationbroadcaster.js to disable notifications.

Steps:

bitcore.config.json

  1. Add a regtest configuration to the bitcoreNode section of your bitcore.config.json.

Example:

json
// bitcore.config.json
{
  "bitcoreNode": {
    "chains": {
      "BTC": {
        // add me:
        "regtest": {
          "chainSource": "p2p",
          "trustedPeers": [
            {
              "host": "127.0.0.1",
              "port": 20020
            }
          ],
          "rpc": {
            "host": "127.0.0.1",
            "port": 20021,
            "username": "bitpaytest",
            "password": "local321"
          }
        }
      }
    }
  }
}
  1. Point regtest to http://localhost:3000 in the bitcoreWalletService.blockchainExplorerOpts section and set allowRegtest to true.
json
// bitcore.config.json
{
  "bitcoreWalletService": {
    "allowRegtest": true,
    "blockchainExplorerOpts": {
      "btc": {
        "livenet": {
          "url": "https://api.bitcore.io"
        },
        "regtest": {
          "url": "http://localhost:3000",
        }
      },
...

Copay changes

copay/app-template/index-template.html

  1. Comment out content security meta tag in the <head>
text
// <meta http-equiv="Content-Security-Policy" content="default-src 'self'  ... >

Creating a wallet on regtest network

Steps:

  1. Set the wallet service URL to
text
http://localhost:3232/bws/api
  1. Select Testnet by pressing the slider button.

Testing on mobile

Requirements:

  • Mobile phone and PC must be connected to the same internet
  • PC desktop ip address for localhost

To find ip address for PC run:

text
// 127.0.0.1 is equal to localhost
ifconfig | grep "inet " | grep -v 127.0.0.1
  1. Inside copay project root directory run:
text
npm run apply:copay
  1. Enter PC ip address followed by port in the mobile phone browser:
text
10.10.11.73:8100
  1. Set wallet service url to PC ip address /bws/api when creating a new wallet
text
http://10.10.11.73:3232/bws/api

REST API

Note: all currency amounts are in units of satoshis (1/100,000,000 of a bitcoin).

Authentication

In order to access a wallet, clients are required to send the headers:

sh
x-identity
  x-signature

Identity is the Peer-ID, this will identify the peer and its wallet. Signature is the current request signature, using requestSigningKey, the m/1/1 derivative of the Extended Private Key.

See Bitcore Wallet Client for implementation details.

GET Endpoints

`/v1/wallets/`: Get wallet information

Returns:

`/v1/txhistory/`: Get Wallet's transaction history

Optional Arguments:

  • skip: Records to skip from the result (defaults to 0)
  • limit: Total number of records to return (return all available records if not specified).
  • reverse: Return oldest transactions first.

Returns:

  • History of incoming and outgoing transactions of the wallet. The list is paginated using the skip & limit params. Each item has the following fields:
  • action ('sent', 'received', 'moved')
  • amount
  • fees
  • time
  • addressTo
  • confirmations
  • proposalId
  • creatorName
  • message
  • actions array ['createdOn', 'type', 'copayerId', 'copayerName', 'comment']

`/v2/txproposals/`: Get Wallet's pending transaction proposals and their status

Returns:

`/v4/addresses/`: Get Wallet's main addresses (does not include change addresses)

Optional Arguments:

  • ignoreMaxGap: [false] Ignore checking less that 20 unused addresses (BIP44 GAP)

Returns:

`/v1/balance/`: Get Wallet's balance

Returns:

  • totalAmount: Wallet's total balance
  • lockedAmount: Current balance of outstanding transaction proposals, that cannot be used on new transactions.
  • availableAmount: Funds available for new proposals.
  • totalConfirmedAmount: Same as totalAmount for confirmed UTXOs only.
  • lockedConfirmedAmount: Same as lockedAmount for confirmed UTXOs only.
  • availableConfirmedAmount: Same as availableAmount for confirmed UTXOs only.
  • byAddress array ['address', 'path', 'amount']: A list of addresses holding funds.
  • totalKbToSendMax: An estimation of the number of KiB required to include all available UTXOs in a tx (including unconfirmed).

`/v1/txnotes/:txid`: Get user notes associated to the specified transaction

Returns:

  • The note associated to the txid as a string.

`/v1/fiatrates/:code`: Get the fiat rate for the specified ISO 4217 code

Optional Arguments:

  • provider: An identifier representing the source of the rates.
  • ts: The timestamp for the fiat rate (defaults to now).

Returns:

  • The fiat exchange rate.

POST Endpoints

`/v1/wallets/`: Create a new Wallet

Required Arguments:

  • name: Name of the wallet
  • m: Number of required peers to sign transactions
  • n: Number of total peers on the wallet
  • pubKey: Wallet Creation Public key to check joining copayer's signatures (the private key is unknown by BWS and must be communicated
    by the creator peer to other peers).

Returns:

  • walletId: Id of the new created wallet

`/v1/wallets/:id/copayers/`: Join a Wallet in creation

Required Arguments:

  • walletId: Id of the wallet to join
  • name: Copayer Name
  • xPubKey - Extended Public Key for this copayer.
  • requestPubKey - Public Key used to check requests from this copayer.
  • copayerSignature - Signature used by other copayers to verify that the copayer joining knows the wallet secret.

Returns:

  • copayerId: Assigned ID of the copayer (to be used on x-identity header)
  • wallet: Object with wallet's information

`/v3/txproposals/`: Add a new temporary transaction proposal

Required Arguments:

  • toAddress: RCPT Bitcoin address.
  • amount: amount (in satoshis) of the mount proposed to be transfered
  • proposalsSignature: Signature of the proposal by the creator peer, using proposalSigningKey.
  • (opt) message: Encrypted private message to peers.
  • (opt) payProUrl: Paypro URL for peers to verify TX
  • (opt) feePerKb: Use an alternative fee per KB for this TX.
  • (opt) excludeUnconfirmedUtxos: Do not use UTXOs of unconfirmed transactions as inputs for this TX.
  • BCH addresses need to be cashaddr without prefix.

Returns:

`/v2/txproposals/:id/publish`: Publish the previously created `temporary` tx proposal

Returns:

`/v3/addresses/`: Request a new main address from wallet . (creates an address on normal conditions)

Returns:

`/v1/txproposals/:id/signatures/`: Sign a transaction proposal

Required Arguments:

  • signatures: All Transaction's input signatures, in order of appearance.

Returns:

`/v1/txproposals/:id/broadcast/`: Broadcast a transaction proposal

Returns:

`/v1/txproposals/:id/rejections`: Reject a transaction proposal

Returns:

`/v1/addresses/scan`: Start an address scan process looking for activity.

Optional Arguments:

  • includeCopayerBranches: Scan all copayer branches following BIP45 recommendation (defaults to false).

`/v1/txconfirmations/`: Subscribe to receive push notifications when the specified transaction gets confirmed

Required Arguments:

  • txid: The transaction to subscribe to.

PUT Endpoints

`/v1/txnotes/:txid/`: Modify a note for a tx

DELETE Endpoints

`/v1/txproposals/:id/`: Deletes a transaction proposal. Only the creator can delete a TX Proposal, and only if it has no other signatures or rejections

Returns:

`/v1/txconfirmations/:txid`: Unsubscribe from transaction `txid` and no longer listen to its confirmation

Push Notifications

Recomended to complete config.js file:

POST Endpoints

`/v1/pushnotifications/subscriptions/`: Adds subscriptions for push notifications service at database

DELETE Endpoints

`/v2/pushnotifications/subscriptions/`: Remove subscriptions for push notifications service from database

Contributing

See CONTRIBUTING.md on the main bitcore repo for information about how to contribute.

License

Code released under the MIT license.

Copyright 2013-2019 BitPay, Inc. Bitcore is a trademark maintained by BitPay, Inc.


File: packages/bitcore-wallet-client/README.header.md

bitcore-wallet-client



The official client library for bitcore-wallet-service.

Description

This package communicates with BWS Bitcore wallet service using the REST API. All REST endpoints are wrapped as simple async methods. All relevant responses from BWS are checked independently by the peers, thus the importance of using this library when talking to a third party BWS instance.

See [Bitcore-CLI] (https://github.com/bitpay/bitcore/tree/master/packages/bitcore-cli) for a simple CLI wallet implementation that relies on BWS and uses bitcore-wallet-client.

Get Started

You can start using bitcore-wallet-client via NPM: by running npm install @bitpay-labs/bitcore-wallet-client from your console.

Example

Start your own local Bitcore wallet service instance. In this example we assume you have bitcore-wallet-service running on your localhost:3232.

Then create two files irene.js and tomas.js with the content below:

**irene.js**

javascript
var Client = require('@bitpay-labs/bitcore-wallet-client');


var fs = require('fs');
var BWS_INSTANCE_URL = 'https://bws.bitpay.com/bws/api'

var client = new Client({
  baseUrl: BWS_INSTANCE_URL,
  verbose: false,
});

client.createWallet("My Wallet", "Irene", 2, 2, {network: 'testnet'}, function(err, secret) {
  if (err) {
    console.log('error: ',err); 
    return
  };
  // Handle err
  console.log('Wallet Created. Share this secret with your copayers: ' + secret);
  fs.writeFileSync('irene.dat', client.export());
});

**tomas.js**

javascript
var Client = require('@bitpay-labs/bitcore-wallet-client');


var fs = require('fs');
var BWS_INSTANCE_URL = 'https://bws.bitpay.com/bws/api'

var secret = process.argv[2];
if (!secret) {
  console.log('./tomas.js <Secret>')

  process.exit(0);
}

var client = new Client({
  baseUrl: BWS_INSTANCE_URL,
  verbose: false,
});

client.joinWallet(secret, "Tomas", {}, function(err, wallet) {
  if (err) {
    console.log('error: ', err);
    return
  };

  console.log('Joined ' + wallet.name + '!');
  fs.writeFileSync('tomas.dat', client.export());


  client.openWallet(function(err, ret) {
    if (err) {
      console.log('error: ', err);
      return
    };
    // Example output for demonstration / debugging purposes
    console.log('\n\n** Wallet Info', ret);

    console.log('\n\nCreating first address:', ret);

    if (ret.wallet.status == 'complete') {
      client.createAddress({}, function(err,addr){
        if (err) {
          console.log('error: ', err);
          return;
        };

        console.log('\nReturn:', addr)
      });
    }
  });
});

Install bitcore-wallet-client before start:

sh
npm i @bitpay-labs/bitcore-wallet-client

Create a new wallet with the first script:

sh
$ node irene.js
info Generating new keys
 Wallet Created. Share this secret with your copayers: JbTDjtUkvWS4c3mgAtJf4zKyRGzdQzZacfx2S7gRqPLcbeAWaSDEnazFJF6mKbzBvY1ZRwZCbvT

Join to this wallet with generated secret:

sh
$ node tomas.js JbTDjtUkvWS4c3mgAtJf4zKyRGzdQzZacfx2S7gRqPLcbeAWaSDEnazFJF6mKbzBvY1ZRwZCbvT
Joined My Wallet!

Wallet Info: [...]

Creating first address:

Return: [...]

Note that the scripts created two files named irene.dat and tomas.dat. With these files you can get status, generate addresses, create proposals, sign transactions, etc.


File: packages/bitcore-wallet-client/README.md

bitcore-wallet-client



The official client library for bitcore-wallet-service.

Description

This package communicates with BWS Bitcore wallet service using the REST API. All REST endpoints are wrapped as simple async methods. All relevant responses from BWS are checked independently by the peers, thus the importance of using this library when talking to a third party BWS instance.

See [Bitcore-CLI] (https://github.com/bitpay/bitcore/tree/master/packages/bitcore-cli) for a simple CLI wallet implementation that relies on BWS and uses bitcore-wallet-client.

Get Started

You can start using bitcore-wallet-client via NPM: by running npm install @bitpay-labs/bitcore-wallet-client from your console.

Example

Start your own local Bitcore wallet service instance. In this example we assume you have bitcore-wallet-service running on your localhost:3232.

Then create two files irene.js and tomas.js with the content below:

**irene.js**

javascript
var Client = require('@bitpay-labs/bitcore-wallet-client');


var fs = require('fs');
var BWS_INSTANCE_URL = 'https://bws.bitpay.com/bws/api'

var client = new Client({
  baseUrl: BWS_INSTANCE_URL,
  verbose: false,
});

client.createWallet("My Wallet", "Irene", 2, 2, {network: 'testnet'}, function(err, secret) {
  if (err) {
    console.log('error: ',err);
    return
  };
  // Handle err
  console.log('Wallet Created. Share this secret with your copayers: ' + secret);
  fs.writeFileSync('irene.dat', client.export());
});

**tomas.js**

javascript
var Client = require('@bitpay-labs/bitcore-wallet-client');


var fs = require('fs');
var BWS_INSTANCE_URL = 'https://bws.bitpay.com/bws/api'

var secret = process.argv[2];
if (!secret) {
  console.log('./tomas.js <Secret>')

  process.exit(0);
}

var client = new Client({
  baseUrl: BWS_INSTANCE_URL,
  verbose: false,
});

client.joinWallet(secret, "Tomas", {}, function(err, wallet) {
  if (err) {
    console.log('error: ', err);
    return
  };

  console.log('Joined ' + wallet.name + '!');
  fs.writeFileSync('tomas.dat', client.export());


  client.openWallet(function(err, ret) {
    if (err) {
      console.log('error: ', err);
      return
    };
    console.log('\n\n** Wallet Info', ret); //TODO

    console.log('\n\nCreating first address:', ret); //TODO
    if (ret.wallet.status == 'complete') {
      client.createAddress({}, function(err,addr){
        if (err) {
          console.log('error: ', err);
          return;
        };

        console.log('\nReturn:', addr)
      });
    }
  });
});

Install bitcore-wallet-client before start:

sh
npm i @bitpay-labs/bitcore-wallet-client

Create a new wallet with the first script:

sh
$ node irene.js
info Generating new keys
 Wallet Created. Share this secret with your copayers: JbTDjtUkvWS4c3mgAtJf4zKyRGzdQzZacfx2S7gRqPLcbeAWaSDEnazFJF6mKbzBvY1ZRwZCbvT

Join to this wallet with generated secret:

sh
$ node tomas.js JbTDjtUkvWS4c3mgAtJf4zKyRGzdQzZacfx2S7gRqPLcbeAWaSDEnazFJF6mKbzBvY1ZRwZCbvT
Joined My Wallet!

Wallet Info: [...]

Creating first address:

Return: [...]

Note that the scripts created two files named irene.dat and tomas.dat. With these files you can get status, generate addresses, create proposals, sign transactions, etc.The MIT License

Copyright (c) 2015-2021 BitPay

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


File: packages/bitcore-tss/README.md

Bitcore Threshold Signature Scheme



A powerful JavaScript library for distributed threshold ECDSA key and signature generation

Principles

A threshold signature scheme allows a group of participants to sign a message in a distributed manner. The signature is valid only if a certain number of participants (the threshold) have signed the message.
This libary is designed to be flexible in that it supports distributed key generation (DKG) which means that the private key is never constructed in any one location, thus ensuring than no single party ever has the full private key in their possession.

The TSS protocols (DKG & DSG) depend on a secure communication channel between the participants.
For example, a central coordination server that all parties connect to over HTTPS

Get Started

To add Bitcore-TSS to your project, run:

sh
npm install @bitpay-labs/bitcore-tss

Documentation

Distributed Key Generation

The DKG protocol is used to generate a shared private key that is distributed among a group of participants. The private key is never constructed in any one location, thus ensuring than no single party ever has the full private key in their possession.

Example

First, you need to instantiate a KeyGen instance.

js
const keygen = new bitcoreTss.KeyGen({
  m: 2, // participant threshold needed to generate a signature
  n: 3, // number of participants
  partyId: 0, // which participant of the 3 are you (0-based...the initiator is always 0)?
  authKey: privateKey, // a private key used for encrypting and signing messages
  seed: seedKey, // Optional - could be the derivation of a 12-word phrase
});

Then, you need to generate the broadcast message to the other participants that you're joining the group.

js
const broadcastMessage = await keygen.initJoin();

// securely send broadcastMessage to the other participants

Once you receive the broadcast messages from the other participants, you need to proceed to the next round of messages.

js
const otherParticipantsMessages = // receive messages from the other participants

const myNextRoundMessage = keygen.nextRound(otherParticipantsMessages);

// securely send myNextRoundMessage to the other participants

Continue through the rounds until the keychain is ready

js
while (!keygen.isKeyChainReady()) {
  const otherParticipantsMessages = // receive messages from the other participants

  const myNextRoundMessage = keygen.nextRound(otherParticipantsMessages);

  // securely send myNextRoundMessage to the other participants
}

const keychain = keygen.getKeyChain();

Congrats! You now have a key share that you can use to sign messages.

Distributed Signature Generation

Once you have your key share, you can use it to sign messages. The process is similar to the DKG protocol - generating a signature requires multiple rounds of message passing.

In this example, we'll use an Ethereum transaction as our use case.

js
const rawTxHex = '0x...'; // your raw hex transaction
const hashBuffer = Buffer.from(Web3.utils.keccak256(rawTxHex).substring(2), 'hex');

const signer = new bitcoreTss.Sign({
  keychain,
  m: 2, // participant threshold needed to generate a signature
  n: 3, // total number of participants
  partyId: 0, // your party id
  messageHash: hashBuffer, // a 32-byte hash of message to sign
  authKey: privateKey, // a private key used for encrypting and signing messages
  derivationPath: 'm' // optional - useful for UTXO chains like Bitcoin that derive lots of addresses
});

Initiate the first round of the signature generation protocol and create a broadcast message to send to the other participants that you wish to sign a message

js
const broadcastMessage = await signer.initJoin();

// securely send broadcastMessage to the other participants

Continue through the rounds until the signature is ready

js
while (!signer.isSignatureReady()) {
  const otherParticipantsMessages = // receive messages from the other participants

  const myNextRoundMessage = signer.nextRound(otherParticipantsMessages);

  // securely send myNextRoundMessage to the other participants
}

Once the signature is ready, you can get it and apply it to your use case. For this example, we're applying the signature to our Ethereum transaction.

js
const CWC = require('@bitpay-labs/crypto-wallet-core');

const sig = signer.getSignature();

const signedTxHex = CWC.Transactions.applySignature({ chain: 'ETH', tx: rawTxHex, signature: sig });

File: packages/bitcore-p2p-doge/docs/index.md

Peer-to-Peer

The bitcore-p2p-doge module provides peer-to-peer networking capabilities for Bitcore, and includes Peer and Pool classes. A Message class is also exposed, in addition to several types of messages. Pool will maintain connection to several peers, Peers represents a node in the bitcoin network, and Message represents data sent to and from a Peer. For detailed technical information about the bitcoin protocol, please visit the Protocol Specification on the Bitcoin Wiki.

Installation

Peer-to-peer is implemented as a separate module.

To add to your project, run:

sh
npm install @bitpay-labs/bitcore-p2p-doge

Quick Start

javascript
var Peer = require('@bitpay-labs/bitcore-p2p-doge').Peer;
var peer = new Peer({host: '5.9.85.34'});

// handle events
peer.on('inv', function(message) {
  // message.inventory[]
});

peer.connect();

File: packages/bitcore-p2p-doge/docs/messages.md

Messages

The bitcoin protocol specifies a set of messages that can be sent from peer to peer. bitcore-p2p-doge provides support for some of these messages.

To create a message, you can use any of the message constructors, here is a simple example:

javascript
var messages = new Messages();
var message = messages.Ping();

There are also several convenient helpers for inventory based messages:

javascript
message = messages.GetData.forTransaction(txHash);
message = messages.GetData.forBlock(blockHash);
message = messages.Inventory.forTransaction(txHash);

As well as sending "tx" and "block" messages with Bitcore instances:

javascript
message = messages.Block(block);
message = messages.Transaction(transaction);

Note: A list of further messages is available below.

For advanced usage, you can also customize which constructor is used for Block and Transaction messages by passing it as an argument to Messages, for example:

javascript
var messages = new Messages({Block: MyBlock, Transaction: MyTransaction});

And additionally a custom network:

javascript
var messages = new Messages({network: Networks.testnet});

List of Messages

Version

The version message (ver) is used on connection creation, to advertise the type of node. The remote node will respond with its version, and no communication is possible until both peers have exchanged their versions. By default, bitcore advertises itself as named bitcore with the current version of the bitcore-p2p-doge package.

VerAck

Finishes the connection handshake started by the ver message.

Inventory

From the bitcoin protocol spec: "Allows a node to advertise its knowledge of one or more objects. It can be received unsolicited, or in reply to getblocks.".

GetData

From the bitcoin protocol spec: getdata is used in response to inv, to retrieve the content of a specific object, and is usually sent after receiving an inv packet, after filtering known elements. It can be used to retrieve transactions, but only if they are in the memory pool or relay set - arbitrary access to transactions in the chain is not allowed to avoid having clients start to depend on nodes having full transaction indexes (which modern nodes do not).

GetData inherits from Inventory, as they both have the same structure.

NotFound

notfound is a response to a getdata, sent if any requested data items could not be relayed, for example, because the requested transaction was not in the memory pool or relay set. Contains inventory information specifying which items were not found.

Ping

Sent to another peer mainly to check the connection is still alive.

Pong

Sent in response to a ping message.

Address and GetAddresses

Provides information on known nodes of the network. GetAddresses is used to query another peer for known addresses.

GetHeaders and Headers

getheaders allows a peer to query another about blockheaders. headers is sent in response to a getheaders message, containing information about block headers.

GetBlocks and Block

Same as getheaders and headers, but the response comes one block at the time.

Transaction

Message that contains a transaction.

Custom Messages

It is possible to extend the default peer to peer messages and add custom ones. First you will need to create a message which resembles the default messages in lib/messages/commands.

Then to add the custom message:

javascript
messages.add('custom', 'Custom', CustomMessage);

var customMessage = messages.Custom('argument');

File: packages/bitcore-p2p-doge/docs/peer.md

Peer

Represents a node from the p2p bitcoin network. The Peer class supports connecting directly to other nodes or through a socks5 proxy like Tor.

Creating a peer

The code to create a new peer looks like this:

javascript
var Peer = require('@bitpay-labs/bitcore-p2p-doge').Peer;

// default port
var livenetPeer = new Peer({host: '5.9.85.34'});
var testnetPeer = new Peer({host: '5.9.85.34', network: Networks.testnet});

// custom port
var livenetPeer = new Peer({host: '5.9.85.34', port: 8334});
var testnetPeer = new Peer({host: '5.9.85.34', port: 18334, network: Networks.testnet});

// use sock5 proxy (Tor)
var peer = new Peer({host: '5.9.85.34'}).setProxy('localhost', 9050);

States

A peer instance is always in one of the following states:

  • disconnected: No connection with the remote node.
  • connecting: While establishing the connection.
  • connected: Exchanging version packages.
  • ready: Connection ready for sending and receiving messages.

You can subscribe to the change of those states as follows:

javascript
var Peer = require('@bitpay-labs/bitcore-p2p-doge').Peer;

var peer = new Peer({host: '5.9.85.34'});

peer.on('ready', function() {
  // peer info
  console.log(peer.version, peer.subversion, peer.bestHeight);
});

peer.on('disconnect', function() {
  console.log('connection closed');
});

peer.connect();

Handle messages

Once connected, a peer instance can send and receive messages. Every time a message arrives it's emitted as a new event. Let's see an example of this:

javascript
var Peer = require('@bitpay-labs/bitcore-p2p-doge').Peer;
var peer = new Peer({host: '5.9.85.34'});

// handle events
peer.on('inv', function(message) {
  // message.inventory[]
});

peer.on('tx', function(message) {
  // message.transaction
});

peer.on('addr', function(message) {
  // message.addresses[]
});

peer.connect();

Sending messages

In order to send messages the Peer class offers the sendMessage(message) method, which receives an instance of a message. All supported messages can be found in the Messages module. For more information about messages refer to the protocol specification.

An example for requesting other connected nodes to a peers looks like this:

javascript
var p2p = require('@bitpay-labs/bitcore-p2p-doge')
var Peer = p2p.Peer;
var Messages = p2p.Messages;
var peer = new Peer({host: '5.9.85.34'});

peer.on('ready', function() {
  var message = new Messages.GetAddresses();
  peer.sendMessage(message);
});

peer.on('addr', function(message) {
  message.addresses.forEach(function(address) {
    // do something
  });
});

peer.connect();

File: packages/bitcore-p2p-doge/docs/pool.md

Pool

A pool maintains a connection of Peers. A pool will discover peers via DNS seeds, as well as when peer addresses are announced through the network.

The quickest way to get connected is to run the following:

javascript
var Pool = require('@bitpay-labs/bitcore-p2p-doge').Pool;
var Networks = require('@bitpay-labs/bitcore-lib-doge').Networks;

var pool = new Pool({network: Networks.livenet});

// connect to the network
pool.connect();

// attach peer events
pool.on('peerinv', function(peer, message) {
  // a new peer message has arrived
});

// will disconnect all peers
pool.disconnect()

For more information about Peer events please read the Peer documentation. Peer events are relayed to the pool, a peer event inv in the pool would be peerinv. When a peer is disconnected the pool will try to connect to the list of known addresses to maintain connection.

Trusted Peers

By default, peers will be added via DNS discovery and as peers are announced in the network. Configuration options can be included to connect only to specific trusted peers:

javascript
var pool = new Pool({
  network: Networks.livenet, // the network object
  dnsSeed: false, // prevent seeding with DNS discovered known peers upon connecting
  listenAddr: false, // prevent new peers being added from addr messages
  addrs: [ // initial peers to connect to
    {
      ip: {
        v4: '127.0.0.1'
      }
    }
  ]
});

pool.connect();

Listening for Peers

It's also possible to listen to incoming socket connections to add peers to the pool. To enable this capability, you can do the following:

javascript
var pool = new Pool({network: Networks.livenet});
pool.listen();

When there are incoming connections the peer will be added to the pool.