-
Notifications
You must be signed in to change notification settings - Fork 12.4k
Expand file tree
/
Copy pathBlockHeader.sol
More file actions
196 lines (165 loc) · 9.26 KB
/
BlockHeader.sol
File metadata and controls
196 lines (165 loc) · 9.26 KB
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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {SafeCast} from "./math/SafeCast.sol";
import {Blockhash} from "./Blockhash.sol";
import {Memory} from "./Memory.sol";
import {RLP} from "./RLP.sol";
/// @dev Library for parsing and verifying RLP-encoded block headers.
library BlockHeader {
using SafeCast for *;
using RLP for *;
/// @dev List of evm versions.
enum Hardforks {
Homestead,
DAO,
TangerineWhistle,
SpuriousDragon,
Byzantium,
Constantinople,
Petersburg,
Istanbul,
MuirGlacier,
Berlin,
London,
ArrowGlacier,
GreyGlacier,
Paris,
Shanghai,
Cancun,
Prague,
Osaka,
Amsterdam
}
/// @dev List of block header fields, in the order they are encoded in the block header RLP.
enum HeaderField {
ParentHash, // Since Homestead
OmmersHash, // Since Homestead
Coinbase, // Since Homestead
StateRoot, // Since Homestead
TransactionsRoot, // Since Homestead
ReceiptsRoot, // Since Homestead
LogsBloom, // Since Homestead
Difficulty, // Since Homestead
Number, // Since Homestead
GasLimit, // Since Homestead
GasUsed, // Since Homestead
Timestamp, // Since Homestead
ExtraData, // Since Homestead
PrevRandao, // Since Homestead (called MixHash before Paris)
Nonce, // Since Homestead
BaseFeePerGas, // Since London
WithdrawalsRoot, // Since Shanghai
BlobGasUsed, // Since Cancun
ExcessBlobGas, // Since Cancun
ParentBeaconBlockRoot, // Since Cancun
RequestsHash, // Since Prague
BlockAccessListHash // Since Amsterdam
}
/// @dev Thrown when the provided block header RLP does not have the expected number of fields for the given hardfork version.
error InvalidBlockHeader(Hardforks expectedVersion);
/// @dev Verifies that the given block header RLP corresponds to a valid block header for the current chain.
function verifyBlockHeader(bytes memory headerRLP) internal view returns (bool) {
return Blockhash.blockHash(getNumber(headerRLP)) == keccak256(headerRLP);
}
/// @dev Extract the parent hash from the block header RLP.
function getParentHash(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.ParentHash)].readBytes32();
}
/// @dev Extract the ommers hash from the block header RLP. This is constant to keccak256(rlp([])) since EIP-3675 (Paris)
function getOmmersHash(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.OmmersHash)].readBytes32();
}
/// @dev Extract the coinbase (a.k.a. beneficiary or miner) address from the block header RLP.
function getCoinbase(bytes memory headerRLP) internal pure returns (address) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.Coinbase)].readAddress();
}
/// @dev Extract the state root from the block header RLP.
function getStateRoot(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.StateRoot)].readBytes32();
}
/// @dev Extract the transactions root from the block header RLP.
function getTransactionsRoot(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.TransactionsRoot)].readBytes32();
}
/// @dev Extract the receipts root from the block header RLP.
function getReceiptsRoot(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.ReceiptsRoot)].readBytes32();
}
/// @dev Extract the logs bloom from the block header RLP.
function getLogsBloom(bytes memory headerRLP) internal pure returns (bytes memory) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.LogsBloom)].readBytes();
}
/// @dev Extract the difficulty from the block header RLP. This is constant to 0 since EIP-3675 (Paris)
function getDifficulty(bytes memory headerRLP) internal pure returns (uint256) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.Difficulty)].readUint256();
}
/// @dev Extract the block number from the block header RLP.
function getNumber(bytes memory headerRLP) internal pure returns (uint256) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.Number)].readUint256();
}
/// @dev Extract the gas used from the block header RLP.
function getGasUsed(bytes memory headerRLP) internal pure returns (uint256) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.GasUsed)].readUint256();
}
/// @dev Extract the gas limit from the block header RLP.
function getGasLimit(bytes memory headerRLP) internal pure returns (uint256) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.GasLimit)].readUint256();
}
/// @dev Extract the timestamp from the block header RLP.
function getTimestamp(bytes memory headerRLP) internal pure returns (uint256) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.Timestamp)].readUint256();
}
/// @dev Extract the extra data from the block header RLP.
function getExtraData(bytes memory headerRLP) internal pure returns (bytes memory) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.ExtraData)].readBytes();
}
/// @dev Extract the prevRandao (a.k.a. mixHash before Paris) from the block header RLP.
function getPrevRandao(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.PrevRandao)].readBytes32();
}
/// @dev Extract the nonce from the block header RLP. This is constant to 0 since EIP-3675 (Paris)
function getNonce(bytes memory headerRLP) internal pure returns (bytes8) {
return bytes8(_parseHeader(headerRLP, Hardforks.Homestead)[uint8(HeaderField.Nonce)].readBytes32());
}
/// @dev Extract the base fee per gas from the block header RLP. This was introduced in London.
function getBaseFeePerGas(bytes memory headerRLP) internal pure returns (uint256) {
return _parseHeader(headerRLP, Hardforks.London)[uint8(HeaderField.BaseFeePerGas)].readUint256();
}
/// @dev Extract the withdrawals root from the block header RLP. This was introduced in Shanghai.
function getWithdrawalsRoot(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Shanghai)[uint8(HeaderField.WithdrawalsRoot)].readBytes32();
}
/// @dev Extract the blob gas used from the block header RLP. This was introduced in Cancun.
function getBlobGasUsed(bytes memory headerRLP) internal pure returns (uint64) {
return _parseHeader(headerRLP, Hardforks.Cancun)[uint8(HeaderField.BlobGasUsed)].readUint256().toUint64();
}
/// @dev Extract the excess blob gas from the block header RLP. This was introduced in Cancun.
function getExcessBlobGas(bytes memory headerRLP) internal pure returns (uint64) {
return _parseHeader(headerRLP, Hardforks.Cancun)[uint8(HeaderField.ExcessBlobGas)].readUint256().toUint64();
}
/// @dev Extract the parent beacon block root from the block header RLP. This was introduced in Cancun.
function getParentBeaconBlockRoot(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Cancun)[uint8(HeaderField.ParentBeaconBlockRoot)].readBytes32();
}
/// @dev Extract the requests hash from the block header RLP. This was introduced in Prague.
function getRequestsHash(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Prague)[uint8(HeaderField.RequestsHash)].readBytes32();
}
/// @dev Extract the block access list hash from the block header RLP. This will be introduced in Amsterdam.
function getBlockAccessListHash(bytes memory headerRLP) internal pure returns (bytes32) {
return _parseHeader(headerRLP, Hardforks.Amsterdam)[uint8(HeaderField.BlockAccessListHash)].readBytes32();
}
/// @dev Internal function to parse the block header RLP and return the list of fields as memory slices.
/// It also checks that the number of fields is at least the expected number for the given hardfork version.
function _parseHeader(bytes memory headerRLP, Hardforks version) private pure returns (Memory.Slice[] memory) {
Memory.Slice[] memory fields = RLP.decodeList(headerRLP);
require(fields.length >= _expectedHeadersLength(version), InvalidBlockHeader(version));
return fields;
}
/// @dev Internal function to return the expected number of fields in the block header RLP for a given hardfork version.
function _expectedHeadersLength(Hardforks version) private pure returns (uint8 count) {
assembly ("memory-safe") {
count := byte(version, 0x0F0F0F0F0F0F0F0F0F0F10101010111415151600000000000000000000000000)
}
}
}