entropa_core/block.rs
1//! Blocks and transactions.
2//!
3//! A [`Block`] is one point in Entropa's growing constellation. It bundles a set of
4//! [`Transaction`]s, the cosmic-entropy `beacon` that seeded this round, the proposing
5//! Probe's public identity, a blake3 `hash` over the canonical preimage, and a
6//! post-quantum `signature` by the proposer over that hash.
7
8use serde::{Deserialize, Serialize};
9
10/// A single transaction — a signal the network records.
11#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
12pub struct Transaction {
13 /// Originating actor (a Probe id, or an external identifier).
14 pub from: String,
15 /// What kind of signal, e.g. `"transfer"`, `"register"`, `"attest"`.
16 pub kind: String,
17 /// Canonical payload or content-hash.
18 pub payload: String,
19}
20
21impl Transaction {
22 pub fn new(
23 from: impl Into<String>,
24 kind: impl Into<String>,
25 payload: impl Into<String>,
26 ) -> Self {
27 Self {
28 from: from.into(),
29 kind: kind.into(),
30 payload: payload.into(),
31 }
32 }
33}
34
35/// One block in the chain.
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct Block {
38 pub index: u64,
39 pub timestamp: u64,
40 pub prev_hash: String,
41 /// Cosmic entropy beacon value that seeded this round.
42 pub beacon: String,
43 pub transactions: Vec<Transaction>,
44 /// Proposing Probe's fingerprint, e.g. `PROBE-1A2B3C4D`.
45 pub proposer_id: String,
46 /// Proposing Probe's hex ML-DSA verifying key (used to verify `signature`).
47 pub proposer_pubkey: String,
48 /// blake3 digest (hex) over the canonical preimage.
49 pub hash: String,
50 /// Proposer's post-quantum ML-DSA signature (hex) over the raw digest bytes.
51 pub signature: String,
52}
53
54/// Compute the canonical blake3 digest that a block's `hash` commits to and that the
55/// proposer signs. Deterministic and order-sensitive — any change to any field
56/// changes the digest.
57pub fn block_digest(
58 index: u64,
59 timestamp: u64,
60 prev_hash: &str,
61 beacon: &str,
62 transactions: &[Transaction],
63 proposer_id: &str,
64) -> [u8; 32] {
65 let mut hasher = blake3::Hasher::new();
66 hasher.update(&index.to_be_bytes());
67 hasher.update(×tamp.to_be_bytes());
68 hasher.update(prev_hash.as_bytes());
69 hasher.update(beacon.as_bytes());
70 hasher.update(proposer_id.as_bytes());
71 // Canonical serialization of the transaction set.
72 let tx_bytes = serde_json::to_vec(transactions).expect("transactions serialize");
73 hasher.update(&tx_bytes);
74 *hasher.finalize().as_bytes()
75}