-
Notifications
You must be signed in to change notification settings - Fork 924
/
consensus.rs
166 lines (158 loc) · 7.33 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
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
use async_trait::async_trait;
use reth_primitives::{
BlockHash, BlockNumber, Header, InvalidTransactionError, SealedBlock, SealedHeader, H256, U256,
};
use std::fmt::Debug;
/// Re-export fork choice state
pub use reth_rpc_types::engine::ForkchoiceState;
/// Consensus is a protocol that chooses canonical chain.
#[async_trait]
#[auto_impl::auto_impl(&, Arc)]
pub trait Consensus: Debug + Send + Sync {
/// Validate if header is correct and follows consensus specification.
///
/// This is called on standalone header to check if all hashes are correct.
fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError>;
/// Validate that the header information regarding parent are correct.
/// This checks the block number, timestamp, basefee and gas limit increment.
///
/// This is called before properties that are not in the header itself (like total difficulty)
/// have been computed.
///
/// **This should not be called for the genesis block**.
///
/// Note: Validating header against its parent does not include other Consensus validations.
fn validate_header_against_parent(
&self,
header: &SealedHeader,
parent: &SealedHeader,
) -> Result<(), ConsensusError>;
/// Validates the given headers
///
/// This ensures that the first header is valid on its own and all subsequent headers are valid
/// on its own and valid against its parent.
///
/// Note: this expects that the headers are in natural order (ascending block number)
fn validate_header_range(&self, headers: &[SealedHeader]) -> Result<(), ConsensusError> {
if headers.is_empty() {
return Ok(())
}
let first = headers.first().expect("checked empty");
self.validate_header(first)?;
let mut parent = first;
for child in headers.iter().skip(1) {
self.validate_header(child)?;
self.validate_header_against_parent(child, parent)?;
parent = child;
}
Ok(())
}
/// Validate if the header is correct and follows the consensus specification, including
/// computed properties (like total difficulty).
///
/// Some consensus engines may want to do additional checks here.
///
/// Note: validating headers with TD does not include other Consensus validation.
fn validate_header_with_total_difficulty(
&self,
header: &Header,
total_difficulty: U256,
) -> Result<(), ConsensusError>;
/// Validate a block disregarding world state, i.e. things that can be checked before sender
/// recovery and execution.
///
/// See the Yellow Paper sections 4.3.2 "Holistic Validity", 4.3.4 "Block Header Validity", and
/// 11.1 "Ommer Validation".
///
/// **This should not be called for the genesis block**.
///
/// Note: validating blocks does not include other validations of the Consensus
fn validate_block(&self, block: &SealedBlock) -> Result<(), ConsensusError>;
}
/// Consensus Errors
#[allow(missing_docs)]
#[derive(thiserror::Error, Debug, PartialEq, Eq, Clone)]
pub enum ConsensusError {
#[error("Block used gas ({gas_used}) is greater than gas limit ({gas_limit}).")]
HeaderGasUsedExceedsGasLimit { gas_used: u64, gas_limit: u64 },
#[error("Block ommer hash ({got:?}) is different from expected: ({expected:?})")]
BodyOmmersHashDiff { got: H256, expected: H256 },
#[error("Block state root ({got:?}) is different from expected: ({expected:?})")]
BodyStateRootDiff { got: H256, expected: H256 },
#[error("Block transaction root ({got:?}) is different from expected ({expected:?})")]
BodyTransactionRootDiff { got: H256, expected: H256 },
#[error("Block withdrawals root ({got:?}) is different from expected ({expected:?})")]
BodyWithdrawalsRootDiff { got: H256, expected: H256 },
#[error("Block with [hash:{hash:?},number: {number}] is already known.")]
BlockKnown { hash: BlockHash, number: BlockNumber },
#[error("Block parent [hash:{hash:?}] is not known.")]
ParentUnknown { hash: BlockHash },
#[error(
"Block number {block_number} does not match parent block number {parent_block_number}"
)]
ParentBlockNumberMismatch { parent_block_number: BlockNumber, block_number: BlockNumber },
#[error(
"Parent hash {got_parent_hash:?} does not match the expected {expected_parent_hash:?}"
)]
ParentHashMismatch { expected_parent_hash: H256, got_parent_hash: H256 },
#[error(
"Block timestamp {timestamp} is in the past compared to the parent timestamp {parent_timestamp}."
)]
TimestampIsInPast { parent_timestamp: u64, timestamp: u64 },
#[error("Block timestamp {timestamp} is in the future compared to our clock time {present_timestamp}.")]
TimestampIsInFuture { timestamp: u64, present_timestamp: u64 },
#[error("Child gas_limit {child_gas_limit} max increase is {parent_gas_limit}/1024.")]
GasLimitInvalidIncrease { parent_gas_limit: u64, child_gas_limit: u64 },
#[error("Child gas_limit {child_gas_limit} max decrease is {parent_gas_limit}/1024.")]
GasLimitInvalidDecrease { parent_gas_limit: u64, child_gas_limit: u64 },
#[error("Base fee missing.")]
BaseFeeMissing,
#[error("Block base fee ({got}) is different than expected: ({expected}).")]
BaseFeeDiff { expected: u64, got: u64 },
#[error("Transaction signer recovery error.")]
TransactionSignerRecoveryError,
#[error("Extra data {len} exceeds max length: ")]
ExtraDataExceedsMax { len: usize },
#[error("Difficulty after merge is not zero")]
TheMergeDifficultyIsNotZero,
#[error("Nonce after merge is not zero")]
TheMergeNonceIsNotZero,
#[error("Ommer root after merge is not empty")]
TheMergeOmmerRootIsNotEmpty,
#[error("Missing withdrawals root")]
WithdrawalsRootMissing,
#[error("Unexpected withdrawals root")]
WithdrawalsRootUnexpected,
#[error("Withdrawal index #{got} is invalid. Expected: #{expected}.")]
WithdrawalIndexInvalid { got: u64, expected: u64 },
#[error("Missing withdrawals")]
BodyWithdrawalsMissing,
#[error("Missing blob gas used")]
BlobGasUsedMissing,
#[error("Unexpected blob gas used")]
BlobGasUsedUnexpected,
#[error("Missing excess blob gas")]
ExcessBlobGasMissing,
#[error("Unexpected excess blob gas")]
ExcessBlobGasUnexpected,
#[error("Missing parent beacon block root")]
ParentBeaconBlockRootMissing,
#[error("Unexpected parent beacon block root")]
ParentBeaconBlockRootUnexpected,
#[error("Blob gas used {blob_gas_used} exceeds maximum allowance {max_blob_gas_per_block}")]
BlobGasUsedExceedsMaxBlobGasPerBlock { blob_gas_used: u64, max_blob_gas_per_block: u64 },
#[error(
"Blob gas used {blob_gas_used} is not a multiple of blob gas per blob {blob_gas_per_blob}"
)]
BlobGasUsedNotMultipleOfBlobGasPerBlob { blob_gas_used: u64, blob_gas_per_blob: u64 },
#[error("Invalid excess blob gas. Expected: {expected}, got: {got}. Parent excess blob gas: {parent_excess_blob_gas}, parent blob gas used: {parent_blob_gas_used}.")]
ExcessBlobGasDiff {
expected: u64,
got: u64,
parent_excess_blob_gas: u64,
parent_blob_gas_used: u64,
},
/// Error for a transaction that violates consensus.
#[error(transparent)]
InvalidTransaction(#[from] InvalidTransactionError),
}