def test_issue(priv_key, receiver, new_issuer=issuer, next_tok_id=curr_token_id + 1, issued_tok_id=curr_token_id): context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = token.locking_script context.utxo.value = input_sats new_data_part = b'\x23' + scryptlib.utils.get_push_int(next_tok_id)[1:] + \ new_issuer.to_bytes() + action_issue new_locking_script = Script(token.code_part.to_bytes() + new_data_part) tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) new_data_part = b'\x23' + scryptlib.utils.get_push_int(issued_tok_id)[1:] + \ receiver.to_bytes() + action_transfer new_locking_script = Script(token.code_part.to_bytes() + new_data_part) tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) sighash = context.tx.signature_hash(0, input_sats, token.locking_script, sighash_flag) sig = priv_key.sign(sighash, hasher=None) sig = sig + pack_byte(sighash_flag) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) return token.issue(Sig(sig), PubKey(receiver), out_sats, out_sats, SigHashPreimage(preimage)).verify(context)
def test_verify_with_change(): deposit_sats = 100000 input_sats = 100000 output_sats = deposit_sats + input_sats change_sats = 547 faucet.set_data_part(scryptlib.utils.get_push_int(1602553516)) context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = faucet.locking_script context.utxo.value = input_sats tx_out_0 = TxOutput(value=output_sats, script_pubkey=faucet.locking_script) context.tx.outputs.append(tx_out_0) tx_out_1 = TxOutput(value=change_sats, script_pubkey=P2PKH_Address(pkh, Bitcoin).to_script()) context.tx.outputs.append(tx_out_1) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = faucet.deposit(SigHashPreimage(preimage), deposit_sats, Ripemd160(pkh), change_sats).verify(context) assert verify_result == True with pytest.raises(bitcoinx.VerifyFailed): faucet.deposit(SigHashPreimage(preimage), deposit_sats, Ripemd160(pkh), change_sats + 1).verify(context)
def test_finish(key_priv, pkh_B, action_A, action_B, total_sats, input_sats, out_sats, change_sats): rps.set_data_part(player_A_data + pkh_B + scryptlib.utils.get_push_int(action_B)[1:]) context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = rps.locking_script context.utxo.value = total_sats change_out = TxOutput(change_sats, P2PKH_Address(pkh_A, Bitcoin).to_script()) context.tx.outputs.append(change_out) if out_sats > 0: pay_out = TxOutput(out_sats, P2PKH_Address(pkh_B, Bitcoin).to_script()) context.tx.outputs.append(pay_out) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) input_idx = 0 utxo_satoshis = context.utxo.value sighash = context.tx.signature_hash(input_idx, utxo_satoshis, rps.locking_script, sighash_flag) sig = key_priv.sign(sighash, hasher=None) sig = sig + pack_byte(sighash_flag) return rps.finish(SigHashPreimage(preimage), action_A, Sig(sig), PubKey(key_pub_A), change_sats).verify(context)
def sale(n_bought, pkh, pub_key): context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = ats.locking_script context.utxo.value = input_sats new_data_part = ats.data_part << pub_key.to_bytes( ) + scryptlib.utils.get_push_int(n_bought)[1:] new_locking_script = Script(ats.code_part.to_bytes() + new_data_part.to_bytes()) change_sats = input_sats - n_bought * SATS_PER_TOKEN out_sats = input_sats + n_bought * SATS_PER_TOKEN # Counter output tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) # Change output change_out = TxOutput( change_sats, P2PKH_Address(pub_key.hash160(), Bitcoin).to_script()) context.tx.outputs.append(change_out) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = ats.buy(SigHashPreimage(preimage), Ripemd160(pkh), change_sats, Bytes(pub_key.to_bytes()), n_bought).verify(context) assert verify_result == True return new_data_part
def test_verify_withdraw(): withdraw_sats = 2000000 fee = 3000 input_sats = 10000000 output_sats = input_sats - withdraw_sats - fee mature_time = 1627122529 faucet.set_data_part(scryptlib.utils.get_push_int(mature_time)) context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = faucet.locking_script context.utxo.value = input_sats new_locking_script = faucet.code_part << Script( scryptlib.utils.get_push_int(mature_time + 300)) tx_out_0 = TxOutput(value=output_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out_0) tx_out_1 = TxOutput(value=withdraw_sats, script_pubkey=P2PKH_Address(pkh, Bitcoin).to_script()) context.tx.outputs.append(tx_out_1) context.tx.inputs[0].sequence = 0xfffffffe context.tx.locktime = mature_time + 300 preimage = scryptlib.utils.get_preimage_from_input_context(context) verify_result = faucet.withdraw(SigHashPreimage(preimage), Ripemd160(pkh)).verify(context) assert verify_result == True # Wrong mature time context.tx.outputs = [] new_locking_script = faucet.code_part << Script( scryptlib.utils.get_push_int(mature_time + 299)) tx_out_0 = TxOutput(value=output_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out_0) tx_out_1 = TxOutput(value=withdraw_sats, script_pubkey=P2PKH_Address(pkh, Bitcoin).to_script()) context.tx.outputs.append(tx_out_1) context.tx.locktime = mature_time + 299 preimage = scryptlib.utils.get_preimage_from_input_context(context) with pytest.raises(bitcoinx.VerifyFailed): faucet.withdraw(SigHashPreimage(preimage), Ripemd160(pkh)).verify(context)
def test_verify_scenario_2(): context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = escrow.locking_script context.utxo.value = input_sats change_out = TxOutput(int(input_sats - fee), P2PKH_Address(pkh_A, Bitcoin).to_script()) context.tx.outputs.append(change_out) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) sighash = context.tx.signature_hash(0, input_sats, escrow.locking_script, sighash_flag) sig_A = key_priv_A.sign(sighash, hasher=None) sig_A = sig_A + pack_byte(sighash_flag) sig_E = key_priv_E.sign(sighash, hasher=None) sig_E = sig_E + pack_byte(sighash_flag) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = escrow.unlock(SigHashPreimage(preimage), PubKey(key_pub_A), Sig(sig_A), PubKey(key_pub_E), Sig(sig_E), Bytes(secret0)).verify(context) assert verify_result == True # Wrong secret with pytest.raises(bitcoinx.VerifyFailed): verify_result = escrow.unlock(SigHashPreimage(preimage), PubKey(key_pub_A), Sig(sig_A), PubKey(key_pub_E), Sig(sig_E), Bytes(secret1)).verify(context)
def test_verify_correct(): # Intial state state = {'counter': 11, 'buf': b'\x12\x34', 'flag': True} counter.set_data_part(state) # Alter state state['counter'] += 1 state['buf'] += b'\xff\xff' state['flag'] = False serialized_state = scryptlib.serializer.serialize_state(state) new_locking_script = Script(counter.code_part.to_bytes() + serialized_state) # Deserialize state from new locking script new_state = scryptlib.serializer.deserialize_state(new_locking_script, state) assert new_state['counter'] == 12 assert new_state['buf'] == b'\x12\x34\xff\xff' assert new_state['flag'] == False context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = counter.locking_script tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) preimage = scryptlib.utils.get_preimage_from_input_context(context) verfiy_result = counter.mutate(SigHashPreimage(preimage), out_sats).verify(context) assert verfiy_result == True
def serialize(self, jsontx): """Create a transaction from json inputs. Inputs must have a redeemPubkey. Outputs must be a list of {'address':address, 'value':satoshi_amount}. """ keypairs = {} inputs = jsontx.get('inputs') outputs = jsontx.get('outputs') locktime = jsontx.get('locktime', 0) for txin in inputs: if txin.get('output'): prevout_hash, prevout_n = txin['output'].split(':') txin['prevout_n'] = int(prevout_n) txin['prevout_hash'] = prevout_hash sec = txin.get('privkey') if sec: privkey = PrivateKey.from_text(sec) txin_type, privkey, compressed = ('p2pkh', privkey.to_bytes(), privkey.is_compressed()) pubkey = privkey.public_key.to_hex() keypairs[pubkey] = privkey, compressed txin['type'] = txin_type txin['x_pubkeys'] = [pubkey] txin['signatures'] = [None] txin['num_sig'] = 1 outputs = [ TxOutput(output['value'], Address.from_string(output['address']).to_script()) for output in outputs ] tx = Transaction.from_io(inputs, outputs, locktime=locktime) tx.sign(keypairs) return tx.as_dict()
def test_tx_unsigned(self): tx = Transaction.from_hex(unsigned_blob) assert tx.version == 1 assert len(tx.inputs) == 1 txin = tx.inputs[0] assert txin.prev_hash.hex( ) == '49f35e43fefd22d8bb9e4b3ff294c6286154c25712baf6ab77b646e5074d6aed' assert txin.prev_idx == 1 assert txin.script_sig.to_hex( ) == '01ff4c53ff0488b21e0000000000000000004f130d773e678a58366711837ec2e33ea601858262f8eaef246a7ebd19909c9a03c3b30e38ca7d797fee1223df1c9827b2a9f3379768f520910260220e0560014600002300' assert txin.sequence == 4294967294 assert txin.value == 20112600 assert txin.signatures == [NO_SIGNATURE] assert txin.x_pubkeys == [ XPublicKey( 'ff0488b21e0000000000000000004f130d773e678a58366711837ec2e33ea601858262f8eaef246a7ebd19909c9a03c3b30e38ca7d797fee1223df1c9827b2a9f3379768f520910260220e0560014600002300' ) ] assert txin.address == address_from_string( '13Vp8Y3hD5Cb6sERfpxePz5vGJizXbWciN') assert txin.threshold == 1 assert tx.outputs == [ TxOutput( 20112408, address_from_string( '1MYXdf4moacvaEKZ57ozerpJ3t9xSeN6LK').to_script()) ] assert tx.locktime == 507231 assert tx.as_dict() == {'hex': unsigned_blob, 'complete': False}
def make_signed_opreturn_transaction( self, wallet_name: Optional[str] = None, password: Optional[str] = None, pushdatas_b64: Optional[List[str]] = None) -> dict: wallet = self._get_wallet(wallet_name) pushdatas = [] for pushdata_b64 in pushdatas_b64: pushdata_bytes = base64.b64decode(pushdata_b64) pushdatas.append(pushdata_bytes) domain = None confirmed_coins = wallet.get_spendable_coins(None, {'confirmed_only': True}) script = (Script() << OP_RETURN).push_many(pushdatas) outputs = [TxOutput(0, script)] tx = wallet.make_unsigned_transaction(confirmed_coins, outputs, app_state.config) wallet.sign_transaction(tx, password) return { "tx_id": tx.txid(), "tx_hex": str(tx), "fee": tx.get_fee(), }
def _mktx(self, outputs, fee=None, change_addr=None, domain=None, nocheck=False, unsigned=False, password=None, locktime=None): self.nocheck = nocheck change_addr = None if change_addr is None else Address.from_string( change_addr) domain = None if domain is None else [ Address.from_string(x) for x in domain ] final_outputs = [] for address, amount in outputs: address = Address.from_string(address) amount = satoshis(amount) final_outputs.append(TxOutput(amount, address.to_script())) coins = self.wallet.get_spendable_coins(domain, self.config) tx = self.wallet.make_unsigned_transaction(coins, final_outputs, self.config, fee, change_addr) if locktime is not None: tx.locktime = locktime if not unsigned: self.wallet.sign_transaction(tx, password) return tx
def _parse_tx_output(self, line): x, y = line.split(',') script = self._parse_output(x) if not isinstance(script, Script): # An Address object script = script.to_script() amount = self._parse_amount(y) return TxOutput(amount, script)
def test_verify_wrong_out_amount(): pkh_0_out_wrong = TxOutput(in_sats - miner_fee + 123, P2PKH_Address(pkh_0, Bitcoin).to_script()) context = create_input_context(in_sats, acs.locking_script, pkh_0_out_wrong) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = acs.unlock(SigHashPreimage(preimage)).verify(context) assert verify_result == False
def _ask_send_split_transaction(self): window = self.window() wallet = self.get_wallet() unused_address = wallet.get_unused_address() outputs = [TxOutput(all, unused_address.to_script())] coins = wallet.get_utxos(None, exclude_frozen=True, mature=True, confirmed_only=False) # Verify that our dust receiving address is in the available UTXOs, if it isn't, the # process has failed in some unexpected way. for coin in coins: if coin['address'] == self.receiving_address: break else: window.show_error( _("Error accessing dust coins for correct splitting.")) self._cleanup_tx_final() return tx = wallet.make_unsigned_transaction(coins, outputs, window.config) amount = tx.output_value() fee = tx.get_fee() msg = [ _("Amount to be sent") + ": " + window.format_amount_and_units(amount), _("Mining fee") + ": " + window.format_amount_and_units(fee), ] if wallet.has_password(): msg.append("") msg.append(_("Enter your password to proceed")) password = window.password_dialog('\n'.join(msg)) else: msg.append(_('Proceed?')) password = None if not window.question('\n'.join(msg)): self._cleanup_tx_final() return def sign_done(success): if success: if not tx.is_complete(): dialog = self.window().show_transaction(tx) dialog.exec() else: extra_text = _("Your split coins") window.broadcast_transaction( wallet, tx, f"{TX_DESC_PREFIX}: {extra_text}", success_text=_("Your coins have now been split.")) self._cleanup_tx_final() window.sign_tx_with_password(tx, sign_done, password)
def get_preimage_after_purchase(key_pub): new_locking_script = Script(token_sale.locking_script.to_bytes() + key_pub.to_bytes() + scryptlib.utils.get_push_int(n_tokens)[1:]) tx_out = TxOutput(value=in_sats + n_tokens * token_price_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) return scryptlib.utils.get_preimage_from_input_context(context)
def increment_counter(counter_obj, prev_txid, prev_out_idx, funding_txid, funding_out_idx, unlock_key_priv, miner_fee): # Get data from previous counter tx r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format( prev_txid)).json() prev_locking_script = Script.from_hex( r['vout'][prev_out_idx]['scriptPubKey']['hex']) prev_counter_bytes = list(prev_locking_script.ops())[-1] prev_counter_val = int.from_bytes(prev_counter_bytes, 'little') unlocked_satoshis_counter = int(r['vout'][prev_out_idx]['value'] * 10**8) # Get data from funding tx r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format( funding_txid)).json() funding_locking_script = Script.from_hex( r['vout'][funding_out_idx]['scriptPubKey']['hex']) unlocked_satoshis_funding = int(r['vout'][funding_out_idx]['value'] * 10**8) # Set data for next iteration counter_obj.set_data_part( scryptlib.utils.get_push_int(prev_counter_val + 1)) ## Construct tx n_sequence = 0xffffffff # Counter input and output prev_tx_hash = hex_str_to_hash(prev_txid) counter_in = TxInput(prev_tx_hash, prev_out_idx, None, n_sequence) out_satoshis = unlocked_satoshis_counter + unlocked_satoshis_funding - miner_fee contract_out = TxOutput(out_satoshis, counter_obj.locking_script) # Funding input funding_tx_hash = hex_str_to_hash(funding_txid) funding_in = TxInput(funding_tx_hash, funding_out_idx, None, n_sequence) tx = Tx(2, [counter_in, funding_in], [contract_out], 0x00000000) # Set input script to unlock previous counter sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) preimage = scryptlib.utils.get_preimage(tx, 0, unlocked_satoshis_counter, prev_locking_script, sighash_flag) increment_func_call = counter_obj.increment(SigHashPreimage(preimage), Int(out_satoshis)) tx.inputs[0].script_sig = increment_func_call.script # Set input script to unlock funding output unlock_key_pub = unlock_key_priv.public_key sighash = tx.signature_hash(1, unlocked_satoshis_funding, funding_locking_script, sighash_flag) sig = unlock_key_priv.sign(sighash, hasher=None) sig = sig + pack_byte(sighash_flag) unlock_script = Script() << sig << unlock_key_pub.to_bytes() tx.inputs[1].script_sig = unlock_script broadcast_tx(tx)
def get_context(hashed_map): new_ls = state_map.get_state_script({'_mpData': Bytes(hashed_map.hex)}) context = scryptlib.create_dummy_input_context() context.utxo.script_pubkey = state_map.locking_script tx_out = TxOutput(value=0, script_pubkey=new_ls) context.tx.outputs.append(tx_out) return context
def get_outputs(self, is_max): if self.payto_address: if is_max: amount = all else: amount = self.amount_edit.get_amount() addr = self.payto_address self.outputs = [TxOutput(amount, addr.to_script())] return self.outputs[:]
def test_verify_wrong_addr(): key_priv = PrivateKey.from_arbitrary_bytes(b'123test') key_pub = key_priv.public_key pkh = key_pub.hash160() pkh_0_out_wrong = TxOutput(in_sats - miner_fee, P2PKH_Address(pkh, Bitcoin).to_script()) context = create_input_context(in_sats, acs.locking_script, pkh_0_out_wrong) preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = acs.unlock(SigHashPreimage(preimage)).verify(context) assert verify_result == False
def initialize_counter(counter_obj, counter_initial_val, funding_txid, funding_out_idx, \ unlock_key_priv, miner_fee, contract_out_sats, change_addr): counter_obj.set_data_part( scryptlib.utils.get_push_int(counter_initial_val)) # Funding TX funding_tx_hash = hex_str_to_hash(funding_txid) unlock_key_pub = unlock_key_priv.public_key r = requests.get('https://api.whatsonchain.com/v1/bsv/main/tx/{}'.format( funding_txid)).json() funding_locking_script = Script.from_hex( r['vout'][funding_out_idx]['scriptPubKey']['hex']) unlocked_satoshis = int(r['vout'][funding_out_idx]['value'] * 10**8) n_sequence = 0xffffffff tx_input = TxInput(funding_tx_hash, funding_out_idx, None, n_sequence) # Output with counter script code contract_out = TxOutput(contract_out_sats, counter_obj.locking_script) # Change output tx_output_script = P2PKH_Address.from_string(change_addr, Bitcoin).to_script() change_out = TxOutput(unlocked_satoshis - miner_fee - contract_out_sats, tx_output_script) tx = Tx(2, [tx_input], [contract_out, change_out], 0x00000000) # Create signature for input sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) sighash = tx.signature_hash(0, unlocked_satoshis, funding_locking_script, sighash_flag) sig = unlock_key_priv.sign(sighash, hasher=None) sig = sig + pack_byte(sighash_flag) # Set script for input unlock_script = Script() << sig << unlock_key_pub.to_bytes() tx.inputs[0].script_sig = unlock_script broadcast_tx(tx)
def test_split(key_priv, balance0, balance1, balance_input0=None, balance_input1=None): if not balance_input0: balance_input0 = balance0 if not balance_input1: balance_input1 = balance1 context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = token.locking_script context.utxo.value = in_sats new_locking_script = Script(token.code_part.to_bytes() + b'\x23' + key_pub_1.to_bytes() + b'\x00' + scryptlib.utils.get_push_int(balance0)[1:]) tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) if balance1 > 0: new_locking_script = Script(token.code_part.to_bytes() + b'\x23' + key_pub_2.to_bytes() + b'\x00' + scryptlib.utils.get_push_int(balance1)[1:]) tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) preimage = scryptlib.utils.get_preimage_from_input_context(context, sighash_flag) input_idx = 0 utxo_satoshis = context.utxo.value sighash = context.tx.signature_hash(input_idx, utxo_satoshis, token.locking_script, sighash_flag) sig = key_priv.sign(sighash, hasher=None) sig = sig + pack_byte(sighash_flag) return token.split( Sig(sig), PubKey(key_pub_1), balance_input0, out_sats, PubKey(key_pub_2), balance_input1, out_sats, SigHashPreimage(preimage) ).verify(context)
def test_tx_unsigned(self): outputs = [ TxOutput( 20112408, Address.from_string( '1MYXdf4moacvaEKZ57ozerpJ3t9xSeN6LK').to_script()) ] expected = { 'inputs': [{ 'address': Address.from_string('13Vp8Y3hD5Cb6sERfpxePz5vGJizXbWciN'), 'num_sig': 1, 'prevout_hash': 'ed6a4d07e546b677abf6ba1257c2546128c694f23f4b9ebbd822fdfe435ef349', 'prevout_n': 1, 'pubkeys': [ '03b5bbebceeb33c1b61f649596b9c3611c6b2853a1f6b48bce05dd54f667fa2166' ], 'scriptSig': '01ff4c53ff0488b21e0000000000000000004f130d773e678a58366711837ec2e33ea601858262f8eaef246a7ebd19909c9a03c3b30e38ca7d797fee1223df1c9827b2a9f3379768f520910260220e0560014600002300', 'sequence': 4294967294, 'signatures': [None], 'type': 'p2pkh', 'value': 20112600, 'x_pubkeys': [ 'ff0488b21e0000000000000000004f130d773e678a58366711837ec2e33ea601858262f8eaef246a7ebd19909c9a03c3b30e38ca7d797fee1223df1c9827b2a9f3379768f520910260220e0560014600002300' ] }], 'lockTime': 507231, 'outputs': outputs, 'version': 1 } tx = transaction.Transaction(unsigned_blob) calc = tx.deserialize() self.assertEqual(calc, expected) self.assertEqual(tx.deserialize(), None) self.assertEqual(tx.as_dict(), { 'hex': unsigned_blob, 'complete': False, 'final': True }) self.assertEqual(tx.outputs(), outputs) self.assertEqual(tx.serialize(), unsigned_blob)
def test_tx_signed(self): expected = { 'inputs': [{ 'address': Address.from_string('13Vp8Y3hD5Cb6sERfpxePz5vGJizXbWciN'), 'num_sig': 1, 'prevout_hash': 'ed6a4d07e546b677abf6ba1257c2546128c694f23f4b9ebbd822fdfe435ef349', 'prevout_n': 1, 'pubkeys': [ '03b5bbebceeb33c1b61f649596b9c3611c6b2853a1f6b48bce05dd54f667fa2166' ], 'scriptSig': '473044022025bdc804c6fe30966f6822dc25086bc6bb0366016e68e880cf6efd2468921f3202200e665db0404f6d6d9f86f73838306ac55bb0d0f6040ac6047d4e820f24f46885412103b5bbebceeb33c1b61f649596b9c3611c6b2853a1f6b48bce05dd54f667fa2166', 'sequence': 4294967294, 'signatures': [ '3044022025bdc804c6fe30966f6822dc25086bc6bb0366016e68e880cf6efd2468921f3202200e665db0404f6d6d9f86f73838306ac55bb0d0f6040ac6047d4e820f24f4688541' ], 'type': 'p2pkh', 'x_pubkeys': [ '03b5bbebceeb33c1b61f649596b9c3611c6b2853a1f6b48bce05dd54f667fa2166' ] }], 'lockTime': 507231, 'outputs': [ TxOutput( 20112408, Address.from_string( '1MYXdf4moacvaEKZ57ozerpJ3t9xSeN6LK').to_script()) ], 'version': 1 } tx = transaction.Transaction(signed_blob) self.assertEqual(tx.deserialize(), expected) self.assertEqual(tx.deserialize(), None) self.assertEqual(tx.as_dict(), { 'hex': signed_blob, 'complete': True, 'final': True }) self.assertEqual(tx.serialize(), signed_blob) tx.update_signatures(signed_blob) self.assertEqual(tx.estimated_size(), 191)
def test_verify_wrong_output(): context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = gol.locking_script new_locking_script = Script(gol.code_part.to_bytes() + wb1) tx_out = TxOutput(value=out_amount, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) preimage = scryptlib.utils.get_preimage_from_input_context(context, sighash_flag) verify_result = gol.play(out_amount, SigHashPreimage(preimage)).verify(context) assert verify_result == False
def test_verify_correct(): context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = p2sh.locking_script context.utxo.value = input_sats tx_out = TxOutput(value=input_sats, script_pubkey=demo_contract.code_part) context.tx.outputs.append(tx_out) preimage = scryptlib.utils.get_preimage_from_input_context(context) verify_result = p2sh.redeem(Bytes(demo_contract.code_part.to_bytes()), SigHashPreimage(preimage)).verify(context) assert verify_result == True
def test_verify_wrong_nextval(): subsequent_counter_val_bytes = scryptlib.utils.get_push_int( COUNTER_INITIAL_VAL + 2) new_locking_script = counter.code_part << Script( subsequent_counter_val_bytes) tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs[0] = tx_out preimage = scryptlib.utils.get_preimage_from_input_context( context, sighash_flag) verify_result = counter.increment(SigHashPreimage(preimage), out_sats, Ripemd160(pkh_0), change_sats - 1).verify(context) assert verify_result == False
def test_verify_incorrect_sat_amount(): context = scryptlib.utils.create_dummy_input_context() context.utxo.script_pubkey = counter_obj.locking_script subsequent_counter_val_bytes = scryptlib.utils.get_push_int(COUNTER_INITIAL_VAL + 1) new_locking_script = counter_obj.code_part << Script(subsequent_counter_val_bytes) tx_out = TxOutput(value=0, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) preimage = scryptlib.utils.get_preimage_from_input_context(context, sighash_flag) new_output_satoshis = 100 verify_result = counter_obj.increment(SigHashPreimage(preimage), Int(new_output_satoshis)).verify(context) assert verify_result == False
def test_merge(input_idx, balance0, balance1): context = scryptlib.utils.create_dummy_input_context() context.utxo.value = in_sats context.input_index = input_idx tx_in = TxInput(context.tx.inputs[0].prev_hash, 1, Script(), 0xffffffff) context.tx.inputs.append(tx_in) prev_txid = context.tx.inputs[0].prev_hash prevouts = prev_txid + b'\x00\x00\x00\x00' + prev_txid + b'\x01\x00\x00\x00' new_locking_script = Script(token.code_part.to_bytes() + b'\x23' + key_pub_2.to_bytes() + scryptlib.utils.get_push_int(balance0)[1:] + scryptlib.utils.get_push_int(balance1)[1:]) tx_out = TxOutput(value=out_sats, script_pubkey=new_locking_script) context.tx.outputs.append(tx_out) if input_idx == 0: balance = balance1 context.utxo.script_pubkey = locking_script_0 key_to_sign = key_priv_0 token.set_data_part(b'\x23' + data_part_0) else: balance = balance0 context.utxo.script_pubkey = locking_script_1 key_to_sign = key_priv_1 token.set_data_part(b'\x23' + data_part_1) sighash_flag = SigHash(SigHash.ALL | SigHash.FORKID) #preimage = scryptlib.utils.get_preimage_from_input_context(context, sighash_flag) if input_idx == 0: preimage = scryptlib.utils.get_preimage(context.tx, input_idx, in_sats, locking_script_0, sighash_flag=sighash_flag) else: preimage = scryptlib.utils.get_preimage(context.tx, input_idx, in_sats, locking_script_1, sighash_flag=sighash_flag) if input_idx == 0: sighash = context.tx.signature_hash(input_idx, in_sats, locking_script_0, sighash_flag) else: sighash = context.tx.signature_hash(input_idx, in_sats, locking_script_1, sighash_flag) sig = key_to_sign.sign(sighash, hasher=None) sig = sig + pack_byte(sighash_flag) return token.merge( Sig(sig), PubKey(key_pub_2), Bytes(prevouts), balance, out_sats, SigHashPreimage(preimage) ).verify(context)
def _ask_send_split_transaction(self) -> None: coins = self._account.get_utxos(exclude_frozen=True, mature=True) # Verify that our dust receiving address is in the available UTXOs, if it isn't, the # process has failed in some unexpected way. for coin in coins: if coin['address'] == self.receiving_script_template: break else: self._main_window.show_error( _("Error accessing dust coins for correct splitting.")) self._cleanup_tx_final() return unused_key = self._account.get_fresh_keys(RECEIVING_SUBPATH, 1)[0] script = self._account.get_script_for_id(unused_key.keyinstance_id) outputs = [TxOutput(all, script)] tx = self._account.make_unsigned_transaction(coins, outputs, self._main_window.config) amount = tx.output_value() fee = tx.get_fee() msg = [ _("Amount to be sent") + ": " + self._main_window.format_amount_and_units(amount), _("Mining fee") + ": " + self._main_window.format_amount_and_units(fee), ] msg.append("") msg.append(_("Enter your password to proceed")) password = self._main_window.password_dialog('\n'.join(msg)) def sign_done(success): if success: if not tx.is_complete(): dialog = self._main_window.show_transaction( self._account, tx) dialog.exec() else: extra_text = _("Your split coins") self._main_window.broadcast_transaction( self._account, tx, f"{TX_DESC_PREFIX}: {extra_text}", success_text=_("Your coins have now been split.")) self._cleanup_tx_final() self._main_window.sign_tx_with_password(tx, sign_done, password)
def change_outputs(self, tx, change_addrs, fee_estimator, dust_threshold): amounts = self.change_amounts(tx, len(change_addrs), fee_estimator, dust_threshold) assert min(amounts) >= 0 assert len(change_addrs) >= len(amounts) # If change is above dust threshold after accounting for the # size of the change output, add it to the transaction. dust = sum(amount for amount in amounts if amount < dust_threshold) amounts = [amount for amount in amounts if amount >= dust_threshold] change = [TxOutput(amount, addr.to_script()) for addr, amount in zip(change_addrs, amounts)] logger.debug('change %s', change) if dust: logger.debug('not keeping dust %s', dust) return change, dust