Author

Topic: Exploring alternative full node implementations - Bcoin (Read 139 times)

legendary
Activity: 2870
Merit: 7490
Crypto Swap Exchange
Reserved.
legendary
Activity: 2870
Merit: 7490
Crypto Swap Exchange
This part explore some feature offered by Bcoin. Bcoin preliminarily developed as JavaScript library. But since i'm not JavaScript developer, i'll just explore few RPC command and few other functionality offered by Bcoin.

Bcoin on browser

One of the guides mention[1] Bcoin has basic Web UI. I decide to try it, but encountered error. The guide seems to be out of date and i didn't relevant information on Bcoin documentation[2-3], so i decide to give up.

Code:
$ npm install webpack webpack-cli
$ npm run webpack-app
npm ERR! Missing script: "webpack-app"
npm ERR!
npm ERR! To see a list of scripts, run:
npm ERR!   npm run

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/user/.npm/_logs/2022-10-12T06_08_46_856Z-debug-0.log
$ node browser/server.js
node:internal/fs/utils:347
    throw err;
    ^

Error: ENOENT: no such file or directory, open '/home/user/bcoin/browser/app.js'
    at Object.openSync (node:fs:594:3)
    at Object.readFileSync (node:fs:462:35)
    at Object. (/home/user/bcoin/browser/server.js:8:16)
    at Module._compile (node:internal/modules/cjs/loader:1126:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1180:10)
    at Module.load (node:internal/modules/cjs/loader:1004:32)
    at Function.Module._load (node:internal/modules/cjs/loader:839:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:17:47 {
  errno: -2,
  syscall: 'open',
  code: 'ENOENT',
  path: '/home/user/bcoin/browser/app.js'
}

CLI

To access Bcoin RPC, you can use either bcoin-cli or any application/library which support JSON-RPC protocol. Aside from RPC command, bcoin-cli also mirror some RPC command directly into bcoin-cli. You can use these command to find out available CLI and RPC command.

Code:
$ ./bcoin-cli help
Commands:
  $ info: Get server info.
  $ broadcast [tx-hex]: Broadcast transaction.
  $ mempool: Get mempool snapshot.
  $ tx [hash/address]: View transactions.
  $ coin [hash+index/address]: View coins.
  $ block [hash/height]: View block.
  $ header [hash/height]: View block header.
  $ filter [hash/height]: View filter.
  $ fee [target]: Estimate smart fee.
  $ reset [height/hash]: Reset chain to desired block.
  $ rpc [command] [args]: Execute RPC command. (`bcoin-cli rpc help` for more)
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc help
Select a command:
stop
help
getblockchaininfo
getbestblockhash
getblockcount
getblock
getblockbyheight
getblockhash
getblockheader
getblockfilter
getchaintips
getdifficulty
getmempoolancestors
getmempooldescendants
getmempoolentry
getmempoolinfo
getrawmempool
gettxout
gettxoutsetinfo
pruneblockchain
verifychain
invalidateblock
reconsiderblock
getnetworkhashps
getmininginfo
prioritisetransaction
getwork
getworklp
getblocktemplate
submitblock
verifyblock
setgenerate
getgenerate
generate
generatetoaddress
estimatefee
estimatepriority
estimatesmartfee
estimatesmartpriority
getinfo
validateaddress
createmultisig
createwitnessaddress
verifymessage
signmessagewithprivkey
setmocktime
getconnectioncount
ping
getpeerinfo
addnode
disconnectnode
getaddednodeinfo
getnettotals
getnetworkinfo
setban
listbanned
clearbanned
getrawtransaction
createrawtransaction
decoderawtransaction
decodescript
sendrawtransaction
signrawtransaction
gettxoutproof
verifytxoutproof
getmemoryinfo
setloglevel

Bcoin RPC also have detailed documentation. But take note it was last updated on October 2019 (equal to bcoin version v2.0.0-dev)[3]. So it's possible some RPC command behavior changed since then.

RPC Calls - Node

getinfo show basic information about Bcoin node and wallet.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getinfo
{
  "version": "2.2.0",
  "protocolversion": 70015,
  "walletversion": 0,
  "balance": 0,
  "blocks": 758305,
  "timeoffset": 0,
  "connections": 1,
  "proxy": "",
  "difficulty": 35610794164371.65,
  "testnet": false,
  "keypoololdest": 0,
  "keypoolsize": 0,
  "unlocked_until": 0,
  "paytxfee": 0.00005,
  "relayfee": 0.00001,
  "errors": ""
}

validateaddress used to validate whether an address is valid or not. As expected, Bcoin can verify P2PKH, P2SH and P2WPKH address[4] without problem.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress 17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem
{
  "isvalid": true,
  "address": "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem",
  "scriptPubKey": "76a91447376c6f537d62177a2c41c4ca9b45829ab9908388ac",
  "isscript": false,
  "iswitness": false
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX
{
  "isvalid": true,
  "address": "3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX",
  "scriptPubKey": "a9148f55563b9a19f321c211e9b9f38cdf686ea0784587",
  "isscript": true,
  "iswitness": false
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
{
  "isvalid": true,
  "address": "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4",
  "scriptPubKey": "0014751e76e8199196d454941c45d1b3a323f1433bd6",
  "isscript": false,
  "iswitness": true,
  "witness_version": 0,
  "witness_program": "751e76e8199196d454941c45d1b3a323f1433bd6"
}

Since i found out Bcoin already support Bech32m, i decide to use some test vector for Bech32m address[5] which represent Taproot/P2TR address on mainnet (which indicated by bc1p prefix). Unsurprisingly, Bcoin passed the test vector. For valid address, Bcoin showing the address is valid with correct scriptPubKey. For invalid address, Bcoin showing the address is invalid, although it doesn't state the cause/reason.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y
{
  "isvalid": true,
  "address": "bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
  "scriptPubKey": "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6",
  "isscript": false,
  "iswitness": true,
  "witness_version": 1,
  "witness_program": "751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0
{
  "isvalid": true,
  "address": "bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0",
  "scriptPubKey": "512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
  "isscript": false,
  "iswitness": true,
  "witness_version": 1,
  "witness_program": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
}

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd
{
  "isvalid": false
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4
{
  "isvalid": false
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1pw5dgrnzv
{
  "isvalid": false
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav
{
  "isvalid": false
}
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc validateaddress bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf
{
  "isvalid": false
}

verifymessage is used to verify signed message. I use 2 recently staked address[6-7] from thread "Stake your Bitcoin address here"[8] as example. Bcoin manage to verify both signed message (from P2PKH and P2WPKH address) without problem. Obviously when i modify the signature/message, Bcoin return false.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc verifymessage "bc1qaen0qmpw4j3lu83n7lzg6jncrgry7r7p0eplyl" "Hz1Oiy3eXgwdUNsMxSKA/GJdx8XvDkY+4LrAP9k0yVkKb+OQOl/tMpBE7qU95N5rpR6ztGbCuKOBRnYxDGQ1J9k=" "Today 19/9/2022 I would like to sign my wallet from Electrum."
true
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc verifymessage "17mtDab5mfK9rwup3UDmKCbaeHwuruFZKV" "IN5zxE8FOEhF+ZgFSuILjaQxrgz0Wk8dbnJ8TmqqAC2wCt3JmzciX2hDm1DEhVNntMN9gg57TuwwrhREyObi7TQ=" "Today is 13 Sept, 2022 and this is palle11 of BTT staking this address here as mine."
true

RPC calls - Block

Bcoin RPC calls about Bitcoin block is very similar with Bitcoin Core RPC calls. As shown below, i include 2 example which used to
1. Obtain genesis block by combining command getblockhash and getblock.
2. Obtain block header of recently mined block by combining command getblockhash and getblock.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getblock $(./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getblockhash 0)
{
  "hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
  "confirmations": 758308,
  "strippedsize": 285,
  "size": 285,
  "weight": 1140,
  "height": 0,
  "version": 1,
  "versionHex": "00000001",
  "merkleroot": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
  "coinbase": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73",
  "tx": [
    "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
  ],
  "time": 1231006505,
  "mediantime": 1231006505,
  "nonce": 2083236893,
  "bits": "1d00ffff",
  "difficulty": 1,
  "chainwork": "0000000000000000000000000000000000000000000000000000000100010001",
  "nTx": 1,
  "previousblockhash": null,
  "nextblockhash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048"
}

Code:
./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getblockheader $(./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getblockhash 758307)
{
  "hash": "000000000000000000062cc24b230d35e91802be5c56ecdc8c83335f1a38c817",
  "confirmations": 1,
  "height": 758307,
  "version": 850198532,
  "versionHex": "32ad0004",
  "merkleroot": "f1348496b539c3ff460915a5c175f791f1605de2193d43ea7212b5256ec31bf8",
  "time": 1665558400,
  "mediantime": 1665557075,
  "nonce": 3182294105,
  "bits": "1707e772",
  "difficulty": 35610794164371.65,
  "chainwork": "000000000000000000000000000000000000000036f62b1a23ff7175f72ac248",
  "previousblockhash": "0000000000000000000279315a5d1ae3883db75104eaab9f8ab425eb8447b81b",
  "nextblockhash": null
}

RPC calls - Mempool

getmempoolinfo is used to get statistic of Bcoin mempool. Compared with Bitcoin Core, Bcoin show less information.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getmempoolinfo
{
  "size": 1926,
  "bytes": 9865640,
  "usage": 9865640,
  "maxmempool": 314572800,
  "mempoolminfee": 0.00001
}

Code:
$ ./bitcoin-cli getmempoolinfo
{
  "loaded": true,
  "size": 2001,
  "bytes": 834058,
  "usage": 4385952,
  "total_fee": 0.05797974,
  "maxmempool": 1024000000,
  "mempoolminfee": 0.00001000,
  "minrelaytxfee": 0.00001000,
  "unbroadcastcount": 0
}

RPC calls - Network

getpeerinfo is used to get information of connected node. Just like above example, Bcoin's getpeerinfo also show less information.

Code:
$ ./bcoin-cli --api-key=test_bcoin --http-port=48332 rpc getpeerinfo
[
  {
    "id": 1,
    "addr": "127.0.0.1:8333",
    "services": "00000449",
    "servicenames": [
      "NETWORK",
      "WITNESS"
    ],
    "relaytxes": true,
    "lastsend": 1665559472,
    "lastrecv": 1665559472,
    "bytessent": 287895,
    "bytesrecv": 4942460,
    "conntime": 2550,
    "timeoffset": 0,
    "pingtime": 0.001,
    "minping": 0,
    "version": 70016,
    "subver": "/Satoshi:23.0.0/",
    "inbound": false,
    "startingheight": 758301,
    "besthash": "000000000000000000062cc24b230d35e91802be5c56ecdc8c83335f1a38c817",
    "bestheight": 758307,
    "banscore": 0,
    "inflight": [],
    "whitelisted": false
  }
]

Code:
$ ./bitcoin-cli getpeerinfo
...
{
  "id": 54,
  "addr": "127.0.0.1:57226",
  "addrbind": "127.0.0.1:8333",
  "addrlocal": "127.0.0.1:8333",
  "network": "not_publicly_routable",
  "services": "0000000000000009",
  "servicesnames": [
    "NETWORK",
    "WITNESS"
  ],
  "relaytxes": true,
  "lastsend": 1665559520,
  "lastrecv": 1665559516,
  "last_transaction": 0,
  "last_block": 0,
  "bytessent": 5003478,
  "bytesrecv": 292272,
  "conntime": 1665556921,
  "timeoffset": 0,
  "pingtime": 0.000206,
  "minping": 0.00019,
  "version": 70015,
  "subver": "/bcoin:2.2.0/",
  "inbound": true,
  "bip152_hb_to": false,
  "bip152_hb_from": false,
  "startingheight": 758301,
  "synced_headers": 758301,
  "synced_blocks": 758301,
  "inflight": [
  ],
  "addr_relay_enabled": true,
  "addr_processed": 1,
  "addr_rate_limited": 0,
  "permissions": [
  ],
  "minfeefilter": 0.00000000,
  "bytessent_per_msg": {
    "addr": 1535,
    "blocktxn": 202447,
    "cmpctblock": 36546,
    "feefilter": 32,
    "getheaders": 1053,
    "inv": 261388,
    "ping": 704,
    "pong": 2784,
    "sendcmpct": 66,
    "sendheaders": 24,
    "tx": 4496749,
    "verack": 24,
    "version": 126
  },
  "bytesrecv_per_msg": {
    "*other*": 21203,
    "addr": 55,
    "getblocks": 1053,
    "getblocktxn": 849,
    "getdata": 264008,
    "headers": 106,
    "inv": 1330,
    "ping": 2784,
    "pong": 704,
    "sendcmpct": 33,
    "verack": 24,
    "version": 123
  },
  "connection_type": "inbound"
},
...

Conclusion

It was fun trying Bcoin, even though initial sync/IBD took some time. But clearly Bcoin isn't best option if you only want to run Bitcoin full node. But for JavaScript developer who want to develop software which need data directly from blockchain, Bcoin should be viable choice (with exception of Taproot support).

Some things i like,

  • Easy compile and installation process.
  • Lots of RPC command which pose similarity with Bitcoin Core RPC.
  • Existance of address index.
  • Production-ready JavaScript library.

Some things i don't like,

  • Some outdated documentation.
  • Lots of disk read/write, which significantly slow down sync on HDD.



[1] https://bcoin.io/guides/browser.html
[2] https://github.com/bcoin-org/bcoin/tree/v2.2.0/docs
[3] https://bcoin.io/api-docs/index.html#introduction
[4] https://en.bitcoin.it/wiki/List_of_address_prefixes
[5] https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki#test-vectors-for-v0-v16-native-segregated-witness-addresses
[6] https://bitcointalksearch.org/topic/m.60965625
[7] https://bitcointalksearch.org/topic/m.60930988
[8] https://bitcointalksearch.org/topic/stake-your-bitcoin-address-here-996318
legendary
Activity: 2870
Merit: 7490
Crypto Swap Exchange
Intro

Continuing previous thread "Exploring alternative full node implementations - Gocoin"[1], this time i decide to try Bcoin[2]. I choose Bcoin since it's 4th fastest node implementation according to Jameson Lopp benchmark[3] and it has been around for some time.

Basic information

  • Bcoin is written in JavaScript language.
  • Bcoin is developed since 2014[4].
  • Bcoin is built for businesses, miners, wallets, and hobbyists.
  • Bcoin already used on business/production environment, including purse.io[5].
  • Bcoin can be used either as full node, wallet (with some accounting feature), data API (through JSON-RPC) or JavaScript library.

My system

  • Debian-based OS
  • Old 6 core CPU
  • 32GB RAM
  • 3.5" HDD (Both Bitcoin Core and Bcoin data stored here)
  • Node.js v16.17.1
  • Bitcoin Core 23.0
  • Gocoin 2.2.0

Compile and installation

The documentation mention several requirement[6], but i already have all of them installed in my system. Although it surprise me Bcoin still support Node.js v10.0.0 which already reach end of life. The compile/installation process is very simple and i didn't experience any problem.

Code:
git clone --depth=1 --branch=v2.2.0 https://github.com/bcoin-org/bcoin
cd bcoin/
npm rebuild
npm install

You can install Bcoin locally or globally. I decide to install it locally since i'd rather not mess with my system. But take note if you install it locally, bcoin binary is located inside directory bin where you ran npm install and bcoin binary is't available on $PATH[7].

Bcoin configuration

To configure Bcoin, there are 4 available options[8]. Those options are config file, CLI parameter, environment variable & JS object constructor. You also can combine them, but you'll have to pay attention to how Bcoin prioritize the configuration options. Bcoin have both node and wallet functionality, so you'll need to make 2 config file.

If you check list of available configuration, you'll find out Bcoin have feature to index transaction and address. But since it could make initial sync/IBD longer, i decide not to enable those features.

I decide to use config file, which is more convenient than typing long CLI parameter or messing with environment variable. If you use non-default directory path, you'll need to explicitly mention on wallet config file[9]. Aside from configuring Bcoin to only connect to my Bitcoin Core node, i try to make configuration which utilize 100% of my system. But there's no guarantee this is most optimal configuration.

Code:
# bcoin.conf
workers: true
workers-size: 6
sigcache-size: 4000000
prefix: /path/to/bcoin/directory
max-files: 7000
cache-size: 16384
log-level: info
mempool-size: 300
replace-by-fee: true
persistent-mempool: true
port: 48333
only: 127.0.0.1:8333
http-port: 48332
api-key: test_bcoin

Code:
# wallet.conf
prefix: /path/to/bcoin/directory
http-port: 48334

I store both config file on directory which used to store blockchain and other files created by bcoin. In addition, i run bcoin on terminal by specifying directory path so bcoin locate config file automatically.

Code:
./bin/bcoin --prefix=/path/to/bcoin/directory

Initial Block Download (IBD)

It took 9 days to complete initial sync/IBD until block 758232. But since i do not turn on my computer 24/7, actually it took about 90 hours 31 minutes (based on Bcoin log files). During sync i notice Bcoin ask for more block/data after few hours. So it's likely bcoin could sync faster if i turn on my computer 24/7.



Despite configuring bcoin to use all CPU and lots of RAM, bcoin doesn't use much of my system. I did not perform detailed logging, but i never see bcoin use more than 3.1GB of RAM and 300% CPU (according to htop). When i use iotop, i found out bcoin perform lots of disk read/write. After short monitoring with iotop -a, Bcoin perform 4.1GB read and 56.9GB write. This is clearly the reason Bcoin is far slower than gocoin during sync (6.8h[10] vs 90h31m).

And talking about disk read/write, size of block/UTXO on Bcoin is only slightly bigger than Bitcoin Core.

Code:
# Bitcoin Core
$ du -sh *
...
459G    blocks
4.8G    chainstate
...

Code:
# Bcoin
$ du -sh *
...
461G    blocks
6.2G    chain
...

Post IBD

After Bcoin finished initial sync/IBD, Bcoin begin to fill the mempool with unconfirmed transaction. What surprise me Bcoin print lots of error message with code "nonstandard" or "duplicate". After quick search, i found it might happen due to limited Taproot support[11], where only Bech32m address format is supported[12]. I also found out Bcoin isn't actively developed[13], which bring concern about future of Bcoin.

Code:
(net) Error: Verification failure: bad-txns-inputs-spent (code=duplicate score=0 hash=de81bda3cd4a2d10efbe2133a9caa3cf7e36c71c1ba014dafbc2c80ccfdd1a01)
(net) Error: Verification failure: scriptpubkey (code=nonstandard score=0 hash=38911ac69ebdc26d6480115f1745d9800f4505cbf3cd17572003097f0f896ac6)



[1] https://bitcointalksearch.org/topic/exploring-alternative-full-node-implementations-gocoin-5407675
[2] https://bcoin.io/
[3] https://blog.lopp.net/2021-bitcoin-node-performance-tests-2/
[4] https://github.com/bcoin-org/bcoin#license
[5] https://purse.io/shop, scroll down to bottom page to see text "Powered by bcoin"
[6] https://github.com/bcoin-org/bcoin/blob/v2.2.0/docs/getting-started.md#requirements
[7] https://github.com/bcoin-org/bcoin/blob/v2.2.0/docs/getting-started.md#starting-up-your-first-bcoin-node
[8] https://github.com/bcoin-org/bcoin/blob/v2.2.0/docs/configuration.md
[9] https://github.com/bcoin-org/bcoin/issues/645
[10] https://bitcointalksearch.org/topic/exploring-alternative-full-node-implementations-gocoin-5407675
[11] https://github.com/bcoin-org/bcoin/issues/1032
[12] https://github.com/bcoin-org/bcoin/pull/1038
[13] https://github.com/bcoin-org/bcoin/issues/1044
Jump to: