open-standards/smart-byte/smart-byte-rs/crates/smart-byte-state/tests/frames.rs
Transaction Science f9fbd5a3af
Some checks failed
smart-byte conformance gate / Validate conformance JSON files (pull_request) Successful in 4s
smart-byte conformance gate / Second implementation reproduces every vector (pull_request) Successful in 5s
smart-byte conformance gate / Spec changes require vector-pack updates (pull_request) Successful in 4s
smart-byte conformance gate / VERSIONS.md and README.md must exist (pull_request) Successful in 3s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 4s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m51s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m24s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m41s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m10s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m38s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 7m45s
standards workspaces build + test / aac-rs (pull_request) Successful in 4m3s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m51s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 2m3s
standards workspaces build + test / map-rs (pull_request) Successful in 5m27s
standards workspaces build + test / mesh-rs (pull_request) Successful in 2m19s
standards workspaces build + test / openpay (pull_request) Successful in 10m49s
standards workspaces build + test / arl-rs (pull_request) Successful in 47m4s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 46m44s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 42m33s
standards workspaces build + test / joulehook-rs (pull_request) Failing after 18m22s
standards workspaces build + test / sense-rs (pull_request) Successful in 10m25s
standards workspaces build + test / macOS energy backend (jcp-energy) (pull_request) Successful in 4m56s
smart-byte: governance, burns and transfers between clusters, with vectors
smart-byte-state implements cluster_state.md:
- governance: Change and Proposal, electorates, the quorum, the time lock;
- burns: Burn and the retired record;
- exports: ExportStatement and Certificate;
- the import checks.

smart-byte-core: Transition::sign_export and the destination member. The
envelope compares frames within a cluster only.

smart-byte-lockstep: the committing nodes sign each committed frame's export
certificates. The certificates are built from a committing node's report,
never from a node whose state diverged.

state_vectors.json grows to 23 vectors (state-013 to state-023 new,
state-011 extended) and is regenerated in place; v1 is DRAFT. Every new check
has a vector that fails an implementation leaving it out. The README
documents the 14 new error classes, and the regeneration log records the
change.

crosscheck/verify_v1.py implements governance, burns, exports and imports
from the spec text. It reproduces every vector, 117 of them, both plain and
under -O.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 11:48:44 -04:00

381 lines
12 KiB
Rust

//! The frame transition and persistence, end to end.
use smart_byte_core::keys::IndexedSignature;
use smart_byte_core::ownership::Transition;
use smart_byte_core::{Aid, Cargo, Envelope, JouleCost, Said, SigningKey};
use smart_byte_keri_witness::{Controller, KeyEvent, KeyPair, Threshold};
use smart_byte_state::demo::Workload;
use smart_byte_state::{Input, InputClass, State, Store};
fn key(label: &str) -> KeyPair {
KeyPair::from_signing(SigningKey::from_bytes(&Said::hash(label.as_bytes()).0))
}
/// A one-key controller, its next key, and the input that incepts it.
fn party(label: &str) -> (Controller, Vec<u8>) {
let (c, icp) = Controller::incept(
vec![key(&format!("{label}-0"))],
vec![key(&format!("{label}-1"))],
Threshold(1),
Threshold(1),
vec![],
Threshold(0),
)
.unwrap();
let input = signed(&c, &KeyEvent::Inception(icp));
(c, input)
}
fn signed(c: &Controller, event: &KeyEvent) -> Vec<u8> {
let sigs: Vec<IndexedSignature> = c
.sign_event(event)
.unwrap()
.into_iter()
.map(|(index, signature)| IndexedSignature {
index: u64::from(index),
signature,
})
.collect();
Input::key_event(event, &sigs)
}
fn classes(report: &smart_byte_state::FrameReport) -> Vec<Result<(), &'static str>> {
report
.results
.iter()
.map(|r| r.outcome.as_ref().map(|_| ()).map_err(|e| e.class()))
.collect()
}
struct World {
state: State,
issuer: Controller,
alice: Controller,
bob: Controller,
byte: Envelope,
mint: Vec<u8>,
}
/// Frame 0 applied: the issuer, Alice and Bob incepted, and a USD byte
/// minted to Alice.
fn world() -> World {
let (issuer, issuer_icp) = party("issuer");
let (alice, alice_icp) = party("alice");
let (bob, bob_icp) = party("bob");
let byte = Envelope::issue(
&issuer.signer(),
alice.aid,
[7; 16],
Cargo::usd_micros(5_000_000),
JouleCost::default(),
);
let mint = Input::mint(&byte.provenance);
let mut state = State::genesis(Said::hash(b"cluster"), [(issuer.aid, 1)], [], 0);
let report = state.apply_frame(&[issuer_icp, alice_icp, bob_icp, mint.clone()]);
assert_eq!(classes(&report), vec![Ok(()); 4]);
World {
state,
issuer,
alice,
bob,
byte,
mint,
}
}
fn transfer(
owner: &Controller,
byte: &Said,
history: [u8; 32],
to: Aid,
frame: u64,
) -> (Vec<u8>, Transition) {
let t = Transition::sign(&owner.signer(), byte, history, to, frame);
(Input::transfer(byte, &t), t)
}
#[test]
fn a_byte_is_minted_and_moves() {
let mut w = world();
assert_eq!(w.state.frame, 1);
let id = w.byte.identity();
let record = &w.state.bytes[&id];
assert_eq!(
(record.owner, record.minted, record.history_hash),
(w.alice.aid, 0, id.0)
);
let (input, t) = transfer(&w.alice, &id, id.0, w.bob.aid, 1);
let report = w.state.apply_frame(&[input]);
assert_eq!(classes(&report), vec![Ok(())]);
assert_eq!(w.state.bytes[&id].owner, w.bob.aid);
assert_eq!(w.state.bytes[&id].history_hash, t.next_history_hash());
// The cluster's view agrees with the envelope a client builds.
let envelope = w.byte.transfer(&w.alice.signer(), w.bob.aid, 1);
assert_eq!(envelope.history_hash(), w.state.bytes[&id].history_hash);
}
#[test]
fn a_replayed_mint_is_refused_in_any_later_frame() {
let mut w = world();
let report = w.state.apply_frame(&[w.mint.clone()]);
assert_eq!(classes(&report), vec![Err("duplicate_byte")]);
assert_eq!(w.state.bytes.len(), 1);
}
#[test]
fn only_a_registered_issuer_mints_and_only_its_cargo_types() {
let mut w = world();
let by_alice = Envelope::issue(
&w.alice.signer(),
w.bob.aid,
[1; 16],
Cargo::usd_micros(1),
JouleCost::default(),
);
let joules = Envelope::issue(
&w.issuer.signer(),
w.bob.aid,
[2; 16],
Cargo::joules(9),
JouleCost::default(),
);
let report = w.state.apply_frame(&[
Input::mint(&by_alice.provenance),
Input::mint(&joules.provenance),
]);
assert_eq!(classes(&report), vec![Err("issuer_not_registered"); 2]);
}
#[test]
fn a_rotation_retires_the_old_keys_in_the_frame_it_lands() {
let mut w = world();
let id = w.byte.identity();
// Alice rotates; in the same frame, a transfer signed with her old key.
let rot = KeyEvent::Rotation(
w.alice
.rotate(
vec![key("alice-2")],
Threshold(1),
vec![],
vec![],
Threshold(0),
)
.unwrap(),
);
let rotation = signed(&w.alice, &rot);
let stale = Transition::sign(
&smart_byte_core::Signer::single(w.alice.aid, 0, key("alice-0").signing),
&id,
id.0,
w.bob.aid,
1,
);
let report = w
.state
.apply_frame(&[Input::transfer(&id, &stale), rotation]);
// Key events apply first, whatever the inputs' order.
assert_eq!(report.results[0].class, Some(InputClass::KeyEvent));
assert_eq!(
classes(&report),
vec![Ok(()), Err("establishment_not_in_force")]
);
// Under the new establishment, it goes through.
let (fresh, _) = transfer(&w.alice, &id, id.0, w.bob.aid, 2);
assert_eq!(classes(&w.state.apply_frame(&[fresh])), vec![Ok(())]);
}
#[test]
fn a_byte_moves_once_per_frame() {
let mut w = world();
let id = w.byte.identity();
let (to_bob, _) = transfer(&w.alice, &id, id.0, w.bob.aid, 1);
let (to_issuer, _) = transfer(&w.alice, &id, id.0, w.issuer.aid, 1);
let report = w.state.apply_frame(&[to_bob.clone(), to_issuer.clone()]);
let mut outcomes = classes(&report);
outcomes.sort();
assert_eq!(outcomes, vec![Ok(()), Err("broken_history_chain")]);
// The input with the lower digest won.
let lower = std::cmp::min(
*blake3::hash(&to_bob).as_bytes(),
*blake3::hash(&to_issuer).as_bytes(),
);
assert_eq!(
(report.results[0].input, report.results[0].outcome.is_ok()),
(lower, true)
);
}
#[test]
fn transfers_are_checked_against_the_byte_and_the_frame() {
let mut w = world();
let id = w.byte.identity();
let (late, _) = transfer(&w.alice, &id, id.0, w.bob.aid, 9);
let (not_owner, _) = transfer(&w.bob, &id, id.0, w.alice.aid, 1);
let (stale_history, _) = transfer(&w.alice, &id, [0; 32], w.bob.aid, 1);
let (unknown, _) = transfer(
&w.alice,
&Said::hash(b"no such byte"),
[0; 32],
w.bob.aid,
1,
);
let report = w
.state
.apply_frame(&[late, not_owner, stale_history, unknown]);
let mut outcomes = classes(&report);
outcomes.sort();
assert_eq!(
outcomes,
vec![
Err("broken_history_chain"),
Err("not_current_owner"),
Err("unknown_byte"),
Err("wrong_frame")
]
);
assert_eq!(w.state.bytes[&id].owner, w.alice.aid);
}
#[test]
fn a_mint_and_its_first_transfer_share_a_frame() {
let (issuer, issuer_icp) = party("issuer");
let (alice, alice_icp) = party("alice");
let byte = Envelope::issue(
&issuer.signer(),
alice.aid,
[3; 16],
Cargo::usd_micros(1),
JouleCost::default(),
);
let id = byte.identity();
let (move_it, _) = transfer(&alice, &id, id.0, issuer.aid, 0);
let mut state = State::genesis(Said::hash(b"cluster"), [(issuer.aid, 1)], [], 0);
let report = state.apply_frame(&[
move_it,
Input::mint(&byte.provenance),
alice_icp,
issuer_icp,
]);
assert_eq!(classes(&report), vec![Ok(()); 4]);
assert_eq!(state.bytes[&id].owner, issuer.aid);
}
#[test]
fn identical_inputs_are_one_input() {
let mut w = world();
let id = w.byte.identity();
let (input, _) = transfer(&w.alice, &id, id.0, w.bob.aid, 1);
let report = w.state.apply_frame(&[input.clone(), input.clone(), input]);
assert_eq!(classes(&report), vec![Ok(())]);
assert_eq!(report.inputs.len(), 1);
}
#[test]
fn a_controller_signs_only_once_its_log_is_in_the_cluster() {
let (issuer, issuer_icp) = party("issuer");
let (carol, carol_icp) = party("carol");
let byte = Envelope::issue(
&issuer.signer(),
carol.aid,
[4; 16],
Cargo::usd_micros(1),
JouleCost::default(),
);
let id = byte.identity();
let mut state = State::genesis(Said::hash(b"cluster"), [(issuer.aid, 1)], [], 0);
state.apply_frame(&[issuer_icp, Input::mint(&byte.provenance)]);
let (early, _) = transfer(&carol, &id, id.0, issuer.aid, 1);
assert_eq!(
classes(&state.apply_frame(&[early])),
vec![Err("unknown_controller")]
);
// Carol's inception and her transfer in one frame: key events first.
let (now, _) = transfer(&carol, &id, id.0, issuer.aid, 2);
assert_eq!(
classes(&state.apply_frame(&[now, carol_icp])),
vec![Ok(()), Ok(())]
);
}
#[test]
fn key_events_extend_the_cluster_s_logs() {
let mut w = world();
let (alice_again, _) = party("alice");
let (dora, _) = party("dora");
let dora_rot = KeyEvent::Rotation({
let mut d = dora;
d.rotate(
vec![key("dora-2")],
Threshold(1),
vec![],
vec![],
Threshold(0),
)
.unwrap()
});
let alice_icp_again = {
let icp = alice_again.key_event_log[0].clone();
signed(&alice_again, &icp)
};
let report = w
.state
.apply_frame(&[alice_icp_again, signed(&w.bob, &dora_rot)]);
let mut outcomes = classes(&report);
outcomes.sort();
assert_eq!(
outcomes,
vec![Err("controller_exists"), Err("unknown_controller")]
);
}
#[test]
fn the_demo_workload_runs_and_is_deterministic() {
let run = || {
let mut workload = Workload::new(3, 2);
let mut state = workload.genesis();
let mut hashes = Vec::new();
for f in 0..5 {
let report = state.apply_frame(&workload.frame(f));
assert_eq!(
report.applied(),
report.results.len(),
"frame {f}: every input applies"
);
hashes.push(state.hash());
}
(state, hashes)
};
let (a, ha) = run();
let (b, hb) = run();
assert_eq!((a.frame, a.bytes.len(), a.controllers.len()), (5, 6, 4));
assert_eq!((ha, a), (hb, b));
}
#[test]
fn a_store_recovers_the_state_and_refuses_a_tampered_log() {
let dir = tempfile::tempdir().unwrap();
let mut workload = Workload::new(2, 1);
let genesis = workload.genesis();
let (mut store, mut state) = Store::open_with_genesis(dir.path(), 3, &genesis).unwrap();
assert_eq!(state, genesis);
for f in 0..5 {
let report = state.apply_frame(&workload.frame(f));
store.commit(report.frame, &report.inputs, &state).unwrap();
}
drop(store);
// Five frames at a cadence of three: a checkpoint at frame 3, two logged.
let (_, recovered) = Store::open_with_genesis(dir.path(), 3, &genesis).unwrap();
assert_eq!(recovered, state);
// A flipped byte in the log's last record.
let log = dir.path().join(smart_byte_state::store::LOG);
let mut bytes = std::fs::read(&log).unwrap();
let last = bytes.len() - 1;
bytes[last] ^= 1;
std::fs::write(&log, bytes).unwrap();
assert!(matches!(
Store::open_with_genesis(dir.path(), 3, &genesis),
Err(smart_byte_state::StoreError::Corrupt(_))
));
}