Uses reusable workflows from core/go-devops for Go testing
(with race detector and coverage) and security scanning
(govulncheck, gitleaks, trivy).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements StatusModel as a cli.FrameModel that renders a single-line
chain status bar showing height, sync percentage, difficulty, peer
count and tip age. Includes formatAge and formatDifficulty helpers
with SI suffixes. Adds core/cli as a direct dependency.
Co-Authored-By: Charon <charon@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add forge.lthn.ai/core/cli to go.mod with replace directive pointing
to the local workspace path. Also adds transitive replace directives
for core/go and core/go-crypt which are dependencies of core/cli.
Co-Authored-By: Charon <charon@lethean.io>
Standalone TUI in go-blockchain using core/cli Frame (bubbletea).
Day-one scope: chain sync status header + block explorer content.
Model library pattern (tui/) with thin cmd/chain/ wiring.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add full V2 transaction verification pipeline: parse SignaturesRaw variant
vector into structured ZC signature data, verify CLSAG GGX ring signatures
per ZC input, verify BPP range proofs, and verify BGE asset surjection
proofs with correct ring construction (mul8 point arithmetic).
Fix three wire format bugs that caused V2 parsing failures:
- RefTypeGlobalIndex (tag 0x1A) uses 8-byte LE, not varint
- Raw uint64_t variant (tagUint64) uses 8-byte LE, not varint
- zarcanum_tx_data_v1 fee uses FIELD() → 8-byte LE, not VARINT_FIELD()
Add cn_point_sub to C++ bridge and Go wrapper for BGE ring construction.
Add GetZCRingOutputs to chain for fetching ZC ring member data.
Co-Authored-By: Charon <charon@lethean.io>
Rewrites the LWMA difficulty algorithm to match the C++ daemon exactly:
- Uses N=60 window with linear weighting (position 1..n)
- Clamps solve times to [-6T, 6T]
- Excludes genesis block from the difficulty window
- Selects target based on hardfork: 120s pre-HF2, 240s post-HF2
On testnet, HF2 activates at height 10 (active from height 11),
doubling the target from 120s to 240s. The previous fixed 120s target
produced exactly half the expected difficulty from height 11 onward.
Integration test verifies all 2576 testnet blocks match the daemon.
Co-Authored-By: Charon <charon@lethean.io>
Local difficulty computation for P2P sync — replaces hardcoded
difficulty=0 with LWMA-based calculation from stored block history.
Co-Authored-By: Charon <charon@lethean.io>
LevinP2PConn wraps a levin.Connection to implement the P2PConnection
interface, handling timed_sync keep-alive responses automatically.
Integration test syncs the full testnet chain (2577 blocks) via P2P
in under 5 seconds.
Co-Authored-By: Charon <charon@lethean.io>
RESPONSE_CHAIN_ENTRY includes the fork-point block as its first
entry. The sync loop now skips blocks already stored to avoid
height validation failures on subsequent chain iterations.
Co-Authored-By: Charon <charon@lethean.io>
SparseChainHistory returned a zero hash when the chain was empty,
which the daemon could not resolve. Send the genesis hash instead
so the peer can locate the fork point and respond with chain entries.
Co-Authored-By: Charon <charon@lethean.io>
Performs handshake, REQUEST_CHAIN with genesis hash, reads
RESPONSE_CHAIN_ENTRY, then REQUEST_GET_OBJECTS with the first block
hash and verifies RESPONSE_GET_OBJECTS returns a non-empty block blob.
Also fixes the existing handshake test return code check — the C++
daemon handler returns 1 (not 0) on success.
Co-Authored-By: Charon <charon@lethean.io>
Three bugs found by integration testing against the C++ testnet daemon:
1. NetworkIDMainnet/Testnet had byte 10 swapped — the C++ #ifndef TESTNET
branch (mainnet) sets P2P_NETWORK_ID_TESTNET_FLAG=1, and the #else
(testnet) sets it to 0. Counter-intuitive but matches compiled binaries.
2. ClientVersion format "Lethean/go-blockchain 0.1.0" was rejected by the
daemon's parse_client_version which expects "major.minor.rev.build[commit]".
Changed to "6.0.1.2[go-blockchain]".
3. RequestChain, RequestGetObjects, and ResponseGetObjects used StringArrayVal
for hash fields, but the C++ daemon uses KV_SERIALIZE_CONTAINER_POD_AS_BLOB
which packs all 32-byte hashes into a single concatenated blob. Also,
ResponseChainEntry.m_block_ids is an object array of block_context_info
(hash + cumulative size), not a simple hash list.
Co-Authored-By: Charon <charon@lethean.io>
P2PSync() runs the REQUEST_CHAIN / REQUEST_GET_OBJECTS loop against
a P2PConnection interface. Reuses processBlockBlobs() for shared
validation logic.
Co-Authored-By: Charon <charon@lethean.io>
Encode/decode for NOTIFY_REQUEST_GET_OBJECTS (2003) and
NOTIFY_RESPONSE_GET_OBJECTS (2004), including BlockCompleteEntry
for block + transaction blob pairs.
Co-Authored-By: Charon <charon@lethean.io>
The block processing logic is now in processBlockBlobs() which takes
raw wire bytes. The RPC processBlock() becomes a thin hex-decode
wrapper. The P2P sync path will call processBlockBlobs() directly.
Co-Authored-By: Charon <charon@lethean.io>
The Zano daemon's get_blocks_details RPC does not populate the blob
field. This adds resolveBlockBlobs() which batch-fetches miner tx
blobs via /gettransactions and reconstructs block wire blobs from
the parsed header (object_in_json AGGREGATED section) and raw tx
bytes. Also fixes regular tx processing to skip the miner tx entry
that the daemon includes in transactions_details.
Co-Authored-By: Charon <charon@lethean.io>
TxInputZC (v2+) inputs have key images that must be tracked for
double-spend detection, same as TxInputToKey.
Co-Authored-By: Charon <charon@lethean.io>
Implements consensus.RingOutputsFn by looking up output public keys from
the chain's global output index and transaction store. Wired into the
sync loop so VerifySignatures=true uses real crypto verification.
Co-Authored-By: Charon <charon@lethean.io>
Connect crypto.CheckRingSignature() to verifyV1Signatures() so
pre-HF4 transactions have their ring signatures cryptographically
verified when a RingOutputsFn callback is provided.
Co-Authored-By: Charon <charon@lethean.io>
Three-part design: NLSAG signature verification, full RPC sync to tip,
and P2P block sync via REQUEST_CHAIN / REQUEST_GET_OBJECTS. 13-task
implementation plan with TDD steps.
Co-Authored-By: Charon <charon@lethean.io>
Fix three bugs in the v2+ wire format and add complete variant tag handlers
for Zarcanum proof and signature structures. Verified byte-identical
round-trip against a real post-HF4 coinbase transaction from testnet block
101 (1323 bytes, tx hash 543bc3c2...3b61e0).
Bugs fixed:
- V2 suffix order was attachment+proofs, corrected to attachment+signatures+proofs
- TransactionHash was hashing full blob, corrected to prefix-only (matching C++)
- tagSignedParts was reading 4 fixed bytes, corrected to two varints
New: TxInputZC type, SignaturesRaw field, tagZarcanumTxDataV1 handler,
proof tags 46-48, signature tags 42-45, crypto blob readers for BPP/BPPE/
BGE/CLSAG GGX/GGXXG/aggregation proof/double Schnorr structures.
Co-Authored-By: Charon <charon@lethean.io>
Add cn_bpp_verify for Bulletproofs++ (1 delta, bpp_crypto_trait_ZC_out)
used by zc_outs_range_proof in post-HF4 transactions. Distinguish from
cn_bppe_verify (2 deltas, bpp_crypto_trait_Zarcanum) used for Zarcanum
PoS proofs.
Key changes:
- Add deserialise_bpp() and cn_bpp_verify() to bridge.cpp
- Add VerifyBPP() Go wrapper in proof.go
- Wire BPPE and BGE stubs into real C++ verify functions
- Add try/catch to all proof verifiers (C++ throws on invalid points)
- Add nil/empty input guards to all Go proof functions
- Test with real BPP proof from testnet block 101 coinbase tx
The BPP proof from tx 543bc3c2... (first post-HF4 coinbase) verifies
successfully through the full CGo pipeline, confirming wire format
deserialisation matches the C++ daemon output.
Co-Authored-By: Charon <charon@lethean.io>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port of C++ get_block_header_mining_hash(). Computes BlockHashingBlob
with nonce=0, Keccak-256's it. CheckNonce wraps RandomX + difficulty.
Co-Authored-By: Charon <charon@lethean.io>
Solo PoW miner against C++ daemon via JSON-RPC. Single-threaded
RandomX nonce grinding with daemon-provided block templates.
Co-Authored-By: Charon <charon@lethean.io>
Add integration test, update architecture docs with consensus/ package
description, record Phase 7 in project history.
Co-Authored-By: Charon <charon@lethean.io>