Skip to main content

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(&timestamp.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}