mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-02-22 20:42:03 +00:00
fixup! feat(core): add Zcash shielded transactions
This commit is contained in:
parent
8bddb42785
commit
8384dc6e58
@ -402,6 +402,15 @@ def sanitize_sign_tx(tx: SignTx, coin: CoinInfo) -> SignTx:
|
||||
if tx.branch_id is not None:
|
||||
raise wire.DataError("Branch ID not enabled on this coin.")
|
||||
|
||||
if tx.orchard_params is not None:
|
||||
if not utils.ZCASH_SHIELDED:
|
||||
raise wire.DataError("Shielded transaction disabled.")
|
||||
elif tx.orchard_params.inputs_count + tx.orchard_params.outputs_count == 0:
|
||||
raise wire.DataError("Orchard bundle must not be empty.")
|
||||
elif tx.orchard_params.inputs_count > 0 and tx.inputs_count > 0:
|
||||
raise wire.DataError(
|
||||
"Spending transparent and Orchard inputs simultaneously is not supported."
|
||||
)
|
||||
return tx
|
||||
|
||||
|
||||
|
@ -35,21 +35,6 @@ FLAGS = const(0b0000_0011) # spends enbled and output enabled
|
||||
MAX_SILENT_ORCHARD_INPUTS = const(8)
|
||||
|
||||
|
||||
def skip_if_empty(func):
|
||||
"""
|
||||
A function decorated by this will not be evaluated,
|
||||
if the Orchard bundle is impty.
|
||||
"""
|
||||
|
||||
async def wrapper(self):
|
||||
if self.actions_count == 0:
|
||||
return
|
||||
else:
|
||||
await func(self)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
class OrchardSigner:
|
||||
def __init__(
|
||||
self,
|
||||
@ -59,26 +44,13 @@ class OrchardSigner:
|
||||
coin: CoinInfo,
|
||||
tx_req: TxRequest,
|
||||
) -> None:
|
||||
assert tx_req.serialized is not None # typing
|
||||
params = tx_info.tx.orchard_params
|
||||
if params is None:
|
||||
self.inputs_count = 0
|
||||
self.outputs_count = 0
|
||||
else:
|
||||
self.inputs_count = params.inputs_count
|
||||
self.outputs_count = params.outputs_count
|
||||
|
||||
if self.inputs_count + self.outputs_count > 0:
|
||||
self.actions_count = max(
|
||||
2, # minimal required amount of actions
|
||||
self.inputs_count,
|
||||
self.outputs_count,
|
||||
)
|
||||
else:
|
||||
self.actions_count = 0
|
||||
|
||||
if self.actions_count == 0:
|
||||
return # no need to initialize other attributes
|
||||
assert params is not None # checked in sanitize_sign_tx
|
||||
self.actions_count = max(
|
||||
2, # minimal required amount of actions
|
||||
self.inputs_count,
|
||||
self.outputs_count,
|
||||
)
|
||||
|
||||
self.tx_info = tx_info
|
||||
self.keychain = OrchardKeychain.from_seed_and_coin(seed, coin)
|
||||
@ -87,7 +59,6 @@ class OrchardSigner:
|
||||
self.tx_req = tx_req
|
||||
assert isinstance(tx_info.sig_hasher, ZcashHasher)
|
||||
self.sig_hasher: ZcashHasher = tx_info.sig_hasher
|
||||
assert params is not None
|
||||
self.anchor = params.anchor
|
||||
self.key_node = self.keychain.derive(params.address_n)
|
||||
|
||||
@ -99,7 +70,6 @@ class OrchardSigner:
|
||||
|
||||
self.rng = None
|
||||
|
||||
@skip_if_empty
|
||||
async def process_inputs(self) -> None:
|
||||
await self.check_orchard_inputs_count()
|
||||
for i in range(self.inputs_count):
|
||||
@ -111,7 +81,6 @@ class OrchardSigner:
|
||||
if self.inputs_count > MAX_SILENT_ORCHARD_INPUTS:
|
||||
yield ConfirmOrchardInputsCountOverThreshold(self.inputs_count)
|
||||
|
||||
@skip_if_empty
|
||||
async def approve_outputs(self) -> None:
|
||||
for i in range(self.outputs_count):
|
||||
txo = await self.get_output(i)
|
||||
@ -121,7 +90,6 @@ class OrchardSigner:
|
||||
else:
|
||||
await self.approver.add_orchard_external_output(txo)
|
||||
|
||||
@skip_if_empty
|
||||
async def compute_digest(self) -> None:
|
||||
# derive shielding seed
|
||||
shielding_seed = self.derive_shielding_seed()
|
||||
@ -233,7 +201,6 @@ class OrchardSigner:
|
||||
ovk = fvk.outgoing_viewing_key()
|
||||
return builder.OutputInfo(ovk, address, txo.amount, txo.memo)
|
||||
|
||||
@skip_if_empty
|
||||
@watch_gc_async
|
||||
async def sign_inputs(self) -> None:
|
||||
sighash = self.sig_hasher.signature_digest()
|
||||
|
@ -55,7 +55,7 @@ class Zcash(Bitcoinlike):
|
||||
|
||||
super().__init__(tx, keychain, coin, approver)
|
||||
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and tx.orchard_params is not None:
|
||||
self.orchard = OrchardSigner(
|
||||
self.tx_info,
|
||||
keychain.seed,
|
||||
@ -63,10 +63,8 @@ class Zcash(Bitcoinlike):
|
||||
coin,
|
||||
self.tx_req,
|
||||
)
|
||||
if self.orchard.inputs_count > 0 and tx.inputs_count > 0:
|
||||
raise DataError(
|
||||
"Cannot spending transparent and Orchard inputs simultaneously is not supported."
|
||||
)
|
||||
else:
|
||||
self.orchard = None
|
||||
|
||||
def create_sig_hasher(self, tx: SignTx | PrevTx) -> ZcashHasher:
|
||||
return ZcashHasher(tx)
|
||||
@ -78,12 +76,12 @@ class Zcash(Bitcoinlike):
|
||||
|
||||
async def step1_process_inputs(self):
|
||||
await super().step1_process_inputs()
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and self.orchard is not None:
|
||||
await self.orchard.process_inputs()
|
||||
|
||||
async def step2_approve_outputs(self):
|
||||
await super().step2_approve_outputs()
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and self.orchard is not None:
|
||||
await self.orchard.approve_outputs()
|
||||
|
||||
async def step3_verify_inputs(self) -> None:
|
||||
@ -97,7 +95,7 @@ class Zcash(Bitcoinlike):
|
||||
self.taproot_only = False # turn off taproot behavior
|
||||
|
||||
async def step4_serialize_inputs(self):
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and self.orchard is not None:
|
||||
# shield actions first to get a sighash
|
||||
await self.orchard.compute_digest()
|
||||
await super().step4_serialize_inputs()
|
||||
@ -111,14 +109,14 @@ class Zcash(Bitcoinlike):
|
||||
write_compact_size(self.serialized_tx, 0) # nOutputsSapling
|
||||
|
||||
# nActionsOrchard
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and self.orchard is not None::
|
||||
write_compact_size(self.serialized_tx, self.orchard.actions_count)
|
||||
else:
|
||||
write_compact_size(self.serialized_tx, 0)
|
||||
|
||||
async def step6_sign_segwit_inputs(self):
|
||||
# transparent inputs were signed in step 4
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and self.orchard is not None:
|
||||
await self.orchard.sign_inputs()
|
||||
|
||||
async def sign_nonsegwit_input(self, i_sign: int) -> None:
|
||||
@ -186,5 +184,5 @@ class Zcash(Bitcoinlike):
|
||||
def set_serialized_signature(self, i: int, signature: bytes) -> None:
|
||||
super().set_serialized_signature(i, signature)
|
||||
assert self.tx_req.serialized is not None
|
||||
if ZCASH_SHIELDED:
|
||||
if ZCASH_SHIELDED and self.orchard is not None:
|
||||
self.tx_req.serialized.signature_type = ZcashSignatureType.TRANSPARENT
|
||||
|
Loading…
Reference in New Issue
Block a user