chore: improve clique signer recovery error (#5613)

This commit is contained in:
Matthias Seitz
2023-11-28 13:57:40 +01:00
committed by GitHub
parent 43d1f5a499
commit ae6f1e39c0

View File

@ -92,26 +92,44 @@ pub fn fill_block_env_with_coinbase(
/// Return the coinbase address for the given header and chain spec.
pub fn block_coinbase(chain_spec: &ChainSpec, header: &Header, after_merge: bool) -> Address {
if chain_spec.chain == Chain::goerli() && !after_merge {
recover_header_signer(header).expect("failed to recover signer")
recover_header_signer(header).unwrap_or_else(|err| {
panic!(
"Failed to recover goerli Clique Consensus signer from header ({}, {}) using extradata {}: {:?}",
header.number, header.hash_slow(), header.extra_data, err
)
})
} else {
header.beneficiary
}
}
/// Error type for recovering Clique signer from a header.
#[derive(Debug, thiserror::Error)]
pub enum CliqueSignerRecoveryError {
/// Header extradata is too short.
#[error("Invalid extra data length")]
InvalidExtraData,
/// Recovery failed.
#[error("Invalid signature: {0}")]
InvalidSignature(#[from] secp256k1::Error),
}
/// Recover the account from signed header per clique consensus rules.
pub fn recover_header_signer(header: &Header) -> Option<Address> {
pub fn recover_header_signer(header: &Header) -> Result<Address, CliqueSignerRecoveryError> {
let extra_data_len = header.extra_data.len();
// Fixed number of extra-data suffix bytes reserved for signer signature.
// 65 bytes fixed as signatures are based on the standard secp256k1 curve.
// Filled with zeros on genesis block.
let signature_start_byte = extra_data_len - 65;
let signature: [u8; 65] = header.extra_data[signature_start_byte..].try_into().ok()?;
let signature: [u8; 65] = header.extra_data[signature_start_byte..]
.try_into()
.map_err(|_| CliqueSignerRecoveryError::InvalidExtraData)?;
let seal_hash = {
let mut header_to_seal = header.clone();
header_to_seal.extra_data = Bytes::from(header.extra_data[..signature_start_byte].to_vec());
header_to_seal.hash_slow()
};
recover_signer(&signature, &seal_hash.0).ok()
recover_signer(&signature, &seal_hash.0).map_err(CliqueSignerRecoveryError::InvalidSignature)
}
/// Returns a new [TxEnv] filled with the transaction's data.