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
use network::ConsensusParams;
use storage::BlockHeaderProvider;
use canon::CanonHeader;
use error::Error;
use work::work_required;
use timestamp::median_timestamp;
use deployments::Deployments;
pub struct HeaderAcceptor<'a> {
pub version: HeaderVersion<'a>,
pub work: HeaderWork<'a>,
pub median_timestamp: HeaderMedianTimestamp<'a>,
}
impl<'a> HeaderAcceptor<'a> {
pub fn new<D: AsRef<Deployments>>(
store: &'a BlockHeaderProvider,
consensus: &'a ConsensusParams,
header: CanonHeader<'a>,
height: u32,
deployments: D,
) -> Self {
let csv_active = deployments.as_ref().csv(height, store, consensus);
HeaderAcceptor {
work: HeaderWork::new(header, store, height, consensus),
median_timestamp: HeaderMedianTimestamp::new(header, store, csv_active),
version: HeaderVersion::new(header, height, consensus),
}
}
pub fn check(&self) -> Result<(), Error> {
try!(self.version.check());
try!(self.work.check());
try!(self.median_timestamp.check());
Ok(())
}
}
pub struct HeaderVersion<'a> {
header: CanonHeader<'a>,
height: u32,
consensus_params: &'a ConsensusParams,
}
impl<'a> HeaderVersion<'a> {
fn new(header: CanonHeader<'a>, height: u32, consensus_params: &'a ConsensusParams) -> Self {
HeaderVersion {
header: header,
height: height,
consensus_params: consensus_params,
}
}
fn check(&self) -> Result<(), Error> {
if (self.header.raw.version < 2 && self.height >= self.consensus_params.bip34_height) ||
(self.header.raw.version < 3 && self.height >= self.consensus_params.bip66_height) ||
(self.header.raw.version < 4 && self.height >= self.consensus_params.bip65_height) {
Err(Error::OldVersionBlock)
} else {
Ok(())
}
}
}
pub struct HeaderWork<'a> {
header: CanonHeader<'a>,
store: &'a BlockHeaderProvider,
height: u32,
consensus: &'a ConsensusParams,
}
impl<'a> HeaderWork<'a> {
fn new(header: CanonHeader<'a>, store: &'a BlockHeaderProvider, height: u32, consensus: &'a ConsensusParams) -> Self {
HeaderWork {
header: header,
store: store,
height: height,
consensus: consensus,
}
}
fn check(&self) -> Result<(), Error> {
let previous_header_hash = self.header.raw.previous_header_hash.clone();
let time = self.header.raw.time;
let work = work_required(previous_header_hash, time, self.height, self.store, self.consensus);
if work == self.header.raw.bits {
Ok(())
} else {
Err(Error::Difficulty { expected: work, actual: self.header.raw.bits })
}
}
}
pub struct HeaderMedianTimestamp<'a> {
header: CanonHeader<'a>,
store: &'a BlockHeaderProvider,
active: bool,
}
impl<'a> HeaderMedianTimestamp<'a> {
fn new(header: CanonHeader<'a>, store: &'a BlockHeaderProvider, csv_active: bool) -> Self {
HeaderMedianTimestamp {
header: header,
store: store,
active: csv_active,
}
}
fn check(&self) -> Result<(), Error> {
if self.active && self.header.raw.time <= median_timestamp(&self.header.raw, self.store) {
Err(Error::Timestamp)
} else {
Ok(())
}
}
}