Skip to main content

Node client

The node module is a JSON-RPC 2.0 client for the Mintlayer node daemon.

use mintlayer_sdk::node::{self, TrustPolicy};

let c = node::Client::new("http://127.0.0.1:3030");

// Or with options:
let c = node::Client::builder("http://127.0.0.1:3030")
.basic_auth("user", "pass") // optional
.timeout(std::time::Duration::from_secs(10)) // optional, default 30s
.build()?;

Default ports: 3030 (mainnet), 13030 (testnet).

Credentials are sent as HTTP basic auth with every request. They are redacted from Debug output, so logging a client never leaks the password. Response bodies are capped at 64 MiB to guard against memory exhaustion from a misconfigured endpoint.

Errors are returned as node::Error:

  • Error::Rpc { code, message } — the daemon answered with a JSON-RPC error.
  • Error::Http(reqwest::Error) — transport failure.
  • Error::Json(serde_json::Error) — the response could not be decoded.
  • Error::IdMismatch { expected, actual } — response id mismatch.
  • Error::ResponseTooLarge { limit } — the 64 MiB cap was exceeded.

Transport security: loopback http:// is fine. For remote daemons use an https:// URL (TLS is built in via rustls) or an authenticated tunnel — basic-auth credentials otherwise transit in cleartext with every request.

Chain state

MethodRPC methodNotes
chainstate_info() -> Result<ChainstateInfo, Error>chainstate_infoHeight, id, timestamps, IBD flag of the tip
best_block_id() -> Result<String, Error>chainstate_best_block_idHex-encoded block id
best_block_height() -> Result<u64, Error>chainstate_best_block_height
block_id_at_height(height: u64) -> Result<Option<String>, Error>chainstate_block_id_at_heightNone when not on the main chain
block_height_in_main_chain(block_id: &str) -> Result<Option<u64>, Error>chainstate_block_height_in_main_chainNone when orphaned or unknown
block(id: &str) -> Result<Option<String>, Error>chainstate_get_blockHex-encoded block; the genesis block cannot be retrieved
block_json(id: &str) -> Result<serde_json::Value, Error>chainstate_get_block_json
mainchain_blocks(from: u64, max_count: u32) -> Result<Vec<String>, Error>chainstate_get_mainchain_blocksUp to max_count hex-encoded blocks
utxo(outpoint: &Outpoint) -> Result<Option<serde_json::Value>, Error>chainstate_get_utxoNone when spent or unknown
stake_pool_balance(pool_address: &str) -> Result<Option<Amount>, Error>chainstate_stake_pool_balancePledge plus delegations
staker_balance(pool_address: &str) -> Result<Option<Amount>, Error>chainstate_staker_balanceStaker's own balance only
pool_decommission_destination(pool_address: &str) -> Result<Option<String>, Error>chainstate_pool_decommission_destination
delegation_share(pool_address, delegation_address) -> Result<Option<Amount>, Error>chainstate_delegation_share
token_info(token_id: &str) -> Result<Option<TokenInfo>, Error>chainstate_token_info
tokens_info(token_ids: &[String]) -> Result<Vec<TokenInfo>, Error>chainstate_tokens_infoBatch lookup, order preserved
order_info(order_id: &str) -> Result<Option<OrderInfo>, Error>chainstate_order_infoSee the nonce quirk below
orders_info_by_currencies(ask, give) -> Result<BTreeMap<String, OrderInfo>, Error>chainstate_orders_info_by_currenciesNone filters match every currency
submit_block(block_hex: &str) -> Result<(), Error>chainstate_submit_blockFor block producers

Amount is a u128 atom count (1 ML = 100,000,000,000 atoms), serialized as a decimal string inside an {"atoms": "..."} object on the wire.

Quirk: in OrderInfo the nonce field is Option<u64> because the daemon returns null while an order has no account spending history; handle both cases.

TokenInfo keeps the type-specific payload as raw JSON because its shape depends on kind ("FungibleToken" or "NonFungibleToken").


Mempool

MethodRPC methodNotes
contains_tx(tx_id: &str) -> Result<bool, Error>mempool_contains_tx
contains_orphan_tx(tx_id: &str) -> Result<bool, Error>mempool_contains_orphan_tx
transaction(tx_id: &str) -> Result<Option<MempoolTx>, Error>mempool_get_transactionMempool and orphan pool
submit_transaction(tx_hex: &str, trust_policy: TrustPolicy) -> Result<(), Error>mempool_submit_transactionLocal mempool only, no P2P broadcast
fee_rate(in_top_x_mb: u32) -> Result<Option<FeeRate>, Error>mempool_get_fee_rateAtoms per kilobyte; None when no estimate
fee_rate_points() -> Result<Vec<FeeRatePoint>, Error>mempool_get_fee_rate_pointsCurve of [size, rate] pairs
memory_usage() -> Result<u64, Error>mempool_memory_usageBytes

P2P

MethodRPC methodNotes
peer_count() -> Result<u64, Error>p2p_get_peer_count
connected_peers() -> Result<Vec<PeerInfo>, Error>p2p_get_connected_peersAddresses, roles, ban scores, pings
bind_addresses() -> Result<Vec<String>, Error>p2p_get_bind_addresses
add_reserved_node(addr: &str) -> Result<(), Error>p2p_add_reserved_node
remove_reserved_node(addr: &str) -> Result<(), Error>p2p_remove_reserved_node
connect(addr: &str) -> Result<(), Error>p2p_connectOne-time connection
disconnect(peer_id: u64) -> Result<(), Error>p2p_disconnect
list_banned() -> Result<Vec<BannedPeer>, Error>p2p_list_banned
ban(address: &str, duration: Duration) -> Result<(), Error>p2p_banDuration is sent as [secs, nanos]
unban(address: &str) -> Result<(), Error>p2p_unban
broadcast_transaction(tx_hex: &str, trust_policy: TrustPolicy) -> Result<(), Error>p2p_submit_transactionThe normal path for publishing a transaction

Node management

MethodRPC methodNotes
node_version() -> Result<String, Error>node_versione.g. "1.3.0"
node_shutdown() -> Result<(), Error>node_shutdownGraceful shutdown

Trust policy

TrustPolicy is applied when submitting a transaction:

VariantMeaning
TrustPolicy::Trusted (default)Accept the transaction only if fully valid against the current chainstate
TrustPolicy::UntrustedAccept the transaction even if some inputs are not yet known

Use Untrusted for transactions received from external sources (so that orphaned spends are not rejected), Trusted for transactions you constructed yourself.

// Submit locally and broadcast in one call:
c.broadcast_transaction(&signed_tx_hex, TrustPolicy::Untrusted).await?;

Top-level client

Client::builder() creates the node client only when a node_url is set; basic_auth applies to the node and wallet clients but never to the unauthenticated indexer.