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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use super::ProtocolVersion;
use chain_core::{
    packer::Codec,
    property::{DeserializeFromSlice, ReadError, Serialize, WriteError},
};
use chain_crypto::{Ed25519, KeyPair, PublicKey, Signature, Verification};
use chain_impl_mockchain::{
    block::{self, Block, BlockDate, ContentsBuilder, Header},
    header::BlockVersion,
    key::Hash,
};
use chain_storage::{BlockInfo, BlockStore};
use rand::Rng;
use std::net::SocketAddr;

const AUTH_NONCE_LEN: usize = 32;

pub struct MockServerData {
    genesis_hash: Hash,
    protocol: ProtocolVersion,
    keypair: KeyPair<Ed25519>,
    profile: poldercast::Profile,
    auth_nonce: [u8; AUTH_NONCE_LEN],
    storage: BlockStore,
    invalid_block0_hash: bool,
}

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error(transparent)]
    Storage(#[from] chain_storage::Error),
    #[error(transparent)]
    Read(#[from] ReadError),
    #[error(transparent)]
    Write(#[from] WriteError),
}

impl MockServerData {
    const TIP_TAG: &'static str = "tip";
    pub fn new(
        genesis_hash: Hash,
        protocol: ProtocolVersion,
        addr: SocketAddr,
        storage: BlockStore,
        invalid_get_blocks_hash: bool,
    ) -> Self {
        let keypair = KeyPair::generate(rand::thread_rng());
        let topology_key = keynesis::key::ed25519::SecretKey::new(rand::thread_rng());
        let profile = poldercast::Profile::new(addr, &topology_key);
        Self {
            genesis_hash,
            protocol,
            keypair,
            profile,
            auth_nonce: [0; AUTH_NONCE_LEN],
            storage,
            invalid_block0_hash: invalid_get_blocks_hash,
        }
    }

    pub fn genesis_hash(&self) -> &Hash {
        &self.genesis_hash
    }

    pub fn get_block(&self, header_id: Hash) -> Result<Block, Error> {
        Ok(Block::deserialize_from_slice(&mut Codec::new(
            self.storage()
                .get_block(header_id.as_ref())
                .unwrap()
                .as_ref(),
        ))?)
    }

    pub fn genesis_block(&self) -> Block {
        self.get_block(self.genesis_hash)
            .expect("genesis block should always be valid")
    }

    pub fn tip(&self) -> Result<Header, Error> {
        let header_id = self
            .storage
            .get_tag(Self::TIP_TAG)?
            .ok_or(chain_storage::Error::BlockNotFound)?;

        Ok(self
            .get_block(Hash::deserialize_from_slice(&mut Codec::new(header_id.as_ref())).unwrap())?
            .header()
            .clone())
    }

    /// block_id must refer to a valid block already in the storage
    pub fn set_tip(&self, block_id: &[u8]) -> Result<(), Error> {
        Ok(self.storage.put_tag(Self::TIP_TAG, block_id)?)
    }

    pub fn put_block(&self, block: &Block) -> Result<(), Error> {
        let id = block.header().hash().serialize_as_vec()?;
        let parent_id = block.header().block_parent_hash().serialize_as_vec()?;
        let chain_length = block.header().chain_length().into();
        let block_info = BlockInfo::new(id, parent_id, chain_length);
        Ok(self
            .storage()
            .put_block(&block.serialize_as_vec()?, block_info)?)
    }

    pub fn profile(&self) -> &poldercast::Profile {
        &self.profile
    }

    pub fn protocol(&self) -> &ProtocolVersion {
        &self.protocol
    }

    pub fn node_id(&self) -> &[u8] {
        self.keypair.public_key().as_ref()
    }

    pub fn node_signature(&self, nonce: &[u8]) -> Vec<u8> {
        let signature = self.keypair.private_key().sign(nonce);
        signature.as_ref().to_vec()
    }

    pub fn generate_auth_nonce(&mut self) -> &[u8] {
        rand::thread_rng().fill(&mut self.auth_nonce[..]);
        &self.auth_nonce
    }

    /// Raw access to the storage. Can be used to play with raw bytes sequences
    /// or get around validations of domain objects, for example to mimic a malicous
    /// adversary
    pub fn storage(&self) -> &BlockStore {
        &self.storage
    }

    pub fn validate_peer_node_id(&self, node_id: &[u8], signature: &[u8]) -> bool {
        let public_key = PublicKey::<Ed25519>::from_binary(node_id).expect("invalid node ID");
        let signature =
            Signature::<[u8], Ed25519>::from_binary(signature).expect("invalid signature");
        match signature.verify(&public_key, &self.auth_nonce) {
            Verification::Success => true,
            Verification::Failed => false,
        }
    }

    pub fn genesis_hash_mut(&mut self) -> &mut Hash {
        &mut self.genesis_hash
    }

    pub fn protocol_mut(&mut self) -> &mut ProtocolVersion {
        &mut self.protocol
    }

    pub fn invalid_block0_hash(&self) -> bool {
        self.invalid_block0_hash
    }
}

pub fn block0() -> Block {
    block::builder(
        BlockVersion::Genesis,
        ContentsBuilder::new().into(),
        |hdr| {
            Ok::<_, ()>(
                hdr.set_genesis()
                    .set_date(BlockDate::first())
                    .into_unsigned_header()
                    .expect("internal error cannot build unsigned block")
                    .generalize(),
            )
        },
    )
    .expect("internal error: block builder cannot return error")
}