Merge pull request #507 from nuttycom/map_authorization

Define transaction::TransactionData::map_authorization
This commit is contained in:
str4d 2022-02-12 03:22:09 +00:00 committed by GitHub
commit 3d935a94e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 165 additions and 0 deletions

View File

@ -76,6 +76,16 @@ pub struct Witness<T> {
pub payload: T,
}
impl<T> Witness<T> {
pub fn map_payload<U, F: FnOnce(T) -> U>(self, f: F) -> Witness<U> {
Witness {
extension_id: self.extension_id,
mode: self.mode,
payload: f(self.payload),
}
}
}
impl Witness<AuthData> {
/// Produce the intermediate format for an extension-specific witness
/// type.

View File

@ -28,6 +28,11 @@ impl Authorization for Unauthorized {
type SpendAuth = ();
}
pub trait MapAuth<A: Authorization, B: Authorization> {
fn map_spend_auth(&self, s: A::SpendAuth) -> B::SpendAuth;
fn map_authorization(&self, a: A) -> B;
}
/// Reads an [`orchard::Bundle`] from a v5 transaction format.
pub fn read_v5_bundle<R: Read>(
mut reader: R,

View File

@ -47,6 +47,12 @@ impl Authorization for Authorized {
type AuthSig = redjubjub::Signature;
}
pub trait MapAuth<A: Authorization, B: Authorization> {
fn map_proof(&self, p: A::Proof) -> B::Proof;
fn map_auth_sig(&self, s: A::AuthSig) -> B::AuthSig;
fn map_authorization(&self, a: A) -> B;
}
#[derive(Debug, Clone)]
pub struct Bundle<A: Authorization> {
pub shielded_spends: Vec<SpendDescription<A>>,
@ -55,6 +61,39 @@ pub struct Bundle<A: Authorization> {
pub authorization: A,
}
impl<A: Authorization> Bundle<A> {
pub fn map_authorization<B: Authorization, F: MapAuth<A, B>>(self, f: F) -> Bundle<B> {
Bundle {
shielded_spends: self
.shielded_spends
.into_iter()
.map(|d| SpendDescription {
cv: d.cv,
anchor: d.anchor,
nullifier: d.nullifier,
rk: d.rk,
zkproof: f.map_proof(d.zkproof),
spend_auth_sig: f.map_auth_sig(d.spend_auth_sig),
})
.collect(),
shielded_outputs: self
.shielded_outputs
.into_iter()
.map(|o| OutputDescription {
cv: o.cv,
cmu: o.cmu,
ephemeral_key: o.ephemeral_key,
enc_ciphertext: o.enc_ciphertext,
out_ciphertext: o.out_ciphertext,
zkproof: f.map_proof(o.zkproof),
})
.collect(),
value_balance: self.value_balance,
authorization: f.map_authorization(self.authorization),
}
}
}
#[derive(Clone)]
pub struct SpendDescription<A: Authorization> {
pub cv: jubjub::ExtendedPoint,

View File

@ -22,6 +22,11 @@ impl Authorization for Authorized {
type ScriptSig = Script;
}
pub trait MapAuth<A: Authorization, B: Authorization> {
fn map_script_sig(&self, s: A::ScriptSig) -> B::ScriptSig;
fn map_authorization(&self, s: A) -> B;
}
#[derive(Debug, Clone, PartialEq)]
pub struct Bundle<A: Authorization> {
pub vin: Vec<TxIn<A>>,
@ -29,6 +34,24 @@ pub struct Bundle<A: Authorization> {
pub authorization: A,
}
impl<A: Authorization> Bundle<A> {
pub fn map_authorization<B: Authorization, F: MapAuth<A, B>>(self, f: F) -> Bundle<B> {
Bundle {
vin: self
.vin
.into_iter()
.map(|txin| TxIn {
prevout: txin.prevout,
script_sig: f.map_script_sig(txin.script_sig),
sequence: txin.sequence,
})
.collect(),
vout: self.vout,
authorization: f.map_authorization(self.authorization),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct OutPoint {
hash: [u8; 32],

View File

@ -28,6 +28,11 @@ impl Authorization for Authorized {
type Witness = tze::AuthData;
}
pub trait MapAuth<A: Authorization, B: Authorization> {
fn map_witness(&self, s: A::Witness) -> B::Witness;
fn map_authorization(&self, s: A) -> B;
}
#[derive(Debug, Clone, PartialEq)]
pub struct Bundle<A: Authorization> {
pub vin: Vec<TzeIn<A::Witness>>,
@ -35,6 +40,23 @@ pub struct Bundle<A: Authorization> {
pub authorization: A,
}
impl<A: Authorization> Bundle<A> {
pub fn map_authorization<B: Authorization, F: MapAuth<A, B>>(self, f: F) -> Bundle<B> {
Bundle {
vin: self
.vin
.into_iter()
.map(|tzein| TzeIn {
prevout: tzein.prevout,
witness: tzein.witness.map_payload(|p| f.map_witness(p)),
})
.collect(),
vout: self.vout,
authorization: f.map_authorization(self.authorization),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct OutPoint {
txid: TxId,

View File

@ -370,6 +370,68 @@ impl<A: Authorization> TransactionData<A> {
digester.digest_tze(self.tze_bundle.as_ref()),
)
}
/// Maps the bundles from one type to another.
///
/// This shouldn't be necessary for most use cases; it is provided for handling the
/// cross-FFI builder logic in `zcashd`.
pub fn map_bundles<B: Authorization>(
self,
f_transparent: impl FnOnce(
Option<transparent::Bundle<A::TransparentAuth>>,
) -> Option<transparent::Bundle<B::TransparentAuth>>,
f_sapling: impl FnOnce(
Option<sapling::Bundle<A::SaplingAuth>>,
) -> Option<sapling::Bundle<B::SaplingAuth>>,
f_orchard: impl FnOnce(
Option<orchard::bundle::Bundle<A::OrchardAuth, Amount>>,
) -> Option<orchard::bundle::Bundle<B::OrchardAuth, Amount>>,
#[cfg(feature = "zfuture")] f_tze: impl FnOnce(
Option<tze::Bundle<A::TzeAuth>>,
) -> Option<tze::Bundle<B::TzeAuth>>,
) -> TransactionData<B> {
TransactionData {
version: self.version,
consensus_branch_id: self.consensus_branch_id,
lock_time: self.lock_time,
expiry_height: self.expiry_height,
transparent_bundle: f_transparent(self.transparent_bundle),
sprout_bundle: self.sprout_bundle,
sapling_bundle: f_sapling(self.sapling_bundle),
orchard_bundle: f_orchard(self.orchard_bundle),
#[cfg(feature = "zfuture")]
tze_bundle: f_tze(self.tze_bundle),
}
}
pub fn map_authorization<B: Authorization>(
self,
f_transparent: impl transparent::MapAuth<A::TransparentAuth, B::TransparentAuth>,
f_sapling: impl sapling::MapAuth<A::SaplingAuth, B::SaplingAuth>,
mut f_orchard: impl orchard_serialization::MapAuth<A::OrchardAuth, B::OrchardAuth>,
#[cfg(feature = "zfuture")] f_tze: impl tze::MapAuth<A::TzeAuth, B::TzeAuth>,
) -> TransactionData<B> {
TransactionData {
version: self.version,
consensus_branch_id: self.consensus_branch_id,
lock_time: self.lock_time,
expiry_height: self.expiry_height,
transparent_bundle: self
.transparent_bundle
.map(|b| b.map_authorization(f_transparent)),
sprout_bundle: self.sprout_bundle,
sapling_bundle: self.sapling_bundle.map(|b| b.map_authorization(f_sapling)),
orchard_bundle: self.orchard_bundle.map(|b| {
b.authorize(
&mut f_orchard,
|f, _, s| f.map_spend_auth(s),
|f, a| f.map_authorization(a),
)
}),
#[cfg(feature = "zfuture")]
tze_bundle: self.tze_bundle.map(|b| b.map_authorization(f_tze)),
}
}
}
impl<A: Authorization> std::fmt::Debug for TransactionData<A> {
@ -505,6 +567,10 @@ impl Transaction {
Transaction { txid, data }
}
pub fn into_data(self) -> TransactionData<Authorized> {
self.data
}
pub fn txid(&self) -> TxId {
self.txid
}