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
use std::collections::BTreeSet;
use crypto::publickey::{public_to_address, recover as ec_recover, Signature};
use engines::{
clique::{ADDRESS_LENGTH, NULL_MIXHASH, NULL_NONCE, SIGNATURE_LENGTH, VANITY_LENGTH},
EngineError,
};
use error::Error;
use ethereum_types::{Address, H160, H256};
use lru_cache::LruCache;
use parking_lot::RwLock;
use rlp::encode;
use types::header::Header;
pub const CREATOR_CACHE_NUM: usize = 4096;
lazy_static! {
static ref CREATOR_BY_HASH: RwLock<LruCache<H256, Address>> = RwLock::new(LruCache::new(CREATOR_CACHE_NUM));
}
pub fn recover_creator(header: &Header) -> Result<Address, Error> {
let mut cache = CREATOR_BY_HASH.write();
if let Some(creator) = cache.get_mut(&header.hash()) {
return Ok(*creator);
}
let data = header.extra_data();
if data.len() < VANITY_LENGTH {
Err(EngineError::CliqueMissingVanity)?
}
if data.len() < VANITY_LENGTH + SIGNATURE_LENGTH {
Err(EngineError::CliqueMissingSignature)?
}
let (signed_data_slice, signature_slice) = data.split_at(data.len() - SIGNATURE_LENGTH);
let signature = {
let mut s = [0; SIGNATURE_LENGTH];
s.copy_from_slice(signature_slice);
s
};
let unsigned_header = &mut header.clone();
unsigned_header.set_extra_data(signed_data_slice.to_vec());
let msg = unsigned_header.hash();
let pubkey = ec_recover(&Signature::from(signature), &msg)?;
let creator = public_to_address(&pubkey);
cache.insert(header.hash(), creator.clone());
Ok(creator)
}
pub fn extract_signers(header: &Header) -> Result<BTreeSet<Address>, Error> {
let data = header.extra_data();
if data.len() <= VANITY_LENGTH + SIGNATURE_LENGTH {
Err(EngineError::CliqueCheckpointNoSigner)?
}
let signers_raw = &data[(VANITY_LENGTH)..data.len() - (SIGNATURE_LENGTH)];
if signers_raw.len() % ADDRESS_LENGTH != 0 {
Err(EngineError::CliqueCheckpointInvalidSigners(
signers_raw.len(),
))?
}
let num_signers = signers_raw.len() / 20;
let signers: BTreeSet<Address> = (0..num_signers)
.map(|i| {
let start = i * ADDRESS_LENGTH;
let end = start + ADDRESS_LENGTH;
H160::from_slice(&signers_raw[start..end])
})
.collect();
Ok(signers)
}
pub fn null_seal() -> Vec<Vec<u8>> {
vec![
encode(&NULL_MIXHASH.as_bytes().to_vec()),
encode(&NULL_NONCE.as_bytes().to_vec()),
]
}