-
Notifications
You must be signed in to change notification settings - Fork 7
/
consensus.rs
112 lines (96 loc) · 3.56 KB
/
consensus.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
use consensus::errors::ConsensusError;
use eyre::Result;
use ssz_rs::prelude::*;
use tracing::{error, info};
use common::types::Block;
use reth_primitives::{
hex::FromHex, revm::env::recover_header_signer, revm_primitives::FixedBytes, Address, Bloom,
Header, B64,
};
#[derive(Debug)]
pub struct Consensus {
pub latest_block: Option<Block>,
signers: Vec<Address>,
}
fn verify(block: &Block) -> Address {
let header = extract_header(&block).unwrap();
// TODO: can this kill the client if it recieves a malicous block?
let creator: Address = recover_header_signer(&header).unwrap_or_else(|| {
panic!(
"Failed to recover Clique Consensus signer from header ({}, {}) using extradata {}",
header.number,
header.hash_slow(),
header.extra_data
)
});
return creator;
}
pub fn extract_header(block: &Block) -> Result<Header> {
Ok(Header {
parent_hash: FixedBytes::new(block.parent_hash.into()),
ommers_hash: FixedBytes::new(block.sha3_uncles.into()),
beneficiary: Address::new(block.miner.into()),
state_root: FixedBytes::new(block.state_root.into()),
transactions_root: FixedBytes::new(block.transactions_root.into()),
receipts_root: FixedBytes::new(block.receipts_root.into()),
withdrawals_root: None,
logs_bloom: Bloom {
0: FixedBytes::new(block.logs_bloom.to_vec().try_into().unwrap()),
},
timestamp: block.timestamp.as_u64(),
mix_hash: FixedBytes::new(block.mix_hash.into()),
nonce: u64::from_be_bytes(B64::from_hex(block.nonce.clone())?.try_into()?),
base_fee_per_gas: None,
number: block.number.as_u64(),
gas_limit: block.gas_limit.as_u64(),
difficulty: block.difficulty.into(),
gas_used: block.gas_used.as_u64(),
extra_data: block.extra_data.0.clone().into(),
parent_beacon_block_root: None,
blob_gas_used: None,
excess_blob_gas: None,
})
}
impl Consensus {
pub fn new() -> Result<Self> {
let signers = [
Address::from_hex("0x0981717712ed2c4919fdbc27dfc804800a9eeff9")?,
Address::from_hex("0x0e5b9aa4925ed1beeb08d1c5a92477a1b719baa7")?,
Address::from_hex("0x0e8705e07bbe1ce2c39093df3d20aaa5120bfc7a")?,
]
.to_vec();
Ok(Consensus {
latest_block: None,
signers,
})
}
pub fn advance(&mut self, block: &Block) -> Result<(), ConsensusError> {
if let Some(latest_block) = self.latest_block.as_ref() {
if latest_block.number.as_u64() > block.number.as_u64() {
error!(
target: "helios::consensus",
"advance block recieved block with invalid block number: expected: {}, actual {}",
self.latest_block.as_ref().unwrap().timestamp.as_u64()+1,
block.timestamp
);
return Err(ConsensusError::NotRelevant);
}
}
let creator = verify(&block);
if !self.signers.contains(&creator) {
error!(
target: "helios::consensus",
"advance block contains invalid block creator: {}",
creator
);
return Err(ConsensusError::InvalidSignature);
}
info!(
target: "helios::consensus",
"PoA consensus client advanced to block {}: {:#?}",
&block.number, &block.hash
);
self.latest_block = Some(block.clone());
Ok(())
}
}