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-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]>
162 lines
5.1 KiB
Rust
162 lines
5.1 KiB
Rust
//! A deterministic workload for simulations and tests: one issuer, a ring of
|
|
//! holders, and the bytes the issuer mints to them passed around the ring.
|
|
//!
|
|
//! Frame 0 carries every party's inception and the mints; each later frame
|
|
//! moves every byte one holder along. Keys derive from labels, so the same
|
|
//! workload produces the same inputs — and so the same state hashes — on
|
|
//! every run.
|
|
|
|
use smart_byte_core::keys::IndexedSignature;
|
|
use smart_byte_core::ownership::Transition;
|
|
use smart_byte_core::{Aid, Blake3Hash, Cargo, Envelope, JouleCost, Said, Signer, SigningKey};
|
|
use smart_byte_keri_witness::{Controller, KeyEvent, KeyPair, Threshold};
|
|
|
|
use crate::input::Input;
|
|
use crate::state::State;
|
|
|
|
/// The cargo type the demo issuer is registered for: USD.
|
|
pub const USD: u64 = 1;
|
|
|
|
/// The demo cluster's identifier.
|
|
pub fn cluster() -> Said {
|
|
Said::hash(b"smart-byte demo cluster")
|
|
}
|
|
|
|
fn key(label: &str) -> KeyPair {
|
|
let seed = Said::hash(format!("smart-byte demo key {label}").as_bytes()).0;
|
|
KeyPair::from_signing(SigningKey::from_bytes(&seed))
|
|
}
|
|
|
|
/// A party: its controller (whose current keys sign) and its inception, as
|
|
/// an input.
|
|
struct Party {
|
|
controller: Controller,
|
|
inception: Vec<u8>,
|
|
}
|
|
|
|
impl Party {
|
|
fn new(label: &str) -> Self {
|
|
let (controller, icp) = Controller::incept(
|
|
vec![key(&format!("{label}-0"))],
|
|
vec![key(&format!("{label}-1"))],
|
|
Threshold(1),
|
|
Threshold(1),
|
|
vec![],
|
|
Threshold(0),
|
|
)
|
|
.expect("a one-key inception");
|
|
let event = KeyEvent::Inception(icp);
|
|
let signatures: Vec<IndexedSignature> = controller
|
|
.sign_event(&event)
|
|
.expect("the controller signs its inception")
|
|
.into_iter()
|
|
.map(|(index, signature)| IndexedSignature {
|
|
index: u64::from(index),
|
|
signature,
|
|
})
|
|
.collect();
|
|
Party {
|
|
inception: Input::key_event(&event, &signatures),
|
|
controller,
|
|
}
|
|
}
|
|
|
|
fn signer(&self) -> Signer {
|
|
self.controller.signer()
|
|
}
|
|
|
|
fn aid(&self) -> Aid {
|
|
self.controller.aid
|
|
}
|
|
}
|
|
|
|
/// A byte in the workload: its identity, owner and history hash.
|
|
struct Held {
|
|
identity: Said,
|
|
owner: usize,
|
|
history: Blake3Hash,
|
|
}
|
|
|
|
/// The workload.
|
|
pub struct Workload {
|
|
issuer: Party,
|
|
holders: Vec<Party>,
|
|
bytes: Vec<Held>,
|
|
mints: Vec<Vec<u8>>,
|
|
}
|
|
|
|
impl Workload {
|
|
/// One issuer, `holders` holders, and `per_holder` USD bytes minted to
|
|
/// each.
|
|
pub fn new(holders: usize, per_holder: usize) -> Self {
|
|
let issuer = Party::new("issuer");
|
|
let holders: Vec<Party> = (0..holders.max(1))
|
|
.map(|i| Party::new(&format!("holder-{i}")))
|
|
.collect();
|
|
let mut bytes = Vec::new();
|
|
let mut mints = Vec::new();
|
|
for (owner, holder) in holders.iter().enumerate() {
|
|
for k in 0..per_holder {
|
|
let nonce: [u8; 16] =
|
|
Said::hash(format!("smart-byte demo nonce {owner}-{k}").as_bytes()).0[..16]
|
|
.try_into()
|
|
.expect("sixteen bytes");
|
|
let micros = 1_000_000 * (1 + (owner * per_holder + k) as i64);
|
|
let byte = Envelope::issue(
|
|
&issuer.signer(),
|
|
holder.aid(),
|
|
nonce,
|
|
Cargo::usd_micros(micros),
|
|
JouleCost::default(),
|
|
);
|
|
mints.push(Input::mint(&byte.provenance));
|
|
bytes.push(Held {
|
|
identity: byte.identity(),
|
|
owner,
|
|
history: byte.identity().0,
|
|
});
|
|
}
|
|
}
|
|
Workload {
|
|
issuer,
|
|
holders,
|
|
bytes,
|
|
mints,
|
|
}
|
|
}
|
|
|
|
/// The genesis state of the demo cluster: the issuer registered for USD,
|
|
/// no peers, and no governance delay.
|
|
pub fn genesis(&self) -> State {
|
|
State::genesis(cluster(), [(self.issuer.aid(), USD)], [], 0)
|
|
}
|
|
|
|
/// Frame `frame`'s inputs. Frame 0 incepts every party and mints; each
|
|
/// later frame moves every byte to the next holder. Frames must be taken
|
|
/// in order.
|
|
pub fn frame(&mut self, frame: u64) -> Vec<Vec<u8>> {
|
|
if frame == 0 {
|
|
let mut inputs = vec![self.issuer.inception.clone()];
|
|
inputs.extend(self.holders.iter().map(|h| h.inception.clone()));
|
|
inputs.extend(self.mints.iter().cloned());
|
|
return inputs;
|
|
}
|
|
let ring = self.holders.len();
|
|
self.bytes
|
|
.iter_mut()
|
|
.map(|held| {
|
|
let to = (held.owner + 1) % ring;
|
|
let t = Transition::sign(
|
|
&self.holders[held.owner].signer(),
|
|
&held.identity,
|
|
held.history,
|
|
self.holders[to].aid(),
|
|
frame,
|
|
);
|
|
held.owner = to;
|
|
held.history = t.next_history_hash();
|
|
Input::transfer(&held.identity, &t)
|
|
})
|
|
.collect()
|
|
}
|
|
}
|