docs: Phase 6 wallet core documentation and integration test
Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
parent
11b50d0491
commit
459ff80f1f
3 changed files with 176 additions and 5 deletions
|
|
@ -18,8 +18,9 @@ wire/ Binary serialisation (CryptoNote varint encoding)
|
|||
difficulty/ PoW + PoS difficulty adjustment (LWMA variant)
|
||||
crypto/ CGo bridge to vendored C++ libcryptonote (keys, signatures, proofs)
|
||||
p2p/ CryptoNote P2P command types (handshake, sync, relay)
|
||||
rpc/ Daemon JSON-RPC 2.0 client (10 endpoints)
|
||||
rpc/ Daemon JSON-RPC 2.0 client (12 endpoints)
|
||||
chain/ Chain storage, indexing, and sync client (go-store backed)
|
||||
wallet/ Wallet core: key management, scanning, signing, TX construction
|
||||
```
|
||||
|
||||
### config/
|
||||
|
|
@ -139,6 +140,10 @@ rather than `MAP_JON_RPC`.
|
|||
- `transactions.go` -- `GetTxDetails`, `GetTransactions` (legacy).
|
||||
- `mining.go` -- `SubmitBlock`.
|
||||
|
||||
**Wallet endpoints:**
|
||||
- `wallet.go` -- `GetRandomOutputs` (for ring decoy selection via `/getrandom_outs1`)
|
||||
and `SendRawTransaction` (for transaction submission via `/sendrawtransaction`).
|
||||
|
||||
**Testing:**
|
||||
- Mock HTTP server tests for all endpoints and error paths.
|
||||
- Build-tagged integration test (`//go:build integration`) against C++ testnet
|
||||
|
|
@ -175,6 +180,54 @@ to the C++ daemon's core containers.
|
|||
- Build-tagged integration test (`//go:build integration`) syncing first 10
|
||||
blocks from C++ testnet daemon on `localhost:46941`.
|
||||
|
||||
### wallet/
|
||||
|
||||
Full send+receive wallet for the Lethean blockchain. Uses interface-driven design
|
||||
with four core abstractions so v1 (NLSAG) implementations ship now and v2+
|
||||
(Zarcanum/CLSAG) slot in later without changing callers.
|
||||
|
||||
**Core interfaces:**
|
||||
- `Scanner` -- detects outputs belonging to a wallet using ECDH derivation.
|
||||
`V1Scanner` implements v0/v1 output detection.
|
||||
- `Signer` -- produces ring signatures for transaction inputs. `NLSAGSigner`
|
||||
wraps the CGo NLSAG ring signature primitives.
|
||||
- `Builder` -- constructs signed transactions. `V1Builder` handles v1
|
||||
transactions with decoy ring selection and ECDH output derivation.
|
||||
- `RingSelector` -- picks decoy outputs for ring signatures.
|
||||
`RPCRingSelector` fetches random outputs from the daemon via RPC.
|
||||
|
||||
**Account management:**
|
||||
- `account.go` -- `Account` struct with spend and view key pairs. Key
|
||||
derivation: `viewSecret = sc_reduce32(Keccak256(spendSecret))`, matching
|
||||
the C++ `account_base::generate()` pattern. Three creation methods:
|
||||
`GenerateAccount()`, `RestoreFromSeed()`, `RestoreViewOnly()`.
|
||||
- `mnemonic.go` -- 25-word CryptoNote mnemonic encoding/decoding using the
|
||||
Electrum 1626-word dictionary. CRC32 checksum word.
|
||||
- Persistence with Argon2id (time=3, mem=64MB, threads=4) + AES-256-GCM
|
||||
encryption via go-store.
|
||||
|
||||
**Transaction extra:**
|
||||
- `extra.go` -- minimal parser for three wallet-critical variant tags: tx
|
||||
public key (tag 22), unlock time (tag 14), derivation hint (tag 11).
|
||||
Unknown tags skipped. Raw bytes preserved for round-tripping.
|
||||
|
||||
**Wallet orchestrator:**
|
||||
- `wallet.go` -- `Wallet` struct tying scanning, building, and sending.
|
||||
`Sync()` scans from last checkpoint to chain tip, detecting owned outputs
|
||||
and spent key images. `Balance()` returns confirmed vs locked amounts.
|
||||
`Send()` performs largest-first coin selection, builds, signs, and submits
|
||||
transactions via RPC. `Transfers()` lists all tracked outputs.
|
||||
|
||||
**Transfer storage:**
|
||||
- `transfer.go` -- `Transfer` struct persisted as JSON in go-store group
|
||||
`transfers`, keyed by key image hex. `IsSpendable()` checks spend status,
|
||||
coinbase maturity (MinedMoneyUnlockWindow=10), and unlock time.
|
||||
|
||||
**Testing:**
|
||||
- Unit tests with go-store `:memory:` for all components.
|
||||
- Build-tagged integration test (`//go:build integration`) syncing from
|
||||
C++ testnet daemon and verifying balance/transfers.
|
||||
|
||||
---
|
||||
|
||||
## Key Types
|
||||
|
|
|
|||
|
|
@ -374,11 +374,70 @@ groups mapping to the C++ daemon's core containers.
|
|||
|
||||
**Dependencies added:** `forge.lthn.ai/core/go-store` (local replace).
|
||||
|
||||
## Phase 6 -- Wallet Core (Planned)
|
||||
## Phase 6 -- Wallet Core
|
||||
|
||||
Implement `wallet/` with key management, output scanning, transaction
|
||||
construction, and balance calculation. Deterministic key derivation from seed
|
||||
phrases. Support for all address types.
|
||||
Commit range: `5b677d1`..`11b50d0`
|
||||
|
||||
Added `wallet/` package implementing full send+receive wallet functionality
|
||||
with interface-driven design for v1/v2+ extensibility.
|
||||
|
||||
### Files added
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `wallet/wordlist.go` | 1626-word Electrum mnemonic dictionary |
|
||||
| `wallet/mnemonic.go` | 25-word seed phrase encode/decode with CRC32 checksum |
|
||||
| `wallet/mnemonic_test.go` | Mnemonic tests (9 tests) |
|
||||
| `wallet/extra.go` | TX extra parser for tags 22/14/11 |
|
||||
| `wallet/extra_test.go` | Extra parsing tests (10 tests) |
|
||||
| `wallet/account.go` | Account key management with Argon2id+AES-256-GCM encryption |
|
||||
| `wallet/account_test.go` | Account tests (6 tests) |
|
||||
| `wallet/transfer.go` | Transfer type and go-store persistence |
|
||||
| `wallet/transfer_test.go` | Transfer tests (15 tests) |
|
||||
| `wallet/scanner.go` | Scanner interface + V1Scanner (ECDH output detection) |
|
||||
| `wallet/scanner_test.go` | Scanner tests (7 tests) |
|
||||
| `wallet/signer.go` | Signer interface + NLSAGSigner (CGo ring signatures) |
|
||||
| `wallet/signer_test.go` | Signer tests (4 tests) |
|
||||
| `wallet/ring.go` | RingSelector interface + RPCRingSelector |
|
||||
| `wallet/ring_test.go` | Ring selection tests (3 tests) |
|
||||
| `wallet/builder.go` | Builder interface + V1Builder (TX construction) |
|
||||
| `wallet/builder_test.go` | Builder tests (3 tests) |
|
||||
| `wallet/wallet.go` | Wallet orchestrator (sync, balance, send) |
|
||||
| `wallet/wallet_test.go` | Wallet orchestrator tests (2 tests) |
|
||||
| `wallet/integration_test.go` | C++ testnet integration test |
|
||||
| `rpc/wallet.go` | GetRandomOutputs + SendRawTransaction RPC endpoints |
|
||||
| `rpc/wallet_test.go` | RPC wallet endpoint tests (4 tests) |
|
||||
|
||||
### Files modified
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `types/types.go` | Added `PublicKey.IsZero()` method |
|
||||
| `crypto/bridge.h` | Added `cn_sc_reduce32()` declaration |
|
||||
| `crypto/bridge.cpp` | Added `cn_sc_reduce32()` implementation |
|
||||
| `crypto/crypto.go` | Added `ScReduce32()` Go wrapper |
|
||||
|
||||
### Key findings
|
||||
|
||||
- **View key derivation requires sc_reduce32.** The raw Keccak-256 of the
|
||||
spend secret key must be reduced modulo the Ed25519 group order before it is
|
||||
a valid scalar. Added `cn_sc_reduce32` to the CGo bridge.
|
||||
|
||||
- **Interface-driven design.** Four core interfaces (Scanner, Signer, Builder,
|
||||
RingSelector) decouple v1 implementations from the orchestrator. Future v2+
|
||||
(Zarcanum/CLSAG) implementations slot in by implementing the same interfaces.
|
||||
|
||||
- **go-store GetAll.** Transfer listing uses `store.GetAll(group)` which returns
|
||||
all key-value pairs in a group, rather than iterating with individual Gets.
|
||||
|
||||
- **CryptoNote mnemonic encoding.** The 1626-word Electrum dictionary encodes
|
||||
4 bytes into 3 words using modular arithmetic: `val = w1 + n*((n-w1+w2)%n) +
|
||||
n*n*((n-w2+w3)%n)` where n=1626. The 25th word is a CRC32 checksum.
|
||||
|
||||
### Tests added
|
||||
|
||||
63 unit tests + 1 integration test = 64 total across wallet/ and rpc/wallet.
|
||||
All passing with `-race` and `go vet`.
|
||||
|
||||
## Phase 7 -- Consensus Rules (Planned)
|
||||
|
||||
|
|
|
|||
59
wallet/integration_test.go
Normal file
59
wallet/integration_test.go
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
|
||||
//
|
||||
// Licensed under the European Union Public Licence (EUPL) version 1.2.
|
||||
// You may obtain a copy of the licence at:
|
||||
//
|
||||
// https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
|
||||
//
|
||||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
//go:build integration
|
||||
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
store "forge.lthn.ai/core/go-store"
|
||||
"forge.lthn.ai/core/go-blockchain/chain"
|
||||
"forge.lthn.ai/core/go-blockchain/rpc"
|
||||
)
|
||||
|
||||
func TestWalletIntegration(t *testing.T) {
|
||||
client := rpc.NewClient("http://localhost:46941")
|
||||
|
||||
s, err := store.New(":memory:")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
c := chain.New(s)
|
||||
|
||||
// Sync chain first.
|
||||
if err := c.Sync(client); err != nil {
|
||||
t.Fatalf("chain sync: %v", err)
|
||||
}
|
||||
|
||||
acc, err := GenerateAccount()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
w := NewWallet(acc, s, c, client)
|
||||
if err := w.Sync(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
confirmed, locked, err := w.Balance()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("Balance: confirmed=%d, locked=%d", confirmed, locked)
|
||||
|
||||
transfers, err := w.Transfers()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("Transfers: %d", len(transfers))
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue