Aere Network public source. Everything here can be checked against the live chain (chain id 2800, https://rpc.aere.network). Scope note, stated up front rather than buried: consensus on chain 2800 is classical secp256k1 ECDSA QBFT. The post-quantum work in this repository is at the signature, precompile, account and transport layers. Nothing here makes the consensus post-quantum, and no document in it should be read as claiming so.
125 lines
5.3 KiB
Solidity
125 lines
5.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity 0.8.23;
|
|
|
|
/**
|
|
* @title AereValidatorManifest — public commitment registry for verification nodes
|
|
* @notice The 3 → 7 → 21 validator transition requires that anyone, anywhere,
|
|
* can verify which binary a validator is running and which operator
|
|
* is running it. This contract is the on-chain manifest of those
|
|
* commitments. It does NOT enroll validators (consensus enrollment is
|
|
* off-chain via Foundation Ledger + QBFT extraData); it makes the
|
|
* operator's claim machine-verifiable.
|
|
*
|
|
* For each validator a node operator registers:
|
|
* - validatorAddress QBFT signer (the address Besu uses to sign blocks)
|
|
* - operatorLabel human-readable name (e.g. "P2P Validator", "Figment")
|
|
* - operatorRegion e.g. "EU-Central / DE / Hetzner FSN-1"
|
|
* - binaryDigest SHA256 of the Besu image they're running
|
|
* - manifestUri where the binary digest's signed manifest lives
|
|
* (typically the published .well-known/besu-image-digest)
|
|
* - declaredAt unix seconds at which the operator made the claim
|
|
*
|
|
* A new commitment FOR THE SAME validatorAddress overwrites the old one,
|
|
* keyed by an incrementing serial — history is queryable via events.
|
|
* There is NO admin override; only the validator's own QBFT signer key
|
|
* can update its commitment. That ties the binary commitment to consensus
|
|
* participation: if the signer is compromised, so is the manifest, and
|
|
* everyone observes simultaneously.
|
|
*
|
|
* GOTCHA: this contract does not, and cannot, verify that the validator
|
|
* IS actually running the claimed binary. That verification is by
|
|
* third-party probing (block signature analysis, P2P handshake
|
|
* fingerprint) + the publicly reproducible build (`verify-besu-image.sh`).
|
|
* The contract gives a single canonical place to ATTEST so audits don't
|
|
* drift across mediums.
|
|
*
|
|
* WHY no admin: the manifest belongs to the operator, not the Foundation.
|
|
* The Foundation publishes its own commitment same as every other
|
|
* operator. "The chain nobody owns" is incompatible with a Foundation
|
|
* that can rewrite operator manifests.
|
|
*/
|
|
contract AereValidatorManifest {
|
|
|
|
struct Commitment {
|
|
bytes32 binaryDigest; // SHA256 (or other) of the Besu container image
|
|
string manifestUri; // ipfs:// or https:// link to the signed manifest
|
|
string operatorLabel;
|
|
string operatorRegion;
|
|
uint64 declaredAt;
|
|
uint256 serial; // monotonic per validator
|
|
}
|
|
|
|
/// @notice validator signer → most recent commitment.
|
|
mapping(address => Commitment) public latest;
|
|
|
|
/// @notice validator signer → next serial. Starts at 1.
|
|
mapping(address => uint256) public nextSerial;
|
|
|
|
/* ================================ events ================================ */
|
|
|
|
event CommitmentDeclared(
|
|
address indexed validator,
|
|
uint256 indexed serial,
|
|
bytes32 indexed binaryDigest,
|
|
string manifestUri,
|
|
string operatorLabel,
|
|
string operatorRegion,
|
|
uint64 declaredAt
|
|
);
|
|
|
|
/* ================================ errors ================================ */
|
|
|
|
error EmptyManifestUri();
|
|
error EmptyOperatorLabel();
|
|
error ZeroDigest();
|
|
|
|
/* =============================== writes =============================== */
|
|
|
|
/// @notice The validator (msg.sender == signer key) declares which binary
|
|
/// it is running + who is running it.
|
|
function declare(
|
|
bytes32 binaryDigest,
|
|
string calldata manifestUri,
|
|
string calldata operatorLabel,
|
|
string calldata operatorRegion
|
|
) external {
|
|
if (binaryDigest == bytes32(0)) revert ZeroDigest();
|
|
if (bytes(manifestUri).length == 0) revert EmptyManifestUri();
|
|
if (bytes(operatorLabel).length == 0) revert EmptyOperatorLabel();
|
|
|
|
uint256 s = ++nextSerial[msg.sender];
|
|
latest[msg.sender] = Commitment({
|
|
binaryDigest: binaryDigest,
|
|
manifestUri: manifestUri,
|
|
operatorLabel: operatorLabel,
|
|
operatorRegion: operatorRegion,
|
|
declaredAt: uint64(block.timestamp),
|
|
serial: s
|
|
});
|
|
|
|
emit CommitmentDeclared(
|
|
msg.sender, s, binaryDigest, manifestUri, operatorLabel, operatorRegion, uint64(block.timestamp)
|
|
);
|
|
}
|
|
|
|
/* ================================ views ================================ */
|
|
|
|
/// @notice True when the validator has declared at least one commitment.
|
|
function isDeclared(address validator) external view returns (bool) {
|
|
return latest[validator].declaredAt != 0;
|
|
}
|
|
|
|
/// @notice Pretty getter for indexers.
|
|
function commitmentOf(address validator) external view returns (
|
|
bytes32 binaryDigest,
|
|
string memory manifestUri,
|
|
string memory operatorLabel,
|
|
string memory operatorRegion,
|
|
uint64 declaredAt,
|
|
uint256 serial
|
|
) {
|
|
Commitment storage c = latest[validator];
|
|
return (c.binaryDigest, c.manifestUri, c.operatorLabel, c.operatorRegion, c.declaredAt, c.serial);
|
|
}
|
|
}
|