Represent coinbase inputs explicitly.
Coinbase inputs are handled differently from other inputs and have different consensus rules, so they should be represented differently in the source code. This lets us discard extraneous details (for instance, it's not necessary to maintain the all-zero hash) and specialize logic.
This commit is contained in:
parent
be56e10abe
commit
4957567409
|
|
@ -152,19 +152,13 @@ impl ZcashDeserialize for BlockHeader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A block in your blockchain.
|
/// A Zcash block, containing a [`BlockHeader`] and a sequence of
|
||||||
///
|
/// [`Transaction`]s.
|
||||||
/// A block is a data structure with two fields:
|
|
||||||
///
|
|
||||||
/// Block header: a data structure containing the block's metadata
|
|
||||||
/// Transactions: an array (vector in Rust) of transactions
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
/// First 80 bytes of the block as defined by the encoding used by
|
/// The block header, containing block metadata.
|
||||||
/// "block" messages.
|
|
||||||
pub header: BlockHeader,
|
pub header: BlockHeader,
|
||||||
|
|
||||||
/// The block transactions.
|
/// The block transactions.
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<Transaction>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
//! transaction types, so that all of the serialization logic is in one place.
|
//! transaction types, so that all of the serialization logic is in one place.
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use std::io;
|
use std::io::{self, Read};
|
||||||
|
|
||||||
use crate::proofs::ZkSnarkProof;
|
use crate::proofs::ZkSnarkProof;
|
||||||
use crate::serialization::{
|
use crate::serialization::{
|
||||||
|
|
@ -34,22 +34,58 @@ impl ZcashDeserialize for OutPoint {
|
||||||
|
|
||||||
impl ZcashSerialize for TransparentInput {
|
impl ZcashSerialize for TransparentInput {
|
||||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||||
self.previous_output.zcash_serialize(&mut writer)?;
|
match self {
|
||||||
self.signature_script.zcash_serialize(&mut writer)?;
|
TransparentInput::PrevOut {
|
||||||
writer.write_u32::<LittleEndian>(self.sequence)?;
|
outpoint,
|
||||||
|
script,
|
||||||
|
sequence,
|
||||||
|
} => {
|
||||||
|
outpoint.zcash_serialize(&mut writer)?;
|
||||||
|
script.zcash_serialize(&mut writer)?;
|
||||||
|
writer.write_u32::<LittleEndian>(*sequence)?;
|
||||||
|
}
|
||||||
|
TransparentInput::Coinbase { data, sequence } => {
|
||||||
|
writer.write_all(&[0; 32][..])?;
|
||||||
|
writer.write_u32::<LittleEndian>(0xffff_ffff)?;
|
||||||
|
assert!(data.len() <= 100);
|
||||||
|
writer.write_compactsize(data.len() as u64)?;
|
||||||
|
writer.write_all(&data[..])?;
|
||||||
|
writer.write_u32::<LittleEndian>(*sequence)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZcashDeserialize for TransparentInput {
|
impl ZcashDeserialize for TransparentInput {
|
||||||
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
|
||||||
Ok(TransparentInput {
|
// This inlines the OutPoint deserialization to peek at the hash value
|
||||||
previous_output: OutPoint::zcash_deserialize(&mut reader)?,
|
// and detect whether we have a coinbase input.
|
||||||
signature_script: Script::zcash_deserialize(&mut reader)?,
|
let bytes = reader.read_32_bytes()?;
|
||||||
|
if bytes == [0; 32] {
|
||||||
|
if reader.read_u32::<LittleEndian>()? != 0xffff_ffff {
|
||||||
|
return Err(SerializationError::Parse("wrong index in coinbase"));
|
||||||
|
}
|
||||||
|
let len = reader.read_compactsize()?;
|
||||||
|
if len > 100 {
|
||||||
|
return Err(SerializationError::Parse("coinbase has too much data"));
|
||||||
|
}
|
||||||
|
let mut data = Vec::with_capacity(len as usize);
|
||||||
|
(&mut reader).take(len).read_to_end(&mut data)?;
|
||||||
|
let sequence = reader.read_u32::<LittleEndian>()?;
|
||||||
|
Ok(TransparentInput::Coinbase { data, sequence })
|
||||||
|
} else {
|
||||||
|
Ok(TransparentInput::PrevOut {
|
||||||
|
outpoint: OutPoint {
|
||||||
|
hash: TransactionHash(bytes),
|
||||||
|
index: reader.read_u32::<LittleEndian>()?,
|
||||||
|
},
|
||||||
|
script: Script::zcash_deserialize(&mut reader)?,
|
||||||
sequence: reader.read_u32::<LittleEndian>()?,
|
sequence: reader.read_u32::<LittleEndian>()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ZcashSerialize for TransparentOutput {
|
impl ZcashSerialize for TransparentOutput {
|
||||||
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use proptest::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
serialization::{ZcashDeserialize, ZcashSerialize},
|
serialization::{ZcashDeserialize, ZcashSerialize},
|
||||||
types::LockTime,
|
types::{LockTime, Script},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -116,6 +116,31 @@ impl Arbitrary for Transaction {
|
||||||
type Strategy = BoxedStrategy<Self>;
|
type Strategy = BoxedStrategy<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl Arbitrary for TransparentInput {
|
||||||
|
type Parameters = ();
|
||||||
|
|
||||||
|
fn arbitrary_with(_args: ()) -> Self::Strategy {
|
||||||
|
prop_oneof![
|
||||||
|
(any::<OutPoint>(), any::<Script>(), any::<u32>())
|
||||||
|
.prop_map(|(outpoint, script, sequence)| {
|
||||||
|
TransparentInput::PrevOut {
|
||||||
|
outpoint,
|
||||||
|
script,
|
||||||
|
sequence,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.boxed(),
|
||||||
|
(vec(any::<u8>(), 0..100), any::<u32>())
|
||||||
|
.prop_map(|(data, sequence)| { TransparentInput::Coinbase { data, sequence } })
|
||||||
|
.boxed(),
|
||||||
|
]
|
||||||
|
.boxed()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Strategy = BoxedStrategy<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn librustzcash_tx_deserialize_and_round_trip() {
|
fn librustzcash_tx_deserialize_and_round_trip() {
|
||||||
let tx = Transaction::zcash_deserialize(&test_vectors::GENERIC_TESTNET_TX[..])
|
let tx = Transaction::zcash_deserialize(&test_vectors::GENERIC_TESTNET_TX[..])
|
||||||
|
|
|
||||||
|
|
@ -23,18 +23,23 @@ pub struct OutPoint {
|
||||||
|
|
||||||
/// A transparent input to a transaction.
|
/// A transparent input to a transaction.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
pub enum TransparentInput {
|
||||||
pub struct TransparentInput {
|
/// A reference to an output of a previous transaction.
|
||||||
|
PrevOut {
|
||||||
/// The previous output transaction reference.
|
/// The previous output transaction reference.
|
||||||
pub previous_output: OutPoint,
|
outpoint: OutPoint,
|
||||||
|
/// The script that authorizes spending `outpoint`.
|
||||||
/// Computational Script for confirming transaction authorization.
|
script: Script,
|
||||||
pub signature_script: Script,
|
/// The sequence number for the output.
|
||||||
|
sequence: u32,
|
||||||
/// Transaction version as defined by the sender. Intended for
|
},
|
||||||
/// "replacement" of transactions when information is updated
|
/// New coins created by the block reward.
|
||||||
/// before inclusion into a block.
|
Coinbase {
|
||||||
pub sequence: u32,
|
/// 100 bytes of arbitrary data.
|
||||||
|
data: Vec<u8>,
|
||||||
|
/// The sequence number for the output.
|
||||||
|
sequence: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A transparent output from a transaction.
|
/// A transparent output from a transaction.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue