#![cfg(test)]
use crate::{
executor::{self, runtime_call},
header,
trie::proof_decode,
};
use core::iter;
#[test]
fn validate_from_proof() {
let test: Test = serde_json::from_str(include_str!("./test-fixture.json")).unwrap();
let runtime = executor::host::HostVmPrototype::new(executor::host::Config {
module: hex::decode(&test.runtime_code).unwrap(),
heap_pages: executor::DEFAULT_HEAP_PAGES,
allow_unresolved_imports: true,
exec_hint: executor::vm::ExecHint::ExecuteOnceWithNonDeterministicValidation,
})
.unwrap();
let call_proof = proof_decode::decode_and_verify_proof(proof_decode::Config {
proof: hex::decode(&test.call_proof).unwrap(),
})
.unwrap();
let scale_encoded_header = hex::decode(test.block_header).unwrap();
let main_trie_root = header::decode(&scale_encoded_header, 4).unwrap().state_root;
let mut validation_in_progress = runtime_call::run(runtime_call::Config {
virtual_machine: runtime,
function_to_call: super::VALIDATION_FUNCTION_NAME,
parameter: super::validate_transaction_runtime_parameters_v3(
iter::once(&hex::decode(test.transaction_bytes).unwrap()),
super::TransactionSource::External,
&header::hash_from_scale_encoded_header(&scale_encoded_header),
),
storage_proof_size_behavior:
runtime_call::StorageProofSizeBehavior::proof_recording_disabled(),
storage_main_trie_changes: Default::default(),
max_log_level: 0,
calculate_trie_changes: false,
})
.unwrap();
loop {
match validation_in_progress {
runtime_call::RuntimeCall::Finished(Ok(_)) => return, runtime_call::RuntimeCall::Finished(Err(_)) => panic!(),
runtime_call::RuntimeCall::StorageGet(get) => {
let value = call_proof
.storage_value(main_trie_root, get.key().as_ref())
.unwrap();
validation_in_progress =
get.inject_value(value.map(|(val, ver)| (iter::once(val), ver)));
}
runtime_call::RuntimeCall::NextKey(nk) => {
let next_key = call_proof
.next_key(
main_trie_root,
nk.key(),
nk.or_equal(),
nk.prefix(),
nk.branch_nodes(),
)
.unwrap();
validation_in_progress = nk.inject_key(next_key);
}
runtime_call::RuntimeCall::ClosestDescendantMerkleValue(mv) => {
let value = call_proof
.closest_descendant_merkle_value(main_trie_root, mv.key())
.unwrap();
validation_in_progress = mv.inject_merkle_value(value);
}
runtime_call::RuntimeCall::SignatureVerification(r) => {
validation_in_progress = r.verify_and_resume()
}
runtime_call::RuntimeCall::LogEmit(r) => validation_in_progress = r.resume(),
runtime_call::RuntimeCall::OffchainStorageSet(r) => validation_in_progress = r.resume(),
runtime_call::RuntimeCall::Offchain(_) => panic!(),
}
}
}
#[derive(serde::Deserialize)]
struct Test {
#[serde(rename = "transactionBytes")]
transaction_bytes: String,
#[serde(rename = "runtimeCode")]
runtime_code: String,
#[serde(rename = "callProof")]
call_proof: String,
#[serde(rename = "blockHeader")]
block_header: String,
}