Skip to content

Commit b71ea44

Browse files
committed
orphan buffer update and BFS
1 parent 3c12a8e commit b71ea44

File tree

4 files changed

+383
-105
lines changed

4 files changed

+383
-105
lines changed

README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Unchained
22

3-
### A post‑quantum, privacy‑preserving proof‑of‑work chain you can run today but is still in heavy development -- I tend to push to prod
3+
### A post‑quantum safe, proof‑of‑work unchain you can run today but is still in heavy development -- I tend to push to prod
44

55
Unchained is a blockchain designed for the next decades of cryptography. It combines:
66
- memory‑hard Argon2id proof‑of‑work,
@@ -9,12 +9,12 @@ Unchained is a blockchain designed for the next decades of cryptography. It comb
99
- efficient Merkle proofs per epoch,
1010
- and a simple, production‑oriented node you can compile and mine in minutes.
1111

12-
You get a straightforward UTXO‑style system with private receiving, deterministic verification, and a gossip network that favors practicality over ceremony.
12+
You get a straightforward UTXO‑style system with private transfers, deterministic verification, and a gossip network that favors practicality over ceremony.
1313

1414
### Unchained
15-
- Post‑quantum by default: Kyber768 (ML‑KEM) for private receiving, and BLAKE3 for fast hashing and domain‑separated derivations throughout.
15+
- Post‑quantum by default: Kyber768 (ML‑KEM) for private transfers, and BLAKE3 for fast hashing and domain‑separated derivations throughout.
1616
- Private by design: recipients get coins via stealth outputs; senders don’t reveal long‑term keys. Inclusion is proven via Merkle paths, not global scans.
17-
- Simple consensus: memory‑hard Argon2id PoW selects coins per epoch; every epoch commits a Merkle root. No heavy scripting, no fragile dependencies.
17+
- Simple consensus: memory‑hard Argon2id PoW selects coins per epoch; every epoch commits a Merkle root.
1818
- Efficient verification: compact proofs; local nodes verify inclusion, nullifier uniqueness, and commitments deterministically.
1919

2020
---
@@ -47,9 +47,7 @@ source "$HOME/.cargo/env"
4747
```bash
4848
git clone https://github.com/Numi2/unchained.git
4949
cd unchained
50-
cargo build --release
51-
# Start a node; it will create a wallet, sync, and can mine depending on config
52-
target/release/unchained
50+
cargo build --release && cargo run --release --bin unchained mine
5351
```
5452

5553
The first run will:

src/epoch.rs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,15 @@ impl Manager {
372372
};
373373

374374
let (difficulty, mem_kib) = if current_epoch > 0 && current_epoch % RETARGET_INTERVAL == 0 {
375-
let mut recent_anchors = Vec::new();
376-
for i in 0..RETARGET_INTERVAL {
377-
let epoch_num = current_epoch.saturating_sub(RETARGET_INTERVAL - i);
378-
if let Ok(Some(anchor)) = self.db.get::<Anchor>("epoch", &epoch_num.to_le_bytes()) {
379-
recent_anchors.push(anchor);
375+
let start = current_epoch.saturating_sub(RETARGET_INTERVAL);
376+
let window = self.db.get_or_build_retarget_window(current_epoch).unwrap_or(None);
377+
match window {
378+
Some(w) if w.len() as u64 == RETARGET_INTERVAL => calculate_retarget_consensus(&w),
379+
_ => {
380+
eprintln!("🔥 Retarget window incomplete starting at {}", start);
381+
prev_anchor.as_ref().map_or((TARGET_LEADING_ZEROS, DEFAULT_MEM_KIB), |p| (p.difficulty, p.mem_kib))
380382
}
381383
}
382-
calculate_retarget_consensus(&recent_anchors)
383384
} else {
384385
prev_anchor.as_ref().map_or((TARGET_LEADING_ZEROS, DEFAULT_MEM_KIB), |p| (p.difficulty, p.mem_kib))
385386
};
@@ -419,20 +420,36 @@ impl Manager {
419420

420421
// Persist selected coins into confirmed coin CF and index selected IDs per-epoch
421422
if let (Some(coin_cf), Some(coin_epoch_cf)) = (self.db.db.cf_handle("coin"), self.db.db.cf_handle("coin_epoch")) {
423+
let rev_cf_opt = self.db.db.cf_handle("coin_epoch_by_epoch");
424+
// Pre-serialize and reuse buffer for coin bodies
425+
let mut coin_buf: Vec<u8> = Vec::with_capacity(256);
422426
for cand in &selected {
423-
// Include creator_pk and lock_hash for spends
424427
let coin = cand.clone().into_confirmed();
425-
if let Ok(bytes) = bincode::serialize(&coin) {
428+
coin_buf.clear();
429+
if bincode::serialize_into(&mut coin_buf, &coin).is_ok() {
430+
batch.put_cf(coin_cf, &coin.id, &coin_buf);
431+
} else if let Ok(bytes) = bincode::serialize(&coin) {
426432
batch.put_cf(coin_cf, &coin.id, &bytes);
427433
}
428434
// Record the epoch number that committed this coin
429435
batch.put_cf(coin_epoch_cf, &coin.id, &current_epoch.to_le_bytes());
436+
// Reverse index: epoch_num||coin_id -> 1 for range scans
437+
if let Some(rev_cf) = rev_cf_opt {
438+
let mut key = Vec::with_capacity(8 + 32);
439+
key.extend_from_slice(&current_epoch.to_le_bytes());
440+
key.extend_from_slice(&coin.id);
441+
batch.put_cf(rev_cf, &key, &[]);
442+
}
430443
}
431444
} else if let Some(coin_cf) = self.db.db.cf_handle("coin") {
432445
// Fallback: write coins even if coin_epoch CF is missing (should not happen)
446+
let mut coin_buf: Vec<u8> = Vec::with_capacity(256);
433447
for cand in &selected {
434448
let coin = cand.clone().into_confirmed();
435-
if let Ok(bytes) = bincode::serialize(&coin) {
449+
coin_buf.clear();
450+
if bincode::serialize_into(&mut coin_buf, &coin).is_ok() {
451+
batch.put_cf(coin_cf, &coin.id, &coin_buf);
452+
} else if let Ok(bytes) = bincode::serialize(&coin) {
436453
batch.put_cf(coin_cf, &coin.id, &bytes);
437454
}
438455
}

0 commit comments

Comments
 (0)