1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use alloc::fmt::Debug;
use core::time::Duration;

use basecoin_store::context::ProvableStore;
use ibc::core::client::context::client_state::ClientStateValidation;
use ibc::core::client::types::Height;
use ibc::core::primitives::prelude::*;
use ibc::core::primitives::Timestamp;
use typed_builder::TypedBuilder;

use crate::context::StoreGenericTestContext;
use crate::hosts::{HostClientState, TestBlock, TestHost};
use crate::testapp::ibc::core::router::MockRouter;
use crate::testapp::ibc::core::types::{MockIbcStore, DEFAULT_BLOCK_TIME_SECS};
use crate::utils::year_2023;

/// Configuration of the [`StoreGenericTestContext`] type for generating dummy contexts.
#[derive(Debug, TypedBuilder)]
#[builder(build_method(into))]
pub struct TestContextConfig<H>
where
    H: TestHost,
{
    #[builder(default)]
    host: H,

    #[builder(default = Duration::from_secs(DEFAULT_BLOCK_TIME_SECS))]
    block_time: Duration,

    #[builder(default = year_2023())]
    latest_timestamp: Timestamp,

    #[builder(default)]
    block_params_history: Vec<H::BlockParams>,

    #[builder(default = Height::new(0, 5).expect("Never fails"))]
    latest_height: Height,
}

impl<S, H> From<TestContextConfig<H>> for StoreGenericTestContext<S, H>
where
    S: ProvableStore + Debug + Default,
    H: TestHost,
    HostClientState<H>: ClientStateValidation<MockIbcStore<S>>,
{
    fn from(params: TestContextConfig<H>) -> Self {
        assert_ne!(
            params.latest_height.revision_height(),
            0,
            "The chain must have a non-zero revision_height"
        );

        // timestamp at height 1
        let genesis_timestamp = (params.latest_timestamp
            - (params.block_time
                * u32::try_from(params.latest_height.revision_height() - 1).expect("no overflow")))
        .expect("no underflow");

        let mut context = Self {
            multi_store: Default::default(),
            host: params.host,
            ibc_store: MockIbcStore::new(
                params.latest_height.revision_number(),
                Default::default(),
            ),
            ibc_router: MockRouter::new_with_transfer(),
        };

        // store is at height 0; no block

        context.advance_genesis_height(genesis_timestamp, &Default::default());

        // store is at height 1; one block

        context = context.advance_block_up_to_height(
            params
                .latest_height
                .sub(params.block_params_history.len() as u64)
                .expect("no error"),
        );

        for block_params in params.block_params_history {
            context.advance_block_height_with_params(params.block_time, &block_params);
        }

        assert_eq!(
            context.host.latest_block().height(),
            params.latest_height,
            "The latest height in the host must match the latest height in the context"
        );

        assert_eq!(
            context.host.latest_block().timestamp(),
            params.latest_timestamp,
            "The latest timestamp in the host must match the latest timestamp in the context"
        );

        context
    }
}