hotshot_query_service/testing/
mocks.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the HotShot Query Service library.
3//
4// This program is free software: you can redistribute it and/or modify it under the terms of the GNU
5// General Public License as published by the Free Software Foundation, either version 3 of the
6// License, or (at your option) any later version.
7// This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
8// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9// General Public License for more details.
10// You should have received a copy of the GNU General Public License along with this program. If not,
11// see <https://www.gnu.org/licenses/>.
12
13use hotshot::traits::{NodeImplementation, implementations::MemoryNetwork};
14use hotshot_example_types::{
15    block_types::{TestBlockHeader, TestBlockPayload, TestMetadata, TestTransaction},
16    membership::{static_committee::StaticStakeTable, strict_membership::StrictMembership},
17    state_types::{TestInstanceState, TestValidatedState},
18    storage_types::TestStorage,
19};
20use hotshot_types::{
21    data::{QuorumProposal, VidCommitment, VidCommon},
22    signature_key::{BLSPubKey, SchnorrPubKey},
23    traits::node_implementation::NodeType,
24};
25use jf_merkle_tree_compat::{
26    ForgetableMerkleTreeScheme, ForgetableUniversalMerkleTreeScheme,
27    prelude::{MerkleProof, Sha3Digest, Sha3Node},
28    universal_merkle_tree::UniversalMerkleTree,
29};
30use serde::{Deserialize, Serialize};
31use vbs::version::StaticVersion;
32use versions::{Upgrade, version};
33
34use crate::{
35    availability::{
36        QueryableHeader, QueryablePayload, TransactionIndex, VerifiableInclusion,
37        VidCommonQueryData,
38    },
39    explorer::traits::{ExplorerHeader, ExplorerTransaction},
40    merklized_state::MerklizedState,
41    types::HeightIndexed,
42};
43
44pub type MockHeader = TestBlockHeader;
45pub type MockPayload = TestBlockPayload;
46pub type MockTransaction = TestTransaction;
47
48pub fn mock_transaction(payload: Vec<u8>) -> MockTransaction {
49    TestTransaction::new(payload)
50}
51
52impl QueryableHeader<MockTypes> for MockHeader {
53    type NamespaceId = i64;
54    type NamespaceIndex = i64;
55
56    fn namespace_id(&self, i: &i64) -> Option<i64> {
57        // Test types only support a single namespace.
58        if *i == 0 { Some(0) } else { None }
59    }
60
61    fn namespace_size(&self, i: &i64, payload_size: usize) -> u64 {
62        // Test types only support a single namespace.
63        if *i == 0 { payload_size as u64 } else { 0 }
64    }
65
66    fn ns_table(&self) -> String {
67        self.metadata.to_string()
68    }
69}
70
71impl ExplorerHeader<MockTypes> for MockHeader {
72    type BalanceAmount = i128;
73    type WalletAddress = [u8; 32];
74    type ProposerId = [u8; 32];
75
76    fn proposer_id(&self) -> Self::ProposerId {
77        [0; 32]
78    }
79
80    fn fee_info_account(&self) -> Self::WalletAddress {
81        [0; 32]
82    }
83
84    fn fee_info_balance(&self) -> Self::BalanceAmount {
85        0
86    }
87
88    fn reward_balance(&self) -> Self::BalanceAmount {
89        0
90    }
91
92    fn namespace_ids(&self) -> Vec<i64> {
93        vec![0]
94    }
95}
96
97impl ExplorerTransaction<MockTypes> for MockTransaction {
98    fn namespace_id(&self) -> i64 {
99        0
100    }
101
102    fn payload_size(&self) -> u64 {
103        self.bytes().len() as u64
104    }
105}
106
107impl HeightIndexed for MockHeader {
108    fn height(&self) -> u64 {
109        self.block_number
110    }
111}
112
113/// A naive inclusion proof for `MockPayload` and `MockTransaction`.
114#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
115pub struct MockInclusionProof(MockPayload);
116
117impl VerifiableInclusion<MockTypes> for MockInclusionProof {
118    fn verify(
119        &self,
120        _metadata: &TestMetadata,
121        tx: &MockTransaction,
122        _payload_commitment: &VidCommitment,
123        _common: &VidCommon,
124    ) -> bool {
125        self.0.transactions.contains(tx)
126    }
127}
128
129impl QueryablePayload<MockTypes> for MockPayload {
130    type Iter<'a> = <Vec<TransactionIndex<MockTypes>> as IntoIterator>::IntoIter;
131    type InclusionProof = MockInclusionProof;
132
133    fn len(&self, _meta: &Self::Metadata) -> usize {
134        self.transactions.len()
135    }
136
137    fn iter(&self, meta: &Self::Metadata) -> Self::Iter<'_> {
138        (0..<TestBlockPayload as QueryablePayload<MockTypes>>::len(self, meta))
139            .map(|i| TransactionIndex {
140                ns_index: 0,
141                position: i as u32,
142            })
143            .collect::<Vec<_>>()
144            .into_iter()
145    }
146
147    fn transaction(
148        &self,
149        _meta: &Self::Metadata,
150        index: &TransactionIndex<MockTypes>,
151    ) -> Option<Self::Transaction> {
152        self.transactions.get(index.position as usize).cloned()
153    }
154
155    fn transaction_proof(
156        &self,
157        _meta: &Self::Metadata,
158        _vid: &VidCommonQueryData<MockTypes>,
159        _index: &TransactionIndex<MockTypes>,
160    ) -> Option<Self::InclusionProof> {
161        Some(MockInclusionProof(self.clone()))
162    }
163}
164
165#[derive(
166    Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
167)]
168pub struct MockTypes;
169
170impl NodeType for MockTypes {
171    type BlockHeader = MockHeader;
172    type BlockPayload = MockPayload;
173    type SignatureKey = BLSPubKey;
174    type Transaction = MockTransaction;
175    type InstanceState = TestInstanceState;
176    type ValidatedState = TestValidatedState;
177    type Membership = StrictMembership<MockTypes, StaticStakeTable<BLSPubKey, SchnorrPubKey>>;
178    type BuilderSignatureKey = BLSPubKey;
179    type StateSignatureKey = SchnorrPubKey;
180}
181
182pub const MOCK_UPGRADE: Upgrade = Upgrade::new(version(0, 1), version(0, 2));
183
184pub type MockBase = StaticVersion<0, 1>;
185
186pub type MockMembership = StrictMembership<MockTypes, StaticStakeTable<BLSPubKey, SchnorrPubKey>>;
187pub type MockQuorumProposal = QuorumProposal<MockTypes>;
188pub type MockNetwork = MemoryNetwork<BLSPubKey>;
189
190pub type MockStorage = TestStorage<MockTypes>;
191
192#[derive(
193    Copy, Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
194)]
195pub struct MockNodeImpl;
196
197impl NodeImplementation<MockTypes> for MockNodeImpl {
198    type Network = MockNetwork;
199    type Storage = MockStorage;
200}
201
202pub type MockMerkleTree = UniversalMerkleTree<usize, Sha3Digest, usize, 8, Sha3Node>;
203
204impl MerklizedState<MockTypes, 8> for MockMerkleTree {
205    type Key = usize;
206    type Entry = usize;
207    type T = Sha3Node;
208    type Commit = Self::Commitment;
209    type Digest = Sha3Digest;
210
211    fn state_type() -> &'static str {
212        "test_tree"
213    }
214
215    fn header_state_commitment_field() -> &'static str {
216        "test_merkle_tree_root"
217    }
218
219    fn tree_height() -> usize {
220        12
221    }
222
223    fn insert_path(
224        &mut self,
225        key: Self::Key,
226        proof: &MerkleProof<Self::Entry, Self::Key, Self::T, 8>,
227    ) -> anyhow::Result<()> {
228        match proof.elem() {
229            Some(elem) => self.remember(key, elem, proof)?,
230            None => self.non_membership_remember(key, proof)?,
231        }
232        Ok(())
233    }
234}