use crate::imp::core::{Bytes32, ChiaBlockRef};
use crate::imp::prover::{ChainSource, CoinsetChainSource};
const STATE_JSON: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/get_blockchain_state.json"
));
const PEAK_RECORD_JSON: &str = r#"{
"block_record": {
"header_hash": "0xb5f2a7c1d3e4f5061728394a5b6c7d8e9f00112233445566778899aabbccddee",
"height": 5421337,
"timestamp": 1717804800,
"prev_transaction_block_height": 5421330
},
"success": true
}"#;
fn peak_header_hash() -> Bytes32 {
Bytes32::from_hex("b5f2a7c1d3e4f5061728394a5b6c7d8e9f00112233445566778899aabbccddee").unwrap()
}
#[test]
fn mocked_get_peak_parses_canned_blockchain_state() {
let server = httpmock::MockServer::start();
let m = server.mock(|when, then| {
when.method(httpmock::Method::POST)
.path("/get_blockchain_state");
then.status(200)
.header("content-type", "application/json")
.body(STATE_JSON);
});
let src = CoinsetChainSource::new(server.base_url());
let block = src.get_peak().expect("get_peak parses the canned state");
m.assert();
assert_eq!(block.height, 5_421_337);
assert_eq!(block.timestamp, 1_717_804_800);
assert_eq!(block.header_hash, peak_header_hash());
}
#[test]
fn mocked_verify_block_accepts_fresh_on_chain_block() {
let server = httpmock::MockServer::start();
let _rec = server.mock(|when, then| {
when.method(httpmock::Method::POST)
.path("/get_block_record_by_height");
then.status(200)
.header("content-type", "application/json")
.body(PEAK_RECORD_JSON);
});
let _state = server.mock(|when, then| {
when.method(httpmock::Method::POST)
.path("/get_blockchain_state");
then.status(200)
.header("content-type", "application/json")
.body(STATE_JSON);
});
let src = CoinsetChainSource::new(server.base_url());
let block = ChiaBlockRef {
header_hash: peak_header_hash(),
height: 5_421_337,
timestamp: 1_717_804_800,
};
src.verify_block(&block, 600)
.expect("a fresh on-chain block verifies");
}
#[test]
fn mocked_verify_block_rejects_block_not_on_chain() {
let server = httpmock::MockServer::start();
server.mock(|when, then| {
when.method(httpmock::Method::POST)
.path("/get_block_record_by_height");
then.status(200)
.header("content-type", "application/json")
.body(PEAK_RECORD_JSON);
});
let src = CoinsetChainSource::new(server.base_url());
let forged = ChiaBlockRef {
header_hash: Bytes32([0xAB; 32]),
height: 5_421_337,
timestamp: 1_717_804_800,
};
assert!(
src.verify_block(&forged, 600).is_err(),
"a header-hash mismatch at the height must be rejected"
);
}
#[test]
#[ignore = "live network: hits https://api.coinset.org; run with --ignored"]
fn live_get_peak_from_coinset_org() {
let src = CoinsetChainSource::default();
match src.get_peak() {
Ok(peak) => {
assert!(peak.height > 5_000_000, "mainnet peak height is large");
assert!(
peak.timestamp > 1_600_000_000,
"peak timestamp is after 2020"
);
assert_ne!(peak.header_hash, Bytes32([0u8; 32]), "non-zero header hash");
}
Err(e) => {
eprintln!("[live] coinset.org get_peak failed (best-effort, skipping): {e}");
}
}
}