chore(core/bitcoin): Add DecredApprover.

pull/1500/head
Andrew Kozlik 3 years ago committed by Andrew Kozlik
parent 523b1051c5
commit 6de20a7dcd

@ -10,7 +10,7 @@ if not utils.BITCOIN_ONLY:
from . import bitcoinlike, decred, zcash from . import bitcoinlike, decred, zcash
if False: if False:
from typing import Optional, Union from typing import Protocol, Optional, Type, Union
from protobuf import FieldCache from protobuf import FieldCache
@ -36,6 +36,19 @@ if False:
TxAckPrevExtraData, TxAckPrevExtraData,
] ]
class SignerClass(Protocol):
def __init__(
self,
tx: SignTx,
keychain: Keychain,
coin: CoinInfo,
approver: Optional[approvers.Approver],
) -> None:
...
async def signer(self) -> None:
...
@with_keychain @with_keychain
async def sign_tx( async def sign_tx(
@ -45,15 +58,12 @@ async def sign_tx(
coin: CoinInfo, coin: CoinInfo,
authorization: Optional[CoinJoinAuthorization] = None, authorization: Optional[CoinJoinAuthorization] = None,
) -> TxRequest: ) -> TxRequest:
approver: Optional[approvers.Approver] = None
if authorization: if authorization:
approver: approvers.Approver = approvers.CoinJoinApprover( approver = approvers.CoinJoinApprover(msg, coin, authorization)
msg, coin, authorization
)
else:
approver = approvers.BasicApprover(msg, coin)
if utils.BITCOIN_ONLY or coin.coin_name in BITCOIN_NAMES: if utils.BITCOIN_ONLY or coin.coin_name in BITCOIN_NAMES:
signer_class = bitcoin.Bitcoin signer_class: Type[SignerClass] = bitcoin.Bitcoin
else: else:
if coin.decred: if coin.decred:
signer_class = decred.Decred signer_class = decred.Decred

@ -2,7 +2,6 @@ from micropython import const
from trezor import wire from trezor import wire
from trezor.messages import OutputScriptType from trezor.messages import OutputScriptType
from trezor.utils import ensure
from apps.common import safety_checks from apps.common import safety_checks
@ -77,11 +76,6 @@ class Approver:
self.weight.add_output(script_pubkey) self.weight.add_output(script_pubkey)
self.total_out += txo.amount self.total_out += txo.amount
async def add_decred_sstx_submission(
self, txo: TxOutput, script_pubkey: bytes
) -> None:
raise NotImplementedError
def add_orig_external_output(self, txo: TxOutput) -> None: def add_orig_external_output(self, txo: TxOutput) -> None:
self.orig_total_out += txo.amount self.orig_total_out += txo.amount
@ -131,13 +125,6 @@ class BasicApprover(Approver):
else: else:
await helpers.confirm_output(txo, self.coin, self.amount_unit) await helpers.confirm_output(txo, self.coin, self.amount_unit)
async def add_decred_sstx_submission(
self, txo: TxOutput, script_pubkey: bytes
) -> None:
ensure(self.coin.decred)
await super().add_external_output(txo, script_pubkey, None)
await helpers.confirm_decred_sstx_submission(txo, self.coin, self.amount_unit)
async def approve_tx(self, tx_info: TxInfo, orig_txs: List[OriginalTxInfo]) -> None: async def approve_tx(self, tx_info: TxInfo, orig_txs: List[OriginalTxInfo]) -> None:
fee = self.total_in - self.total_out fee = self.total_in - self.total_out

@ -73,12 +73,16 @@ class Bitcoin:
tx: SignTx, tx: SignTx,
keychain: Keychain, keychain: Keychain,
coin: CoinInfo, coin: CoinInfo,
approver: approvers.Approver, approver: Optional[approvers.Approver],
) -> None: ) -> None:
self.tx_info = TxInfo(self, helpers.sanitize_sign_tx(tx, coin)) self.tx_info = TxInfo(self, helpers.sanitize_sign_tx(tx, coin))
self.keychain = keychain self.keychain = keychain
self.coin = coin self.coin = coin
self.approver = approver
if approver is not None:
self.approver = approver
else:
self.approver = approvers.BasicApprover(tx, coin)
# set of indices of inputs which are segwit # set of indices of inputs which are segwit
self.segwit: Set[int] = set() self.segwit: Set[int] = set()

@ -11,6 +11,7 @@ from apps.common.writers import write_bitcoin_varint
from .. import multisig, scripts_decred, writers from .. import multisig, scripts_decred, writers
from ..common import ecdsa_hash_pubkey, ecdsa_sign from ..common import ecdsa_hash_pubkey, ecdsa_sign
from . import approvers, helpers, progress from . import approvers, helpers, progress
from .approvers import BasicApprover
from .bitcoin import Bitcoin from .bitcoin import Bitcoin
DECRED_SERIALIZE_FULL = const(0 << 16) DECRED_SERIALIZE_FULL = const(0 << 16)
@ -37,6 +38,16 @@ if False:
from .hash143 import Hash143 from .hash143 import Hash143
class DecredApprover(BasicApprover):
async def add_decred_sstx_submission(
self, txo: TxOutput, script_pubkey: bytes
) -> None:
# NOTE: The following calls Approver.add_external_output(), not BasicApprover.add_external_output().
# This is needed to skip calling helpers.confirm_output(), which is what BasicApprover would do.
await super(BasicApprover, self).add_external_output(txo, script_pubkey, None)
await helpers.confirm_decred_sstx_submission(txo, self.coin, self.amount_unit)
class DecredHash: class DecredHash:
def __init__(self, h_prefix: HashWriter) -> None: def __init__(self, h_prefix: HashWriter) -> None:
self.h_prefix = h_prefix self.h_prefix = h_prefix
@ -65,11 +76,13 @@ class Decred(Bitcoin):
tx: SignTx, tx: SignTx,
keychain: Keychain, keychain: Keychain,
coin: CoinInfo, coin: CoinInfo,
approver: approvers.Approver, approver: Optional[approvers.Approver],
) -> None: ) -> None:
ensure(coin.decred) ensure(coin.decred)
self.h_prefix = HashWriter(blake256()) self.h_prefix = HashWriter(blake256())
ensure(approver is None)
approver = DecredApprover(tx, coin)
super().__init__(tx, keychain, coin, approver) super().__init__(tx, keychain, coin, approver)
self.write_tx_header(self.serialized_tx, self.tx_info.tx, witness_marker=True) self.write_tx_header(self.serialized_tx, self.tx_info.tx, witness_marker=True)
@ -233,6 +246,8 @@ class Decred(Bitcoin):
return scripts_decred.output_script_paytoopreturn(op_return_data) return scripts_decred.output_script_paytoopreturn(op_return_data)
async def approve_staking_ticket(self) -> None: async def approve_staking_ticket(self) -> None:
assert isinstance(self.approver, DecredApprover)
if self.tx_info.tx.outputs_count != 3: if self.tx_info.tx.outputs_count != 3:
raise wire.DataError("Ticket has wrong number of outputs.") raise wire.DataError("Ticket has wrong number of outputs.")

@ -30,7 +30,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import helpers, bitcoin from apps.bitcoin.sign_tx import helpers, bitcoin
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -160,8 +159,7 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoin.Bitcoin(tx, keychain, coin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin, approver).signer()
for request, response in chunks(messages, 2): for request, response in chunks(messages, 2):
res = signer.send(request) res = signer.send(request)
if isinstance(res, tuple): if isinstance(res, tuple):
@ -289,8 +287,7 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoin.Bitcoin(tx, keychain, coin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):
@ -350,8 +347,7 @@ class TestSignSegwitTxNativeP2WPKH(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoin.Bitcoin(tx, keychain, coin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
if expected_response is None: if expected_response is None:
with self.assertRaises(wire.DataError): with self.assertRaises(wire.DataError):

@ -29,7 +29,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import bitcoinlike, helpers from apps.bitcoin.sign_tx import bitcoinlike, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -161,8 +160,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, None).signer()
signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):
@ -290,8 +288,7 @@ class TestSignSegwitTxNativeP2WPKH_GRS(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, None).signer()
signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):

@ -30,7 +30,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import bitcoin, helpers from apps.bitcoin.sign_tx import bitcoin, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -157,8 +156,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoin.Bitcoin(tx, keychain, coin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):
@ -294,8 +292,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoin.Bitcoin(tx, keychain, coin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):
@ -401,8 +398,7 @@ class TestSignSegwitTxP2WPKHInP2SH(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoin.Bitcoin(tx, keychain, coin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin, approver).signer()
i = 0 i = 0
messages_count = int(len(messages) / 2) messages_count = int(len(messages) / 2)
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):

@ -29,7 +29,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import bitcoinlike, helpers from apps.bitcoin.sign_tx import bitcoinlike, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -161,8 +160,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, None).signer()
signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):
@ -298,8 +296,7 @@ class TestSignSegwitTxP2WPKHInP2SH_GRS(unittest.TestCase):
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, None).signer()
signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):

@ -28,7 +28,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.common.paths import AlwaysMatchingSchema from apps.common.paths import AlwaysMatchingSchema
from apps.bitcoin.sign_tx import bitcoin, helpers from apps.bitcoin.sign_tx import bitcoin, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -164,8 +163,7 @@ class TestSignTxFeeThreshold(unittest.TestCase):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '') seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
keychain = Keychain(seed, coin_bitcoin.curve_name, [AlwaysMatchingSchema]) keychain = Keychain(seed, coin_bitcoin.curve_name, [AlwaysMatchingSchema])
approver = BasicApprover(tx, coin_bitcoin) signer = bitcoin.Bitcoin(tx, keychain, coin_bitcoin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin_bitcoin, approver).signer()
for request, response in chunks(messages, 2): for request, response in chunks(messages, 2):
res = signer.send(request) res = signer.send(request)
if isinstance(res, tuple): if isinstance(res, tuple):

@ -28,7 +28,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import bitcoin, helpers from apps.bitcoin.sign_tx import bitcoin, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -110,8 +109,7 @@ class TestSignTx(unittest.TestCase):
seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '') seed = bip39.seed('alcohol woman abuse must during monitor noble actual mixed trade anger aisle', '')
ns = get_schemas_for_coin(coin_bitcoin) ns = get_schemas_for_coin(coin_bitcoin)
keychain = Keychain(seed, coin_bitcoin.curve_name, ns) keychain = Keychain(seed, coin_bitcoin.curve_name, ns)
approver = BasicApprover(tx, coin_bitcoin) signer = bitcoin.Bitcoin(tx, keychain, coin_bitcoin, None).signer()
signer = bitcoin.Bitcoin(tx, keychain, coin_bitcoin, approver).signer()
for request, response in chunks(messages, 2): for request, response in chunks(messages, 2):
res = signer.send(request) res = signer.send(request)

@ -1,7 +1,7 @@
from common import * from common import *
from trezor.utils import chunks from trezor.utils import chunks
from trezor.crypto import bip32, bip39 from trezor.crypto import bip39
from trezor.messages.SignTx import SignTx from trezor.messages.SignTx import SignTx
from trezor.messages.TxAckInput import TxAckInput from trezor.messages.TxAckInput import TxAckInput
from trezor.messages.TxAckInputWrapper import TxAckInputWrapper from trezor.messages.TxAckInputWrapper import TxAckInputWrapper
@ -28,7 +28,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import decred, helpers from apps.bitcoin.sign_tx import decred, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -190,8 +189,7 @@ class TestSignTxDecred(unittest.TestCase):
) )
ns = get_schemas_for_coin(coin_decred) ns = get_schemas_for_coin(coin_decred)
keychain = Keychain(seed, coin_decred.curve_name, ns) keychain = Keychain(seed, coin_decred.curve_name, ns)
approver = BasicApprover(tx, coin_decred) signer = decred.Decred(tx, keychain, coin_decred, None).signer()
signer = decred.Decred(tx, keychain, coin_decred, approver).signer()
for request, response in chunks(messages, 2): for request, response in chunks(messages, 2):
res = signer.send(request) res = signer.send(request)
@ -353,8 +351,7 @@ class TestSignTxDecred(unittest.TestCase):
) )
ns = get_schemas_for_coin(coin_decred) ns = get_schemas_for_coin(coin_decred)
keychain = Keychain(seed, coin_decred.curve_name, ns) keychain = Keychain(seed, coin_decred.curve_name, ns)
approver = BasicApprover(tx, coin_decred) signer = decred.Decred(tx, keychain, coin_decred, None).signer()
signer = decred.Decred(tx, keychain, coin_decred, approver).signer()
for request, response in chunks(messages, 2): for request, response in chunks(messages, 2):
res = signer.send(request) res = signer.send(request)

@ -28,7 +28,6 @@ from apps.common import coins
from apps.common.keychain import Keychain from apps.common.keychain import Keychain
from apps.bitcoin.keychain import get_schemas_for_coin from apps.bitcoin.keychain import get_schemas_for_coin
from apps.bitcoin.sign_tx import bitcoinlike, helpers from apps.bitcoin.sign_tx import bitcoinlike, helpers
from apps.bitcoin.sign_tx.approvers import BasicApprover
EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray()) EMPTY_SERIALIZED = TxRequestSerializedType(serialized_tx=bytearray())
@ -104,8 +103,7 @@ class TestSignTx_GRS(unittest.TestCase):
seed = bip39.seed(' '.join(['all'] * 12), '') seed = bip39.seed(' '.join(['all'] * 12), '')
ns = get_schemas_for_coin(coin) ns = get_schemas_for_coin(coin)
keychain = Keychain(seed, coin.curve_name, ns) keychain = Keychain(seed, coin.curve_name, ns)
approver = BasicApprover(tx, coin) signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, None).signer()
signer = bitcoinlike.Bitcoinlike(tx, keychain, coin, approver).signer()
for request, expected_response in chunks(messages, 2): for request, expected_response in chunks(messages, 2):
response = signer.send(request) response = signer.send(request)
if isinstance(response, tuple): if isinstance(response, tuple):

Loading…
Cancel
Save