BIP 34: Check last minimal encoding of encoded heights in coinbase tx

See: https://github.com/bitcoin/bips/blob/master/bip-0034.mediawiki
This commit is contained in:
sanket1729 2022-09-06 01:24:50 -07:00
parent fd3e01d6e3
commit 840520042a
1 changed files with 16 additions and 10 deletions

View File

@ -317,7 +317,7 @@ impl Block {
// Citing the spec: // Citing the spec:
// Add height as the first item in the coinbase transaction's scriptSig, // Add height as the first item in the coinbase transaction's scriptSig,
// and increase block version to 2. The format of the height is // and increase block version to 2. The format of the height is
// "serialized CScript" -- first byte is number of bytes in the number // "minimally encoded serialized CScript"" -- first byte is number of bytes in the number
// (will be 0x03 on main net for the next 150 or so years with 2^23-1 // (will be 0x03 on main net for the next 150 or so years with 2^23-1
// blocks), following bytes are little-endian representation of the // blocks), following bytes are little-endian representation of the
// number (including a sign bit). Height is the height of the mined // number (including a sign bit). Height is the height of the mined
@ -331,14 +331,14 @@ impl Block {
let input = cb.input.first().ok_or(Bip34Error::NotPresent)?; let input = cb.input.first().ok_or(Bip34Error::NotPresent)?;
let push = input.script_sig.instructions_minimal().next().ok_or(Bip34Error::NotPresent)?; let push = input.script_sig.instructions_minimal().next().ok_or(Bip34Error::NotPresent)?;
match push.map_err(|_| Bip34Error::NotPresent)? { match push.map_err(|_| Bip34Error::NotPresent)? {
script::Instruction::PushBytes(b) if b.len() <= 8 => { script::Instruction::PushBytes(b) => {
// Expand the push to exactly 8 bytes (LE). // Check that the number is encoded in the minimal way.
let mut full = [0; 8]; let h = script::read_scriptint(b).map_err(|_e| Bip34Error::UnexpectedPush(b.to_vec()))?;
full[0..b.len()].copy_from_slice(b); if h < 0 {
Ok(util::endian::slice_to_u64_le(&full)) Err(Bip34Error::NegativeHeight)
} else {
Ok(h as u64)
} }
script::Instruction::PushBytes(b) if b.len() > 8 => {
Err(Bip34Error::UnexpectedPush(b.to_vec()))
} }
_ => Err(Bip34Error::NotPresent), _ => Err(Bip34Error::NotPresent),
} }
@ -355,6 +355,8 @@ pub enum Bip34Error {
NotPresent, NotPresent,
/// The BIP34 push was larger than 8 bytes. /// The BIP34 push was larger than 8 bytes.
UnexpectedPush(Vec<u8>), UnexpectedPush(Vec<u8>),
/// The BIP34 push was negative.
NegativeHeight,
} }
impl fmt::Display for Bip34Error { impl fmt::Display for Bip34Error {
@ -365,6 +367,7 @@ impl fmt::Display for Bip34Error {
Bip34Error::UnexpectedPush(ref p) => { Bip34Error::UnexpectedPush(ref p) => {
write!(f, "unexpected byte push of > 8 bytes: {:?}", p) write!(f, "unexpected byte push of > 8 bytes: {:?}", p)
} }
Bip34Error::NegativeHeight => write!(f, "negative BIP34 height"),
} }
} }
} }
@ -376,7 +379,10 @@ impl std::error::Error for Bip34Error {
use self::Bip34Error::*; use self::Bip34Error::*;
match self { match self {
Unsupported | NotPresent | UnexpectedPush(_) => None, Unsupported |
NotPresent |
UnexpectedPush(_) |
NegativeHeight => None,
} }
} }
} }