use std::fmt::Debug;
use async_trait::async_trait;
use committable::{Commitment, Committable};
use hotshot_types::{
data::{fake_commitment, BlockError, Leaf, ViewNumber},
traits::{
block_contents::BlockHeader,
node_implementation::NodeType,
states::{InstanceState, StateDelta, TestableState, ValidatedState},
BlockPayload,
},
vid::VidCommon,
};
use rand::Rng;
use serde::{Deserialize, Serialize};
use vbs::version::Version;
pub use crate::node_types::TestTypes;
use crate::{
block_types::{TestBlockPayload, TestTransaction},
testable_delay::{DelayConfig, SupportedTraitTypesForAsyncDelay, TestableDelay},
};
#[derive(Clone, Debug, Default)]
pub struct TestInstanceState {
pub delay_config: DelayConfig,
}
impl InstanceState for TestInstanceState {}
impl TestInstanceState {
pub fn new(delay_config: DelayConfig) -> Self {
TestInstanceState { delay_config }
}
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct TestStateDelta {}
impl StateDelta for TestStateDelta {}
#[derive(PartialEq, Eq, Hash, Serialize, Deserialize, Clone, Debug)]
pub struct TestValidatedState {
block_height: u64,
prev_state_commitment: Commitment<Self>,
}
impl Committable for TestValidatedState {
fn commit(&self) -> Commitment<Self> {
committable::RawCommitmentBuilder::new("Test State Commit")
.u64_field("block_height", self.block_height)
.field("prev_state_commitment", self.prev_state_commitment)
.finalize()
}
fn tag() -> String {
"TEST_STATE".to_string()
}
}
impl Default for TestValidatedState {
fn default() -> Self {
Self {
block_height: 0,
prev_state_commitment: fake_commitment(),
}
}
}
#[async_trait]
impl TestableDelay for TestValidatedState {
async fn run_delay_settings_from_config(delay_config: &DelayConfig) {
if let Some(settings) =
delay_config.get_setting(&SupportedTraitTypesForAsyncDelay::ValidatedState)
{
Self::handle_async_delay(settings).await;
}
}
}
impl<TYPES: NodeType> ValidatedState<TYPES> for TestValidatedState {
type Error = BlockError;
type Instance = TestInstanceState;
type Delta = TestStateDelta;
type Time = ViewNumber;
async fn validate_and_apply_header(
&self,
instance: &Self::Instance,
_parent_leaf: &Leaf<TYPES>,
_proposed_header: &TYPES::BlockHeader,
_vid_common: VidCommon,
_version: Version,
_view_number: u64,
) -> Result<(Self, Self::Delta), Self::Error> {
Self::run_delay_settings_from_config(&instance.delay_config).await;
Ok((
TestValidatedState {
block_height: self.block_height + 1,
prev_state_commitment: self.commit(),
},
TestStateDelta {},
))
}
fn from_header(block_header: &TYPES::BlockHeader) -> Self {
Self {
block_height: block_header.block_number(),
..Default::default()
}
}
fn on_commit(&self) {}
fn genesis(_instance: &Self::Instance) -> (Self, Self::Delta) {
(Self::default(), TestStateDelta {})
}
}
impl<TYPES: NodeType<BlockPayload = TestBlockPayload>> TestableState<TYPES> for TestValidatedState {
fn create_random_transaction(
_state: Option<&Self>,
rng: &mut dyn rand::RngCore,
padding: u64,
) -> <TYPES::BlockPayload as BlockPayload<TYPES>>::Transaction {
const RANDOM_TX_BASE_SIZE: usize = 8;
let mut tx = rng.gen::<[u8; RANDOM_TX_BASE_SIZE]>().to_vec();
let padding = vec![0; padding.try_into().expect("transaction padding too large")];
tx.extend(padding);
TestTransaction::new(tx)
}
}