Archive of the libbitcoin Slack #general channel.
/v1/block/hash/[hash] /v1/block/height/[height] /v1/block/hash/[hash]/header /v1/block/height/[height]/header /v1/transaction/[hash]
?format=json|text|data&witness=true|false
enum explore_targets
{
/// /v[]/block/hash/[bkhash] {1}
/// /v[]/block/height/[height] {1}
block,
/// /v[]/block/hash/[bkhash]/header {1}
/// /v[]/block/height/[height]/header {1}
header,
/// -----------------------------------------------------------------------
/// /v[]/block/hash/[bkhash]/transactions {all txs in the block}
/// /v[]/block/height/[height]/transactions {all txs in the block}
block_txs,
/// /v[]/block/hash/[bkhash]/transaction/[position] {1}
/// /v[]/block/height/[height]/transaction/[position] {1}
block_tx,
/// /v[]/transaction/[txhash] {1}
transaction,
/// /v[]/transaction/[txhash]/block {1 - confirmed}
tx_block,
/// -----------------------------------------------------------------------
/// /v[]/inputs/[txhash] {all inputs in the tx}
inputs,
/// /v[]/input/[txhash]/[index] {1}
input,
/// /v[]/input/[txhash]/[index]/script {1}
input_script,
/// /v[]/input/[txhash]/[index]/witness {1}
input_witness,
/// -----------------------------------------------------------------------
/// /v[]/outputs/[txhash] {all outputs in the tx}
outputs,
/// /v[]/output/[txhash]/[index] {1}
output,
/// /v[]/output/[txhash]/[index]/script {1}
output_script,
/// /v[]/output/[txhash]/[index]/spender {1 - confirmed}
output_spender,
/// /v[]/output/[txhash]/[index]/spenders {all}
output_spenders,
/// -----------------------------------------------------------------------
/// /v[]/address/[output-script-hash] {all}
address,
/// /v[]/block/hash/[bkhash]/filter/[type] {1}
/// /v[]/block/height/[height]/filter/[type] {1}
filter,
/// /v[]/block/hash/[bkhash]/filter/[type]/hash {1}
/// /v[]/block/height/[height]/filter/[type]/hash {1}
filter_hash,
/// /v[]/block/hash/[bkhash]/filter/[type]/header {1}
/// /v[]/block/height/[height]/filter/[type]/header {1}
filter_header
};
/v1/block/hash/[bkhash] {1}
/v1/block/height/[height] {1}
/v1/block/hash/[bkhash]/header {1}
/v1/block/height/[height]/header {1}
/v1/block/hash/[bkhash]/fees {1}
/v1/block/height/[height]/fees {1}
/v1/block/hash/[bkhash]/filter/[type] {1}
/v1/block/height/[height]/filter/[type] {1}
/v1/block/hash/[bkhash]/filter/[type]/hash {1}
/v1/block/height/[height]/filter/[type]/hash {1}
/v1/block/hash/[bkhash]/filter/[type]/header {1}
/v1/block/height/[height]/filter/[type]/header {1}
/v1/block/hash/[bkhash]/txs {all txs in the block}
/v1/block/height/[height]/txs {all txs in the block}
/v1/block/hash/[bkhash]/tx/[position] {1}
/v1/block/height/[height]/tx/[position] {1}
-----------------------------------------------------------------------
/v1/tx/[txhash] {1}
/v1/tx/[txhash]/block {1 - if confirmed}
/v1/tx/[txhash]/fee {1}
-----------------------------------------------------------------------
/v1/input/[txhash] {all inputs in the tx}
/v1/input/[txhash]/[index] {1}
/v1/input/[txhash]/[index]/script {1}
/v1/input/[txhash]/[index]/witness {1}
-----------------------------------------------------------------------
/v1/output/[txhash] {all outputs in the tx}
/v1/output/[txhash]/[index] {1}
/v1/output/[txhash]/[index]/script {1}
/v1/output/[txhash]/[index]/spender {1 - if confirmed}
/v1/output/[txhash]/[index]/spenders {all}
-----------------------------------------------------------------------
/v1/address/[output-script-hash] {all}
/v1/address/[output-script-hash]/unconfirmed {all unconfirmed}
/v1/address/[output-script-hash]/confirmed {all unconfirmed}
/v1/address/[output-script-hash]/balance {all confirmed}2025-12-05T18:46:15Z.5 Header [0000000000000000000178231b20e267f3e51399b0325f0e8b5f2abdec561c07:925565] from [45.23.183.89:8333] block unconfirmable[log] application = true news = true session = true protocol = false quitting = false proxy = false remote = true fault = true verbose = false #objects = false # debug builds only
m <enter> for menu options (with node running).application log level.1HckjUpRGcrrRAtFaaCAUaGjsPx9oYmLaZ, which returns 5,179,483 outputs. This is a 178MB result in raw form. On a warm node this takes 7 secs to generate, which includes enumeration via the address table multimap, and lookup of each tx's hash and the output offset, to generate the output point, and the full buffering of the result. On a cold node it takes 2.7 min (mostly SSD read). There's no caching involved in the warm server, so with the chain memory resident, the warm time is close to the initial time.std::atomic_bool protocol_explore::stopping_{} which is updated in the strand:
void protocol_explore::stopping(const code& ec) NOEXCEPT
{
BC_ASSERT(stranded());
stopping_.store(true);
dispatcher_.stop(ec);
protocol_html::stopping(ec);
}[{"point":{"hash":"db9847575ef720b8b5582bac74bcedef1b6a08903ddc27638024b8d0d3ba0400","index":0},"value":1270486495},{"point":{"hash":"2f480f47702a6c099e4d8a53c68cf0e882524fb2d417b3fb8ce0420285420600","index":0},"value":1296713611},{"point":{"hash":"72007a9deb5c1832e095330bb30a8296e23acfc2b1e5994f24f9ef1bae7c0700","index":0},"value":1282065814},
...
] (edited)[{"point":{"hash":"ec16c4bdaf9c9f62778868694ba6ff01feb6a2bc624fb6d87eb8d9b17c6c3f04","index":0},"value":77595},{"point":{"hash":"79ea12ee2bb1728f03a35eaf0ccd4f8ec87ce7382ee82ddffa65b901df801212","index":0},"value":53163},{"point":{"hash":"cadcefdd2ba9917490ad619b2a90a954e3e018b597b0a5a750eaa5b191518e2b","index":0},"value":22556},{"point":{"hash":"4909fae2720cdd9620ad27d1537dcb83c4ac30f097fddae9cdd001b6535fef3c","index":0},"value":74609},{"point":{"hash":"a0e3d5062fd654fabd3ad37a7a206ab36ae9b69ddfca9473afbc3567f002a543","index":0},"value":4873},{"point":{"hash":"b44fc0d27baf40d412c6402923df8fc2b87611ab659f3456251ce34b643b5352","index":0},"value":37400},{"point":{"hash":"ff8090e0d0ebf2f956d456efd1d3a0a9dcb3634a96af86efdef8d888a5343b6d","index":0},"value":150000},{"point":{"hash":"1d05d899ec4043838c6658a7ed416b8c842e087f4495cf5d7adba3d7dea87972","index":0},"value":109904},{"point":{"hash":"aa8d5245516b08133716c6b88a3f393eacd8878680c9a5a3c434f7c03a662878","index":0},"value":107954},{"point":{"hash":"fb7aed4a84e061524d01ca08328ccd8234339b448a979560ff16e89128010ab9","index":0},"value":374084},{"point":{"hash":"33cdcbd55d2a96a2d8eb1e1e368f84e1fedf9a181e30fa4a3e11aa81a43262c7","index":0},"value":340249},{"point":{"hash":"8e8ca91038965142170669175c0673b98c6de16e1cf28c54eb37dfb80f3bd6ca","index":0},"value":75116},{"point":{"hash":"bb16fa968ca18aea8f6b8be9ae574d39c81063ce2c30bd434ff0843ea1ea3cea","index":0},"value":73950},{"point":{"hash":"f1a7cdda517d1c7e030480121a3f5b57a6f7f2857c9610792a6f90f9fbfc66fa","index":0},"value":362631},{"point":{"hash":"1e1b7d5355b288d52f4d1b3a25f4a9d53749dd7a8828d3f747ff2c1a3df07b62","index":1},"value":2818071},{"point":{"hash":"c388319c5828c6240974d7936ccec68d713325b7b4bb1febb182dc4fc32f4884","index":1},"value":100000},{"point":{"hash":"91b9b31a676762f846628bc4dd6e89d9c9731de5fc1ed926b643ad405a504d7e","index":2},"value":462582},{"point":{"hash":"53df9a90a4aa6e1951aba0348e94633b8e756e28ba0ab167fea6a8bd77b0fdb1","index":46},"value":14755},{"point":{"hash":"19e862404694f8e04cedf15d5458bf969184b708a86a72fafd749fd0b97cc21f","index":53},"value":1033541},{"point":{"hash":"4e4775e68f43d12134cd8da13af79afb39d6c1d4747bfa4815f506fd20684b4d","index":65},"value":21611},{"point":{"hash":"68e6d45692cd1ed09d2e4f7ac6dda8e45a999bb21f9a69e95b391407249b5907","index":81},"value":21777}]5.2 million outputs) bitcoin address (returning all outputs points and spend value) has been reduced from several minutes to 30 secs. Chrome remains unable to present the json (aw snap). Chrome renders the base16 text format in 3.6 mins, which is funny since we produce it (end-to-end, warm server) in < 20 secs. The raw data rendering, that Chrome sends straight to a file, takes 17.5 secs to generate, and 2.2 ms for Chrome to download and serialize to a file. The original largest address warm query only took 7 secs, so you may be wondering why it's now 17.5 secs, but that's because I'm now (1) sorting the outputs, and (2) querying the value for every output.[database] turbo = true
?turbo[=true]
turbo button was reborn!
~7,500 outputs (mentioned yesterday) takes 1.62 seconds and the same query warm takes ~20 milliseconds.~2 ms without turbo, but with turbo consistently takes ~1.5 ms. So probably optimal for a caller to always use it, if it's enabled. So I'll change the query string default to true (but retain it for ongoing testing).
http://localhost:81/v1/address/50d8b0211a23e12edf9890c7e0a474f7a87a0a53c0e11285d577991ed3931abdnetwork::socket class, pertaining to closing websocket connections. Another day refactoring all server base classes from libbitcoin-network into libbitcoin-node. These all now are managed via node::session_server and can be moved up to libbitcoin-server at some point with little refactoring.[socket] endpoint and inherited protocol_explore -> protocol_html -> protocol_ws -> protocol_http -> protocol. Websockets requires underlying http for the "upgrade" handshake, and while not all html sites may use websockets, placing it into the hierarchy simplifies configuration. So there's just a simple bool option to disable the upgrade if not used by the endpoint. So websockets is now enabled on the explore and web endpoints, disabled on web. This means websocket connections are on the same port as the http requests for a given endpoint. I haven't integrated ws dispatch for explore yet thought.protocol_bitcoind -> protocol_http -> protocol. This simply overrides protocol_http::handle_receive_post() and dispatches the universal request object (which automatically detects and parses up the json body), via the dispatcher for the bitcoind interface. So just a matter of implementing each of the methods. Initially it's just the node methods, so something like this:
/// Blockchain methods.
method<"getbestblockhash">{},
method<"getblock", string_t, optional<0_u32>>{ "blockhash", "verbosity" },
method<"getblockchaininfo">{},
method<"getblockcount">{},
method<"getblockfilter", string_t, optional<"basic"_t>>{ "blockhash", "filtertype" },
method<"getblockhash", number_t>{ "height" },
method<"getblockheader", string_t, optional<true>>{ "blockhash", "verbose" },
method<"getblockstats", string_t, optional<empty::array>>{ "hash_or_height", "stats" },
method<"getchaintxstats", optional<-1_i32>, optional<""_t>>{ "nblocks", "blockhash" },
method<"getchainwork">{},
method<"gettxout", string_t, number_t, optional<true>>{ "txid", "n", "include_mempool" },
method<"gettxoutsetinfo">{},
method<"pruneblockchain", number_t>{ "height" },
method<"savemempool">{},
method<"scantxoutset", string_t, optional<empty::array>>{ "action", "scanobjects" },
method<"verifychain", optional<4_u32>, optional<288_u32>>{ "checklevel", "nblocks" },
method<"verifytxoutset", string_t>{ "input_verify_flag" },bitcoind node-based json-rpc handlers stubbed in, along with request deserialization and dispatch. Also created a test form to post rpc message to the http endpoint. This is held up by the need to handle the browser's OPTION messages, for cross-origin handling. The work for both handing option and cross-origin/CORS was done previously in the base protocol_http and protocol_html, just need to connect the dots. After that it's just hooking up the queries. So probably a couple days and this will be functional, and just for grins we can drop a quick functional test suite on an embedded page.<ctrl-c> event handler. But the caller disconnect is a per-channel signal that comes from the socket, and is only picked up by an async read handler being invoked. But while we are handling a call, there is no read handler pending. We resubscribe to the channel upon call completion. So even though the work is off strand, there was nothing to capture the close until the call completed. I resolved this by creating an async_wait method on the socket, which will pick up termination. The challenge was cleanly registering and deregistering this before and after the potentially long-running calls. That's all done and working now.53.5 minutes to block 900,000 on my windows dev box. That beats the 900k world record exactly 10%. For context, the $350 mini usually beats my dev box by a bit (because it hash shani and avx512). We'll keep optimizing to make sure we can still hit under an 1 hour on 2Gbps Internet at 1M blocks.47.6 minutes to block 900,000. That puts the 1 million blocks in 60 minutes target well within reach.bitcoind json-rpc endpoint. One method done just as the proof, others all stubbed in. The rest of it is downhill from here :).// github.com/bitcoin/bitcoin/blob/master/doc/REST-interface.md
static constexpr std::tuple methods
{
// blocks (block_part is bin|hex only)
method<"block", uint8_t, system::hash_cptr>{ "media", "hash" },
method<"block_hash", uint8_t, uint32_t>{ "media", "height" },
method<"block_txs", uint8_t, system::hash_cptr>{ "media", "hash" },
method<"block_headers", uint8_t, system::hash_cptr, uint32_t>{ "media", "hash", "count" },
method<"block_part", uint8_t, system::hash_cptr, uint32_t, uint32_t>{ "media", "hash", "offset", "size" },
method<"block_spent_tx_outputs", uint8_t, system::hash_cptr>{ "media", "hash" },
// client filters
method<"block_filter", uint8_t, system::hash_cptr, uint8_t>{ "media", "hash", "type" },
method<"block_filter_headers", uint8_t, system::hash_cptr, uint8_t>{ "media", "hash", "type" },
// unspent outputs
method<"get_utxos", uint8_t, system::hash_cptr, uint8_t>{ "media", "hash", "type" },
method<"get_utxos_confirmed", uint8_t, system::hash_cptr, uint8_t>{ "media", "hash", "type" },
// mempool (json only)
method<"mempool", optional<true>, optional<false>>{ "verbose", "sequence" },
// info (json only)
method<"chain_information">{},
method<"mempool_information">{},
method<"fork_information", nullable<system::hash_cptr>>{ "hash" }
};bitcoind-json-rpc and bitcoind-rest compatibility interfaces are defined and functional (incomplete) on the [bitcoind] endpoint, alongside the native [explore] http/ws rest interface (complete on http, ws functional) and embedded (or directory override) block explorer, and the [web] html embedded (or directory) dashboard/admin site (functional). Next is to get the [electrum] endpoint/interface up (json-rpc over tcp). That's all the endpoints apart from stratum (and [stratum_v1] is the same endpoint type as Electrum, just different methods).rpc_ with terminated_, within the rpc::body class.libbitcoin-node with latest master. I'm not very familar so it's more than likely I've misunderstood something. Running bn --newstore on a fresh install fails after all database files are successfully created. The error message is confusing me. Ideally I'd like to create a regtest config.
I'm using the following minimal config:
$ cat /tmp/bn.cfg [log] path = /tmp/bn-logs [database] path = /tmp/bn-db [inbound] bind = 127.0.0.1:18445 connections = 1 [outbound] connections = 0 $ bn --config /tmp/bn.cfg --newstore
All files are created, opened, loaded, unloaded, and closed successfully: create::create_file(header_head) ... create::close_file(filter_tx_body) Database creation failed with error 'file failed to load, disk may be full'.
-n but with outbound.connections = 0 in the config will cause the node to just idle and do nothing as it will not connect to any peers.[log]
path = {logdir}
[bitcoin]
# Regtest genesis block (hex-encoded)
genesis_block = {genesis_hex}
# Regtest proof of work limit (0x207fffff = 545259519)
proof_of_work_limit = 545259519
# Accept any valid chain (no minimum work requirement)
minimum_work = 0000000000000000000000000000000000000000000000000000000000000000
[forks]
# Regtest allows easy mining without real proof of work
difficult = false
[network]
# Regtest network magic (0xDAB5BFFA = 3669344250)
identifier = 3669344250
[inbound]
# Listen for P2P connections
bind = 127.0.0.1:{p2p_port}
connections = 10
enable_loopback = true
[outbound]
# Disable outbound connections to prevent contacting mainnet seeds
connections = 0
host_pool_capacity = 0
[database]
path = {datadir}
# Tiny regtest DB profile (avoid multi-GB prealloc).
header_buckets = 1
header_size = 1000
txs_buckets = 1
txs_size = 1000
tx_buckets = 1
tx_size = 1000
point_buckets = 1
point_size = 1000
strong_tx_buckets = 1
strong_tx_size = 1000
input_size = 1000
ins_size = 1000
output_size = 1000
outs_size = 1000
candidate_size = 1000
confirmed_size = 1000
duplicate_buckets = 1
duplicate_size = 100
prevout_buckets = 0
prevout_size = 1
validated_bk_buckets = 1
validated_bk_size = 1000
validated_tx_buckets = 1
validated_tx_size = 1000
address_buckets = 1
address_size = 1000
filter_bk_buckets = 0
filter_tx_buckets = 0
[node]
# Don't delay inbound peers waiting for "current" chain state (regtest genesis is old).
delay_inbound = false--help and --version still reference bn) 🙂
./libbitcoin-server/console/bs --help
Usage: bn [-abdfhiklnrsv] [--config value] [--test value] [--write value]
Info: Runs a full bitcoin node.
Options (named):
-a [--slabs] Scan and display store slab measures.
-b [--backup] Backup to a snapshot (can also do live).
-c [--config] Specify path to a configuration settings file.
-d [--hardware] Display hardware compatibility.
-f [--flags] Scan and display all flag transitions.
-h [--help] Display command line options.
-i [--information] Scan and display store information.
-k [--buckets] Scan and display all bucket densities.
-l [--collisions] Scan and display hashmap collision stats (may exceed
RAM and result in SIGKILL).
-n [--newstore] Create new store in configured directory.
-r [--restore] Restore from most recent snapshot.
-s [--settings] Display all configuration settings.
-t [--test] Run built-in read test and display.
-v [--version] Display version information.
-w [--write] Run built-in write test and display. (edited)[endpoint] maximum_request = 4,000,000 minimum_buffer = 4,000,000
network::channel_rpc and ::protocol_rpc so that they are both templatized on a specific rpc (json-rpc) interface. This allows node::protocol_electrum and node::protocol_stratum_v1 to just derive from the network::protocol_rpc<interface::electrum> and implement the electrum rpc method handlers, and of course the same for network::protocol_rpc<interface::stratum_v1>.[web] # admin website (embedded or local) # websockets enabled [explore] # html block explorer (embedded or local) # rest interface (json, hex, binary) # websockets enabled [bitcoind] # bitcoind json-rpc (post) # bitcoind rest (get) [electrum] # json-rpc over tcp [stratum_v1] # json-rpc over tcp [incoming] # p2p (tcp) [outgoing] # p2p (tcp) [manual] # p2p (tcp)(edited)
stratum_v1 rpc handlers. These sit on the same base as electrum, so they everything is fully functional apart from populating the responses. Currently they all send error::not_implemented, eg:
bool protocol_stratum_v1::handle_mining_subscribe(const code& ec,
rpc_interface::mining_subscribe, const std::string& user_agent,
double extranonce1_size) NOEXCEPT
{
if (stopped(ec)) return false;
send_code(error::not_implemented);
return true;
} enum class protocol_version
{
/// Invalid version.
v0_0,
/// 2011, initial protocol negotiation.
v0_6,
/// 2012, enhanced protocol negotiation.
v0_8,
/// 2012, added pruning limits and transport indicators.
v0_9,
/// 2013, baseline for core methods in the official specification.
v0_10,
/// 2014, 1.x series, deprecations of utxo and block number methods.
v1_0,
/// 2015, updated version response and introduced scripthash methods.
v1_1,
/// 2017, added optional parameters for transactions and headers.
v1_2,
/// 2018, defaulted raw headers and introduced new block methods.
v1_3,
/// 2019, removed deserialized headers and added merkle proof features.
v1_4,
/// 2019, modifications for auxiliary proof-of-work handling.
v1_4_1,
/// 2020, added scripthash unsubscribe functionality.
v1_4_2,
/// 2022, updated response formats and added fee estimation modes.
v1_6
};WolfSSL sources and start looking at TLS for each of our protocols (http/s, ws/s, p2p/s, rpc/s [zmq/s, sv2/s]). I believe that each can be integrated in basically the same manner entirely at the socket level.2025-12-31T06:13:05Z.2 Accepted electrum connection [127.0.0.1:64158] on binding [0.0.0.0:50001]. 2025-12-31T06:13:05Z.2 Inbound electrum channel start [127.0.0.1:64158] success 2025-12-31T06:13:06Z.0 Rpc request: [1024] server.version(...). 2025-12-31T06:13:06Z.0 Rpc response: [62], success.