hivecomb
Hive blockchain keys, Graphene serialization and offline transaction signing, in Rust.
[]
= "0.1"
Rust 1.88+. #![forbid(unsafe_code)]. Python and Node.js bindings live in the same
repository.
Signing needs no network
A transaction needs exactly two things from outside itself: the chain id, which is a compile-time constant, and a recent block reference, which stays valid far longer than any submit window. So signing is pure CPU, and the key never has to sit on a machine that talks to a node.
use ;
use ;
// A published test key, used by no Hive account.
let key = from_wif?;
// The only input from the chain. Cache it; refresh it out of band.
let block_ref = from_block_id?;
let tx = new?;
let signed = tx.sign?; // no network, ever
let envelope = signed.to_json?; // ready to broadcast
# Ok::
Runnable: cargo run --example sign_offline --no-default-features.
Feature flags
The core stays small. --no-default-features builds keys, serialization and signing
with no HTTP client and no async runtime compiled in at all.
| feature | |
|---|---|
rpc |
JSON-RPC layer: node failover, typed accessors, block streaming |
ureq-transport |
a working blocking transport (default) |
async |
runtime-agnostic async RPC, including racing one request across nodes |
reqwest-transport |
a working async transport, on tokio |
memo |
encrypted memos (ECDH + AES-CBC) |
bip32 |
BIP-32 / BIP-39 hierarchical keys |
bip38 |
BIP-38 encrypted WIFs |
wallet |
encrypted key store: scrypt + AES-256-GCM |
Default: rpc, ureq-transport, memo, bip38, bip32, wallet. Every combination
is checked warning-free in CI.
What is here
- All 48 signable operations and 43 virtual ones, with round-trip wire serialization.
- Keys: WIF, BIP-32, BIP-38, BIP-39, brain keys, Hive's master-password scheme.
- Encrypted memos, interoperable with Keychain, hive-js, dhive and beem.
- An encrypted wallet, and a
TaposCachethat refuses to hand out a stale reference. Authority::check, which answers three ways — satisfied, not satisfied, or not from these keys alone, when an authority defers to accounts that were not looked up. Most active Hive accounts share posting rights this way.
Racing, when a deadline is real
Sequential failover has a worst case of the sum of the timeouts. Three sick nodes at
fifteen seconds each is forty-five seconds before the fourth is tried, and a transaction
that misses its window is simply lost. AsyncNodeClient::race fires at several nodes at
once and takes the first answer: worst case, one timeout.
Measured with two dead nodes in front of a working one: 878 ms racing, 3,366 ms sequential.
How this is verified
- Against hived itself. A node is asked to serialize each operation and the digests
are compared. 57/57 identical. This found four defects that 295 unit tests and a
differential oracle against
beemhad all missed. - Against beem, the Python library this reimplements: a 150-case differential digest corpus, 0 unexpected divergences.
- On the live chain. A transaction signed by this crate was accepted into block 109242605, filed under the transaction id computed offline.
One accepted transaction is a proof, not a track record. What is and is not established is written down in BROADCAST.md, and the comparison against the other Rust Hive libraries — including where they are ahead — is in COMPARISON.md.
Credit
A reimplementation of beem by Holger Nahrstaedt,
descending from python-bitshares and python-graphenelib by Fabian Schuh. The
protocol knowledge is theirs; this is a translation. See
CREDITS.md.
MIT.