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:
parent
fd3e01d6e3
commit
840520042a
|
@ -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 {
|
||||||
script::Instruction::PushBytes(b) if b.len() > 8 => {
|
Ok(h as u64)
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue