mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-19 04:45:48 +00:00
Convert Transaction into a wrapping struct with impl Deref
Users who have a Transaction can now only obtain an immutable reference to its underlying data.
This commit is contained in:
parent
0c81695731
commit
1f11c404dc
@ -1,6 +1,7 @@
|
|||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use sapling_crypto::redjubjub::Signature;
|
use sapling_crypto::redjubjub::Signature;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
use serialize::Vector;
|
use serialize::Vector;
|
||||||
|
|
||||||
@ -10,6 +11,8 @@ mod sighash;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
pub use self::sighash::{signature_hash, signature_hash_data, SIGHASH_ALL};
|
||||||
|
|
||||||
use self::components::{Amount, JSDescription, OutputDescription, SpendDescription, TxIn, TxOut};
|
use self::components::{Amount, JSDescription, OutputDescription, SpendDescription, TxIn, TxOut};
|
||||||
|
|
||||||
const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270;
|
const OVERWINTER_VERSION_GROUP_ID: u32 = 0x03C48270;
|
||||||
@ -18,21 +21,64 @@ const SAPLING_VERSION_GROUP_ID: u32 = 0x892F2085;
|
|||||||
const SAPLING_TX_VERSION: u32 = 4;
|
const SAPLING_TX_VERSION: u32 = 4;
|
||||||
|
|
||||||
/// A Zcash transaction.
|
/// A Zcash transaction.
|
||||||
pub struct Transaction {
|
pub struct Transaction(TransactionData);
|
||||||
overwintered: bool,
|
|
||||||
version: u32,
|
impl Deref for Transaction {
|
||||||
version_group_id: u32,
|
type Target = TransactionData;
|
||||||
vin: Vec<TxIn>,
|
|
||||||
vout: Vec<TxOut>,
|
fn deref(&self) -> &TransactionData {
|
||||||
lock_time: u32,
|
&self.0
|
||||||
expiry_height: u32,
|
}
|
||||||
value_balance: Amount,
|
}
|
||||||
shielded_spends: Vec<SpendDescription>,
|
|
||||||
shielded_outputs: Vec<OutputDescription>,
|
pub struct TransactionData {
|
||||||
joinsplits: Vec<JSDescription>,
|
pub overwintered: bool,
|
||||||
joinsplit_pubkey: [u8; 32],
|
pub version: u32,
|
||||||
joinsplit_sig: [u8; 64],
|
pub version_group_id: u32,
|
||||||
binding_sig: Option<Signature>,
|
pub vin: Vec<TxIn>,
|
||||||
|
pub vout: Vec<TxOut>,
|
||||||
|
pub lock_time: u32,
|
||||||
|
pub expiry_height: u32,
|
||||||
|
pub value_balance: Amount,
|
||||||
|
pub shielded_spends: Vec<SpendDescription>,
|
||||||
|
pub shielded_outputs: Vec<OutputDescription>,
|
||||||
|
pub joinsplits: Vec<JSDescription>,
|
||||||
|
pub joinsplit_pubkey: [u8; 32],
|
||||||
|
pub joinsplit_sig: [u8; 64],
|
||||||
|
pub binding_sig: Option<Signature>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransactionData {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TransactionData {
|
||||||
|
overwintered: true,
|
||||||
|
version: SAPLING_TX_VERSION,
|
||||||
|
version_group_id: SAPLING_VERSION_GROUP_ID,
|
||||||
|
vin: vec![],
|
||||||
|
vout: vec![],
|
||||||
|
lock_time: 0,
|
||||||
|
expiry_height: 0,
|
||||||
|
value_balance: Amount(0),
|
||||||
|
shielded_spends: vec![],
|
||||||
|
shielded_outputs: vec![],
|
||||||
|
joinsplits: vec![],
|
||||||
|
joinsplit_pubkey: [0u8; 32],
|
||||||
|
joinsplit_sig: [0u8; 64],
|
||||||
|
binding_sig: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header(&self) -> u32 {
|
||||||
|
let mut header = self.version;
|
||||||
|
if self.overwintered {
|
||||||
|
header |= 1 << 31;
|
||||||
|
}
|
||||||
|
header
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn freeze(self) -> Transaction {
|
||||||
|
Transaction(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
@ -97,7 +143,7 @@ impl Transaction {
|
|||||||
false => None,
|
false => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Transaction {
|
Ok(Transaction(TransactionData {
|
||||||
overwintered,
|
overwintered,
|
||||||
version,
|
version,
|
||||||
version_group_id,
|
version_group_id,
|
||||||
@ -112,7 +158,7 @@ impl Transaction {
|
|||||||
joinsplit_pubkey,
|
joinsplit_pubkey,
|
||||||
joinsplit_sig,
|
joinsplit_sig,
|
||||||
binding_sig,
|
binding_sig,
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||||
@ -169,12 +215,4 @@ impl Transaction {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header(&self) -> u32 {
|
|
||||||
let mut header = self.version;
|
|
||||||
if self.overwintered {
|
|
||||||
header |= 1 << 31;
|
|
||||||
}
|
|
||||||
header
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,8 @@ use pairing::{PrimeField, PrimeFieldRepr};
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
components::{Amount, Script},
|
components::{Amount, Script},
|
||||||
Transaction, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, SAPLING_VERSION_GROUP_ID,
|
Transaction, TransactionData, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION,
|
||||||
|
SAPLING_VERSION_GROUP_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
||||||
@ -53,7 +54,7 @@ enum SigHashVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SigHashVersion {
|
impl SigHashVersion {
|
||||||
fn from_tx(tx: &Transaction) -> Self {
|
fn from_tx(tx: &TransactionData) -> Self {
|
||||||
if tx.overwintered {
|
if tx.overwintered {
|
||||||
match tx.version_group_id {
|
match tx.version_group_id {
|
||||||
OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter,
|
OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter,
|
||||||
@ -66,7 +67,7 @@ impl SigHashVersion {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prevout_hash(tx: &Transaction) -> Vec<u8> {
|
fn prevout_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
let mut data = Vec::with_capacity(tx.vin.len() * 36);
|
let mut data = Vec::with_capacity(tx.vin.len() * 36);
|
||||||
for t_in in &tx.vin {
|
for t_in in &tx.vin {
|
||||||
t_in.prevout.write(&mut data).unwrap();
|
t_in.prevout.write(&mut data).unwrap();
|
||||||
@ -76,7 +77,7 @@ fn prevout_hash(tx: &Transaction) -> Vec<u8> {
|
|||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sequence_hash(tx: &Transaction) -> Vec<u8> {
|
fn sequence_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
let mut data = Vec::with_capacity(tx.vin.len() * 4);
|
let mut data = Vec::with_capacity(tx.vin.len() * 4);
|
||||||
for t_in in &tx.vin {
|
for t_in in &tx.vin {
|
||||||
(&mut data)
|
(&mut data)
|
||||||
@ -88,7 +89,7 @@ fn sequence_hash(tx: &Transaction) -> Vec<u8> {
|
|||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outputs_hash(tx: &Transaction) -> Vec<u8> {
|
fn outputs_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1));
|
let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1));
|
||||||
for t_out in &tx.vout {
|
for t_out in &tx.vout {
|
||||||
t_out.write(&mut data).unwrap();
|
t_out.write(&mut data).unwrap();
|
||||||
@ -98,7 +99,7 @@ fn outputs_hash(tx: &Transaction) -> Vec<u8> {
|
|||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn joinsplits_hash(tx: &Transaction) -> Vec<u8> {
|
fn joinsplits_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
let mut data = Vec::with_capacity(
|
let mut data = Vec::with_capacity(
|
||||||
tx.joinsplits.len() * if tx.version < SAPLING_TX_VERSION {
|
tx.joinsplits.len() * if tx.version < SAPLING_TX_VERSION {
|
||||||
1802 // JSDescription with PHGR13 proof
|
1802 // JSDescription with PHGR13 proof
|
||||||
@ -115,7 +116,7 @@ fn joinsplits_hash(tx: &Transaction) -> Vec<u8> {
|
|||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shielded_spends_hash(tx: &Transaction) -> Vec<u8> {
|
fn shielded_spends_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
|
let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
|
||||||
for s_spend in &tx.shielded_spends {
|
for s_spend in &tx.shielded_spends {
|
||||||
s_spend.cv.write(&mut data).unwrap();
|
s_spend.cv.write(&mut data).unwrap();
|
||||||
@ -129,7 +130,7 @@ fn shielded_spends_hash(tx: &Transaction) -> Vec<u8> {
|
|||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shielded_outputs_hash(tx: &Transaction) -> Vec<u8> {
|
fn shielded_outputs_hash(tx: &TransactionData) -> Vec<u8> {
|
||||||
let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948);
|
let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948);
|
||||||
for s_out in &tx.shielded_outputs {
|
for s_out in &tx.shielded_outputs {
|
||||||
s_out.write(&mut data).unwrap();
|
s_out.write(&mut data).unwrap();
|
||||||
@ -139,8 +140,8 @@ fn shielded_outputs_hash(tx: &Transaction) -> Vec<u8> {
|
|||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature_hash(
|
pub fn signature_hash_data(
|
||||||
tx: &Transaction,
|
tx: &TransactionData,
|
||||||
consensus_branch_id: u32,
|
consensus_branch_id: u32,
|
||||||
hash_type: u32,
|
hash_type: u32,
|
||||||
transparent_input: Option<(usize, Script, Amount)>,
|
transparent_input: Option<(usize, Script, Amount)>,
|
||||||
@ -219,3 +220,12 @@ pub fn signature_hash(
|
|||||||
SigHashVersion::Sprout => unimplemented!(),
|
SigHashVersion::Sprout => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn signature_hash(
|
||||||
|
tx: &Transaction,
|
||||||
|
consensus_branch_id: u32,
|
||||||
|
hash_type: u32,
|
||||||
|
transparent_input: Option<(usize, Script, Amount)>,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
signature_hash_data(tx, consensus_branch_id, hash_type, transparent_input)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user