Skip to content
Permalink
Browse files

Move tx_utils to network API.

  • Loading branch information
richardkiss committed Dec 29, 2018
1 parent ffe178f commit 4fdd19eec52db768438d062f2b7a5f1844570be2
@@ -16,7 +16,6 @@
from .dump import dump_tx

from pycoin.coins.exceptions import BadSpendableError
from pycoin.coins.tx_utils import distribute_from_split_pool
from pycoin.convention import tx_fee, satoshi_to_mbtc
from pycoin.encoding.hexbytes import b2h, h2b, h2b_rev
from pycoin.key.subpaths import subpaths_for_path_range
@@ -534,7 +533,7 @@ def generate_tx(network, txs, spendables, payables, args):
fee = args.fee
try:
if len(payables) > 0:
distribute_from_split_pool(tx, fee)
network.tx_utils.distribute_from_split_pool(tx, fee)
except ValueError as ex:
print("warning: %s" % ex.args[0], file=sys.stderr)
return tx
@@ -1,14 +1,11 @@

from pycoin.symbols.btc import network as BitcoinMainnet

from ..convention import tx_fee


class SecretExponentMissing(Exception):
pass


def create_tx(spendables, payables, fee="standard", lock_time=0, version=1, network=BitcoinMainnet):
def create_tx(network, spendables, payables, fee="standard", lock_time=0, version=1):
"""
This function provides the easiest way to create an unsigned transaction.
@@ -34,7 +31,7 @@ def create_tx(spendables, payables, fee="standard", lock_time=0, version=1, netw
Usage::
>>> spendables = spendables_for_address("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH")
>>> tx = create_tx(spendables, ["1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP"], fee=0)
>>> tx = create_tx(network, spendables, ["1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP"], fee=0)
This will move all available reported funds from 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH
to 1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP, with no transaction fees (which means it might
@@ -113,7 +110,7 @@ def distribute_from_split_pool(tx, fee):
return zero_count


def sign_tx(tx, wifs=[], network=BitcoinMainnet, **kwargs):
def sign_tx(network, tx, wifs=[], **kwargs):
"""
:param tx: a transaction
:param wifs: the list of WIFs required to sign this transaction.
@@ -126,16 +123,16 @@ def sign_tx(tx, wifs=[], network=BitcoinMainnet, **kwargs):
Usage::
>> sign_tx(tx, wifs=["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"])
>> sign_tx(network, tx, wifs=["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"])
"""
keychain = network.keychain()
keychain.add_secrets((network.parse.wif(_) for _ in wifs))
solver = tx.Solver(tx)
solver.sign(keychain, **kwargs)


def create_signed_tx(spendables, payables, wifs=[], fee="standard",
lock_time=0, version=1, netcode='BTC', network=BitcoinMainnet, **kwargs):
def create_signed_tx(network, spendables, payables, wifs=[], fee="standard",
lock_time=0, version=1, **kwargs):
"""
This convenience function calls :func:`create_tx` and :func:`sign_tx` in turn. Read the documentation
for those functions for information on the parameters.
@@ -145,15 +142,15 @@ def create_signed_tx(spendables, payables, wifs=[], fee="standard",
>>> spendables = spendables_for_address("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH")
>>> wifs = ["KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"]
>>> payables = ["1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP"]
>>> tx = create_signed_tx(spendables, payables, wifs=wifs, fee=0)
>>> tx = create_signed_tx(network, spendables, payables, wifs=wifs, fee=0)
This will move all available reported funds from 1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH
to 1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP, with no transaction fees (which means it might
take a while to confirm, possibly never).
"""

tx = create_tx(spendables, payables, fee=fee, lock_time=lock_time, version=version, network=network)
sign_tx(tx, wifs=wifs, netcode=netcode, **kwargs)
tx = create_tx(network, spendables, payables, fee=fee, lock_time=lock_time, version=version)
sign_tx(network, tx, wifs=wifs, **kwargs)
for idx, tx_out in enumerate(tx.txs_in):
if not tx.is_solution_ok(idx):
raise SecretExponentMissing("failed to sign spendable for %s" %
@@ -1,6 +1,7 @@
from pycoin.block import Block
from pycoin.coins.bitcoin.ScriptTools import BitcoinScriptTools
from pycoin.coins.bitcoin.Tx import Tx
from pycoin.coins.tx_utils import create_tx, split_with_remainder, distribute_from_split_pool, sign_tx, create_signed_tx
from pycoin.contrib.msg_signing import MessageSigner
from pycoin.contrib.who_signed import WhoSigned
from pycoin.ecdsa.secp256k1 import secp256k1_generator
@@ -256,6 +257,25 @@ def network_build_hash160_lookup(iter):
network.tx.solve.build_p2sh_lookup = build_p2sh_lookup
network.tx.solve.build_sec_lookup = build_sec_lookup

def my_create_tx(*args, **kwargs):
return create_tx(network, *args, **kwargs)

def my_sign_tx(*args, **kwargs):
return sign_tx(network, *args, **kwargs)

def my_create_signed_tx(*args, **kwargs):
return create_signed_tx(network, *args, **kwargs)

def my_split_with_remainder(*args, **kwargs):
return split_with_remainder(network, *args, **kwargs)

network.tx_utils = API()
network.tx_utils.create_tx = my_create_tx
network.tx_utils.sign_tx = my_sign_tx
network.tx_utils.create_signed_tx = my_create_signed_tx
network.tx_utils.split_with_remainder = my_split_with_remainder
network.tx_utils.distribute_from_split_pool = distribute_from_split_pool

network.annotate = Annotate(script_tools, network.address)

network.who_signed = WhoSigned(script_tools, network.address, generator)
@@ -9,7 +9,6 @@

import sys

from pycoin.coins.tx_utils import create_tx
from pycoin.symbols.btc import network


@@ -31,7 +30,7 @@ def main():
assert network.parse.address(payable) is not None

# create the unsigned transaction
tx = create_tx([spendable], [payable])
tx = network.tx_utils.create_tx([spendable], [payable])

print("here is the transaction: %s" % tx.as_hex(include_unspents=True))

@@ -2,7 +2,6 @@

import sys

from pycoin.coins.tx_utils import sign_tx
from pycoin.encoding.hexbytes import h2b
from pycoin.symbols.btc import network

@@ -31,7 +30,7 @@ def main():
p2sh_lookup = network.tx.solve.build_p2sh_lookup([p2sh_script])

# sign the transaction with the given WIF
sign_tx(tx, wifs=[wif], p2sh_lookup=p2sh_lookup)
network.tx_utils.sign_tx(tx, wifs=[wif], p2sh_lookup=p2sh_lookup)

bad_solution_count = tx.bad_solution_count()
print("tx %s now has %d bad solution(s)" % (tx.id(), bad_solution_count))
@@ -1,6 +1,5 @@
import unittest

from pycoin.coins.tx_utils import create_tx, sign_tx
from pycoin.encoding.bytes32 import to_bytes_32
from pycoin.encoding.hash import double_sha256
from pycoin.encoding.hexbytes import b2h, b2h_rev, h2b
@@ -56,18 +55,18 @@ def test_segwit_create_tx(self):
tx_out_index = 0
spendable = Tx.Spendable(coin_value, script, tx_hash, tx_out_index)
key2 = network.keys.private(2)
tx = create_tx([spendable], [(key2.address(), coin_value)])
tx = network.tx_utils.create_tx([spendable], [(key2.address(), coin_value)])
self.check_unsigned(tx)
sign_tx(tx, [key1.wif()])
network.tx_utils.sign_tx(tx, [key1.wif()])
self.check_signed(tx)
self.assertEqual(len(tx.txs_in[0].witness), 2)

s1 = network.contract.for_p2pkh(key1.hash160())
address = network.address.for_p2s_wit(s1)
spendable.script = network.contract.for_address(address)
tx = create_tx([spendable], [(key2.address(), coin_value)])
tx = network.tx_utils.create_tx([spendable], [(key2.address(), coin_value)])
self.check_unsigned(tx)
sign_tx(tx, [key1.wif()], p2sh_lookup=network.tx.solve.build_p2sh_lookup([s1]))
network.tx_utils.sign_tx(tx, [key1.wif()], p2sh_lookup=network.tx.solve.build_p2sh_lookup([s1]))
self.check_signed(tx)

def test_issue_224(self):
@@ -1,8 +1,6 @@
import itertools
import unittest

from pycoin.coins.tx_utils import create_tx
from pycoin.ecdsa.secp256k1 import secp256k1_generator
from pycoin.symbols.btc import network


@@ -17,7 +15,7 @@ def multisig_M_of_N_individually(self, M, N):
tx_out = Tx.TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
for partial_key_list in itertools.permutations(keys[:N], M):
tx2 = create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
for key in partial_key_list:
self.assertEqual(tx2.bad_solution_count(), 1)
hash160_lookup = network.tx.solve.build_hash160_lookup([key.secret_exponent()])
@@ -1,6 +1,5 @@
import unittest

from pycoin.coins import tx_utils
from pycoin.cmds.tx import DEFAULT_VERSION
from pycoin.encoding.hexbytes import h2b
from pycoin.symbols.btc import network
@@ -32,7 +31,7 @@ def multisig_M_of_N(self, M, N, unsigned_id, signed_id):
script = network.contract.for_multisig(m=M, sec_keys=[key.sec() for key in keys[:N]])
tx_out = TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
self.assertEqual(tx2.id(), unsigned_id)
self.assertEqual(tx2.bad_solution_count(), 1)
hash160_lookup = network.tx.solve.build_hash160_lookup((key.secret_exponent() for key in keys[:M]))
@@ -58,7 +57,7 @@ def test_multisig_one_at_a_time(self):
script = network.contract.for_multisig(m=M, sec_keys=[key.sec() for key in keys[:N]])
tx_out = TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
ids = ["403e5bfc59e097bb197bf77a692d158dd3a4f7affb4a1fa41072dafe7bec7058",
"5931d9995e83721243dca24772d7012afcd4378996a8b953c458175f15a544db",
"9bb4421088190bbbb5b42a9eaa9baed7ec7574a407c25f71992ba56ca43d9c44",
@@ -104,7 +103,7 @@ def test_sign_pay_to_script_multisig(self):
script = network.contract.for_address(address)
tx_out = TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address])
hash160_lookup = network.tx.solve.build_hash160_lookup((key.secret_exponent() for key in keys[:N]))
p2sh_lookup = network.tx.solve.build_p2sh_lookup([underlying_script])
tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup)
@@ -3,7 +3,6 @@
import unittest

from pycoin.coins.exceptions import BadSpendableError
from pycoin.coins.tx_utils import create_signed_tx
from pycoin.symbols.btc import network


@@ -40,7 +39,7 @@ def test_simple_spend(self):
]

for count in range(1, 11):
tx = create_signed_tx(spendables, BITCOIN_ADDRESSES[1:count+1], wifs=WIFS[:1])
tx = network.tx_utils.create_signed_tx(spendables, BITCOIN_ADDRESSES[1:count+1], wifs=WIFS[:1])
self.assertEqual(tx.bad_solution_count(), 0)
self.assertEqual(tx.fee(), FEE)
self.assertEqual(tx.id(), EXPECTED_IDS[count-1])
@@ -58,32 +57,32 @@ def test_confirm_input(self):
COIN_VALUE = 100000000
spendables = [Spendable(COIN_VALUE, network.contract.for_address(BITCOIN_ADDRESSES[0]), FAKE_HASH, 0)]

tx_1 = create_signed_tx(spendables, BITCOIN_ADDRESSES[1:2], wifs=WIFS[:1])
tx_1 = network.tx_utils.create_signed_tx(spendables, BITCOIN_ADDRESSES[1:2], wifs=WIFS[:1])

spendables = tx_1.tx_outs_as_spendable()

tx_db = dict((tx.hash(), tx) for tx in [tx_1])

tx_2 = create_signed_tx(spendables, BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2 = network.tx_utils.create_signed_tx(spendables, BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2.validate_unspents(tx_db)

tx_2 = create_signed_tx([s.as_dict() for s in spendables], BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2 = network.tx_utils.create_signed_tx([s.as_dict() for s in spendables], BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2.validate_unspents(tx_db)

tx_2 = create_signed_tx([s.as_text() for s in spendables], BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2 = network.tx_utils.create_signed_tx([s.as_text() for s in spendables], BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2.validate_unspents(tx_db)

def test_confirm_input_raises(self):
# create a fake Spendable
COIN_VALUE = 100000000
spendables = [Spendable(COIN_VALUE, network.contract.for_address(BITCOIN_ADDRESSES[0]), FAKE_HASH, 0)]

tx_1 = create_signed_tx(spendables, BITCOIN_ADDRESSES[1:2], wifs=WIFS[:1])
tx_1 = network.tx_utils.create_signed_tx(spendables, BITCOIN_ADDRESSES[1:2], wifs=WIFS[:1])
spendables = tx_1.tx_outs_as_spendable()
spendables[0].coin_value += 100

tx_db = dict((tx.hash(), tx) for tx in [tx_1])
tx_2 = create_signed_tx(spendables, BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])
tx_2 = network.tx_utils.create_signed_tx(spendables, BITCOIN_ADDRESSES[2:3], wifs=WIFS[:3])

self.assertRaises(BadSpendableError, tx_2.validate_unspents, tx_db)

@@ -218,8 +218,6 @@ def tx_from_b64(h):
self.assertEqual(tx_to_validate.bad_solution_count(), 0)

def _make_tx(self, input_script, other_scripts=[]):
from pycoin.coins.tx_utils import create_signed_tx

cv = int(50*1e8)

key = self._key
@@ -232,7 +230,7 @@ def _make_tx(self, input_script, other_scripts=[]):
coinbase_tx.txs_out[0].script = input_script
spendable = coinbase_tx.tx_outs_as_spendable()[0]
payables = [(address, cv)]
tx = create_signed_tx(spendables=[spendable], payables=payables, wifs=[wif], p2sh_lookup=p2sh_lookup)
tx = network.tx_utils.create_signed_tx(spendables=[spendable], payables=payables, wifs=[wif], p2sh_lookup=p2sh_lookup)
tx.unspents = [spendable]
print(tx.as_hex(include_unspents=True))
return tx
@@ -1,6 +1,5 @@
import unittest

from pycoin.coins import tx_utils
from pycoin.satoshi.flags import SIGHASH_ALL
from pycoin.symbols.btc import network

@@ -18,7 +17,7 @@ def multisig_M_of_N(self, M, N, unsigned_id, signed_id):
script = network.contract.for_multisig(m=M, sec_keys=[key.sec() for key in keys[:N]])
tx_out = Tx.TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
self.assertEqual(tx2.id(), unsigned_id)
self.assertEqual(tx2.bad_solution_count(), 1)
hash160_lookup = network.tx.solve.build_hash160_lookup((key.secret_exponent() for key in keys[:M]))
@@ -46,7 +45,7 @@ def test_multisig_one_at_a_time(self):
script = network.contract.for_multisig(m=M, sec_keys=[key.sec() for key in keys[:N]])
tx_out = Tx.TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
ids = ["403e5bfc59e097bb197bf77a692d158dd3a4f7affb4a1fa41072dafe7bec7058",
"5931d9995e83721243dca24772d7012afcd4378996a8b953c458175f15a544db",
"9bb4421088190bbbb5b42a9eaa9baed7ec7574a407c25f71992ba56ca43d9c44",
@@ -72,7 +71,7 @@ def test_sign_pay_to_script_multisig(self):
script = network.contract.for_address(address)
tx_out = Tx.TxOut(1000000, script)
tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address])
tx2 = network.tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address])
hash160_lookup = network.tx.solve.build_hash160_lookup((key.secret_exponent() for key in keys[:N]))
p2sh_lookup = network.tx.solve.build_p2sh_lookup([underlying_script])
tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup)

0 comments on commit 4fdd19e

Please sign in to comment.
You can’t perform that action at this time.