mod common;
use chia_protocol::CoinState;
use dig_clvm::ValidationConfig;
use dig_block::prelude::*;
use dig_block::traits::SignerError;
struct EmptyCoins;
impl CoinLookup for EmptyCoins {
fn get_coin_state(&self, _id: &Bytes32) -> Option<CoinState> {
None
}
fn get_chain_height(&self) -> u64 {
0
}
fn get_chain_timestamp(&self) -> u64 {
0
}
}
struct SmokeSigner {
sk: chia_bls::SecretKey,
}
impl SmokeSigner {
fn new() -> Self {
let (sk, _) = common::stv_test_proposer_keypair();
Self { sk }
}
fn public_key(&self) -> PublicKey {
self.sk.public_key()
}
}
impl BlockSigner for SmokeSigner {
fn sign_block(&self, header_hash: &Bytes32) -> Result<Signature, SignerError> {
Ok(chia_bls::sign(&self.sk, header_hash.as_ref()))
}
}
#[test]
fn prelude_covers_quickstart_surface() {
let _: Option<L2BlockHeader> = None;
let _: Option<L2Block> = None;
let _: Option<AttestedBlock> = None;
let _: Option<Checkpoint> = None;
let _: Option<CheckpointSubmission> = None;
let _: Option<Receipt> = None;
let _: Option<ReceiptList> = None;
let _ = ReceiptStatus::Success;
let _: Option<SignerBitmap> = None;
let _ = BlockStatus::Pending;
let _ = CheckpointStatus::Pending;
let _: Option<BlockError> = None;
let _: Option<BuilderError> = None;
let _: Option<CheckpointError> = None;
let _: Cost = 0;
let _: Bytes32 = Bytes32::default();
let _: Signature = Signature::default();
let _: PublicKey = PublicKey::default();
let _: Option<ExecutionResult> = None;
let _: Option<BlockBuilder> = None;
let _: Option<CheckpointBuilder> = None;
}
#[test]
fn builder_output_validates_end_to_end() {
let signer = SmokeSigner::new();
let pk = signer.public_key();
let parent = Bytes32::new([0x11; 32]);
let l1_hash = Bytes32::new([0x22; 32]);
let mut builder = BlockBuilder::new(
1, 0, parent, 100, l1_hash,
0,
);
let bundle = common::test_spend_bundle();
builder
.add_spend_bundle(bundle, 0, 0)
.expect("add bundle");
let additions_snapshot = builder.additions.clone();
let removals_snapshot = builder.removals.clone();
let mut ephemeral_additions = additions_snapshot.clone();
for coin_spend in &builder.spend_bundles[0].coin_spends {
ephemeral_additions.push(coin_spend.coin);
}
let state_root =
dig_block::compute_state_root_from_delta(&ephemeral_additions, &removals_snapshot);
let receipts_root = dig_block::EMPTY_ROOT;
let block = builder
.build(state_root, receipts_root, &signer)
.expect("builder must produce a valid block");
block
.validate_structure()
.expect("builder output must be structurally valid");
let exec = ExecutionResult {
additions: ephemeral_additions,
removals: removals_snapshot,
..Default::default()
};
let returned_root = block
.validate_state(&exec, &EmptyCoins, &pk)
.expect("tier 3 with aligned state_root");
assert_eq!(returned_root, state_root);
let _ = ValidationConfig::default(); }
#[test]
fn wire_round_trip_via_public_serde() {
let signer = SmokeSigner::new();
let mut builder = BlockBuilder::new(
1,
0,
Bytes32::new([0x33; 32]),
1,
Bytes32::new([0x44; 32]),
0,
);
builder
.add_spend_bundle(common::test_spend_bundle(), 0, 0)
.expect("add bundle");
let mut additions = builder.additions.clone();
let removals = builder.removals.clone();
for coin_spend in &builder.spend_bundles[0].coin_spends {
additions.push(coin_spend.coin);
}
let state_root = dig_block::compute_state_root_from_delta(&additions, &removals);
let block = builder
.build(state_root, dig_block::EMPTY_ROOT, &signer)
.expect("builder");
let bytes = block.to_bytes();
let decoded = L2Block::from_bytes(&bytes).expect("decode");
assert_eq!(block.header, decoded.header);
assert_eq!(decoded.to_bytes(), bytes);
}
#[test]
fn traits_are_object_safe() {
let boxed_coins: Box<dyn CoinLookup> = Box::new(EmptyCoins);
assert_eq!(boxed_coins.get_chain_height(), 0);
let _ = boxed_coins.get_coin_state(&Bytes32::default());
let signer = SmokeSigner::new();
let boxed_signer: Box<dyn BlockSigner> = Box::new(signer);
let sig = boxed_signer
.sign_block(&Bytes32::new([0xAB; 32]))
.expect("sign");
assert_ne!(sig, Signature::default());
}
#[test]
fn empty_inputs_produce_empty_roots() {
assert_eq!(dig_block::compute_spends_root(&[]), dig_block::EMPTY_ROOT);
assert_eq!(
dig_block::compute_additions_root(&[]),
dig_block::EMPTY_ROOT
);
assert_eq!(dig_block::compute_removals_root(&[]), dig_block::EMPTY_ROOT);
assert_eq!(dig_block::compute_receipts_root(&[]), dig_block::EMPTY_ROOT);
assert_eq!(
dig_block::compute_state_root_from_delta(&[], &[]),
dig_block::EMPTY_ROOT
);
}
#[test]
fn protocol_constants_exposed_at_crate_root() {
assert_eq!(dig_block::VERSION_V1, 1);
assert_eq!(dig_block::VERSION_V2, 2);
assert_eq!(dig_block::MAX_BLOCK_SIZE, 10_000_000);
assert_eq!(dig_block::MAX_COST_PER_BLOCK, 550_000_000_000);
assert_eq!(dig_block::MAX_FUTURE_TIMESTAMP_SECONDS, 300);
assert_eq!(dig_block::HASH_LEAF_PREFIX, 0x01);
assert_eq!(dig_block::HASH_TREE_PREFIX, 0x02);
assert_eq!(dig_block::MAX_VALIDATORS, 65_536);
assert_eq!(dig_block::DFSP_ACTIVATION_HEIGHT, u64::MAX);
assert_ne!(dig_block::EMPTY_ROOT, dig_block::ZERO_HASH);
}