Release 0.10.1, cut from dev at 702f6b9 and merged to stable in #1629. Crate versions are derived from the changesets that landed since 0.10.0; breaking changes take a minor bump under 0.x.
Crate versions
| Crate | 0.10.0 cycle | 0.10.1 cycle |
|---|---|---|
| zainod | 0.10.0 | 0.10.1 |
| zaino-serve | 0.8.0 | 0.9.0 |
| zaino-state | 0.9.0 | 0.10.0 |
| zaino-proto | 0.6.0 | 0.6.1 |
| zaino-primitives | 0.2.1 | 0.3.0 |
| zaino-rpc | 0.2.1 | 0.3.0 |
| zaino-source | 0.2.1 | 0.2.2 |
| zaino-source-zebra | 0.2.1 | 0.2.2 |
| zaino-source-zebra-rpc | 0.2.1 | 0.2.2 |
| zaino-source-zebra-readstate | 0.2.1 | 0.2.2 |
| zaino-source-macros | 0.1.0 | 0.1.1 |
| zaino-convert-zebra | 0.2.1 | 0.3.0 |
| zaino-consensus | 0.1.1 | 0.2.0 |
| zaino-mempool | 0.2.1 | 0.2.2 |
| zaino-mempool-service | 0.2.1 | 0.2.2 |
| zaino-chain-head | 0.1.1 | 0.2.0 |
| zaino-chain-head-service | 0.1.1 | 0.2.0 |
| zaino-chain-store | 0.1.0 | 0.1.1 |
| zaino-chain-store-zainodb | 0.1.0 | 0.2.0 |
| zaino-address | 0.1.1 | 0.1.2 |
| zaino-common | 0.5.2 | 0.5.3 |
| zaino-encoding | 0.1.0 | 0.1.1 |
| zaino-status | 0.1.1 | 0.1.2 |
Bold: the crate carries a breaking change; see its migration notes below. Docker images: zingodevops/zaino:0.10.1 and zingodevops/zaino:0.10.1-no-tls (also under zingodevops/zainod). All crates are on crates.io.
Changes by crate
zainod 0.10.1
Added
- The gRPC server offers
zaino.index.v1.IndexedTipService, a Zaino extension that lets a client wait for a newly indexed block without polling. The lightwalletd protocol is unchanged. - The metrics listener (
metrics_endpoint) runs on its own thread and runtime and also serves/livez(fails once the indexer loop stops reporting for 30s). - Graceful shutdown on
SIGTERM, through the same close path as an internal shutdown. - Process metrics (
process_cpu_seconds_total,process_resident_memory_bytes, fds, threads) sampled on scrape,zainod.restarts_total, and explicit bucket ladders for every histogram (none scrape as summaries any more).
Changed
- dependency
zaino-chain-head-service0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-rpc0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-serve0.8.0→0.9.0 crossed the requirement^0.8.0 - dependency
zaino-state0.9.0→0.10.0 crossed the requirement^0.9.0
Fixed
- A
metrics_endpointconfigured on a binary built withoutprometheusnow warns instead of being silently ignored; a non-private bind warns that the listener is unauthenticated. - A
metrics_endpointthat fails to bind now fails startup with the error, instead of leaving the process running with no/metrics, no/livez, and no upkeep of the recorder's histogram samples. The listener is bound before the recorder is installed.
zaino-serve 0.9.0
Added
- Serve
IndexedTipService/SubscribeIndexedTipson the gRPC server. A subscription first receives the current indexed tip, then each canonical tip change, including a same-height reorg. A slow client receives only the latest tip, and graceful shutdown ends open subscriptions. - JSON-RPC serving metrics
zaino.jsonrpc.request_duration_seconds{method}andzaino.jsonrpc.errors_total{method,code}; unregistered method names are labelledunknown.
Changed
BlockDeltas::from_domainand thegetblockchaininfopool-balance rendering are infallible, because the domain types already guarantee the range. TheDeltaAmountOutOfRangeandPoolBalanceOutOfRangeerrors are removed.
Migration: Remove handling forDeltaAmountOutOfRangeandPoolBalanceOutOfRange, and drop the?on the now-infallible conversions.- Removed
zaino.grpc.requests_total(=zaino.grpc.request_duration_seconds_count);zaino.grpc.errors_total{code}now carries the status name (NotFound). Featureprometheusremoved.
Migration: Usezaino.grpc.request_duration_seconds_countfor request volume. - dependency
zaino-consensus0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-state0.9.0→0.10.0 crossed the requirement^0.9.0
Fixed
- Confirmation counts in verbose blocks, verbose headers, block deltas and transaction outputs are checked: a value below -1, a block value of 0, or a count past
u32is rejected instead of passed through. getaddressdeltasrejects an invalid address as invalid params instead of admitting it.z_gettreestatewrites the Orchard and IronwoodfinalRootin display order. Only the Sapling root is byte-reversed for display, so both pools previously named a root no chain ever had.getblockchaininforenderschainSupplywith its value; every backend previously reported it as zero.
Internal
- The block-header render test builds its chainwork from a compile-time constant.
zaino-state 0.10.0
Added
- Add a stream of indexed-tip changes, driven by the existing watch notifications instead of polling.
Changed
- Sync-loop metrics: added
zaino.sync.consecutive_failuresandzaino.sync.backoff_seconds.
Migration: Removed metrics:zaino.sync.lag_blocks(derivezaino.chain.tip_height - zaino.sync.finalized_height),iterations_total,iteration_duration_seconds,errors_total,has_reached_tip,reached_tip_at. Featureprometheusremoved. - dependency
zaino-chain-head0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-chain-head-service0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-chain-store-zainodb0.1.0→0.2.0 crossed the requirement^0.1.0 - dependency
zaino-consensus0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-convert-zebra0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-rpc0.2.1→0.3.0 crossed the requirement^0.2.1
Fixed
- An address's net value no longer rejects busy address history as corrupt. Gross receipts and spends may exceed the supply; only an impossible net value is refused.
getrawtransactionin verbose mode reportstimeandblocktimefrom the containing block's header.
Internal
- Confirmation counts use the exact confirmation state types.
- Transparent addresses are constructed through the validating constructor.
- Chain-head blocks converted for serving now carry no chain work, instead of reinterpreting the window's anchor-relative total as an absolute one.
-
- The chain-index proptests run against a persistent finalised state and wait for it to finish building; they no longer exercise ephemeral mode.
- Generated chains are relinked (merkle root and parent hash) so the finalised state's write-path checks accept them, which also re-enables make_chain.
- Test-only: the chain-head test builds block work through SingleBlockWork::new, and the orphaned golden module that no mod declaration named is deleted.
zaino-proto 0.6.1
Added
- Add the
zaino.index.v1.IndexedTipServiceprotocol with theSubscribeIndexedTipsserver-streaming call.
zaino-primitives 0.3.0
Added
- Add RelativeChainWork, the proof-of-work total a run of blocks holds, measured from where the run begins rather than from genesis.
types::TransparentAddressKey— how an index keys a transparent output: a 20-byte hash and the script form it came from. Shared vocabulary, because both halves of an address's history key by it and a consumer merging them must not have to translate.from_scriptsharesclassify_script, so a store indexing an output and a chain head reporting on one cannot classify it differently.
Changed
- Zatoshi quantities are three checked types:
Zatoshis(an amount,0 ..= supply),ZatoshisFlowSum(an accumulation of movements, bounded only byu128), andSignedZatoshis(a movement or a net,-supply ..= supply).accumulate,sum_balancesandZatoshisFlowSum::netare the only arithmetic, andAddressBalance.receivedis aZatoshisFlowSum. (#1504, #1505)
Migration:SignedZatoshis::new(i64)is removed: parse a value withSignedZatoshis::try_new, or derive one withZatoshisFlowSum::net. ReadAddressBalance.receivedas aZatoshisFlowSum, since lifetime receipts can exceed the supply. - The
Confirmations = i64alias is replaced byBlockConfirmations(NotInBestChainorConfirmed(NonZeroU32)) andTxConfirmations(MempoolorMined(BlockConfirmations)). Each type converts to and from the RPC integer withto_rpc_i64andtry_from_rpc_i64.
Migration: Replace sign checks on the integer with the enum variants oris_in_best_chain. Build a best-chain block's value withBlockConfirmations::of_best_chain_block(height, tip). TransparentAddressis validated at construction:try_newaccepts only P2PKH and P2SH addresses of any Zcash network and rejects other kinds with a typedTransparentAddressError.network()returns the newAddressNetwork, andscript_type()returns the address'sScriptType.
Migration: ReplaceTransparentAddress::newwithTransparentAddress::try_newand handleTransparentAddressError.- Chain work is two types:
AbsoluteChainWork, the cumulative work from genesis, andSingleBlockWork, one block's contribution, withgenesis,accumulateandrollbackoperations. Each work error is defined in the module that raises it.
Migration: Replace the single chain-work type withAbsoluteChainWorkfor totals andSingleBlockWorkfor one block's work. TreeSizeis a checked newtype backed byu32.TreeRootInfo,BlockTreeSizesandChainMetadatause it in place ofu64andu32fields, and an oversized value is refused instead of truncated.ChainMetadata::ZEROandChainMetadata::neware added. (#549)
Migration: Build tree sizes withTreeSize::from(u32)or its checked constructor, and read them throughTreeSize.CompactDifficultyis validated at construction and computes work natively (nBits to target to work). A valid but very small target reports a typedWorkOverWidthinstead of panicking.
Migration: Construct difficulty values throughCompactDifficulty's checked constructor and handleCompactDifficultyError.EncryptedCiphertextis renamedCompactCiphertext, because it holds only the 52-byte compact prefix. It is a[u8; 52]behind an exact-lengthtry_new.
Migration: RenameEncryptedCiphertexttoCompactCiphertext, and construct it withtry_newfrom exactly 52 bytes.- SingleBlockWork::new takes a NonZeroU128 and is infallible; SingleBlockWork::try_new and ZeroWork are removed.
Migration: Prove the value non-zero before the call: SingleBlockWork::new(NonZeroU128::new(work).expect(...)) or, for a literal, a const evaluated at compile time. Handle a zero where the integer is produced; the constructor no longer reports it. - AbsoluteChainWork::try_from_reported and ChainWorkOverWidth are removed; no validator Zaino reads reports chainwork, so no wire value converts into the type. to_be_bytes and a new from_be_bytes, with ChainWorkBytesError, are the one definition of the 32-byte form.
Migration: Build an AbsoluteChainWork from a NonZeroU128 through new, or fold it from SingleBlockWork values. Read 32 stored bytes with from_be_bytes, which refuses an over-width or all-zero value; there is no absence case.
zaino-rpc 0.3.0
Changed
RpcClient::call/call_with_timeouttakemethod: &'static str(bounds metric-label cardinality). Outbound metrics are nowzaino.rpc.outbound.duration_seconds{method}andzaino.rpc.outbound.errors_total{method,outcome}(transport_error,rpc_error,retried).
Migration: Pass method names as string literals. Removed metrics:zaino.rpc.outbound.requests_total,request_duration_seconds,retries_total. Featureprometheusremoved.
zaino-source 0.2.2
Added
OneShotGetCommitmentTreeRootsByHeight, with its resilient twinGetCommitmentTreeRootsByHeight: tree roots at the best-chain block at a height, answering with the block's hash alongside the roots. The hash names which block answered, so a consumer pairing this query with a concurrent hash-addressed read can detect a reorg between the two.
Changed
- dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
Internal
- Tree sizes use the checked
TreeSizetype. - Difficulty and ciphertexts use the checked
zaino-primitivestypes.
zaino-source-zebra 0.2.2
Changed
- dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
zaino-source-zebra-rpc 0.2.2
Changed
- dependency
zaino-convert-zebra0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-rpc0.2.1→0.3.0 crossed the requirement^0.2.1
Fixed
- A signed zatoshi value outside
-supply ..= supplyin a validator reply fails as a typed parse error. - Confirmation counts from the validator are parsed into the exact confirmation states and rejected when invalid.
- Transparent addresses from the validator are validated, with a typed error for an invalid one.
- The unnamed
chainSupplytotal in agetblockchaininforeply keeps its value. - The chainwork fields of getblockheader, getblock, and getblockchaininfo are no longer parsed and read as None; Zebra omits or zeroes them, and a reply without the key no longer fails.
Internal
- Adapter call helpers take
&'static strmethod names, followingzaino-rpc.
zaino-source-zebra-readstate 0.2.2
Changed
- dependency
zaino-convert-zebra0.2.1→0.3.0 crossed the requirement^0.2.1 - dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
Fixed
- A signed zatoshi value outside
-supply ..= supplyin the read state fails as a typed parse error. - Transparent addresses from the read state are validated, with a typed error for an invalid one.
getblockchaininforeports thetransparent,lockboxandironwoodpools, so the Ironwood pool no longer reads as empty across NU6.3 activation.chainSupplyis the total over every pool, not the transparent balance.
Internal
- Confirmation counts use the exact confirmation state types.
zaino-source-macros 0.1.1
Internal
- The published package carries a README, keywords and categories.
- The macros build on
syn3.
zaino-convert-zebra 0.3.0
Changed
transaction_from_zebratakes only the transaction; a transaction's position, and whether it is the coinbase, now comes from its order in the block.ConvertErrorgains aBlockvariant for converted transactions that do not form a valid block.
Migration: Drop the position argument fromtransaction_from_zebracalls, and matchConvertError::Block.ConvertErrorgainsDifficultyandCiphertextvariants. A ciphertext shorter than the compact prefix is a typed error instead of a panic.
Migration: MatchConvertError::DifficultyandConvertError::Ciphertext.- dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
zaino-consensus 0.2.0
Changed
work_from_bits,WorkErrorand theworkmodule are removed;zaino-primitivesowns the one native difficulty pipeline.
Migration: Compute work throughzaino_primitives'CompactDifficulty.
zaino-mempool 0.2.2
Changed
- dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
zaino-mempool-service 0.2.2
Added
- Poll-loop metrics
zaino.mempool.transactions,zaino.mempool.bytes{kind},zaino.mempool.unadmitted,zaino.mempool.poll_seconds.
Changed
- dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
zaino-chain-head 0.2.0
Added
ChainHeadBlockSourceis a bound alias over sixzaino-sourceports, not five: it now also requiresOneShotGetCommitmentTreeRootsByHeight. A source that implements the bound by hand must answer the new port.
Changed
- ChainHeadWork is removed; a retained block's work is now a RelativeChainWork from zaino-primitives, measured from the anchor rather than from the anchor's parent.
Migration: Replace ChainHeadWork with zaino_primitives::types::RelativeChainWork. ChainHeadWork::as_u128 has no replacement: an anchor-relative total cannot be converted to an absolute chain work, which is what that method allowed. The anchor's own work is now RelativeChainWork::ZERO, so a window's totals are each one block's work lower than before; comparisons between them are unaffected. - dependency
zaino-consensus0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
Internal
- Block work uses the
zaino-primitiveschain-work types.
zaino-chain-head-service 0.2.0
Added
- The catch-up walk fetches each block and its tree roots concurrently, through the height-addressed
OneShotGetCommitmentTreeRootsByHeightport. The two reads can straddle a reorg, so the walk compares the hash that the roots answer names against the block it fetched, and refetches the roots by hash on a mismatch.
Changed
ChainHeadAdvanceError::SourceUnavailablecarries the source'sFetchErrorinstead of aString, soError::source()returns the transport cause and itsFailureMode. A rejected query stays underInconsistentSource, naming the query.
Migration: MatchSourceUnavailable(fetch_error)and format the error withDisplaywhere a message was read from theString.- The
prometheusfeature and the implicitmetricsfeature are removed; reorg metrics are always emitted and cost nothing without an installed recorder.
Migration: Removeprometheusormetricsfrom this crate's feature list in dependent manifests. - dependency
zaino-chain-head0.1.1→0.2.0 crossed the requirement^0.1.1 - dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
Fixed
- The chain head now follows the validator when its tip moves to a lower block. Previously a retained block with more work pulled the tip back up, so a rollback was never followed. A heavier retained block is now logged as a warning instead.
- After a rollback or a reorg onto a shorter branch, heights above the new tip are no longer reported as part of the best chain. The blocks there stay available as a competing branch.
- A block from the validator that does not attach directly to the chain head's tip (wrong height or wrong parent) now fails the update as inconsistent validator data, instead of being added to the best chain.
- Reorg handling and reorg detection no longer recurse once per block. A reorg deeper than roughly 130 blocks, or a validator rollback below the retained window, overflowed the stack and aborted the process; both now walk iteratively and terminate at the retained window. (#1551)
- Every block that crosses the consensus seam is handed off to the freeze stream. Trimming ran before the handoff read the blocks it emits, so an iteration advancing the tip by more than eleven blocks settled blocks it never handed off, and reported nothing.
- The chain head follows the validator's tip, including a tip that rolls back, and refuses a block labelled with a height other than the next one. Before, the heaviest retained block won and a mislabelled block joined the best chain. The previous rule stays as a crate-private policy, TipSelection::HeaviestRetained.
zaino.sync.reorg_total/reorg_depthnow count reorgs won by a longer chain (previously missed by a height comparison); depth = blocks rewritten back to the fork point. An old tip that an advance pushed below the retained window, or that a re-anchor dropped, is an advance and not a reorg; only an old tip still inside the window counts as a reorg of unknown depth. Featureprometheusremoved; emission is unconditional.
Internal
- The in-memory chain head stores its tip block separately from the other retained blocks, so it can never be empty.
- The snapshot keeps its own invariants in the type: the tip is a field, so the graph is never empty; a block becomes canonical only as a checked child of the tip; a branch switch rewinds to the fork point first. A crate-private ChainGraph contract, with a model-based property test, runs against every implementation.
- The snapshot's tip lookup goes through a single
tip_blockaccessor. (#1482) - Value balances use the checked zatoshi quantity types.
- Fold a window's work from RelativeChainWork::ZERO at the anchor. A work overflow while extending the window is reported as ChainHeadAdvanceError::InconsistentSource rather than ReorgFailure.
- The extending block's work is proven non-zero on the NonZeroU128 step before SingleBlockWork::new, with the same error message as before.
zaino-chain-store 0.1.1
Changed
- dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
Internal
- Address balances use the checked zatoshi quantity types.
zaino-chain-store-zainodb 0.2.0
Changed
-
The crate's own chain-work type is replaced by a re-export of the
zaino-primitivestype. The on-disk format is unchanged.
Migration: Import chain work fromzaino_primitives. -
The crate's difficulty wrapper and its ciphertext pad-or-truncate helpers are removed in favour of the
zaino-primitivestypes.
Migration: Usezaino_primitives'CompactDifficultyandCompactCiphertext. -
- BlockContext, BlockHeaderData and IndexedBlock take a Work parameter: AbsoluteChainWork or Option (default).
-
Only the AbsoluteChainWork form has a stored encoding.
-
DbWrite::write_block takes IndexedBlock.
-
StoredBlockRead answers from the v1 backend only.
-
On-disk format unchanged.
Migration: - BlockContext::new and conversion::indexed_block take the chainwork in either form. -
indexed_block_from_stored yields IndexedBlock; widen with map_chainwork(Some).
-
Chain-head blocks carry None and do not type-check against the writer.
-
Sync and store metrics reworked. Added:
zaino.sync.fetched_height,block_fetch_seconds,treestate_fetch_seconds,block_assemble_seconds,batch_write_seconds,fsync_seconds,batch_blocks,accumulator_seconds{mode},accumulator_height,zaino.sync.fetched_{transactions,transparent_inputs,transparent_outputs,sapling_spends,sapling_outputs,orchard_actions,ironwood_actions}_total,zaino.db.validated_height,validation_seconds,on_demand_validations_total,map_size_bytes,used_bytes,zaino.migration.progress_height.zaino.sync.finalized_heightnow means committed and fsynced.
Migration: Removed:zaino.sync.block_build_seconds(sum of the three per-block spans),zaino.sync.block_write_seconds(→batch_write_seconds+fsync_seconds),zaino.sync.{transactions,sapling_outputs,orchard_actions}_total(→fetched_*_total),zaino.sync.last_block_written_at,zaino.db.tip_height(→zaino.sync.finalized_height),zaino.db.finalised_ephemeral,zaino.db.accumulator_built_height(→zaino.sync.accumulator_height),zaino.db.accumulator_rebuild_active(rebuild progress is logged). Throughput counters count fetched blocks: a failed commit or restart re-counts. Featureprometheusremoved; emission is unconditional (no-op without a recorder). -
FinalisedStateMode::EphemeralRoutedsplit intoEphemeralSyncingandEphemeralMigrating.
Migration: Match both new variants whereverEphemeralRoutedwas matched. -
dependency
zaino-primitives0.2.1→0.3.0 crossed the requirement^0.2.1
Fixed
- A signed zatoshi value outside
-supply ..= supplyread from disk fails as a typed error. -
- chainwork_from_parent takes the block's height; genesis seeds its own work, an unknown parent above genesis is ParentChainWorkUnknown.
- chainwork_from_parent_if_known maps that error to None for the zebra-block builder.
- A missing parent chainwork is StoreError::DataUnavailable on every build path.
Internal
- The persistent chainwork row is written from the primitive's wire render and read back through its integer, with the width and non-zero checks at the store boundary. The on-disk format is unchanged.
zaino-address 0.1.2
Internal
- The packaged lockfile picks up the workspace's minor and patch dependency updates.
zaino-common 0.5.3
Internal
- The packaged lockfile picks up the workspace's minor and patch dependency updates.
zaino-encoding 0.1.1
Internal
- The published package carries a README, keywords and categories.
zaino-status 0.1.2
Internal
- The published package carries a README, keywords and categories.