Exemple #1
0
    def broadcastTransaction(self, transaction):
        print(transaction)
        t = Tx.tx_from_hex(transaction)

        deserializer = serializers.TxSerializer()
        tx = deserializer.deserialize(BytesIO(bytearray.fromhex(transaction)))
        h = t.id()
        print('BROADCAST:', str(tx.calculate_hash())[2:-1], h)

        #try:
        #	t = Tx.tx_from_hex (transaction)
        #	print ('OMG',t.id ())
        #except Exception as e:
        #	print (e)

        if not h in self.db['mempool']:
            mp = self.db['mempool']
            mp[h] = tx
            self.db['mempool'] = mp
            self.db.sync()

        self.mempooltimer = Timer(1.0, self.announceTransactions)
        self.mempooltimer.start()

        return h
 def get_tx(self, tx_hash):
     url = "%s/rawtx/%s" % (self.base_url, b2h_rev(tx_hash))
     result = json.loads(urlopen(url).read().decode("utf8"))
     tx = Tx.tx_from_hex(result["rawtx"])
     if tx.hash() == tx_hash:
         return tx
     return None
Exemple #3
0
 def get_tx(self, tx_hash):
     URL = "%s/api/rawtx/%s" % (self.base_url, b2h_rev(tx_hash))
     r = json.loads(urlopen(URL).read().decode("utf8"))
     tx = Tx.tx_from_hex(r['rawtx'])
     if tx.hash() == tx_hash:
         return tx
     return None
Exemple #4
0
	def broadcastTransaction (self, transaction):
		print (transaction)
		t = Tx.tx_from_hex (transaction)

		deserializer = serializers.TxSerializer ()
		tx = deserializer.deserialize (BytesIO (bytearray.fromhex(transaction)))
		h = t.id ()
		print ('BROADCAST:', str (tx.calculate_hash ())[2:-1], h)

		#try:
		#	t = Tx.tx_from_hex (transaction)
		#	print ('OMG',t.id ())
		#except Exception as e:
		#	print (e)

		if not h in self.db['mempool']:
			mp = self.db['mempool']
			mp[h] = tx
			self.db['mempool'] = mp
			self.db.sync ()

		self.mempooltimer = Timer (1.0, self.announceTransactions)
		self.mempooltimer.start ()

		return h
def check_unprocessed(top_height):
    for tx_hash in unprocessed_txs.members():
        txid = hash_to_hex(tx_hash).decode()
        tx = Tx.tx_from_hex(txs[tx_hash].decode())
        tx_blockchain = get_tx(txid)
        logging.info('Checking %s' % txid)
        if tx_blockchain.block_height == -1:
            continue
        if top_height - tx_blockchain.block_height + 1 >= REQUIRED_CONFIRMATIONS:  # off by one error - if tx in top block that is 1 conf
            unprocessed_txs.remove(tx_hash)
            for out in tx.txs_out:
                address = out.bitcoin_address()
                if address not in all_addresses:
                    continue
                account = Account(addr_to_uid[address])
                satoshis = out.coin_value
                satoshis = int(satoshis / (1 + account.tip.get()))  # scale for tip
                account.total_coins.incr(satoshis)
                node_minutes_d = calc_node_minutes(satoshis, exchange_rate=exchange_rate.get())
                account.total_minutes.incr(node_minutes_d)
                total_nodeminutes.incr(node_minutes_d)
                nodes_recently_updated.append(account.uid)
                account.add_msg('Detected payment via txid: %s' % (txid,))
                account.add_msg('Increased total paid by %.8f to %.8f (considering tip of %d %%)' % (satoshis / COIN, account.total_coins.get() / COIN, account.tip.get() * 100))
                account.add_msg('Increased node life by %d minutes; expiring around %s' % (node_minutes_d, account.get_expiry().isoformat()))
Exemple #6
0
 def get_tx(self, tx_hash):
     URL = "%s/api/rawtx/%s" % (self.base_url, b2h_rev(tx_hash))
     r = json.loads(urlopen(URL).read().decode("utf8"))
     tx = Tx.tx_from_hex(r['rawtx'])
     if tx.hash() == tx_hash:
         return tx
     return None
def main():
    tx = Tx.tx_from_hex(sys.argv[1])
    print('Input Scripts:')
    for inp in tx.txs_in:
        print(' - ' + disassemble(inp.script))
    print('Output Scripts:')
    for out in tx.txs_out:
        print(' - ' + disassemble(out.script))
Exemple #8
0
    def sign_with_paths(self, tx, input_chain_paths, output_chain_paths, spend_id=None, verifications=None, callback=None):
        """
        Have the Oracle sign the transaction

        :param tx: the transaction to be signed
        :type tx: Tx
        :param input_chain_paths: the derivation path for each input, or None if the input does not need to be signed
        :type input_chain_paths: list[str or None]
        :param output_chain_paths: the derivation path for each change output, or None if the output is not change
        :type output_chain_paths: list[str or None]
        :param spend_id: an additional hex ID to disambiguate sends to the same outputs
        :type spend_id: str
        :param verifications: an optional dictionary with authorization code for each verification type.  Keys include "otp" and "code" (for SMS).
        :type verifications: dict of [str, str]
        :return: a dictionary with the transaction in 'transaction' if successful
        :rtype: dict
        """
        req = self._create_oracle_request(input_chain_paths, output_chain_paths, spend_id, tx, verifications, callback=callback)
        body = json.dumps(req)
        url = self._url() + "/transactions"
        if self.verbose > 0:
            print(body)
        self._request_logger.before('post', url, self._default_headers, body)
        response = requests.post(url, body, headers=self._default_headers)
        self._request_logger.after('post', url, response)
        if response.status_code >= 500:
            raise OracleInternalError(response.content)
        result = response.json()
        if response.status_code == 200 and result.get('result', None) == 'success':
            tx = None
            if 'transaction' in result:
                tx = Tx.tx_from_hex(result['transaction']['bytes'])
            return SignatureResult({
                'transaction': tx,
                'now': result['now'],
                'spend_id': result['spendId'],
                'deferral': result.get('deferral')
            })
        if result.get('result') == 'deferred':
            deferral = result['deferral']
            until = None
            if deferral and deferral['reason'] == 'delay':
                tzlocal = dateutil.tz.tzlocal()
                until = dateutil.parser.parse(deferral['until']).astimezone(tzlocal)
                #remain = int((until - datetime.datetime.now(tzlocal)).total_seconds())
            raise OracleDeferralException(deferral.get('verifications'), until, result['spendId'])
        elif result.get('result') == 'rejected':
            raise OracleRejectionException()
        elif result.get('result') == 'locked':
            raise OracleLockoutException()
        elif result.get('error') == 'Platform  velocity  hard-limit  exceeded':
            raise OraclePlatformVelocityHardLimitException('Platform  velocity  hard-limit  exceeded')
        elif response.status_code == 200 or response.status_code == 400:
            raise OracleError(response.content)
        else:
            raise IOError("Unknown response %d" % (response.status_code,))
Exemple #9
0
    def post(self):
        logging.info("transaction coming in")
        hextx = self.get_argument('hextx', None)
        subkeys = self.get_argument('subkeys', None)
        payoutaddress = self.get_argument('payoutaddress', None)
        fees = self.get_argument('fees', None)

        print subkeys

        if not hextx or not subkeys or not payoutaddress or not fees:
            logging.error("Did not receive trans or tree argument")
            return

        fees = tornado.escape.json_decode(fees)
        subkeys = tornado.escape.json_decode(subkeys)
        seed = mnemonic.Mnemonic.to_seed(PHRASE)
        wallet = BIP32Node.from_master_secret(seed)

        wifs = []
        keys = []
        for subkey in subkeys:
            key = wallet.subkey_for_path(subkey)
            keys.append(key)
            wifs.append(key.wif())

        underlying_script = ScriptMultisig(
            n=N, sec_keys=[key.sec() for key in keys[:M]]).script()
        address = address_for_pay_to_script(underlying_script)

        tx2 = Tx.tx_from_hex(hextx)

        # first tx out, need another for the 1% to our wallet
        script = standard_tx_out_script(payoutaddress)
        tx_out = TxOut(fees['seller'], script)
        # TODO: figure out final wallet. This is sending to my phone
        script = standard_tx_out_script("1LhkvTTxFXam672vjwbABtkp9td7dxCwyB")
        tx2_out = TxOut(fees['bestcrow'], script)

        txs_out = [tx_out, tx2_out]
        tx2.txs_out = txs_out

        hash160_lookup = build_hash160_lookup(key.secret_exponent()
                                              for key in keys)
        p2sh_lookup = build_p2sh_lookup([underlying_script])
        tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup)

        print tx2.as_hex()
        self.write(tx2.as_hex())
Exemple #10
0
	def broadcastTransaction (self, transaction):
		#print (transaction)
		t = Tx.tx_from_hex (transaction)
		h = t.id ()
		#print ('BROADCAST:', t.id ())

		if not h in self.db['mempool']:
			mp = self.db['mempool']
			mp[h] = t
			self.db['mempool'] = mp
			self.db.sync ()

		self.mempooltimer = Timer (1.0, self.announceTransactions)
		self.mempooltimer.start ()

		return h
Exemple #11
0
    def broadcastTransaction(self, transaction):
        #print (transaction)
        t = Tx.tx_from_hex(transaction)
        h = t.id()
        #print ('BROADCAST:', t.id ())

        if not h in self.db['mempool']:
            mp = self.db['mempool']
            mp[h] = t
            self.db['mempool'] = mp
            self.db.sync()

        self.mempooltimer = Timer(1.0, self.announceTransactions)
        self.mempooltimer.start()

        return h
Exemple #12
0
	def got_message(self, message):
		if self.last_sent + 30 * 60 < time.time():
			self.send_message(bitcoin.messages.msg_ping(self.ver_send))
		self.print_debug("Received: %s" % repr(message))
		if message.command == "version":
			self.send_message(bitcoin.messages.msg_verack(self.ver_send))
			self.ver_send = min(self.ver_send, message.protover)
		elif message.command == "verack":
			self.ver_recv = self.ver_send
		elif message.command == "inv":
			self.request_objects(message.inv)
		elif message.command == "tx":
			self.new_tx_callback(Tx.tx_from_hex(message.tx.serialize().encode('hex')))
		elif message.command == "block":
			self.new_block_callback(Block.parse(cStringIO.StringIO(message.block.serialize())))  # todo - use msg_block or block stream_serialize
		else:
			self.print_debug("received unknown message %s: %s" % (message.command, repr(message)))
def pycoin_sign_raw_transaction(tx_hex, private_key_wif):
    for char in private_key_wif:
        if char not in script.b58_digits:
            raise exceptions.TransactionError('invalid private key')

    if config.TESTNET:
        allowable_wif_prefixes = [config.PRIVATEKEY_VERSION_TESTNET]
    else:
        allowable_wif_prefixes = [config.PRIVATEKEY_VERSION_MAINNET]

    secret_exponent, compressed = wif_to_tuple_of_secret_exponent_compressed(
                    private_key_wif, allowable_wif_prefixes=allowable_wif_prefixes)
    public_pair = public_pair_for_secret_exponent(generator_secp256k1, secret_exponent)
    hash160 = public_pair_to_hash160_sec(public_pair, compressed)
    hash160_lookup = {hash160: (secret_exponent, public_pair, compressed)}

    tx = Tx.tx_from_hex(tx_hex)
    for idx, tx_in in enumerate(tx.txs_in):
        tx.sign_tx_in(hash160_lookup, idx, tx_in.script, hash_type=SIGHASH_ALL)

    return tx.as_hex()
Exemple #14
0
def pycoin_sign_raw_transaction(tx_hex, private_key_wif):
    for char in private_key_wif:
        if char not in script.b58_digits:
            raise exceptions.TransactionError('invalid private key')

    if config.TESTNET:
        allowable_wif_prefixes = [config.PRIVATEKEY_VERSION_TESTNET]
    else:
        allowable_wif_prefixes = [config.PRIVATEKEY_VERSION_MAINNET]

    secret_exponent, compressed = wif_to_tuple_of_secret_exponent_compressed(
                    private_key_wif, allowable_wif_prefixes=allowable_wif_prefixes)
    public_pair = public_pair_for_secret_exponent(generator_secp256k1, secret_exponent)
    hash160 = public_pair_to_hash160_sec(public_pair, compressed)
    hash160_lookup = {hash160: (secret_exponent, public_pair, compressed)}

    tx = Tx.tx_from_hex(tx_hex)
    for idx, tx_in in enumerate(tx.txs_in):
        tx.sign_tx_in(hash160_lookup, idx, tx_in.script, hash_type=SIGHASH_ALL)

    return tx.as_hex()
import mnemonic

from pycoin.key.BIP32Node import BIP32Node

from pycoin.tx.tx_utils import *
from pycoin.tx import Tx

# variables we'll receive from POST request
tree = [u'0/0/122', u'0/0/123', u'0/0/124']
hex_tx = "010000000116a487e650ea0a55fa7a833b41ef63837da98efa717bbccd1c665c0d1e18f7a70100000000ffffffff01905f0100000000001976a9143f0bd6a98028466602aa347950811e714f7ee76988ac00000000"

# generate wif's
phrase = "sample core fitness wrong unusual inch hurry chaos myself credit welcome margin"
seed = mnemonic.Mnemonic.to_seed(phrase)
# XTN == testnet
wallet = BIP32Node.from_master_secret(seed, 'XTN')

wif = []
for subkey in tree:
    key = wallet.subkey_for_path(subkey)
    wif.append(key.wif())

# sign tx
tx2 = Tx.tx_from_hex(hex_tx)
signed = sign_tx(tx2, wif)
print signed
    def sign_with_paths(self,
                        tx,
                        input_chain_paths,
                        output_chain_paths,
                        spend_id=None,
                        verifications=None,
                        callback=None):
        """
        Have the Oracle sign the transaction

        :param tx: the transaction to be signed
        :type tx: Tx
        :param input_chain_paths: the derivation path for each input, or None if the input does not need to be signed
        :type input_chain_paths: list[str or None]
        :param output_chain_paths: the derivation path for each change output, or None if the output is not change
        :type output_chain_paths: list[str or None]
        :param spend_id: an additional hex ID to disambiguate sends to the same outputs
        :type spend_id: str
        :param verifications: an optional dictionary with authorization code for each verification type.  Keys include "otp" and "code" (for SMS).
        :type verifications: dict of [str, str]
        :return: a dictionary with the transaction in 'transaction' if successful
        :rtype: dict
        """
        req = self._create_oracle_request(input_chain_paths,
                                          output_chain_paths,
                                          spend_id,
                                          tx,
                                          verifications,
                                          callback=callback)
        body = json.dumps(req)
        url = self._url() + "/transactions"
        if self.verbose > 0:
            print(body)
        self._request_logger.before('post', url, self._default_headers, body)
        response = requests.post(url, body, headers=self._default_headers)
        self._request_logger.after('post', url, response,
                                   self._default_headers, body)
        if response.status_code >= 500:
            raise OracleInternalError(response.content)
        result = response.json()
        if response.status_code == 200 and result.get('result',
                                                      None) == 'success':
            tx = None
            if 'transaction' in result:
                tx = Tx.tx_from_hex(result['transaction']['bytes'])
            return SignatureResult({
                'transaction': tx,
                'now': result['now'],
                'spend_id': result['spendId'],
                'deferral': result.get('deferral')
            })
        if result.get('result') == 'deferred':
            deferral = result['deferral']
            until = None
            if deferral and deferral['reason'] == 'delay':
                tzlocal = dateutil.tz.tzlocal()
                until = dateutil.parser.parse(
                    deferral['until']).astimezone(tzlocal)
                #remain = int((until - datetime.datetime.now(tzlocal)).total_seconds())
            raise OracleDeferralException(deferral.get('verifications'), until,
                                          result['spendId'])
        elif result.get('result') == 'rejected':
            raise OracleRejectionException()
        elif result.get('result') == 'locked':
            raise OracleLockoutException()
        elif result.get('error') == 'Platform  velocity  hard-limit  exceeded':
            raise OraclePlatformVelocityHardLimitException(
                'Platform  velocity  hard-limit  exceeded')
        elif response.status_code == 200 or response.status_code == 400:
            raise OracleError(response.content)
        else:
            raise IOError("Unknown response %d" % (response.status_code, ))
Exemple #17
0
for s in spendables:
    print s
    txs_in.append(s.tx_in())

# make tx_out on web server
script = standard_tx_out_script(address)
tx_out = TxOut(100000, script)
txs_out = [tx_out]

tx1 = Tx(version=1, txs_in=txs_in, txs_out=txs_out)
tx1.set_unspents(txs_out)

txhex = tx1.as_hex(include_unspents=True)

# send txhex to private key server
tx2 = Tx.tx_from_hex(txhex)
script = standard_tx_out_script("1F8P3QEErMhm3fw6o23brRNQVaSMrG1maE")
tx_out = TxOut(50000, script)
script = standard_tx_out_script("1Dv9YWfVYMK1FjBhrCBc1diajSZKBj78MB")
tx2_out = TxOut(50000, script)

txs_out = [tx_out, tx2_out]
tx2.txs_out = txs_out

hash160_lookup = build_hash160_lookup(key.secret_exponent()
                                      for key in keys[:M])
p2sh_lookup = build_p2sh_lookup([underlying_script])

tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup)
print tx2.as_hex()
logging.basicConfig(level=logging.INFO)

if __name__ == '__main__':
    while True:
        latest_block = get_latest_block()
        best_block_hash = latest_block.hash
        top_height = latest_block.height
        if best_block_hash == last_block_checked.get():
            time.sleep(10)  # only do this at most once per block
            continue
        logging.info('Latest block: %s' % best_block_hash)

        for tx_hash in unprocessed_txs.members():
            txid = hash_to_hex(tx_hash).decode()
            tx = Tx.tx_from_hex(txs[tx_hash].decode())
            tx_blockchain = get_tx(txid)
            logging.info('Checking %s' % txid)
            if tx_blockchain.block_height == -1:
                continue
            if top_height - tx_blockchain.block_height + 1 >= REQUIRED_CONFIRMATIONS:  # off by one error - if tx in top block that is 1 conf
                unprocessed_txs.remove(tx_hash)
                for out in tx.txs_out:
                    address = out.bitcoin_address()
                    if address not in all_addresses:
                        continue
                    account = Account(addr_to_uid[address])
                    satoshis = out.coin_value
                    satoshis = int(satoshis / (1 + account.tip.get()))  # scale for tip
                    account.total_coins.incr(satoshis)
                    node_minutes_d = calc_node_minutes(satoshis, exchange_rate=exchange_rate.get())
Exemple #19
0
def main():
    parser = argparse.ArgumentParser(
        description="Manipulate bitcoin (or alt coin) transactions.",
        epilog=EPILOG)

    parser.add_argument('-t', "--transaction-version", type=int,
                        help='Transaction version, either 1 (default) or 3 (not yet supported).')

    parser.add_argument('-l', "--lock-time", type=parse_locktime, help='Lock time; either a block'
                        'index, or a date/time (example: "2014-01-01T15:00:00"')

    parser.add_argument('-n', "--network", default="BTC",
                        help='Define network code (M=Bitcoin mainnet, T=Bitcoin testnet).')

    parser.add_argument('-a', "--augment", action='store_true',
                        help='augment tx by adding any missing spendable metadata by fetching'
                             ' inputs from cache and/or web services')

    parser.add_argument("-i", "--fetch-spendables", metavar="address", action="append",
                        help='Add all unspent spendables for the given bitcoin address. This information'
                        ' is fetched from web services.')

    parser.add_argument('-f', "--private-key-file", metavar="path-to-private-keys", action="append",
                        help='file containing WIF or BIP0032 private keys. If file name ends with .gpg, '
                        '"gpg -d" will be invoked automatically. File is read one line at a time, and if '
                        'the file contains only one WIF per line, it will also be scanned for a bitcoin '
                        'address, and any addresses found will be assumed to be public keys for the given'
                        ' private key.',
                        type=argparse.FileType('r'))

    parser.add_argument('-g', "--gpg-argument", help='argument to pass to gpg (besides -d).', default='')

    parser.add_argument("--remove-tx-in", metavar="tx_in_index_to_delete", action="append", type=int,
                        help='remove a tx_in')

    parser.add_argument("--remove-tx-out", metavar="tx_out_index_to_delete", action="append", type=int,
                        help='remove a tx_out')

    parser.add_argument('-F', "--fee", help='fee, in satoshis, to pay on transaction, or '
                        '"standard" to auto-calculate. This is only useful if the "split pool" '
                        'is used; otherwise, the fee is automatically set to the unclaimed funds.',
                        default="standard", metavar="transaction-fee", type=parse_fee)

    parser.add_argument('-C', "--cache", help='force the resultant transaction into the transaction cache.'
                        ' Mostly for testing.', action='store_true'),

    parser.add_argument('-u', "--show-unspents", action='store_true',
                        help='show TxOut items for this transaction in Spendable form.')

    parser.add_argument('-b', "--bitcoind-url",
                        help='URL to bitcoind instance to validate against (http://user:pass@host:port).')

    parser.add_argument('-o', "--output-file", metavar="path-to-output-file", type=argparse.FileType('wb'),
                        help='file to write transaction to. This supresses most other output.')

    parser.add_argument("argument", nargs="+", help='generic argument: can be a hex transaction id '
                        '(exactly 64 characters) to be fetched from cache or a web service;'
                        ' a transaction as a hex string; a path name to a transaction to be loaded;'
                        ' a spendable 4-tuple of the form tx_id/tx_out_idx/script_hex/satoshi_count '
                        'to be added to TxIn list; an address/satoshi_count to be added to the TxOut '
                        'list; an address to be added to the TxOut list and placed in the "split'
                        ' pool".')

    args = parser.parse_args()

    # defaults

    txs = []
    spendables = []
    payables = []

    key_iters = []

    TX_ID_RE = re.compile(r"^[0-9a-fA-F]{64}$")

    # there are a few warnings we might optionally print out, but only if
    # they are relevant. We don't want to print them out multiple times, so we
    # collect them here and print them at the end if they ever kick in.

    warning_tx_cache = None
    warning_get_tx = None
    warning_spendables = None

    if args.private_key_file:
        wif_re = re.compile(r"[1-9a-km-zA-LMNP-Z]{51,111}")
        # address_re = re.compile(r"[1-9a-kmnp-zA-KMNP-Z]{27-31}")
        for f in args.private_key_file:
            if f.name.endswith(".gpg"):
                gpg_args = ["gpg", "-d"]
                if args.gpg_argument:
                    gpg_args.extend(args.gpg_argument.split())
                gpg_args.append(f.name)
                popen = subprocess.Popen(gpg_args, stdout=subprocess.PIPE)
                f = popen.stdout
            for line in f.readlines():
                # decode
                if isinstance(line, bytes):
                    line = line.decode("utf8")
                # look for WIFs
                possible_keys = wif_re.findall(line)

                def make_key(x):
                    try:
                        return Key.from_text(x)
                    except Exception:
                        return None

                keys = [make_key(x) for x in possible_keys]
                for key in keys:
                    if key:
                        key_iters.append((k.wif() for k in key.subkeys("")))

                # if len(keys) == 1 and key.hierarchical_wallet() is None:
                #    # we have exactly 1 WIF. Let's look for an address
                #   potential_addresses = address_re.findall(line)

    # we create the tx_db lazily
    tx_db = None

    for arg in args.argument:

        # hex transaction id
        if TX_ID_RE.match(arg):
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_get_tx = message_about_get_tx_env()
                tx_db = get_tx_db()
            tx = tx_db.get(h2b_rev(arg))
            if not tx:
                for m in [warning_tx_cache, warning_get_tx, warning_spendables]:
                    if m:
                        print("warning: %s" % m, file=sys.stderr)
                parser.error("can't find Tx with id %s" % arg)
            txs.append(tx)
            continue

        # hex transaction data
        try:
            tx = Tx.tx_from_hex(arg)
            txs.append(tx)
            continue
        except Exception:
            pass

        try:
            key = Key.from_text(arg)
            # TODO: check network
            if key.wif() is None:
                payables.append((key.address(), 0))
                continue
            # TODO: support paths to subkeys
            key_iters.append((k.wif() for k in key.subkeys("")))
            continue
        except Exception:
            pass

        if os.path.exists(arg):
            try:
                with open(arg, "rb") as f:
                    if f.name.endswith("hex"):
                        f = io.BytesIO(codecs.getreader("hex_codec")(f).read())
                    tx = Tx.parse(f)
                    txs.append(tx)
                    try:
                        tx.parse_unspents(f)
                    except Exception as ex:
                        pass
                    continue
            except Exception:
                pass

        parts = arg.split("/")
        if len(parts) == 4:
            # spendable
            try:
                spendables.append(Spendable.from_text(arg))
                continue
            except Exception:
                pass

        # TODO: fix allowable_prefixes
        allowable_prefixes = b'\0'
        if len(parts) == 2 and encoding.is_valid_bitcoin_address(
                parts[0], allowable_prefixes=allowable_prefixes):
            try:
                payables.append(parts)
                continue
            except ValueError:
                pass

        parser.error("can't parse %s" % arg)

    if args.fetch_spendables:
        warning_spendables = message_about_spendables_for_address_env()
        for address in args.fetch_spendables:
            spendables.extend(spendables_for_address(address))

    for tx in txs:
        if tx.missing_unspents() and args.augment:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_get_tx = message_about_get_tx_env()
                tx_db = get_tx_db()
            tx.unspents_from_db(tx_db, ignore_missing=True)

    txs_in = []
    txs_out = []
    unspents = []
    # we use a clever trick here to keep each tx_in corresponding with its tx_out
    for tx in txs:
        smaller = min(len(tx.txs_in), len(tx.txs_out))
        txs_in.extend(tx.txs_in[:smaller])
        txs_out.extend(tx.txs_out[:smaller])
        unspents.extend(tx.unspents[:smaller])
    for tx in txs:
        smaller = min(len(tx.txs_in), len(tx.txs_out))
        txs_in.extend(tx.txs_in[smaller:])
        txs_out.extend(tx.txs_out[smaller:])
        unspents.extend(tx.unspents[smaller:])
    for spendable in spendables:
        txs_in.append(spendable.tx_in())
        unspents.append(spendable)
    for address, coin_value in payables:
        script = standard_tx_out_script(address)
        txs_out.append(TxOut(coin_value, script))

    lock_time = args.lock_time
    version = args.transaction_version

    # if no lock_time is explicitly set, inherit from the first tx or use default
    if lock_time is None:
        if txs:
            lock_time = txs[0].lock_time
        else:
            lock_time = DEFAULT_LOCK_TIME

    # if no version is explicitly set, inherit from the first tx or use default
    if version is None:
        if txs:
            version = txs[0].version
        else:
            version = DEFAULT_VERSION

    if args.remove_tx_in:
        s = set(args.remove_tx_in)
        txs_in = [tx_in for idx, tx_in in enumerate(txs_in) if idx not in s]

    if args.remove_tx_out:
        s = set(args.remove_tx_out)
        txs_out = [tx_out for idx, tx_out in enumerate(txs_out) if idx not in s]

    tx = Tx(txs_in=txs_in, txs_out=txs_out, lock_time=lock_time, version=version, unspents=unspents)

    fee = args.fee
    try:
        distribute_from_split_pool(tx, fee)
    except ValueError as ex:
        print("warning: %s" % ex.args[0], file=sys.stderr)

    unsigned_before = tx.bad_signature_count()
    if unsigned_before > 0 and key_iters:
        def wif_iter(iters):
            while len(iters) > 0:
                for idx, iter in enumerate(iters):
                    try:
                        wif = next(iter)
                        yield wif
                    except StopIteration:
                        iters = iters[:idx] + iters[idx+1:]
                        break

        print("signing...", file=sys.stderr)
        sign_tx(tx, wif_iter(key_iters))

    unsigned_after = tx.bad_signature_count()
    if unsigned_after > 0 and key_iters:
        print("warning: %d TxIn items still unsigned" % unsigned_after, file=sys.stderr)

    if len(tx.txs_in) == 0:
        print("warning: transaction has no inputs", file=sys.stderr)

    if len(tx.txs_out) == 0:
        print("warning: transaction has no outputs", file=sys.stderr)

    include_unspents = (unsigned_after > 0)
    tx_as_hex = tx.as_hex(include_unspents=include_unspents)

    if args.output_file:
        f = args.output_file
        if f.name.endswith(".hex"):
            f.write(tx_as_hex.encode("utf8"))
        else:
            tx.stream(f)
            if include_unspents:
                tx.stream_unspents(f)
        f.close()
    elif args.show_unspents:
        for spendable in tx.tx_outs_as_spendable():
            print(spendable.as_text())
    else:
        if not tx.missing_unspents():
            check_fees(tx)
        dump_tx(tx, args.network)
        if include_unspents:
            print("including unspents in hex dump since transaction not fully signed")
        print(tx_as_hex)

    if args.cache:
        if tx_db is None:
            warning_tx_cache = message_about_tx_cache_env()
            warning_get_tx = message_about_get_tx_env()
            tx_db = get_tx_db()
        tx_db.put(tx)

    if args.bitcoind_url:
        if tx_db is None:
            warning_tx_cache = message_about_tx_cache_env()
            warning_get_tx = message_about_get_tx_env()
            tx_db = get_tx_db()
        validate_bitcoind(tx, tx_db, args.bitcoind_url)

    if tx.missing_unspents():
        print("\n** can't validate transaction as source transactions missing", file=sys.stderr)
    else:
        try:
            if tx_db is None:
                warning_tx_cache = message_about_tx_cache_env()
                warning_get_tx = message_about_get_tx_env()
                tx_db = get_tx_db()
            tx.validate_unspents(tx_db)
            print('all incoming transaction values validated')
        except BadSpendableError as ex:
            print("\n**** ERROR: FEES INCORRECTLY STATED: %s" % ex.args[0], file=sys.stderr)
        except Exception as ex:
            print("\n*** can't validate source transactions as untampered: %s" %
                  ex.args[0], file=sys.stderr)

    # print warnings
    for m in [warning_tx_cache, warning_get_tx, warning_spendables]:
        if m:
            print("warning: %s" % m, file=sys.stderr)
Exemple #20
0
#!/usr/bin/env python3

import argparse
import sys
from pycoin.tx import Tx

from models import txs, known_txs, unprocessed_txs, addr_to_uid, Account, known_blocks, all_addresses
from wallet import process_tx_initial

parser = argparse.ArgumentParser()
parser.add_argument('--tx-hex')
parser.add_argument('--txid')
args = parser.parse_args()

if args.txid in known_txs:
    sys.exit()

tx = Tx.tx_from_hex(args.tx_hex)
process_tx_initial(tx)