This repository has been archived by the owner on Oct 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
BlockHeader.h
210 lines (183 loc) · 7.88 KB
/
BlockHeader.h
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
// Aleth: Ethereum C++ client, tools and libraries.
// Copyright 2014-2019 Aleth Authors.
// Licensed under the GNU General Public License, Version 3.
#pragma once
#include "ChainOperationParams.h"
#include "Common.h"
#include "Exceptions.h"
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include <algorithm>
namespace dev
{
namespace eth
{
enum IncludeSeal
{
WithoutSeal = 0,
WithSeal = 1,
OnlySeal = 2
};
enum Strictness
{
CheckEverything,
QuickNonce,
IgnoreSeal,
CheckNothingNew
};
// TODO: for implementing soon.
/*enum Check
{
CheckBasic,
CheckExtended,
CheckBlock,
CheckParent,
CheckSeal,
CheckSealQuickly,
CheckAll = CheckBasic | CheckExtended | CheckBlock | CheckParent | CheckSeal,
};
using Checks = FlagSet<Check>;*/
enum BlockDataType
{
HeaderData,
BlockData
};
DEV_SIMPLE_EXCEPTION(NoHashRecorded);
DEV_SIMPLE_EXCEPTION(GenesisBlockCannotBeCalculated);
/** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method
* populate(). This will not conduct any verification above basic formating. In this case extra
* verification can be performed through verify().
*
* The object may also be populated from an entire block through the explicit
* constructor BlockHeader(bytesConstRef) and manually with the populate() method. These will
* conduct verification of the header against the other information in the block.
*
* The object may be populated with a template given a parent BlockHeader object with the
* populateFromParent() method. The genesis block info may be retrieved with genesis() and the
* corresponding RLP block created with createGenesisBlock().
*
* To determine the header hash without the nonce (for sealing), the method hash(WithoutNonce) is
* provided.
*
* The default constructor creates an empty object, which can be tested against with the boolean
* conversion operator.
*/
class BlockHeader
{
friend class BlockChain;
public:
static const unsigned BasicFields = 13;
BlockHeader();
explicit BlockHeader(bytesConstRef _data, BlockDataType _bdt = BlockData, h256 const& _hashWith = h256());
explicit BlockHeader(bytes const& _data, BlockDataType _bdt = BlockData, h256 const& _hashWith = h256()): BlockHeader(&_data, _bdt, _hashWith) {}
BlockHeader(BlockHeader const& _other);
BlockHeader& operator=(BlockHeader const& _other);
static h256 headerHashFromBlock(bytes const& _block) { return headerHashFromBlock(&_block); }
static h256 headerHashFromBlock(bytesConstRef _block);
static RLP extractHeader(bytesConstRef _block);
explicit operator bool() const { return m_timestamp >= 0; }
bool operator==(BlockHeader const& _cmp) const
{
return m_parentHash == _cmp.parentHash() &&
m_sha3Uncles == _cmp.sha3Uncles() &&
m_author == _cmp.author() &&
m_stateRoot == _cmp.stateRoot() &&
m_transactionsRoot == _cmp.transactionsRoot() &&
m_receiptsRoot == _cmp.receiptsRoot() &&
m_logBloom == _cmp.logBloom() &&
m_difficulty == _cmp.difficulty() &&
m_number == _cmp.number() &&
m_gasLimit == _cmp.gasLimit() &&
m_gasUsed == _cmp.gasUsed() &&
m_timestamp == _cmp.timestamp() &&
m_extraData == _cmp.extraData();
}
bool operator!=(BlockHeader const& _cmp) const { return !operator==(_cmp); }
void clear();
void noteDirty() const { Guard l(m_hashLock); m_hashWithout = m_hash = h256(); }
void populateFromParent(BlockHeader const& parent);
// TODO: pull out into abstract class Verifier.
void verify(Strictness _s = CheckEverything, BlockHeader const& _parent = BlockHeader(), bytesConstRef _block = bytesConstRef()) const;
void verify(Strictness _s, bytesConstRef _block) const { verify(_s, BlockHeader(), _block); }
h256 hash(IncludeSeal _i = WithSeal) const;
void streamRLP(RLPStream& _s, IncludeSeal _i = WithSeal) const;
void setParentHash(h256 const& _v) { m_parentHash = _v; noteDirty(); }
void setSha3Uncles(h256 const& _v) { m_sha3Uncles = _v; noteDirty(); }
void setTimestamp(int64_t _v) { m_timestamp = _v; noteDirty(); }
void setAuthor(Address const& _v) { m_author = _v; noteDirty(); }
void setRoots(h256 const& _t, h256 const& _r, h256 const& _u, h256 const& _s) { m_transactionsRoot = _t; m_receiptsRoot = _r; m_stateRoot = _s; m_sha3Uncles = _u; noteDirty(); }
void setGasUsed(u256 const& _v) { m_gasUsed = _v; noteDirty(); }
void setNumber(int64_t _v) { m_number = _v; noteDirty(); }
void setGasLimit(u256 const& _v) { m_gasLimit = _v; noteDirty(); }
void setExtraData(bytes const& _v) { m_extraData = _v; noteDirty(); }
void setLogBloom(LogBloom const& _v) { m_logBloom = _v; noteDirty(); }
void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); }
template <class T> void setSeal(unsigned _offset, T const& _value) { Guard l(m_sealLock); if (m_seal.size() <= _offset) m_seal.resize(_offset + 1); m_seal[_offset] = rlp(_value); noteDirty(); }
template <class T> void setSeal(T const& _value) { setSeal(0, _value); }
h256 const& parentHash() const { return m_parentHash; }
h256 const& sha3Uncles() const { return m_sha3Uncles; }
bool hasUncles() const { return m_sha3Uncles != EmptyListSHA3; }
int64_t timestamp() const { return m_timestamp; }
Address const& author() const { return m_author; }
h256 const& stateRoot() const { return m_stateRoot; }
h256 const& transactionsRoot() const { return m_transactionsRoot; }
h256 const& receiptsRoot() const { return m_receiptsRoot; }
u256 const& gasUsed() const { return m_gasUsed; }
int64_t number() const { return m_number; }
u256 const& gasLimit() const { return m_gasLimit; }
bytes const& extraData() const { return m_extraData; }
LogBloom const& logBloom() const { return m_logBloom; }
u256 const& difficulty() const { return m_difficulty; }
template <class T> T seal(unsigned _offset = 0) const { T ret; Guard l(m_sealLock); if (_offset < m_seal.size()) ret = RLP(m_seal[_offset]).convert<T>(RLP::VeryStrict); return ret; }
private:
void populate(RLP const& _header);
void streamRLPFields(RLPStream& _s) const;
std::vector<bytes> seal() const
{
Guard l(m_sealLock);
return m_seal;
}
h256 hashRawRead() const
{
Guard l(m_hashLock);
return m_hash;
}
h256 hashWithoutRawRead() const
{
Guard l(m_hashLock);
return m_hashWithout;
}
h256 m_parentHash;
h256 m_sha3Uncles;
h256 m_stateRoot;
h256 m_transactionsRoot;
h256 m_receiptsRoot;
LogBloom m_logBloom;
int64_t m_number = 0;
u256 m_gasLimit;
u256 m_gasUsed;
bytes m_extraData;
int64_t m_timestamp = -1;
Address m_author;
u256 m_difficulty;
std::vector<bytes> m_seal; ///< Additional (RLP-encoded) header fields.
mutable Mutex m_sealLock;
mutable h256 m_hash; ///< (Memoised) SHA3 hash of the block header with seal.
mutable h256 m_hashWithout; ///< (Memoised) SHA3 hash of the block header without seal.
mutable Mutex m_hashLock; ///< A lock for both m_hash and m_hashWithout.
mutable Logger m_logger{createLogger(VerbosityDebug, "blockhdr")};
};
inline std::ostream& operator<<(std::ostream& _out, BlockHeader const& _bi)
{
_out << _bi.hash(WithoutSeal) << " " << _bi.parentHash() << " " << _bi.sha3Uncles() << " " << _bi.author() << " " << _bi.stateRoot() << " " << _bi.transactionsRoot() << " " <<
_bi.receiptsRoot() << " " << _bi.logBloom() << " " << _bi.difficulty() << " " << _bi.number() << " " << _bi.gasLimit() << " " <<
_bi.gasUsed() << " " << _bi.timestamp();
return _out;
}
}
}