def create_payment_tx(self, deposit_tx, redeem_script, amount, fee): # Find P2SH output index in deposit_tx deposit_utxo_index = deposit_tx.output_index_for_address(redeem_script.hash160()) # Look up deposit amount deposit_amount = deposit_tx.outputs[deposit_utxo_index].value - fee # Build unsigned payment transaction inputs = [bitcoin.TransactionInput(deposit_tx.hash, deposit_utxo_index, bitcoin.Script(), 0xffffffff)] outputs = [ bitcoin.TransactionOutput( amount, bitcoin.Script.build_p2pkh(redeem_script.merchant_public_key.hash160())), bitcoin.TransactionOutput( deposit_amount - amount, bitcoin.Script.build_p2pkh(redeem_script.customer_public_key.hash160()))] payment_tx = bitcoin.Transaction(bitcoin.Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, 0x0) # Sign payment transaction public_key = redeem_script.customer_public_key private_key = self._wallet.get_private_for_public(public_key) assert private_key, "Redeem script public key not found in wallet." sig = payment_tx.get_signature_for_input(0, bitcoin.Transaction.SIG_HASH_ALL, private_key, redeem_script)[0] # Update input script sig script_sig = bitcoin.Script([ sig.to_der() + bitcoin.utils.pack_compact_int(bitcoin.Transaction.SIG_HASH_ALL), "OP_1", bytes(redeem_script)]) payment_tx.inputs[0].script = script_sig return payment_tx
def test_redeem_script(): # Redeem script parmaeters merchant_public_key = mock.MockPaymentChannelServer.PRIVATE_KEY.public_key customer_public_key = mock.MockTwo1Wallet.PRIVATE_KEY.public_key expiration_time = 1450223410 serialized_redeem_script = "63210316f5d704b828c3252432886a843649730e08ae01bbbd5c6bde63756d7f54f961ad670432a77056b175682103ee071c95cb772e57a6d8f4f987e9c61b857e63d9f3b5be7a84bdba0b5847099dac" # nopep8 # Test construction redeem_script = statemachine.PaymentChannelRedeemScript( merchant_public_key, customer_public_key, expiration_time) assert redeem_script.to_hex() == serialized_redeem_script assert redeem_script.merchant_public_key.compressed_bytes == merchant_public_key.compressed_bytes assert redeem_script.customer_public_key.compressed_bytes == customer_public_key.compressed_bytes assert redeem_script.expiration_time == expiration_time # Test deserialization redeem_script = statemachine.PaymentChannelRedeemScript.from_bytes( codecs.decode(serialized_redeem_script, "hex_codec")) assert redeem_script.to_hex() == serialized_redeem_script assert redeem_script.merchant_public_key.compressed_bytes == merchant_public_key.compressed_bytes assert redeem_script.customer_public_key.compressed_bytes == customer_public_key.compressed_bytes assert redeem_script.expiration_time == expiration_time # Test invalid deserialization with pytest.raises(ValueError): # Invalid length scr = bitcoin.Script(["OP_NOP"]) statemachine.PaymentChannelRedeemScript.from_bytes(bytes(scr)) with pytest.raises(ValueError): # Invalid opcode scr = bitcoin.Script.from_hex(serialized_redeem_script) scr[-1] = "OP_NOP" statemachine.PaymentChannelRedeemScript.from_bytes(bytes(scr))
def build_signed_transaction(self, addresses_and_amounts, use_unconfirmed=False, insert_into_cache=False, fees=None, expiration=0): address = list(addresses_and_amounts.keys())[0] amount = addresses_and_amounts[address] inputs = [ bitcoin.TransactionInput(self.MOCK_UTXO, self.MOCK_UTXO_INDEX, bitcoin.Script(), 0xffffffff) ] outputs = [ bitcoin.TransactionOutput( amount, bitcoin.Script.build_p2sh( utils.address_to_key_hash(address)[1])) ] tx = bitcoin.Transaction( bitcoin.Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, 0x0) tx.sign_input(0, bitcoin.Transaction.SIG_HASH_ALL, self.PRIVATE_KEY, self.MOCK_UTXO_SCRIPT_PUBKEY) return [tx]
def create_unsigned_payment_tx(self, deposit_tx, redeem_script, amount, fee): # Find P2SH output index in deposit_tx deposit_utxo_index = deposit_tx.output_index_for_address( redeem_script.hash160()) # Look up deposit amount deposit_amount = deposit_tx.outputs[deposit_utxo_index].value - fee # Build unsigned payment transaction inputs = [ bitcoin.TransactionInput(deposit_tx.hash, deposit_utxo_index, bitcoin.Script(), 0xffffffff), ] outputs = [ bitcoin.TransactionOutput( amount, bitcoin.Script.build_p2pkh( redeem_script.merchant_public_key.hash160())), bitcoin.TransactionOutput( deposit_amount - amount, bitcoin.Script.build_p2pkh( redeem_script.customer_public_key.hash160())), ] payment_tx = bitcoin.Transaction( bitcoin.Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, 0x0) return payment_tx
def create_refund_tx(self, deposit_tx, redeem_script, expiration_time, fee): # Find P2SH output index in deposit_tx deposit_utxo_index = deposit_tx.output_index_for_address( redeem_script.hash160()) # Look up deposit amount deposit_amount = deposit_tx.outputs[deposit_utxo_index].value - fee # Build unsigned refund transaction inputs = [ bitcoin.TransactionInput(deposit_tx.hash, deposit_utxo_index, bitcoin.Script(), 0xfffffffe), ] outputs = [ bitcoin.TransactionOutput( deposit_amount, bitcoin.Script.build_p2pkh( redeem_script.customer_public_key.hash160())), ] refund_tx = bitcoin.Transaction( bitcoin.Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, expiration_time) # Sign refund transaction public_key = redeem_script.customer_public_key private_key = self._wallet.get_private_for_public(public_key) assert private_key, "Redeem script public key not found in wallet." sig = refund_tx.get_signature_for_input( 0, bitcoin.Transaction.SIG_HASH_ALL, private_key, redeem_script)[0] # Update input script sig hash_type = bitcoin.utils.pack_compact_int( bitcoin.Transaction.SIG_HASH_ALL) script_sig = bitcoin.Script( [sig.to_der() + hash_type, b"\x00", bytes(redeem_script)]) refund_tx.inputs[0].script = script_sig return refund_tx
def _build_void_transaction(price=None, address=None): price = price or 1000 address = address or '19tAqnusJv2XoyxsC1UzuBTdG9dCAgafEX' _, hash160 = bitcoin.utils.address_to_key_hash(address) h = codecs.encode(b'test hash for a fake payment txn', 'hex_codec').decode() outpoint = bitcoin.Hash(h) inputs = [bitcoin.TransactionInput( outpoint=outpoint, outpoint_index=0, script=bitcoin.Script(), sequence_num=0xffffffff )] outputs = [bitcoin.TransactionOutput(value=price, script=bitcoin.Script.build_p2pkh(hash160))] txn = bitcoin.Transaction( version=bitcoin.Transaction.DEFAULT_TRANSACTION_VERSION, inputs=inputs, outputs=outputs, lock_time=0 ) return txn
def create_payment_tx(self, deposit_tx, redeem_script, amount, fee): payment_tx = self.create_unsigned_payment_tx(deposit_tx, redeem_script, amount, fee) # Sign payment transaction public_key = redeem_script.customer_public_key private_key = self._wallet.get_private_for_public(public_key) assert private_key, "Redeem script public key not found in wallet." sig = payment_tx.get_signature_for_input( 0, bitcoin.Transaction.SIG_HASH_ALL, private_key, redeem_script)[0] # Update input script sig hash_type = bitcoin.utils.pack_compact_int( bitcoin.Transaction.SIG_HASH_ALL) script_sig = bitcoin.Script( [sig.to_der() + hash_type, "OP_1", bytes(redeem_script)]) payment_tx.inputs[0].script = script_sig return payment_tx