zcash_transparent: Refactor code so it compiles in its new crate
This commit is contained in:
parent
1a3eeab703
commit
e4915f99c4
|
@ -1249,6 +1249,7 @@ dependencies = [
|
|||
"zcash_primitives",
|
||||
"zcash_proofs",
|
||||
"zcash_protocol",
|
||||
"zcash_transparent",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6424,7 +6425,9 @@ dependencies = [
|
|||
name = "zcash_protocol"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"core2",
|
||||
"document-features",
|
||||
"hex",
|
||||
"incrementalmerkletree",
|
||||
"incrementalmerkletree-testing",
|
||||
"memuse",
|
||||
|
|
|
@ -6,6 +6,9 @@ and this library adheres to Rust's notion of
|
|||
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- `zcash_protocol::TxId` (moved from `zcash_primitives::transaction`).
|
||||
|
||||
## [0.4.2] - 2024-12-13
|
||||
### Added
|
||||
- `no-std` compatibility (`alloc` is required). A default-enabled `std` feature
|
||||
|
|
|
@ -28,6 +28,10 @@ memuse = { workspace = true, optional = true }
|
|||
# - Documentation
|
||||
document-features = { workspace = true, optional = true }
|
||||
|
||||
# - Encodings
|
||||
core2.workspace = true
|
||||
hex.workspace = true
|
||||
|
||||
# - Test dependencies
|
||||
proptest = { workspace = true, optional = true }
|
||||
incrementalmerkletree = { workspace = true, optional = true }
|
||||
|
|
|
@ -31,6 +31,9 @@ pub mod local_consensus;
|
|||
pub mod memo;
|
||||
pub mod value;
|
||||
|
||||
mod txid;
|
||||
pub use txid::TxId;
|
||||
|
||||
/// A Zcash shielded transfer protocol.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ShieldedProtocol {
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
use alloc::string::ToString;
|
||||
use core::fmt;
|
||||
use core2::io::{self, Read, Write};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use memuse::DynamicUsage;
|
||||
|
||||
/// The identifier for a Zcash transaction.
|
||||
///
|
||||
/// - For v1-4 transactions, this is a double-SHA-256 hash of the encoded transaction.
|
||||
/// This means that it is malleable, and only a reliable identifier for transactions
|
||||
/// that have been mined.
|
||||
/// - For v5 transactions onwards, this identifier is derived only from "effecting" data,
|
||||
/// and is non-malleable in all contexts.
|
||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
pub struct TxId([u8; 32]);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
memuse::impl_no_dynamic_usage!(TxId);
|
||||
|
||||
impl fmt::Debug for TxId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// The (byte-flipped) hex string is more useful than the raw bytes, because we can
|
||||
// look that up in RPC methods and block explorers.
|
||||
let txid_str = self.to_string();
|
||||
f.debug_tuple("TxId").field(&txid_str).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TxId {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut data = self.0;
|
||||
data.reverse();
|
||||
formatter.write_str(&hex::encode(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for TxId {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxId> for [u8; 32] {
|
||||
fn from(value: TxId) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TxId {
|
||||
pub const fn from_bytes(bytes: [u8; 32]) -> Self {
|
||||
TxId(bytes)
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut hash = [0u8; 32];
|
||||
reader.read_exact(&mut hash)?;
|
||||
Ok(TxId::from_bytes(hash))
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(&self.0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ zcash_protocol = {workspace = true, features = ["local-consensus"] }
|
|||
|
||||
# Transparent
|
||||
secp256k1.workspace = true
|
||||
transparent.workspace = true
|
||||
|
||||
# Sprout
|
||||
ed25519-zebra = "4"
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::{
|
|||
convert::{TryFrom, TryInto},
|
||||
};
|
||||
|
||||
use ::transparent::sighash::SighashType;
|
||||
use bellman::groth16;
|
||||
use group::GroupEncoding;
|
||||
use orchard::note_encryption::OrchardDomain;
|
||||
|
@ -283,7 +284,7 @@ pub(crate) fn inspect(
|
|||
let sig = secp256k1::ecdsa::Signature::from_der(
|
||||
&txin.script_sig.0[1..1 + sig_len],
|
||||
);
|
||||
let hash_type = txin.script_sig.0[1 + sig_len];
|
||||
let hash_type = SighashType::parse(txin.script_sig.0[1 + sig_len]);
|
||||
let pubkey_bytes = &txin.script_sig.0[1 + sig_len + 2..];
|
||||
let pubkey = secp256k1::PublicKey::from_slice(pubkey_bytes);
|
||||
|
||||
|
@ -293,13 +294,18 @@ pub(crate) fn inspect(
|
|||
i, e
|
||||
);
|
||||
}
|
||||
if hash_type.is_none() {
|
||||
eprintln!(" ⚠️ Txin {} has invalid sighash type", i);
|
||||
}
|
||||
if let Err(e) = pubkey {
|
||||
eprintln!(
|
||||
" ⚠️ Txin {} has invalid pubkey encoding: {}",
|
||||
i, e
|
||||
);
|
||||
}
|
||||
if let (Ok(sig), Ok(pubkey)) = (sig, pubkey) {
|
||||
if let (Ok(sig), Some(hash_type), Ok(pubkey)) =
|
||||
(sig, hash_type, pubkey)
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
if pubkey_to_address(&pubkey) != addr {
|
||||
eprintln!(" ⚠️ Txin {} pubkey does not match coin's script_pubkey", i);
|
||||
|
@ -307,14 +313,16 @@ pub(crate) fn inspect(
|
|||
|
||||
let sighash = signature_hash(
|
||||
tx,
|
||||
&SignableInput::Transparent {
|
||||
hash_type,
|
||||
index: i,
|
||||
// For P2PKH these are the same.
|
||||
script_code: &coin.script_pubkey,
|
||||
script_pubkey: &coin.script_pubkey,
|
||||
value: coin.value,
|
||||
},
|
||||
&SignableInput::Transparent(
|
||||
::transparent::sighash::SignableInput::from_parts(
|
||||
hash_type,
|
||||
i,
|
||||
// For P2PKH these are the same.
|
||||
&coin.script_pubkey,
|
||||
&coin.script_pubkey,
|
||||
coin.value,
|
||||
),
|
||||
),
|
||||
txid_parts,
|
||||
);
|
||||
let msg = secp256k1::Message::from_slice(sighash.as_ref())
|
||||
|
|
|
@ -95,7 +95,21 @@ impl Signer {
|
|||
// TODO
|
||||
|
||||
input
|
||||
.sign(index, &self.tx_data, &self.txid_parts, sk, &self.secp)
|
||||
.sign(
|
||||
index,
|
||||
|input| {
|
||||
v5_signature_hash(
|
||||
&self.tx_data,
|
||||
&SignableInput::Transparent(input),
|
||||
&self.txid_parts,
|
||||
)
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
},
|
||||
sk,
|
||||
&self.secp,
|
||||
)
|
||||
.map_err(Error::TransparentSign)?;
|
||||
|
||||
// Update transaction modifiability:
|
||||
|
|
|
@ -24,8 +24,8 @@ and this library adheres to Rust's notion of
|
|||
- `zcash_primitives::transaction::components::transparent`:
|
||||
- `builder::TransparentBuilder::add_input` now takes `secp256k1::PublicKey`
|
||||
instead of `secp256k1::SecretKey`.
|
||||
- `Bundle<Unauthorized>::apply_signatures` now takes an additional argument
|
||||
`&TransparentSigningSet`.
|
||||
- `Bundle<Unauthorized>::apply_signatures` has had its arguments replaced with
|
||||
a function providing the sighash calculation, and `&TransparentSigningSet`.
|
||||
- `builder::Error` has a new variant `MissingSigningKey`.
|
||||
- `zcash_primitives::transaction::builder`:
|
||||
- `Builder::add_orchard_spend` now takes `orchard::keys::FullViewingKey`
|
||||
|
@ -38,6 +38,9 @@ and this library adheres to Rust's notion of
|
|||
- `&TransparentSigningSet`
|
||||
- `&[sapling::zip32::ExtendedSpendingKey]`
|
||||
- `&[orchard::keys::SpendAuthorizingKey]`
|
||||
- `zcash_primitives::transaction::sighash`:
|
||||
- `SignableInput::Transparent` is now a wrapper around
|
||||
`zcash_transparent::sighash::SignableInput`.
|
||||
|
||||
## [0.20.0] - 2024-11-14
|
||||
|
||||
|
|
|
@ -806,10 +806,14 @@ impl<'a, P: consensus::Parameters, U: sapling::builder::ProverProgress> Builder<
|
|||
.clone()
|
||||
.map(|b| {
|
||||
b.apply_signatures(
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
&unauthed_tx,
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
&txid_parts,
|
||||
|input| {
|
||||
*signature_hash(
|
||||
&unauthed_tx,
|
||||
&SignableInput::Transparent(input),
|
||||
&txid_parts,
|
||||
)
|
||||
.as_ref()
|
||||
},
|
||||
transparent_signing_set,
|
||||
)
|
||||
})
|
||||
|
|
|
@ -13,9 +13,7 @@ mod tests;
|
|||
|
||||
use blake2b_simd::Hash as Blake2bHash;
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use memuse::DynamicUsage;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::ops::Deref;
|
||||
|
@ -60,63 +58,7 @@ const ZFUTURE_VERSION_GROUP_ID: u32 = 0xFFFFFFFF;
|
|||
#[cfg(zcash_unstable = "zfuture")]
|
||||
const ZFUTURE_TX_VERSION: u32 = 0x0000FFFF;
|
||||
|
||||
/// The identifier for a Zcash transaction.
|
||||
///
|
||||
/// - For v1-4 transactions, this is a double-SHA-256 hash of the encoded transaction.
|
||||
/// This means that it is malleable, and only a reliable identifier for transactions
|
||||
/// that have been mined.
|
||||
/// - For v5 transactions onwards, this identifier is derived only from "effecting" data,
|
||||
/// and is non-malleable in all contexts.
|
||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||
pub struct TxId([u8; 32]);
|
||||
|
||||
memuse::impl_no_dynamic_usage!(TxId);
|
||||
|
||||
impl fmt::Debug for TxId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// The (byte-flipped) hex string is more useful than the raw bytes, because we can
|
||||
// look that up in RPC methods and block explorers.
|
||||
let txid_str = self.to_string();
|
||||
f.debug_tuple("TxId").field(&txid_str).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TxId {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut data = self.0;
|
||||
data.reverse();
|
||||
formatter.write_str(&hex::encode(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for TxId {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TxId> for [u8; 32] {
|
||||
fn from(value: TxId) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TxId {
|
||||
pub fn from_bytes(bytes: [u8; 32]) -> Self {
|
||||
TxId(bytes)
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
let mut hash = [0u8; 32];
|
||||
reader.read_exact(&mut hash)?;
|
||||
Ok(TxId::from_bytes(hash))
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(&self.0)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub use zcash_protocol::TxId;
|
||||
|
||||
/// The set of defined transaction format versions.
|
||||
///
|
||||
|
@ -611,12 +553,12 @@ impl Transaction {
|
|||
|
||||
fn from_data_v4(data: TransactionData<Authorized>) -> io::Result<Self> {
|
||||
let mut tx = Transaction {
|
||||
txid: TxId([0; 32]),
|
||||
txid: TxId::from_bytes([0; 32]),
|
||||
data,
|
||||
};
|
||||
let mut writer = HashWriter::default();
|
||||
tx.write(&mut writer)?;
|
||||
tx.txid.0.copy_from_slice(&writer.into_hash());
|
||||
tx.txid = TxId::from_bytes(writer.into_hash().into());
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
|
@ -706,7 +648,7 @@ impl Transaction {
|
|||
txid.copy_from_slice(&hash_bytes);
|
||||
|
||||
Ok(Transaction {
|
||||
txid: TxId(txid),
|
||||
txid: TxId::from_bytes(txid),
|
||||
data: TransactionData {
|
||||
version,
|
||||
consensus_branch_id,
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
use blake2b_simd::Hash as Blake2bHash;
|
||||
|
||||
use super::{
|
||||
components::amount::NonNegativeAmount, sighash_v4::v4_signature_hash,
|
||||
sighash_v5::v5_signature_hash, Authorization, TransactionData, TxDigests, TxVersion,
|
||||
};
|
||||
use crate::{
|
||||
legacy::Script,
|
||||
sapling::{self, bundle::GrothProofBytes},
|
||||
sighash_v4::v4_signature_hash, sighash_v5::v5_signature_hash, Authorization, TransactionData,
|
||||
TxDigests, TxVersion,
|
||||
};
|
||||
use crate::sapling::{self, bundle::GrothProofBytes};
|
||||
|
||||
#[cfg(zcash_unstable = "zfuture")]
|
||||
use {super::components::Amount, crate::extensions::transparent::Precondition};
|
||||
|
@ -16,13 +13,7 @@ pub use transparent::sighash::*;
|
|||
|
||||
pub enum SignableInput<'a> {
|
||||
Shielded,
|
||||
Transparent {
|
||||
hash_type: u8,
|
||||
index: usize,
|
||||
script_code: &'a Script,
|
||||
script_pubkey: &'a Script,
|
||||
value: NonNegativeAmount,
|
||||
},
|
||||
Transparent(transparent::sighash::SignableInput<'a>),
|
||||
#[cfg(zcash_unstable = "zfuture")]
|
||||
Tze {
|
||||
index: usize,
|
||||
|
@ -35,7 +26,7 @@ impl<'a> SignableInput<'a> {
|
|||
pub fn hash_type(&self) -> u8 {
|
||||
match self {
|
||||
SignableInput::Shielded => SIGHASH_ALL,
|
||||
SignableInput::Transparent { hash_type, .. } => *hash_type,
|
||||
SignableInput::Transparent(input) => input.hash_type().encode(),
|
||||
#[cfg(zcash_unstable = "zfuture")]
|
||||
SignableInput::Tze { .. } => SIGHASH_ALL,
|
||||
}
|
||||
|
|
|
@ -186,8 +186,8 @@ pub fn v4_signature_hash<
|
|||
);
|
||||
} else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE {
|
||||
match (tx.transparent_bundle.as_ref(), signable_input) {
|
||||
(Some(b), SignableInput::Transparent { index, .. }) if index < &b.vout.len() => {
|
||||
h.update(single_output_hash(&b.vout[*index]).as_bytes())
|
||||
(Some(b), SignableInput::Transparent(input)) if input.index() < &b.vout.len() => {
|
||||
h.update(single_output_hash(&b.vout[*input.index()]).as_bytes())
|
||||
}
|
||||
_ => h.update(&[0; 32]),
|
||||
};
|
||||
|
@ -235,18 +235,13 @@ pub fn v4_signature_hash<
|
|||
|
||||
match signable_input {
|
||||
SignableInput::Shielded => (),
|
||||
SignableInput::Transparent {
|
||||
index,
|
||||
script_code,
|
||||
value,
|
||||
..
|
||||
} => {
|
||||
SignableInput::Transparent(input) => {
|
||||
if let Some(bundle) = tx.transparent_bundle.as_ref() {
|
||||
let mut data = vec![];
|
||||
bundle.vin[*index].prevout.write(&mut data).unwrap();
|
||||
script_code.write(&mut data).unwrap();
|
||||
data.extend_from_slice(&value.to_i64_le_bytes());
|
||||
data.extend_from_slice(&bundle.vin[*index].sequence.to_le_bytes());
|
||||
bundle.vin[*input.index()].prevout.write(&mut data).unwrap();
|
||||
input.script_code().write(&mut data).unwrap();
|
||||
data.extend_from_slice(&input.value().to_i64_le_bytes());
|
||||
data.extend_from_slice(&bundle.vin[*input.index()].sequence.to_le_bytes());
|
||||
h.update(&data);
|
||||
} else {
|
||||
panic!(
|
||||
|
|
|
@ -89,10 +89,10 @@ fn transparent_sig_digest<A: TransparentAuthorizingContext>(
|
|||
txid_digests.sequence_digest
|
||||
};
|
||||
|
||||
let outputs_digest = if let SignableInput::Transparent { index, .. } = input {
|
||||
let outputs_digest = if let SignableInput::Transparent(input) = input {
|
||||
if flag_single {
|
||||
if *index < bundle.vout.len() {
|
||||
transparent_outputs_hash(&[&bundle.vout[*index]])
|
||||
if *input.index() < bundle.vout.len() {
|
||||
transparent_outputs_hash(&[&bundle.vout[*input.index()]])
|
||||
} else {
|
||||
transparent_outputs_hash::<TxOut>(&[])
|
||||
}
|
||||
|
@ -110,17 +110,11 @@ fn transparent_sig_digest<A: TransparentAuthorizingContext>(
|
|||
//S.2g.iii: scriptPubKey (field encoding)
|
||||
//S.2g.iv: nSequence (4-byte unsigned little-endian)
|
||||
let mut ch = hasher(ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION);
|
||||
if let SignableInput::Transparent {
|
||||
index,
|
||||
script_pubkey,
|
||||
value,
|
||||
..
|
||||
} = input
|
||||
{
|
||||
let txin = &bundle.vin[*index];
|
||||
if let SignableInput::Transparent(input) = input {
|
||||
let txin = &bundle.vin[*input.index()];
|
||||
txin.prevout.write(&mut ch).unwrap();
|
||||
ch.write_all(&value.to_i64_le_bytes()).unwrap();
|
||||
script_pubkey.write(&mut ch).unwrap();
|
||||
ch.write_all(&input.value().to_i64_le_bytes()).unwrap();
|
||||
input.script_pubkey().write(&mut ch).unwrap();
|
||||
ch.write_all(&txin.sequence.to_le_bytes()).unwrap();
|
||||
}
|
||||
let txin_sig_digest = ch.finalize();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use ::transparent::sighash::SighashType;
|
||||
use blake2b_simd::Hash as Blake2bHash;
|
||||
use std::ops::Deref;
|
||||
|
||||
|
@ -9,10 +10,7 @@ use crate::{
|
|||
|
||||
use super::{
|
||||
sapling,
|
||||
sighash::{
|
||||
SignableInput, TransparentAuthorizingContext, SIGHASH_ALL, SIGHASH_ANYONECANPAY,
|
||||
SIGHASH_NONE, SIGHASH_SINGLE,
|
||||
},
|
||||
sighash::{SignableInput, TransparentAuthorizingContext},
|
||||
sighash_v4::v4_signature_hash,
|
||||
sighash_v5::v5_signature_hash,
|
||||
testing::arb_tx,
|
||||
|
@ -136,13 +134,15 @@ fn zip_0143() {
|
|||
for tv in self::data::zip_0143::make_test_vectors() {
|
||||
let tx = Transaction::read(&tv.tx[..], tv.consensus_branch_id).unwrap();
|
||||
let signable_input = match tv.transparent_input {
|
||||
Some(n) => SignableInput::Transparent {
|
||||
hash_type: tv.hash_type as u8,
|
||||
index: n as usize,
|
||||
script_code: &tv.script_code,
|
||||
script_pubkey: &tv.script_code,
|
||||
value: NonNegativeAmount::from_nonnegative_i64(tv.amount).unwrap(),
|
||||
},
|
||||
Some(n) => {
|
||||
SignableInput::Transparent(::transparent::sighash::SignableInput::from_parts(
|
||||
SighashType::parse(tv.hash_type as u8).unwrap(),
|
||||
n as usize,
|
||||
&tv.script_code,
|
||||
&tv.script_code,
|
||||
NonNegativeAmount::from_nonnegative_i64(tv.amount).unwrap(),
|
||||
))
|
||||
}
|
||||
_ => SignableInput::Shielded,
|
||||
};
|
||||
|
||||
|
@ -158,13 +158,15 @@ fn zip_0243() {
|
|||
for tv in self::data::zip_0243::make_test_vectors() {
|
||||
let tx = Transaction::read(&tv.tx[..], tv.consensus_branch_id).unwrap();
|
||||
let signable_input = match tv.transparent_input {
|
||||
Some(n) => SignableInput::Transparent {
|
||||
hash_type: tv.hash_type as u8,
|
||||
index: n as usize,
|
||||
script_code: &tv.script_code,
|
||||
script_pubkey: &tv.script_code,
|
||||
value: NonNegativeAmount::from_nonnegative_i64(tv.amount).unwrap(),
|
||||
},
|
||||
Some(n) => {
|
||||
SignableInput::Transparent(::transparent::sighash::SignableInput::from_parts(
|
||||
SighashType::parse(tv.hash_type as u8).unwrap(),
|
||||
n as usize,
|
||||
&tv.script_code,
|
||||
&tv.script_code,
|
||||
NonNegativeAmount::from_nonnegative_i64(tv.amount).unwrap(),
|
||||
))
|
||||
}
|
||||
_ => SignableInput::Shielded,
|
||||
};
|
||||
|
||||
|
@ -287,27 +289,30 @@ fn zip_0244() {
|
|||
let bundle = txdata.transparent_bundle().unwrap();
|
||||
let value = bundle.authorization.input_amounts[index];
|
||||
let script_pubkey = &bundle.authorization.input_scriptpubkeys[index];
|
||||
let signable_input = |hash_type| SignableInput::Transparent {
|
||||
hash_type,
|
||||
index,
|
||||
script_code: script_pubkey,
|
||||
script_pubkey,
|
||||
value,
|
||||
let signable_input = |hash_type| {
|
||||
SignableInput::Transparent(::transparent::sighash::SignableInput::from_parts(
|
||||
hash_type,
|
||||
index,
|
||||
script_pubkey,
|
||||
script_pubkey,
|
||||
value,
|
||||
))
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
v5_signature_hash(&txdata, &signable_input(SIGHASH_ALL), &txid_parts).as_ref(),
|
||||
v5_signature_hash(&txdata, &signable_input(SighashType::ALL), &txid_parts).as_ref(),
|
||||
&tv.sighash_all.unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
v5_signature_hash(&txdata, &signable_input(SIGHASH_NONE), &txid_parts).as_ref(),
|
||||
v5_signature_hash(&txdata, &signable_input(SighashType::NONE), &txid_parts)
|
||||
.as_ref(),
|
||||
&tv.sighash_none.unwrap()
|
||||
);
|
||||
|
||||
if index < bundle.vout.len() {
|
||||
assert_eq!(
|
||||
v5_signature_hash(&txdata, &signable_input(SIGHASH_SINGLE), &txid_parts)
|
||||
v5_signature_hash(&txdata, &signable_input(SighashType::SINGLE), &txid_parts)
|
||||
.as_ref(),
|
||||
&tv.sighash_single.unwrap()
|
||||
);
|
||||
|
@ -318,7 +323,7 @@ fn zip_0244() {
|
|||
assert_eq!(
|
||||
v5_signature_hash(
|
||||
&txdata,
|
||||
&signable_input(SIGHASH_ALL | SIGHASH_ANYONECANPAY),
|
||||
&signable_input(SighashType::ALL_ANYONECANPAY),
|
||||
&txid_parts,
|
||||
)
|
||||
.as_ref(),
|
||||
|
@ -328,7 +333,7 @@ fn zip_0244() {
|
|||
assert_eq!(
|
||||
v5_signature_hash(
|
||||
&txdata,
|
||||
&signable_input(SIGHASH_NONE | SIGHASH_ANYONECANPAY),
|
||||
&signable_input(SighashType::NONE_ANYONECANPAY),
|
||||
&txid_parts,
|
||||
)
|
||||
.as_ref(),
|
||||
|
@ -339,7 +344,7 @@ fn zip_0244() {
|
|||
assert_eq!(
|
||||
v5_signature_hash(
|
||||
&txdata,
|
||||
&signable_input(SIGHASH_SINGLE | SIGHASH_ANYONECANPAY),
|
||||
&signable_input(SighashType::SINGLE_ANYONECANPAY),
|
||||
&txid_parts,
|
||||
)
|
||||
.as_ref(),
|
||||
|
|
|
@ -420,7 +420,7 @@ pub fn to_txid(
|
|||
digests.tze_digests.as_ref(),
|
||||
);
|
||||
|
||||
TxId(<[u8; 32]>::try_from(txid_digest.as_bytes()).unwrap())
|
||||
TxId::from_bytes(<[u8; 32]>::try_from(txid_digest.as_bytes()).unwrap())
|
||||
}
|
||||
|
||||
/// Digester which constructs a digest of only the witness data.
|
||||
|
|
|
@ -9,9 +9,6 @@ use std::ops::Shl;
|
|||
|
||||
use zcash_encoding::Vector;
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
pub mod keys;
|
||||
|
||||
/// Defined script opcodes.
|
||||
///
|
||||
/// Most of the opcodes are unused by this crate, but we define them so that the alternate
|
||||
|
|
|
@ -3,26 +3,18 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
|
||||
use zcash_protocol::value::{BalanceError, ZatBalance as Amount, Zatoshis as NonNegativeAmount};
|
||||
|
||||
use crate::{
|
||||
legacy::{Script, TransparentAddress},
|
||||
transaction::{
|
||||
components::{
|
||||
amount::{Amount, BalanceError, NonNegativeAmount},
|
||||
transparent::{self, Authorization, Authorized, Bundle, TxIn, TxOut},
|
||||
},
|
||||
sighash::TransparentAuthorizingContext,
|
||||
},
|
||||
address::{Script, TransparentAddress},
|
||||
bundle::{Authorization, Authorized, Bundle, TxIn, TxOut},
|
||||
pczt,
|
||||
sighash::{SighashType, SignableInput, TransparentAuthorizingContext},
|
||||
};
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
use {
|
||||
crate::transaction::{
|
||||
self as tx,
|
||||
components::transparent::OutPoint,
|
||||
sighash::{signature_hash, SighashType, SignableInput, SIGHASH_ALL},
|
||||
TransactionData, TxDigests,
|
||||
},
|
||||
blake2b_simd::Hash as Blake2bHash,
|
||||
crate::{bundle::OutPoint, sighash::SIGHASH_ALL},
|
||||
sha2::Digest,
|
||||
};
|
||||
|
||||
|
@ -206,7 +198,7 @@ impl TransparentBuilder {
|
|||
(Amount::from(input_sum) - Amount::from(output_sum)).ok_or(BalanceError::Underflow)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Option<transparent::Bundle<Unauthorized>> {
|
||||
pub fn build(self) -> Option<Bundle<Unauthorized>> {
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
let vin: Vec<TxIn<Unauthorized>> = self
|
||||
.inputs
|
||||
|
@ -220,7 +212,7 @@ impl TransparentBuilder {
|
|||
if vin.is_empty() && self.vout.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(transparent::Bundle {
|
||||
Some(Bundle {
|
||||
vin,
|
||||
vout: self.vout,
|
||||
authorization: Unauthorized {
|
||||
|
@ -231,12 +223,13 @@ impl TransparentBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_for_pczt(self) -> Option<transparent::pczt::Bundle> {
|
||||
/// Builds a bundle containing the given inputs and outputs, for inclusion in a PCZT.
|
||||
pub fn build_for_pczt(self) -> Option<pczt::Bundle> {
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
let inputs = self
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|i| transparent::pczt::Input {
|
||||
.map(|i| pczt::Input {
|
||||
prevout_txid: i.utxo.hash,
|
||||
prevout_index: i.utxo.n,
|
||||
sequence: None,
|
||||
|
@ -267,7 +260,7 @@ impl TransparentBuilder {
|
|||
let outputs = self
|
||||
.vout
|
||||
.into_iter()
|
||||
.map(|o| transparent::pczt::Output {
|
||||
.map(|o| pczt::Output {
|
||||
value: o.value,
|
||||
script_pubkey: o.script_pubkey,
|
||||
// We don't currently support spending P2SH coins, so we only ever see
|
||||
|
@ -280,7 +273,7 @@ impl TransparentBuilder {
|
|||
})
|
||||
.collect();
|
||||
|
||||
Some(transparent::pczt::Bundle { inputs, outputs })
|
||||
Some(pczt::Bundle { inputs, outputs })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,12 +316,15 @@ impl TransparentAuthorizingContext for Unauthorized {
|
|||
}
|
||||
|
||||
impl Bundle<Unauthorized> {
|
||||
pub fn apply_signatures(
|
||||
#[cfg_attr(not(feature = "transparent-inputs"), allow(unused_variables))]
|
||||
pub fn apply_signatures<F>(
|
||||
self,
|
||||
#[cfg(feature = "transparent-inputs")] mtx: &TransactionData<tx::Unauthorized>,
|
||||
#[cfg(feature = "transparent-inputs")] txid_parts_cache: &TxDigests<Blake2bHash>,
|
||||
calculate_sighash: F,
|
||||
signing_set: &TransparentSigningSet,
|
||||
) -> Result<Bundle<Authorized>, Error> {
|
||||
) -> Result<Bundle<Authorized>, Error>
|
||||
where
|
||||
F: Fn(SignableInput) -> [u8; 32],
|
||||
{
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
let script_sigs = self
|
||||
.authorization
|
||||
|
@ -343,17 +339,13 @@ impl Bundle<Unauthorized> {
|
|||
.find(|(_, pubkey)| pubkey == &info.pubkey)
|
||||
.ok_or(Error::MissingSigningKey)?;
|
||||
|
||||
let sighash = signature_hash(
|
||||
mtx,
|
||||
&SignableInput::Transparent {
|
||||
hash_type: SIGHASH_ALL,
|
||||
index,
|
||||
script_code: &info.coin.script_pubkey, // for p2pkh, always the same as script_pubkey
|
||||
script_pubkey: &info.coin.script_pubkey,
|
||||
value: info.coin.value,
|
||||
},
|
||||
txid_parts_cache,
|
||||
);
|
||||
let sighash = calculate_sighash(SignableInput {
|
||||
hash_type: SighashType::ALL,
|
||||
index,
|
||||
script_code: &info.coin.script_pubkey, // for p2pkh, always the same as script_pubkey
|
||||
script_pubkey: &info.coin.script_pubkey,
|
||||
value: info.coin.value,
|
||||
});
|
||||
|
||||
let msg = secp256k1::Message::from_slice(sighash.as_ref()).expect("32 bytes");
|
||||
let sig = signing_set.secp.sign_ecdsa(&msg, sk);
|
||||
|
@ -369,7 +361,7 @@ impl Bundle<Unauthorized> {
|
|||
#[cfg(not(feature = "transparent-inputs"))]
|
||||
let script_sigs = std::iter::empty::<Result<Script, Error>>();
|
||||
|
||||
Ok(transparent::Bundle {
|
||||
Ok(Bundle {
|
||||
vin: self
|
||||
.vin
|
||||
.iter()
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
//! Structs representing the components within Zcash transactions.
|
||||
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use zcash_protocol::TxId;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use zcash_protocol::value::{BalanceError, ZatBalance as Amount, Zatoshis as NonNegativeAmount};
|
||||
|
||||
use crate::{
|
||||
legacy::{Script, TransparentAddress},
|
||||
transaction::{sighash::TransparentAuthorizingContext, TxId},
|
||||
address::{Script, TransparentAddress},
|
||||
sighash::TransparentAuthorizingContext,
|
||||
};
|
||||
|
||||
use super::amount::{Amount, BalanceError, NonNegativeAmount};
|
||||
|
||||
pub mod builder;
|
||||
pub mod pczt;
|
||||
|
||||
pub trait Authorization: Debug {
|
||||
type ScriptSig: Debug + Clone + PartialEq;
|
||||
}
|
||||
|
@ -23,7 +21,7 @@ pub trait Authorization: Debug {
|
|||
/// information for creating sighashes.
|
||||
#[derive(Debug)]
|
||||
pub struct EffectsOnly {
|
||||
inputs: Vec<TxOut>,
|
||||
pub(crate) inputs: Vec<TxOut>,
|
||||
}
|
||||
|
||||
impl Authorization for EffectsOnly {
|
||||
|
@ -56,11 +54,6 @@ pub trait MapAuth<A: Authorization, B: Authorization> {
|
|||
}
|
||||
|
||||
/// The identity map.
|
||||
///
|
||||
/// This can be used with [`TransactionData::map_authorization`] when you want to map the
|
||||
/// authorization of a subset of a transaction's bundles.
|
||||
///
|
||||
/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization
|
||||
impl MapAuth<Authorized, Authorized> for () {
|
||||
fn map_script_sig(
|
||||
&self,
|
||||
|
@ -138,8 +131,8 @@ impl<A: Authorization> Bundle<A> {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct OutPoint {
|
||||
hash: TxId,
|
||||
n: u32,
|
||||
pub(crate) hash: TxId,
|
||||
pub(crate) n: u32,
|
||||
}
|
||||
|
||||
impl OutPoint {
|
||||
|
@ -156,7 +149,7 @@ impl OutPoint {
|
|||
#[cfg(any(test, feature = "test-dependencies"))]
|
||||
pub const fn fake() -> Self {
|
||||
OutPoint {
|
||||
hash: TxId([1u8; 32]),
|
||||
hash: TxId::from_bytes([1u8; 32]),
|
||||
n: 1,
|
||||
}
|
||||
}
|
||||
|
@ -262,8 +255,9 @@ pub mod testing {
|
|||
use proptest::collection::vec;
|
||||
use proptest::prelude::*;
|
||||
use proptest::sample::select;
|
||||
use zcash_protocol::value::testing::arb_zatoshis;
|
||||
|
||||
use crate::{legacy::Script, transaction::components::amount::testing::arb_nonnegative_amount};
|
||||
use crate::address::Script;
|
||||
|
||||
use super::{Authorized, Bundle, OutPoint, TxIn, TxOut};
|
||||
|
||||
|
@ -301,7 +295,7 @@ pub mod testing {
|
|||
}
|
||||
|
||||
prop_compose! {
|
||||
pub fn arb_txout()(value in arb_nonnegative_amount(), script_pubkey in arb_script()) -> TxOut {
|
||||
pub fn arb_txout()(value in arb_zatoshis(), script_pubkey in arb_script()) -> TxOut {
|
||||
TxOut { value, script_pubkey }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use zcash_protocol::consensus::{self, NetworkConstants};
|
|||
use zcash_spec::PrfExpand;
|
||||
use zip32::AccountId;
|
||||
|
||||
use super::TransparentAddress;
|
||||
use crate::address::TransparentAddress;
|
||||
|
||||
/// The scope of a transparent key.
|
||||
///
|
||||
|
|
|
@ -4,12 +4,9 @@ use std::collections::BTreeMap;
|
|||
|
||||
use bip32::ChildNumber;
|
||||
use getset::Getters;
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
use zcash_protocol::{value::Zatoshis, TxId};
|
||||
|
||||
use crate::{
|
||||
legacy::Script,
|
||||
transaction::{sighash::SighashType, TxId},
|
||||
};
|
||||
use crate::{address::Script, sighash::SighashType};
|
||||
|
||||
mod parse;
|
||||
pub use parse::ParseError;
|
||||
|
@ -37,7 +34,7 @@ pub use tx_extractor::{TxExtractorError, Unbound};
|
|||
/// This struct is for representing Sapling in a partially-created transaction. If you
|
||||
/// have a fully-created transaction, use [the regular `Bundle` struct].
|
||||
///
|
||||
/// [the regular `Bundle` struct]: super::Bundle
|
||||
/// [the regular `Bundle` struct]: crate::bundle::Bundle
|
||||
#[derive(Debug, Getters)]
|
||||
#[getset(get = "pub")]
|
||||
pub struct Bundle {
|
||||
|
@ -68,7 +65,7 @@ impl Bundle {
|
|||
/// This struct is for representing transparent spends in a partially-created transaction.
|
||||
/// If you have a fully-created transaction, use [the regular `TxIn` struct].
|
||||
///
|
||||
/// [the regular `TxIn` struct]: super::TxIn
|
||||
/// [the regular `TxIn` struct]: crate::bundle::TxIn
|
||||
#[derive(Debug, Getters)]
|
||||
#[getset(get = "pub")]
|
||||
pub struct Input {
|
||||
|
@ -185,7 +182,7 @@ pub struct Input {
|
|||
/// transaction. If you have a fully-created transaction, use
|
||||
/// [the regular `TxOut` struct].
|
||||
///
|
||||
/// [the regular `TxOut` struct]: super::TxOut
|
||||
/// [the regular `TxOut` struct]: crate::bundle::TxOut
|
||||
#[derive(Debug, Getters)]
|
||||
#[getset(get = "pub")]
|
||||
pub struct Output {
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use bip32::ChildNumber;
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
use zcash_protocol::{value::Zatoshis, TxId};
|
||||
|
||||
use crate::{
|
||||
legacy::Script,
|
||||
transaction::{sighash::SighashType, TxId},
|
||||
};
|
||||
use crate::{address::Script, sighash::SighashType};
|
||||
|
||||
use super::{Bip32Derivation, Bundle, Input, Output};
|
||||
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
use blake2b_simd::Hash as Blake2bHash;
|
||||
|
||||
use crate::transaction::{
|
||||
sighash::{SignableInput, TransparentAuthorizingContext},
|
||||
sighash_v5::v5_signature_hash,
|
||||
Authorization, TransactionData, TxDigests,
|
||||
};
|
||||
use crate::sighash::SignableInput;
|
||||
|
||||
impl super::Input {
|
||||
/// Signs the transparent spend with the given spend authorizing key.
|
||||
|
@ -12,43 +6,37 @@ impl super::Input {
|
|||
/// It is the caller's responsibility to perform any semantic validity checks on the
|
||||
/// PCZT (for example, comfirming that the change amounts are correct) before calling
|
||||
/// this method.
|
||||
pub fn sign<
|
||||
TA: TransparentAuthorizingContext,
|
||||
A: Authorization<TransparentAuth = TA>,
|
||||
C: secp256k1::Signing,
|
||||
>(
|
||||
pub fn sign<C: secp256k1::Signing, F>(
|
||||
&mut self,
|
||||
index: usize,
|
||||
mtx: &TransactionData<A>,
|
||||
txid_parts: &TxDigests<Blake2bHash>,
|
||||
calculate_sighash: F,
|
||||
sk: &secp256k1::SecretKey,
|
||||
secp: &secp256k1::Secp256k1<C>,
|
||||
) -> Result<(), SignerError> {
|
||||
let hash_type = self.sighash_type.encode();
|
||||
) -> Result<(), SignerError>
|
||||
where
|
||||
F: FnOnce(SignableInput) -> [u8; 32],
|
||||
{
|
||||
let pubkey = sk.public_key(secp).serialize();
|
||||
|
||||
// Check that the corresponding pubkey appears in either `script_pubkey` or
|
||||
// `redeem_script`.
|
||||
// TODO
|
||||
|
||||
let sighash = v5_signature_hash(
|
||||
mtx,
|
||||
&SignableInput::Transparent {
|
||||
hash_type,
|
||||
index,
|
||||
script_code: self.redeem_script.as_ref().unwrap_or(&self.script_pubkey), // for p2pkh, always the same as script_pubkey
|
||||
script_pubkey: &self.script_pubkey,
|
||||
value: self.value,
|
||||
},
|
||||
txid_parts,
|
||||
);
|
||||
let sighash = calculate_sighash(SignableInput {
|
||||
hash_type: self.sighash_type,
|
||||
index,
|
||||
// for p2pkh, always the same as script_pubkey
|
||||
script_code: self.redeem_script.as_ref().unwrap_or(&self.script_pubkey),
|
||||
script_pubkey: &self.script_pubkey,
|
||||
value: self.value,
|
||||
});
|
||||
|
||||
let msg = secp256k1::Message::from_slice(sighash.as_ref()).expect("32 bytes");
|
||||
let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes");
|
||||
let sig = secp.sign_ecdsa(&msg, sk);
|
||||
|
||||
// Signature has to have the SighashType appended to it.
|
||||
let mut sig_bytes: Vec<u8> = sig.serialize_der()[..].to_vec();
|
||||
sig_bytes.extend([hash_type]);
|
||||
sig_bytes.extend([self.sighash_type.encode()]);
|
||||
|
||||
self.partial_signatures.insert(pubkey, sig_bytes);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ripemd::Ripemd160;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::legacy::{Script, TransparentAddress};
|
||||
use crate::address::{Script, TransparentAddress};
|
||||
|
||||
impl super::Bundle {
|
||||
/// Finalizes the spends for this bundle.
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
use zcash_protocol::value::Zatoshis;
|
||||
|
||||
use crate::{
|
||||
legacy::Script,
|
||||
transaction::{
|
||||
components::{transparent, OutPoint},
|
||||
sighash::TransparentAuthorizingContext,
|
||||
},
|
||||
address::Script,
|
||||
bundle::{Authorization, EffectsOnly, OutPoint, TxIn, TxOut},
|
||||
sighash::TransparentAuthorizingContext,
|
||||
};
|
||||
|
||||
use super::Input;
|
||||
|
@ -15,10 +13,10 @@ impl super::Bundle {
|
|||
///
|
||||
/// This is used by the Signer role to produce the transaction sighash.
|
||||
///
|
||||
/// [regular `Bundle`]: transparent::Bundle
|
||||
/// [regular `Bundle`]: super::Bundle
|
||||
pub fn extract_effects(
|
||||
&self,
|
||||
) -> Result<Option<transparent::Bundle<transparent::EffectsOnly>>, TxExtractorError> {
|
||||
) -> Result<Option<crate::bundle::Bundle<EffectsOnly>>, TxExtractorError> {
|
||||
self.to_tx_data(|_| Ok(()), |bundle| Ok(effects_only(bundle)))
|
||||
}
|
||||
|
||||
|
@ -26,8 +24,8 @@ impl super::Bundle {
|
|||
///
|
||||
/// This is used by the Transaction Extractor role to produce the final transaction.
|
||||
///
|
||||
/// [regular `Bundle`]: transparent::Bundle
|
||||
pub fn extract(self) -> Result<Option<transparent::Bundle<Unbound>>, TxExtractorError> {
|
||||
/// [regular `Bundle`]: super::Bundle
|
||||
pub fn extract(self) -> Result<Option<crate::bundle::Bundle<Unbound>>, TxExtractorError> {
|
||||
self.to_tx_data(
|
||||
|input| {
|
||||
input
|
||||
|
@ -43,11 +41,11 @@ impl super::Bundle {
|
|||
&self,
|
||||
script_sig: F,
|
||||
bundle_auth: G,
|
||||
) -> Result<Option<transparent::Bundle<A>>, E>
|
||||
) -> Result<Option<crate::bundle::Bundle<A>>, E>
|
||||
where
|
||||
A: transparent::Authorization,
|
||||
A: Authorization,
|
||||
E: From<TxExtractorError>,
|
||||
F: Fn(&Input) -> Result<<A as transparent::Authorization>::ScriptSig, E>,
|
||||
F: Fn(&Input) -> Result<<A as Authorization>::ScriptSig, E>,
|
||||
G: FnOnce(&Self) -> Result<A, E>,
|
||||
{
|
||||
let vin = self
|
||||
|
@ -56,7 +54,7 @@ impl super::Bundle {
|
|||
.map(|input| {
|
||||
let prevout = OutPoint::new(input.prevout_txid.into(), input.prevout_index);
|
||||
|
||||
Ok(transparent::TxIn {
|
||||
Ok(TxIn {
|
||||
prevout,
|
||||
script_sig: script_sig(input)?,
|
||||
sequence: input.sequence.unwrap_or(std::u32::MAX),
|
||||
|
@ -67,7 +65,7 @@ impl super::Bundle {
|
|||
let vout = self
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|output| transparent::TxOut {
|
||||
.map(|output| TxOut {
|
||||
value: output.value,
|
||||
script_pubkey: output.script_pubkey.clone(),
|
||||
})
|
||||
|
@ -76,7 +74,7 @@ impl super::Bundle {
|
|||
Ok(if vin.is_empty() && vout.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(transparent::Bundle {
|
||||
Some(crate::bundle::Bundle {
|
||||
vin,
|
||||
vout,
|
||||
authorization: bundle_auth(self)?,
|
||||
|
@ -93,25 +91,25 @@ pub enum TxExtractorError {
|
|||
MissingScriptSig,
|
||||
}
|
||||
|
||||
fn effects_only(bundle: &super::Bundle) -> transparent::EffectsOnly {
|
||||
fn effects_only(bundle: &super::Bundle) -> EffectsOnly {
|
||||
let inputs = bundle
|
||||
.inputs
|
||||
.iter()
|
||||
.map(|input| transparent::TxOut {
|
||||
.map(|input| TxOut {
|
||||
value: input.value,
|
||||
script_pubkey: input.script_pubkey.clone(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
transparent::EffectsOnly { inputs }
|
||||
EffectsOnly { inputs }
|
||||
}
|
||||
|
||||
/// Authorizing data for a transparent bundle in a transaction that is just missing
|
||||
/// binding signatures.
|
||||
#[derive(Debug)]
|
||||
pub struct Unbound(transparent::EffectsOnly);
|
||||
pub struct Unbound(EffectsOnly);
|
||||
|
||||
impl transparent::Authorization for Unbound {
|
||||
impl Authorization for Unbound {
|
||||
type ScriptSig = Script;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ripemd::Ripemd160;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::legacy::{Script, TransparentAddress};
|
||||
use crate::address::{Script, TransparentAddress};
|
||||
|
||||
use super::{Bip32Derivation, Bundle, Input, Output};
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use ripemd::Ripemd160;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use crate::legacy::TransparentAddress;
|
||||
use crate::address::TransparentAddress;
|
||||
|
||||
impl super::Input {
|
||||
/// Verifies the consistency of this transparent input.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use getset::Getters;
|
||||
use zcash_protocol::value::Zatoshis;
|
||||
|
||||
use crate::{address::Script, bundle::Authorization};
|
||||
|
@ -55,3 +56,34 @@ pub trait TransparentAuthorizingContext: Authorization {
|
|||
/// providing these inputs.
|
||||
fn input_scriptpubkeys(&self) -> Vec<Script>;
|
||||
}
|
||||
|
||||
/// A transparent input that is signable because we know its value and `script_pubkey`.
|
||||
#[derive(Debug, Getters)]
|
||||
#[getset(get = "pub")]
|
||||
pub struct SignableInput<'a> {
|
||||
pub(crate) hash_type: SighashType,
|
||||
pub(crate) index: usize,
|
||||
pub(crate) script_code: &'a Script,
|
||||
pub(crate) script_pubkey: &'a Script,
|
||||
pub(crate) value: Zatoshis,
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-dependencies")]
|
||||
impl<'a> SignableInput<'a> {
|
||||
/// Constructs a signable input from its parts.
|
||||
pub fn from_parts(
|
||||
hash_type: SighashType,
|
||||
index: usize,
|
||||
script_code: &'a Script,
|
||||
script_pubkey: &'a Script,
|
||||
value: Zatoshis,
|
||||
) -> Self {
|
||||
Self {
|
||||
hash_type,
|
||||
index,
|
||||
script_code,
|
||||
script_pubkey,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue