|
|
|
|
@ -83,9 +83,17 @@ impl Efficiency {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Microjoules per accepted output token — the headline energy figure, matching
|
|
|
|
|
/// the family's `uj_per_accepted_token` convention. `0` if no tokens accepted.
|
|
|
|
|
pub fn uj_per_accepted_token(&self) -> u64 {
|
|
|
|
|
self.energy.uj().checked_div(self.tokens_out).unwrap_or(0)
|
|
|
|
|
/// the family's `uj_per_accepted_token` convention: `None` when no tokens were
|
|
|
|
|
/// accepted, because the division is undefined then.
|
|
|
|
|
///
|
|
|
|
|
/// It is not `0`. This is a cost-per-result figure, so `0` is its *optimum* —
|
|
|
|
|
/// returning it for an uncomputable ratio reported the worst outcome (spend
|
|
|
|
|
/// that bought nothing, `completed: false`) as the best one, and the figure is
|
|
|
|
|
/// sealed and read straight back out rather than recomputed. `mesh/SPEC.md`
|
|
|
|
|
/// §6 states the family convention this matches: "omitted when no tokens were
|
|
|
|
|
/// accepted".
|
|
|
|
|
pub fn uj_per_accepted_token(&self) -> Option<u64> {
|
|
|
|
|
self.energy.uj().checked_div(self.tokens_out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Accepted tokens per second — real decode throughput. `0.0` if no time
|
|
|
|
|
@ -101,7 +109,10 @@ impl Efficiency {
|
|
|
|
|
/// Micro-USD of value per accepted token — economic efficiency — when a value
|
|
|
|
|
/// figure is given. `None` otherwise (never invented).
|
|
|
|
|
pub fn uusd_per_accepted_token(&self) -> Option<u64> {
|
|
|
|
|
self.value_uusd.map(|v| v.checked_div(self.tokens_out).unwrap_or(0))
|
|
|
|
|
// `and_then`, not `map(... .unwrap_or(0))`: with no accepted tokens the
|
|
|
|
|
// ratio is undefined, and this function's contract is that a value figure
|
|
|
|
|
// is never invented.
|
|
|
|
|
self.value_uusd.and_then(|v| v.checked_div(self.tokens_out))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Commit this measurement to an external energy attestation — the raw report
|
|
|
|
|
@ -141,14 +152,22 @@ impl Efficiency {
|
|
|
|
|
"energy_uj": self.energy.uj(),
|
|
|
|
|
"provenance": self.energy.provenance.jcr1_label(),
|
|
|
|
|
"wall_ns": self.wall_ns,
|
|
|
|
|
"uj_per_accepted_token": self.uj_per_accepted_token(),
|
|
|
|
|
"seq": seq,
|
|
|
|
|
"prev": prev.to_hex(),
|
|
|
|
|
"steward": steward,
|
|
|
|
|
});
|
|
|
|
|
// Omitted when undefined, never sealed as 0 — the same shape
|
|
|
|
|
// `mesh-receipt` seals its wedge metric with, and what `mesh/SPEC.md` §6
|
|
|
|
|
// specifies. Canonical CBOR sorts keys, so insertion order here never
|
|
|
|
|
// reaches the wire.
|
|
|
|
|
if let Some(uj) = self.uj_per_accepted_token() {
|
|
|
|
|
o["uj_per_accepted_token"] = json!(uj);
|
|
|
|
|
}
|
|
|
|
|
if let Some(v) = self.value_uusd {
|
|
|
|
|
o["value_uusd"] = json!(v);
|
|
|
|
|
o["uusd_per_accepted_token"] = json!(self.uusd_per_accepted_token().unwrap_or(0));
|
|
|
|
|
if let Some(per) = self.uusd_per_accepted_token() {
|
|
|
|
|
o["uusd_per_accepted_token"] = json!(per);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if let Some(a) = &self.energy_attestation {
|
|
|
|
|
o["energy_attestation"] = json!(a);
|
|
|
|
|
@ -242,8 +261,10 @@ pub struct EfficiencyReceipt {
|
|
|
|
|
pub provenance: String,
|
|
|
|
|
/// Wall-clock nanoseconds.
|
|
|
|
|
pub wall_ns: u64,
|
|
|
|
|
/// Microjoules per accepted token (headline).
|
|
|
|
|
pub uj_per_accepted_token: u64,
|
|
|
|
|
/// Microjoules per accepted token (headline). `None` when the receipt sealed
|
|
|
|
|
/// no figure because no tokens were accepted — an undefined ratio, not zero
|
|
|
|
|
/// cost per token.
|
|
|
|
|
pub uj_per_accepted_token: Option<u64>,
|
|
|
|
|
/// Value delivered, micro-USD (when stated).
|
|
|
|
|
pub value_uusd: Option<u64>,
|
|
|
|
|
/// Hex content-id commitment to an external energy attestation (when present) —
|
|
|
|
|
@ -298,7 +319,7 @@ pub fn verify(envelope: &[u8], steward: &str, pubkey: &[u8; 32]) -> Result<Effic
|
|
|
|
|
energy_uj: u("energy_uj")?,
|
|
|
|
|
provenance: s("provenance")?,
|
|
|
|
|
wall_ns: u("wall_ns")?,
|
|
|
|
|
uj_per_accepted_token: u("uj_per_accepted_token")?,
|
|
|
|
|
uj_per_accepted_token: v.get("uj_per_accepted_token").and_then(Value::as_u64),
|
|
|
|
|
value_uusd: v.get("value_uusd").and_then(Value::as_u64),
|
|
|
|
|
energy_attestation: v.get("energy_attestation").and_then(Value::as_str).map(str::to_string),
|
|
|
|
|
seq: u("seq")?,
|
|
|
|
|
@ -356,24 +377,33 @@ pub struct Totals {
|
|
|
|
|
impl Totals {
|
|
|
|
|
/// Total tokens per completed unit — *including* the waste of failed attempts.
|
|
|
|
|
/// The number that beats "cost per token": it charges every attempt against the
|
|
|
|
|
/// results actually delivered. `0` if nothing completed.
|
|
|
|
|
pub fn tokens_per_completed_unit(&self) -> u64 {
|
|
|
|
|
/// results actually delivered. `None` when nothing completed.
|
|
|
|
|
///
|
|
|
|
|
/// The claim is that it "charges every attempt against the results actually
|
|
|
|
|
/// delivered", which it stops doing precisely when nothing was delivered: the
|
|
|
|
|
/// denominator is zero and the ratio is undefined. Reporting `0` there named
|
|
|
|
|
/// the cheapest possible cost per result for spend that produced none.
|
|
|
|
|
pub fn tokens_per_completed_unit(&self) -> Option<u64> {
|
|
|
|
|
self.completed_tokens
|
|
|
|
|
.saturating_add(self.wasted_tokens)
|
|
|
|
|
.checked_div(self.completed_units)
|
|
|
|
|
.unwrap_or(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Total microjoules per completed unit, including waste.
|
|
|
|
|
pub fn uj_per_completed_unit(&self) -> u64 {
|
|
|
|
|
/// Total microjoules per completed unit, including waste. `None` when nothing
|
|
|
|
|
/// completed — see [`Self::tokens_per_completed_unit`].
|
|
|
|
|
pub fn uj_per_completed_unit(&self) -> Option<u64> {
|
|
|
|
|
self.completed_uj
|
|
|
|
|
.saturating_add(self.wasted_uj)
|
|
|
|
|
.checked_div(self.completed_units)
|
|
|
|
|
.unwrap_or(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Micro-USD of value delivered per joule spent (including waste) — the ultimate
|
|
|
|
|
/// efficiency figure. `0.0` if no energy spent.
|
|
|
|
|
///
|
|
|
|
|
/// Kept as `0.0`, unlike the cost-per-unit ratios above: higher is better here,
|
|
|
|
|
/// so the fallback is this figure's *worst* value, not its optimum. The same
|
|
|
|
|
/// holds for [`Efficiency::tokens_per_sec`]. A zero that understates is not the
|
|
|
|
|
/// defect those `Option`s fix.
|
|
|
|
|
pub fn value_per_joule(&self) -> f64 {
|
|
|
|
|
let total_uj = self.completed_uj.saturating_add(self.wasted_uj);
|
|
|
|
|
if total_uj == 0 {
|
|
|
|
|
@ -384,13 +414,15 @@ impl Totals {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The share of spent tokens that bought nothing (0.0–1.0).
|
|
|
|
|
pub fn waste_fraction(&self) -> f64 {
|
|
|
|
|
/// The share of spent tokens that bought nothing (0.0–1.0). `None` when no
|
|
|
|
|
/// tokens were spent at all, since `0.0` is this figure's optimum — an empty
|
|
|
|
|
/// ledger reported a perfect zero-waste record.
|
|
|
|
|
pub fn waste_fraction(&self) -> Option<f64> {
|
|
|
|
|
let total = self.completed_tokens.saturating_add(self.wasted_tokens);
|
|
|
|
|
if total == 0 {
|
|
|
|
|
0.0
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
self.wasted_tokens as f64 / total as f64
|
|
|
|
|
Some(self.wasted_tokens as f64 / total as f64)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -438,7 +470,7 @@ mod tests {
|
|
|
|
|
#[test]
|
|
|
|
|
fn the_four_metrics_compute_from_the_inputs() {
|
|
|
|
|
let e = measurement("t", true, 500, 1_000_000, Some(2_000_000));
|
|
|
|
|
assert_eq!(e.uj_per_accepted_token(), 2_000); // 1e6 µJ / 500 tok
|
|
|
|
|
assert_eq!(e.uj_per_accepted_token(), Some(2_000)); // 1e6 µJ / 500 tok
|
|
|
|
|
assert_eq!(e.tokens_per_sec(), 500.0); // 500 tok / 1 s
|
|
|
|
|
assert_eq!(e.uusd_per_accepted_token(), Some(4_000)); // 2e6 µUSD / 500
|
|
|
|
|
assert_eq!(e.tokens_total(), 2_500); // 4×500 in + 500 out
|
|
|
|
|
@ -450,6 +482,96 @@ mod tests {
|
|
|
|
|
assert_eq!(e.uusd_per_accepted_token(), None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The case the sealed headline figure used to misreport: 10 J spent,
|
|
|
|
|
/// nothing accepted, `completed: false` — which the crate documents as
|
|
|
|
|
/// meaning "the tokens/joules below bought nothing".
|
|
|
|
|
///
|
|
|
|
|
/// The ratio is undefined, and `0` is the *optimum* of a cost-per-result
|
|
|
|
|
/// figure — better than any successful run — so the receipt seals no figure
|
|
|
|
|
/// rather than the best possible one. `mesh/SPEC.md` §6 specifies the same
|
|
|
|
|
/// convention: "omitted when no tokens were accepted".
|
|
|
|
|
#[test]
|
|
|
|
|
fn spend_that_bought_nothing_seals_no_headline_figure() {
|
|
|
|
|
let sk = key();
|
|
|
|
|
let e = measurement("t", false, 0, 10_000_000, None);
|
|
|
|
|
assert_eq!(e.energy.uj(), 10_000_000, "the spend is real");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
e.uj_per_accepted_token(),
|
|
|
|
|
None,
|
|
|
|
|
"0 uJ/token would read as free, and as better than any completed run"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let wire = e.wire(0, &ContentId([0u8; 32]), "did:jcp:eff");
|
|
|
|
|
assert!(
|
|
|
|
|
wire.get("uj_per_accepted_token").is_none(),
|
|
|
|
|
"an undefined figure is omitted from the signed core, not sealed as 0: {wire}"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let env = e.seal(0, &ContentId([0u8; 32]), &sk, "did:jcp:eff");
|
|
|
|
|
let rec = verify(&env, "did:jcp:eff", &sk.verifying_key().to_bytes())
|
|
|
|
|
.expect("a receipt without the figure still verifies");
|
|
|
|
|
assert_eq!(rec.uj_per_accepted_token, None);
|
|
|
|
|
assert_eq!(rec.energy_uj, 10_000_000, "and the spend is still on it");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The value projection is not invented either. `value_uusd` is an input and
|
|
|
|
|
/// still seals; the per-token ratio derived from it does not.
|
|
|
|
|
#[test]
|
|
|
|
|
fn a_value_figure_is_not_invented_without_accepted_tokens() {
|
|
|
|
|
let e = measurement("t", false, 0, 10_000_000, Some(2_000_000));
|
|
|
|
|
assert_eq!(e.uusd_per_accepted_token(), None);
|
|
|
|
|
|
|
|
|
|
let wire = e.wire(0, &ContentId([0u8; 32]), "did:jcp:eff");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
wire.get("value_uusd").and_then(Value::as_u64),
|
|
|
|
|
Some(2_000_000),
|
|
|
|
|
"the stated value is an input, not a ratio"
|
|
|
|
|
);
|
|
|
|
|
assert!(wire.get("uusd_per_accepted_token").is_none());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The aggregate half, through the real seal -> verify -> aggregate path:
|
|
|
|
|
/// units that spent energy and completed nothing have no cost per completed
|
|
|
|
|
/// unit. Not 0, which would be the cheapest ledger expressible.
|
|
|
|
|
#[test]
|
|
|
|
|
fn a_ledger_with_nothing_completed_reports_no_cost_per_unit() {
|
|
|
|
|
let sk = key();
|
|
|
|
|
let pk = sk.verifying_key().to_bytes();
|
|
|
|
|
let recs: Vec<EfficiencyReceipt> = (0..3)
|
|
|
|
|
.map(|i| {
|
|
|
|
|
let e = measurement("t", false, 0, 10_000_000, None);
|
|
|
|
|
let env = e.seal(i, &ContentId([0u8; 32]), &sk, "did:jcp:eff");
|
|
|
|
|
verify(&env, "did:jcp:eff", &pk).expect("seals and verifies")
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
for r in &recs {
|
|
|
|
|
assert_eq!(r.uj_per_accepted_token, None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let t = aggregate(&recs);
|
|
|
|
|
assert_eq!(t.completed_units, 0);
|
|
|
|
|
assert_eq!(t.wasted_units, 3);
|
|
|
|
|
assert_eq!(t.wasted_uj, 30_000_000, "30 J of real spend");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
t.uj_per_completed_unit(),
|
|
|
|
|
None,
|
|
|
|
|
"0 uJ per completed unit would be the cheapest record possible"
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(t.tokens_per_completed_unit(), None);
|
|
|
|
|
|
|
|
|
|
// An empty ledger has no waste share at all, rather than a perfect one.
|
|
|
|
|
assert_eq!(Totals::default().waste_fraction(), None);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The figures whose zero fallback is their *worst* value keep it: a zero
|
|
|
|
|
/// that understates is not the defect the `Option`s above fix.
|
|
|
|
|
#[test]
|
|
|
|
|
fn a_fallback_toward_the_worst_value_is_left_alone() {
|
|
|
|
|
let e = measurement("t", true, 0, 1_000, None);
|
|
|
|
|
assert_eq!(e.tokens_per_sec(), 0.0, "throughput: higher is better");
|
|
|
|
|
assert_eq!(Totals::default().value_per_joule(), 0.0, "value: higher is better");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn seal_verify_round_trips_and_tamper_fails() {
|
|
|
|
|
let sk = key();
|
|
|
|
|
@ -459,7 +581,7 @@ mod tests {
|
|
|
|
|
assert_eq!(rec.task, "fix-123");
|
|
|
|
|
assert!(rec.completed);
|
|
|
|
|
assert_eq!(rec.tokens_out, 400);
|
|
|
|
|
assert_eq!(rec.uj_per_accepted_token, 2_000);
|
|
|
|
|
assert_eq!(rec.uj_per_accepted_token, Some(2_000));
|
|
|
|
|
assert_eq!(rec.value_uusd, Some(1_000_000));
|
|
|
|
|
assert_eq!(rec.tokens_per_sec(), 400.0);
|
|
|
|
|
|
|
|
|
|
@ -520,9 +642,9 @@ mod tests {
|
|
|
|
|
assert_eq!(t.completed_tokens, 3_000);
|
|
|
|
|
assert_eq!(t.wasted_tokens, 4_500);
|
|
|
|
|
// tokens per completed unit charges ALL spend (7500) to the 2 done units.
|
|
|
|
|
assert_eq!(t.tokens_per_completed_unit(), 3_750);
|
|
|
|
|
assert_eq!(t.tokens_per_completed_unit(), Some(3_750));
|
|
|
|
|
assert_eq!(t.value_uusd, 1_000_000);
|
|
|
|
|
// more than half the tokens bought nothing — the number "cost/token" hides.
|
|
|
|
|
assert!(t.waste_fraction() > 0.5);
|
|
|
|
|
assert!(t.waste_fraction().expect("tokens were spent") > 0.5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|