transaction: rm hardcoded sighash magic numbers
This commit is contained in:
@@ -39,7 +39,7 @@ from .util import bfh, bh2u, chunks, TxMinedInfo
|
||||
from .invoices import PR_PAID
|
||||
from .bitcoin import redeem_script_to_address
|
||||
from .crypto import sha256, sha256d
|
||||
from .transaction import Transaction, PartialTransaction, TxInput
|
||||
from .transaction import Transaction, PartialTransaction, TxInput, Sighash
|
||||
from .logging import Logger
|
||||
from .lnonion import decode_onion_error, OnionFailureCode, OnionRoutingFailure
|
||||
from . import lnutil
|
||||
@@ -1101,7 +1101,7 @@ class Channel(AbstractChannel):
|
||||
data = self.config[LOCAL].current_htlc_signatures
|
||||
htlc_sigs = list(chunks(data, 64))
|
||||
htlc_sig = htlc_sigs[htlc_relative_idx]
|
||||
remote_htlc_sig = ecc.der_sig_from_sig_string(htlc_sig) + b'\x01'
|
||||
remote_htlc_sig = ecc.der_sig_from_sig_string(htlc_sig) + Sighash.to_sigbytes(Sighash.ALL)
|
||||
return remote_htlc_sig
|
||||
|
||||
def revoke_current_commitment(self):
|
||||
@@ -1554,7 +1554,7 @@ class Channel(AbstractChannel):
|
||||
assert self.signature_fits(tx)
|
||||
tx.sign({bh2u(self.config[LOCAL].multisig_key.pubkey): (self.config[LOCAL].multisig_key.privkey, True)})
|
||||
remote_sig = self.config[LOCAL].current_commitment_signature
|
||||
remote_sig = ecc.der_sig_from_sig_string(remote_sig) + b"\x01"
|
||||
remote_sig = ecc.der_sig_from_sig_string(remote_sig) + Sighash.to_sigbytes(Sighash.ALL)
|
||||
tx.add_signature_to_txin(txin_idx=0,
|
||||
signing_pubkey=self.config[REMOTE].multisig_key.pubkey.hex(),
|
||||
sig=remote_sig.hex())
|
||||
|
||||
@@ -25,7 +25,7 @@ from .util import (bh2u, bfh, log_exceptions, ignore_exceptions, chunks, OldTask
|
||||
UnrelatedTransactionException)
|
||||
from . import transaction
|
||||
from .bitcoin import make_op_return
|
||||
from .transaction import PartialTxOutput, match_script_against_template
|
||||
from .transaction import PartialTxOutput, match_script_against_template, Sighash
|
||||
from .logging import Logger
|
||||
from .lnonion import (new_onion_packet, OnionFailureCode, calc_hops_data_for_payment,
|
||||
process_onion_packet, OnionPacket, construct_onion_error, OnionRoutingFailure,
|
||||
@@ -2039,8 +2039,8 @@ class Peer(Logger):
|
||||
assert our_scriptpubkey
|
||||
# estimate fee of closing tx
|
||||
dummy_sig, dummy_tx = chan.make_closing_tx(our_scriptpubkey, their_scriptpubkey, fee_sat=0)
|
||||
our_sig = None
|
||||
closing_tx = None
|
||||
our_sig = None # type: Optional[bytes]
|
||||
closing_tx = None # type: Optional[PartialTransaction]
|
||||
is_initiator = chan.constraints.is_initiator
|
||||
our_fee, our_fee_range = self.get_shutdown_fee_range(chan, dummy_tx, is_local)
|
||||
|
||||
@@ -2185,11 +2185,11 @@ class Peer(Logger):
|
||||
closing_tx.add_signature_to_txin(
|
||||
txin_idx=0,
|
||||
signing_pubkey=chan.config[LOCAL].multisig_key.pubkey.hex(),
|
||||
sig=bh2u(der_sig_from_sig_string(our_sig) + b'\x01'))
|
||||
sig=bh2u(der_sig_from_sig_string(our_sig) + Sighash.to_sigbytes(Sighash.ALL)))
|
||||
closing_tx.add_signature_to_txin(
|
||||
txin_idx=0,
|
||||
signing_pubkey=chan.config[REMOTE].multisig_key.pubkey.hex(),
|
||||
sig=bh2u(der_sig_from_sig_string(their_sig) + b'\x01'))
|
||||
sig=bh2u(der_sig_from_sig_string(their_sig) + Sighash.to_sigbytes(Sighash.ALL)))
|
||||
# save local transaction and set state
|
||||
try:
|
||||
self.lnworker.wallet.adb.add_transaction(closing_tx)
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Dict, Tuple, Optional, List, Any, Callable
|
||||
from electrum import bip32, constants
|
||||
from electrum.i18n import _
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.transaction import PartialTransaction
|
||||
from electrum.transaction import PartialTransaction, Sighash
|
||||
from electrum.wallet import Standard_Wallet, Multisig_Wallet, Deterministic_Wallet
|
||||
from electrum.util import bh2u, UserFacingException
|
||||
from electrum.base_wizard import ScriptTypeNotSupported, BaseWizard
|
||||
@@ -523,7 +523,8 @@ class BitBox02Client(HardwareClientBase):
|
||||
# Fill signatures
|
||||
if len(sigs) != len(tx.inputs()):
|
||||
raise Exception("Incorrect number of inputs signed.") # Should never occur
|
||||
signatures = [bh2u(ecc.der_sig_from_sig_string(x[1])) + "01" for x in sigs]
|
||||
sighash = Sighash.to_sigbytes(Sighash.ALL).hex()
|
||||
signatures = [bh2u(ecc.der_sig_from_sig_string(x[1])) + sighash for x in sigs]
|
||||
tx.update_signatures(signatures)
|
||||
|
||||
def sign_message(self, keypath: str, message: bytes, script_type: str) -> bytes:
|
||||
|
||||
@@ -23,7 +23,7 @@ from electrum import ecc
|
||||
from electrum.ecc import msg_magic
|
||||
from electrum.wallet import Standard_Wallet
|
||||
from electrum import constants
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, Sighash
|
||||
from electrum.i18n import _
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.util import to_string, UserCancelled, UserFacingException, bfh
|
||||
@@ -645,7 +645,7 @@ class DigitalBitbox_KeyStore(Hardware_KeyStore):
|
||||
sig_r = int(signed['sig'][:64], 16)
|
||||
sig_s = int(signed['sig'][64:], 16)
|
||||
sig = ecc.der_sig_from_r_and_s(sig_r, sig_s)
|
||||
sig = to_hexstr(sig) + '01'
|
||||
sig = to_hexstr(sig) + Sighash.to_sigbytes(Sighash.ALL).hex()
|
||||
tx.add_signature_to_txin(txin_idx=i, signing_pubkey=pubkey_bytes.hex(), sig=sig)
|
||||
except UserCancelled:
|
||||
raise
|
||||
|
||||
@@ -7,7 +7,7 @@ from electrum.util import bfh, bh2u, UserCancelled, UserFacingException
|
||||
from electrum.bip32 import BIP32Node
|
||||
from electrum import constants
|
||||
from electrum.i18n import _
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, Sighash
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.plugin import Device, runs_in_hwd_thread
|
||||
from electrum.base_wizard import ScriptTypeNotSupported
|
||||
@@ -330,7 +330,8 @@ class KeepKeyPlugin(HW_PluginBase):
|
||||
outputs = self.tx_outputs(tx, keystore=keystore)
|
||||
signatures = client.sign_tx(self.get_coin_name(), inputs, outputs,
|
||||
lock_time=tx.locktime, version=tx.version)[0]
|
||||
signatures = [(bh2u(x) + '01') for x in signatures]
|
||||
sighash = Sighash.to_sigbytes(Sighash.ALL).hex()
|
||||
signatures = [(bh2u(x) + sighash) for x in signatures]
|
||||
tx.update_signatures(signatures)
|
||||
|
||||
@runs_in_hwd_thread
|
||||
|
||||
@@ -8,7 +8,7 @@ from electrum.bip32 import BIP32Node
|
||||
from electrum import constants
|
||||
from electrum.i18n import _
|
||||
from electrum.plugin import Device, runs_in_hwd_thread
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, Sighash
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.base_wizard import ScriptTypeNotSupported
|
||||
|
||||
@@ -300,7 +300,8 @@ class SafeTPlugin(HW_PluginBase):
|
||||
outputs = self.tx_outputs(tx, keystore=keystore)
|
||||
signatures = client.sign_tx(self.get_coin_name(), inputs, outputs,
|
||||
lock_time=tx.locktime, version=tx.version)[0]
|
||||
signatures = [(bh2u(x) + '01') for x in signatures]
|
||||
sighash = Sighash.to_sigbytes(Sighash.ALL).hex()
|
||||
signatures = [(bh2u(x) + sighash) for x in signatures]
|
||||
tx.update_signatures(signatures)
|
||||
|
||||
@runs_in_hwd_thread
|
||||
|
||||
@@ -7,7 +7,7 @@ from electrum.bip32 import BIP32Node, convert_bip32_path_to_list_of_uint32 as pa
|
||||
from electrum import constants
|
||||
from electrum.i18n import _
|
||||
from electrum.plugin import Device, runs_in_hwd_thread
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput
|
||||
from electrum.transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, Sighash
|
||||
from electrum.keystore import Hardware_KeyStore
|
||||
from electrum.base_wizard import ScriptTypeNotSupported, HWD_SETUP_NEW_WALLET
|
||||
from electrum.logging import get_logger
|
||||
@@ -370,7 +370,8 @@ class TrezorPlugin(HW_PluginBase):
|
||||
amount_unit=self.get_trezor_amount_unit(),
|
||||
serialize=False,
|
||||
prev_txes=prev_tx)
|
||||
signatures = [(bh2u(x) + '01') for x in signatures]
|
||||
sighash = Sighash.to_sigbytes(Sighash.ALL).hex()
|
||||
signatures = [(bh2u(x) + sighash) for x in signatures]
|
||||
tx.update_signatures(signatures)
|
||||
|
||||
@runs_in_hwd_thread
|
||||
|
||||
@@ -11,7 +11,7 @@ from electrum.lnutil import (RevocationStore, get_per_commitment_secret_from_see
|
||||
ScriptHtlc, extract_nodeid, calc_fees_for_commitment_tx, UpdateAddHtlc, LnFeatures,
|
||||
ln_compare_features, IncompatibleLightningFeatures, ChannelType)
|
||||
from electrum.util import bh2u, bfh, MyEncoder
|
||||
from electrum.transaction import Transaction, PartialTransaction
|
||||
from electrum.transaction import Transaction, PartialTransaction, Sighash
|
||||
from electrum.lnworker import LNWallet
|
||||
|
||||
from . import ElectrumTestCase
|
||||
@@ -725,7 +725,8 @@ class TestLNUtil(ElectrumTestCase):
|
||||
assert len(pubkey) == 33
|
||||
assert len(privkey) == 33
|
||||
tx.sign({bh2u(pubkey): (privkey[:-1], True)})
|
||||
tx.add_signature_to_txin(txin_idx=0, signing_pubkey=remote_pubkey.hex(), sig=remote_signature + "01")
|
||||
sighash = Sighash.to_sigbytes(Sighash.ALL).hex()
|
||||
tx.add_signature_to_txin(txin_idx=0, signing_pubkey=remote_pubkey.hex(), sig=remote_signature + sighash)
|
||||
|
||||
def test_get_compressed_pubkey_from_bech32(self):
|
||||
self.assertEqual(b'\x03\x84\xef\x87\xd9d\xa2\xaaa7=\xff\xb8\xfe=t8[}>;\n\x13\xa8e\x8eo:\xf5Mi\xb5H',
|
||||
|
||||
@@ -90,19 +90,25 @@ class MissingTxInputAmount(Exception):
|
||||
|
||||
|
||||
class Sighash(IntEnum):
|
||||
# note: this is not an IntFlag, as ALL|NONE != SINGLE
|
||||
|
||||
ALL = 1
|
||||
NONE = 2
|
||||
SINGLE = 3
|
||||
ANYONECANPAY = 0x80
|
||||
|
||||
@classmethod
|
||||
def is_valid(cls, sighash) -> bool:
|
||||
def is_valid(cls, sighash: int) -> bool:
|
||||
for flag in Sighash:
|
||||
for base_flag in [Sighash.ALL, Sighash.NONE, Sighash.SINGLE]:
|
||||
if (flag & ~0x1f | base_flag) == sighash:
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def to_sigbytes(cls, sighash: int) -> bytes:
|
||||
return sighash.to_bytes(length=1, byteorder="big")
|
||||
|
||||
|
||||
class TxOutput:
|
||||
scriptpubkey: bytes
|
||||
@@ -1940,7 +1946,7 @@ class PartialTransaction(Transaction):
|
||||
txin = inputs[txin_index]
|
||||
sighash = txin.sighash if txin.sighash is not None else Sighash.ALL
|
||||
if not Sighash.is_valid(sighash):
|
||||
raise Exception("SIGHASH_FLAG not supported!")
|
||||
raise Exception(f"SIGHASH_FLAG ({sighash}) not supported!")
|
||||
nHashType = int_to_hex(sighash, 4)
|
||||
preimage_script = self.get_preimage_script(txin)
|
||||
if txin.is_segwit():
|
||||
@@ -1966,6 +1972,8 @@ class PartialTransaction(Transaction):
|
||||
nSequence = int_to_hex(txin.nsequence, 4)
|
||||
preimage = nVersion + hashPrevouts + hashSequence + outpoint + scriptCode + amount + nSequence + hashOutputs + nLocktime + nHashType
|
||||
else:
|
||||
if sighash != Sighash.ALL:
|
||||
raise Exception(f"SIGHASH_FLAG ({sighash}) not supported! (for legacy sighash)")
|
||||
txins = var_int(len(inputs)) + ''.join(txin.serialize_to_network(script_sig=bfh(preimage_script) if txin_index==k else b"").hex()
|
||||
for k, txin in enumerate(inputs))
|
||||
txouts = var_int(len(outputs)) + ''.join(o.serialize_to_network().hex() for o in outputs)
|
||||
@@ -1994,12 +2002,11 @@ class PartialTransaction(Transaction):
|
||||
txin = self.inputs()[txin_index]
|
||||
txin.validate_data(for_signing=True)
|
||||
sighash = txin.sighash if txin.sighash is not None else Sighash.ALL
|
||||
sighash_type = sighash.to_bytes(length=1, byteorder="big").hex()
|
||||
pre_hash = sha256d(bfh(self.serialize_preimage(txin_index,
|
||||
bip143_shared_txdigest_fields=bip143_shared_txdigest_fields)))
|
||||
privkey = ecc.ECPrivkey(privkey_bytes)
|
||||
sig = privkey.sign_transaction(pre_hash)
|
||||
sig = bh2u(sig) + sighash_type
|
||||
sig = bh2u(sig) + Sighash.to_sigbytes(sighash).hex()
|
||||
return sig
|
||||
|
||||
def is_complete(self) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user