This repository has been archived by the owner on Jun 11, 2022. It is now read-only.
/
builder.rs
153 lines (137 loc) · 5.23 KB
/
builder.rs
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
//! block builder tooling and more
//!
use crate::block::{
BftProof, Block, BlockContentHash, BlockContents, BlockDate, BlockId, BlockVersion,
ChainLength, Common, GenesisPraosProof, Header, KESSignature, Message, Proof,
};
use crate::key::{make_signature, make_signature_update};
use crate::leadership;
use crate::stake;
use crate::transaction::{AuthenticatedTransaction, NoExtra};
use chain_addr::Address;
use chain_crypto::{
Curve25519_2HashDH, Ed25519Extended, SecretKey, SumEd25519_12, VerifiableRandomFunction,
};
pub struct BlockBuilder {
pub common: Common,
pub contents: BlockContents,
}
impl From<Block> for BlockBuilder {
fn from(block: Block) -> BlockBuilder {
BlockBuilder {
common: block.header.common,
contents: block.contents,
}
}
}
/// block builder to build and finalize the construction of a block
impl BlockBuilder {
/// default setting, equivalent to writing a genesis block (the empty block)
pub fn new() -> BlockBuilder {
use chain_core::property::BlockId;
BlockBuilder {
common: Common {
block_content_size: 0,
block_content_hash: BlockContentHash::zero(),
any_block_version: BlockVersion::Genesis.into(),
block_parent_hash: BlockId::zero(),
block_date: BlockDate::first(),
chain_length: ChainLength(0),
},
contents: BlockContents::new(Vec::new()),
}
}
/// set the block date
pub fn date(&mut self, block_date: BlockDate) -> &mut Self {
self.common.block_date = block_date;
self
}
/// set the chain_length
pub fn chain_length(&mut self, chain_length: ChainLength) -> &mut Self {
self.common.chain_length = chain_length;
self
}
/// set the parent hash
pub fn parent(&mut self, block_parent_hash: BlockId) -> &mut Self {
self.common.block_parent_hash = block_parent_hash;
self
}
/// set a transaction in the block to build
///
/// Equivalent to call `block_builder.message(Message::Transaction(transaction))`
pub fn transaction(
&mut self,
signed_transaction: AuthenticatedTransaction<Address, NoExtra>,
) -> &mut Self {
self.message(Message::Transaction(signed_transaction))
}
/// add a message in the block to build
pub fn message(&mut self, message: Message) -> &mut Self {
self.contents.0.push(message);
self
}
/// set multiple messages in the block to build
pub fn messages<I>(&mut self, messages: I) -> &mut Self
where
I: IntoIterator<Item = Message>,
{
self.contents.0.extend(messages);
self
}
fn make_block(self, proof: Proof) -> Block {
Block {
header: Header {
common: self.common,
proof: proof,
},
contents: self.contents,
}
}
fn finalize_common(&mut self, block_version: BlockVersion) -> &mut Self {
let (content_hash, content_size) = self.contents.compute_hash_size();
self.common.block_content_hash = content_hash;
self.common.block_content_size = content_size as u32;
self.common.any_block_version = block_version.into();
self
}
/// create a genesis block (i.e. no signature)
///
/// This is the first ever block of the blockchain and it is expected
/// the data to be `0.0` and the hash to be `00000000000000...`.
pub fn make_genesis_block(mut self) -> Block {
use chain_core::property::BlockId as _;
assert!(self.common.block_parent_hash == BlockId::zero());
assert!(self.common.block_date == BlockDate::first());
assert_eq!(self.common.chain_length, ChainLength(0));
self.finalize_common(BlockVersion::Genesis);
self.make_block(Proof::None)
}
/// create a BFT Block. this block will be signed with the given private key
pub fn make_bft_block(mut self, bft_signing_key: &SecretKey<Ed25519Extended>) -> Block {
assert_ne!(self.common.chain_length, ChainLength(0));
self.finalize_common(BlockVersion::Ed25519Signed);
let bft_proof = BftProof {
leader_id: leadership::bft::LeaderId(bft_signing_key.to_public()),
signature: super::BftSignature(make_signature(bft_signing_key, &self.common)),
};
self.make_block(Proof::Bft(bft_proof))
}
/// create a Praos/Genesis block, this block will be signed with the
/// given KES key.
pub fn make_genesis_praos_block(
mut self,
node_id: &stake::StakePoolId,
kes_signing_key: &mut SecretKey<SumEd25519_12>,
vrf_proof: <Curve25519_2HashDH as VerifiableRandomFunction>::VerifiedRandomOutput,
) -> Block {
assert_ne!(self.common.chain_length, ChainLength(0));
self.finalize_common(BlockVersion::KesVrfproof);
let genesis_praos_proof = GenesisPraosProof {
node_id: node_id.clone(),
vrf_proof: vrf_proof,
// ! SECURITY FIXME ! : also include id and vrf proof.
kes_proof: KESSignature(make_signature_update(kes_signing_key, &self.common)),
};
self.make_block(Proof::GenesisPraos(genesis_praos_proof))
}
}