Exemplo n.º 1
0
    def run(self):
        self.logger.info("starting to mine")

        pool_target = utils.bits_to_target(self.notify_msg.bits_pool)
        for enonce2_num in range(0, 2 ** (self.enonce2_size * 8)):
            enonce2 = enonce2_num.to_bytes(self.enonce2_size, byteorder="big")

            cb_txn, _ = Transaction.from_bytes(
                self.notify_msg.coinb1 + self.enonce1 + enonce2 + self.notify_msg.coinb2)
            cb = CompactBlock(self.notify_msg.height,
                              self.notify_msg.version,
                              Hash(self.notify_msg.prev_block_hash),
                              self.notify_msg.ntime,
                              self.notify_msg.nbits,  # lower difficulty work for testing
                              self.notify_msg.merkle_edge,
                              cb_txn)
            for nonce in range(0xffffffff):
                cb.block_header.nonce = nonce
                h = cb.block_header.hash.to_int('little')
                if h < pool_target:
                    self.logger.info("Found Share")
                    share = Share(
                        enonce2=enonce2,
                        nonce=nonce,
                        work_id=self.notify_msg.work_id,
                        otime=self.notify_msg.ntime)
                    self.event_loop.call_soon_threadsafe(
                        asyncio.async,
                        self.handle_found_cb(share)
                    )
                    time.sleep(0.3)
Exemplo n.º 2
0
    def run(self):
        self.logger.info("starting to mine")

        pool_target = utils.bits_to_target(self.notify_msg.bits_pool)
        for enonce2_num in range(0, 2**(self.enonce2_size * 8)):
            enonce2 = enonce2_num.to_bytes(self.enonce2_size, byteorder="big")

            cb_txn, _ = Transaction.from_bytes(self.notify_msg.coinb1 +
                                               self.enonce1 + enonce2 +
                                               self.notify_msg.coinb2)
            cb = CompactBlock(
                self.notify_msg.height,
                self.notify_msg.version,
                Hash(self.notify_msg.prev_block_hash),
                self.notify_msg.ntime,
                self.notify_msg.nbits,  # lower difficulty work for testing
                self.notify_msg.merkle_edge,
                cb_txn)
            for nonce in range(0xffffffff):
                cb.block_header.nonce = nonce
                h = cb.block_header.hash.to_int('little')
                if h < pool_target:
                    self.logger.info("Found Share")
                    share = Share(enonce2=enonce2,
                                  nonce=nonce,
                                  work_id=self.notify_msg.work_id,
                                  otime=self.notify_msg.ntime)
                    self.event_loop.call_soon_threadsafe(
                        asyncio. async, self.handle_found_cb(share))
                    time.sleep(0.3)
Exemplo n.º 3
0
    def set_txn_side_effect_for_hd_discovery(self):
        # For each used account, there are at least 2 calls required:
        # 1 for the first DISCOVERY_INCREMENT payout addresses and 1
        # for the first DISCOVERY_INCREMENT change
        # addresses. Depending on the number of used addresses for the
        # account, this will change.

        effects = []

        n = self._num_used_accounts
        if n == 0:
            n = 1

        for acct_num in range(n):
            for change in [0, 1]:
                num_used = self._num_used_addresses[acct_num][change]
                r = math.ceil(
                    (num_used + HDAccount.GAP_LIMIT) / self.address_increment)
                k = 'change_addresses' if change else 'payout_addresses'
                addr_list = self._acct_keys[acct_num][k]

                if change:
                    metadata = dict(
                        block=234790 + r,
                        block_hash=Hash(
                            "000000000000000007d57f03ebe36dbe4f87ab2f340e93b45999ab249b6dc0df"
                        ),
                        confirmations=23890 - r)
                else:
                    metadata = dict(block=None,
                                    block_hash=None,
                                    confirmations=0)

                if r == 0:
                    r = 1
                for i in range(r):
                    start = i * self.address_increment
                    end = (i + 1) * self.address_increment
                    addr_range = range(start, end)

                    out = TransactionOutput(value=10000,
                                            script=Script.build_p2pkh(
                                                address_to_key_hash(
                                                    addr_list[i])[1]))
                    dummy_txn = Transaction(1, [], [out], 0)

                    m = MockTxnDict(num_used=num_used,
                                    addr_range=addr_range,
                                    addr_list=addr_list,
                                    used_value=[
                                        dict(metadata=metadata,
                                             transaction=dummy_txn)
                                    ],
                                    unused_value=[])
                    effects.append(m)

        self.get_transactions.side_effect = effects

        return len(effects)
Exemplo n.º 4
0
    def from_bytes(b):
        """ Deserializes a byte stream into a WalletTransaction.

        Args:
            b (bytes): byte stream starting with the version.

        Returns:
            tuple: First element of the tuple is the WalletTransaction,
                   second is the remainder of the byte stream.
        """
        t, b1 = Transaction.from_bytes()
        return WalletTransaction.from_transaction(t), b1
Exemplo n.º 5
0
    def from_bytes(b):
        """ Deserializes a byte stream into a WalletTransaction.

        Args:
            b (bytes): byte stream starting with the version.

        Returns:
            tuple: First element of the tuple is the WalletTransaction,
                   second is the remainder of the byte stream.
        """
        t, b1 = Transaction.from_bytes()
        return WalletTransaction.from_transaction(t), b1
Exemplo n.º 6
0
def mine_work(work_msg, enonce1, enonce2_size):
    """ Mines the work using a CPU to find a valid solution

        Loops until the CPU finds a valid solution of the given work.

    Todo:
        slow down the click echo when on a 21BC

    Args:
        work_msg (WorkNotification): the work given by the pool API
        enonce1 (bytes): extra nonce required to make the coinbase transaction
        enonce2_size (int): size of the extra nonce 2 in bytes

    """
    pool_target = utils.bits_to_target(work_msg.bits_pool)
    for enonce2_num in range(0, 2 ** (enonce2_size * 8)):
        enonce2 = enonce2_num.to_bytes(enonce2_size, byteorder="big")

        cb_txn, _ = Transaction.from_bytes(
            work_msg.coinb1 + enonce1 + enonce2 + work_msg.coinb2)
        cb = CompactBlock(work_msg.height,
                          work_msg.version,
                          Hash(work_msg.prev_block_hash),
                          work_msg.ntime,
                          work_msg.nbits,  # lower difficulty work for testing
                          work_msg.merkle_edge,
                          cb_txn)

        row_counter = 0
        for nonce in range(0xffffffff):

            if nonce % 6e3 == 0:
                click.echo(click.style(u'█', fg='green'), nl=False)
                row_counter += 1
            if row_counter > 40:
                row_counter = 0
                click.echo("")

            cb.block_header.nonce = nonce
            h = cb.block_header.hash.to_int('little')
            if h < pool_target:
                share = Share(
                    enonce2=enonce2,
                    nonce=nonce,
                    work_id=work_msg.work_id,
                    otime=int(time.time()))
                # adds a new line at the end of progress bar
                click.echo("")
                return share

        click.echo("Exhausted enonce1 space. Changing enonce2")
Exemplo n.º 7
0
    def set_txn_side_effect_for_index(self, account_index, address_index,
                                      change):
        dummy_txn = Transaction(1, [], [], 0)
        metadata = dict(block_height=234790,
                        block_hash=Hash("000000000000000007d57f03ebe36dbe4f87ab2f340e93b45999ab249b6dc0df"),
                        confirmations=23890)

        k = 'change_addresses' if change else 'payout_addresses'
        addr_list = self._acct_keys[account_index][k]
        mtd = MockTxnDict(num_used=address_index + 1,
                          addr_range=range(address_index, address_index + 1),
                          addr_list=addr_list,
                          used_value=[dict(metadata=metadata,
                                           transaction=dummy_txn)],
                          unused_value=[])
        self.get_transactions.side_effect = [mtd]
Exemplo n.º 8
0
    def from_bytes(b):
        """ Creates a Block from a serialized byte stream.

        Args:
            b (bytes): The byte stream, starting with the block version.
        
        Returns:
            block, b (tuple): A tuple. The first item is the deserialized block
            and the second is the remainder of the byte stream.
        """
        bh, b = BlockHeader.from_bytes(b)
        num_txns, b = unpack_compact_int(b)
        txns = []
        for i in range(num_txns):
            t, b = Transaction.from_bytes(b)
            txns.append(t)

        return Block.from_blockheader(bh, txns), b
Exemplo n.º 9
0
    def from_bytes(b):
        """ Creates a Block from a serialized byte stream.

        Args:
            b (bytes): The byte stream, starting with the block version.
        
        Returns:
            block, b (tuple): A tuple. The first item is the deserialized block
            and the second is the remainder of the byte stream.
        """
        bh, b = BlockHeader.from_bytes(b)
        num_txns, b = unpack_compact_int(b)
        txns = []
        for i in range(num_txns):
            t, b = Transaction.from_bytes(b)
            txns.append(t)

        return Block.from_blockheader(bh, txns), b
Exemplo n.º 10
0
    def redeem_payment(self, price, request_headers, **kwargs):
        """Validate the transaction and broadcast it to the blockchain."""
        raw_tx = request_headers[OnChain.http_payment_data]
        logger.debug('[BitServ] Receieved transaction: {}'.format(raw_tx))

        # verify txn is above dust limit
        if price < OnChain.DUST_LIMIT:
            raise PaymentBelowDustLimitError(
                'Payment amount is below dust limit ({} Satoshi)'.format(
                    OnChain.DUST_LIMIT))

        try:
            payment_tx = Transaction.from_hex(raw_tx)
        except:
            raise InvalidPaymentParameterError('Invalid transaction hex.')

        # Find the output with the merchant's address
        payment_index = payment_tx.output_index_for_address(
            kwargs.get('address', self.address))
        if payment_index is None:
            raise InvalidPaymentParameterError('Not paid to merchant.')

        # Verify that the payment is made for the correct amount
        if payment_tx.outputs[payment_index].value != price:
            raise InsufficientPaymentError('Incorrect payment amount.')

        # Synchronize the next block of code to manage its atomicity
        with self.lock:
            # Verify that we haven't seen this transaction before
            if self.db.lookup(str(payment_tx.hash)):
                raise DuplicatePaymentError('Payment already used.')
            else:
                self.db.create(str(payment_tx.hash), price)

            try:
                # Broadcast payment to network
                txid = self.provider.broadcast_transaction(raw_tx)
                logger.debug('[BitServ] Broadcasted: ' + txid)
            except Exception as e:
                # Roll back the database entry if the broadcast fails
                self.db.delete(str(payment_tx.hash))
                raise TransactionBroadcastError(str(e))

        return True
Exemplo n.º 11
0
    def redeem_payment(self, price, request_headers, **kwargs):
        """Validate the transaction and broadcast it to the blockchain."""
        raw_tx = request_headers[OnChain.http_payment_data]
        logger.debug("[BitServ] Receieved transaction: {}".format(raw_tx))

        # verify txn is above dust limit
        if price < OnChain.DUST_LIMIT:
            raise PaymentBelowDustLimitError(
                "Payment amount is below dust limit ({} Satoshi)".format(OnChain.DUST_LIMIT)
            )

        try:
            payment_tx = Transaction.from_hex(raw_tx)
        except:
            raise InvalidPaymentParameterError("Invalid transaction hex.")

        # Find the output with the merchant's address
        payment_index = payment_tx.output_index_for_address(kwargs.get("address", self.address))
        if payment_index is None:
            raise InvalidPaymentParameterError("Not paid to merchant.")

        # Verify that the payment is made for the correct amount
        if payment_tx.outputs[payment_index].value != price:
            raise InsufficientPaymentError("Incorrect payment amount.")

        # Synchronize the next block of code to manage its atomicity
        with self.lock:
            # Verify that we haven't seen this transaction before
            if self.db.lookup(str(payment_tx.hash)):
                raise DuplicatePaymentError("Payment already used.")
            else:
                self.db.create(str(payment_tx.hash), price)

            try:
                # Broadcast payment to network
                txid = self.provider.broadcast_transaction(raw_tx)
                logger.debug("[BitServ] Broadcasted: " + txid)
            except Exception as e:
                # Roll back the database entry if the broadcast fails
                self.db.delete(str(payment_tx.hash))
                raise TransactionBroadcastError(str(e))

        return True
Exemplo n.º 12
0
def mine_work(work_msg, enonce1, enonce2_size):
    pool_target = utils.bits_to_target(work_msg.bits_pool)
    for enonce2_num in range(0, 2**(enonce2_size * 8)):
        enonce2 = enonce2_num.to_bytes(enonce2_size, byteorder="big")

        cb_txn, _ = Transaction.from_bytes(work_msg.coinb1 + enonce1 +
                                           enonce2 + work_msg.coinb2)
        cb = CompactBlock(
            work_msg.height,
            work_msg.version,
            Hash(work_msg.prev_block_hash),
            work_msg.ntime,
            work_msg.nbits,  # lower difficulty work for testing
            work_msg.merkle_edge,
            cb_txn)

        row_counter = 0
        for nonce in range(0xffffffff):

            if nonce % 6e3 == 0:
                click.echo(click.style(u'█', fg='green'), nl=False)
                row_counter += 1
            if row_counter > 40:
                row_counter = 0
                click.echo("")

            cb.block_header.nonce = nonce
            h = cb.block_header.hash.to_int('little')
            if h < pool_target:
                share = Share(enonce2=enonce2,
                              nonce=nonce,
                              work_id=work_msg.work_id,
                              otime=int(time.time()))
                # adds a new line at the end of progress bar
                click.echo("")
                return share

        click.echo("Exhausted enonce1 space. Changing enonce2")
Exemplo n.º 13
0
Arquivo: mine.py Projeto: iweave/two1
def mine_work(work_msg, enonce1, enonce2_size):
    pool_target = utils.bits_to_target(work_msg.bits_pool)
    for enonce2_num in range(0, 2 ** (enonce2_size * 8)):
        enonce2 = enonce2_num.to_bytes(enonce2_size, byteorder="big")

        cb_txn, _ = Transaction.from_bytes(
            work_msg.coinb1 + enonce1 + enonce2 + work_msg.coinb2)
        cb = CompactBlock(work_msg.height,
                          work_msg.version,
                          Hash(work_msg.prev_block_hash),
                          work_msg.ntime,
                          work_msg.nbits,  # lower difficulty work for testing
                          work_msg.merkle_edge,
                          cb_txn)

        row_counter = 0
        for nonce in range(0xffffffff):

            if nonce % 6e3 == 0:
                click.echo(click.style(u'█', fg='green'), nl=False)
                row_counter += 1
            if row_counter > 40:
                row_counter = 0
                click.echo("")

            cb.block_header.nonce = nonce
            h = cb.block_header.hash.to_int('little')
            if h < pool_target:
                share = Share(
                    enonce2=enonce2,
                    nonce=nonce,
                    work_id=work_msg.work_id,
                    otime=int(time.time()))
                # adds a new line at the end of progress bar
                click.echo("")
                return share

        click.echo("Exhausted enonce1 space. Changing enonce2")
Exemplo n.º 14
0
from two1.lib.bitcoin.txn import Transaction
from two1.lib.wallet import Wallet
from two1.lib.bitcoin.script import Script
from two1.lib.blockchain.twentyone_provider import TwentyOneProvider
import two1.lib.bitcoin as bitcoin

provider = TwentyOneProvider()
wallet = Wallet()

pubkey = input("Please enter the public key that was used to create the script")
tx_hex = input("Please enter the transaction hex")
server_pubkey = input("Please enter server pub key")
white_pubkey = input("Please enter white pub key")
black_pubkey = input("Please enter black pub key")


their_pubkey = PublicKey.from_bytes(pubkey)
tx = Transaction.from_hex(tx_hex)

private_key = wallet.get_private_for_public(their_pubkey)
public_keys = [PublicKey.from_bytes(server_pubkey).compressed_bytes, PublicKey.from_bytes(white_pubkey).compressed_bytes, PublicKey.from_bytes(black_pubkey).compressed_bytes]
redeem_script = Script.build_multisig_redeem(2, public_keys)

for i, inp in enumerate(tx.inputs):
   tx.sign_input(i, bitcoin.Transaction.SIG_HASH_ALL, private_key, redeem_script)

txid = provider.broadcast_transaction(tx.to_hex())

print("Transaction ID: {}".format(txid))

Exemplo n.º 15
0
 def from_hex(h):
     return WalletTransaction.from_transaction(Transaction.from_hex(h))
Exemplo n.º 16
0
    def txn_from_json(txn_json):
        """ Returns a new Transaction from a JSON-serialized transaction

        Args:
            txn_json: JSON with the following format:

        {
        "hash": "0bf0de38c26195919179f...",
        "block_hash": "000000000000000...",
        "block_height": 303404,
        "block_time": "2014-05-30T23:54:55Z",
        "chain_received_at": "2015-08-13T10:52:21.718Z",
        "confirmations": 69389,
        "lock_time": 0,
        "inputs": [
          {
            "transaction_hash": "0bf0de38c2619...",
            "output_hash": "b84a66c46e24fe71f9...",
            "output_index": 0,
            "value": 300000,
            "addresses": [
              "3L7dKYQGNoZub928CJ8NC2WfrM8U8GGBjr"
            ],
            "script_signature": "03046022100de7b67b9...",
            "script_signature_hex": "00493046022100de7b...",
            "sequence": 4294967295
          }
        ],
        "outputs": [
          {
            "transaction_hash": "0bf0de38c261959...",
            "output_index": 0,
            "value": 290000,
            "addresses": [
              "1K4nPxBMy6sv7jssTvDLJWk1ADHBZEoUVb"
            ],
            "script": "OP_DUP OP_HASH160 c629680b8d...",
            "script_hex": "76a914c629680b8d13...",
            "script_type": "pubkeyhash",
            "required_signatures": 1,
            "spent": false,
            "spending_transaction": null
          }
        ],
        "fees": 10000,
        "amount": 290000
        },
        Transaction.DEFAULT_TRANSACTION_VERSION

        Returns:
            two1.lib.bitcoin.Transaction: a deserialized transaction derived
                from the provided json.

        """
        inputs = []
        outputs = []
        addr_keys = set()
        for i in txn_json["inputs"]:
            if 'coinbase' in i:
                inputs.append(
                    CoinbaseInput(height=txn_json["block_height"] or 0,
                                  raw_script=bytes.fromhex(i['coinbase']),
                                  sequence=i['sequence'],
                                  block_version=1))
            else:
                # Script length etc. are not returned so we need to
                # prepend that.
                script, _ = Script.from_bytes(
                    pack_var_str(bytes.fromhex(i["script_signature_hex"])))
                inputs.append(
                    TransactionInput(Hash(i["output_hash"]), i["output_index"],
                                     script, i["sequence"]))
            if "addresses" in i:
                addr_keys.add(i["addresses"][0])

        for i in txn_json["outputs"]:
            script, _ = Script.from_bytes(
                pack_var_str(bytes.fromhex(i["script_hex"])))
            outputs.append(TransactionOutput(i["value"], script))
            if "addresses" in i:
                addr_keys.add(i["addresses"][0])

        txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs,
                          outputs, txn_json["lock_time"])

        return txn, addr_keys
Exemplo n.º 17
0
 def from_hex(h):
     return WalletTransaction.from_transaction(
         Transaction.from_hex(h))
Exemplo n.º 18
0
def cmd_sign(id):
    body = request.data
    body_len = len(body)

    # get associated metadata
    try:
        cursor = connection.cursor()
        row = cursor.execute("SELECT * FROM metadata WHERE hd_index = ?", (id,)).fetchone()
        if row is None:
            abort(404)

        hd_index = int(row[0])
        owner_key = PublicKey.from_bytes(row[3])
    except:
        abort(500)

    # check content-length
    clen_str = request.headers.get('content-length')
    if clen_str is None:
        abort(400)
    clen = int(clen_str)
    if clen != body_len:
        abort(400)

    # check content-type
    ctype = request.headers.get('content-type')
    if ctype is None or ctype != 'application/json':
        abort(400)

    # parse JSON body
    try:
        in_obj = json.loads(body)
        if (not 'msg' in in_obj or not 'sig' in in_obj or
            not 'hash_type' in in_obj or
            not 'input_idx' in in_obj or not 'script' in in_obj):
            abort(400)
        hash_type = int(in_obj['hash_type'])
        input_idx = int(in_obj['input_idx'])
        script = Script.from_bytes(binascii.unhexlify(in_obj['script']))
        tx_hex = binascii.unhexlify(in_obj['msg'])

        broadcast = False
        if 'broadcast' in in_obj and in_obj['broadcast'] == True:
            broadcast = True
    except:
        abort(400)

    # validate base64-encoded signature on hex-encoded transaction
    try:
        rc = PublicKey.verify_bitcoin(tx_hex, in_obj['sig'], owner_key.address())
        if not rc:
            abort(400)

        tx = Transaction.from_hex(tx_hex)
    except:
        abort(400)
        
    # get HD wallet account, privkey for this contract
    acct = wallet._check_and_get_accounts([SRV_ACCT])
    hd_privkey = acct.get_private_key(False, hd_index)

    # try to sign the input
    try:
        tx.sign_input(input_idx, hash_type, hd_privkey, script)
    except:
        abort(400)

    # broadcast transaction to network
    if broadcast:
        wallet.broadcast(tx)

    # return updated transaction
    output_data = tx.to_hex()

    return (output_data, 200, {
        'Content-length': len(output_data),
        'Content-type': 'text/plain',
    })
Exemplo n.º 19
0
    def txn_from_json(txn_json):
        """
        Args:
            txn_json: Json with the following format:
        {
        "block_hash": "0000000000000000af64802c79...",
        "block_height": 292586,
        "hash": "b4735a0690dab16b8789fceaf81c511f...",
        "addresses": [
            "18KXZzuC3xvz6upUMQpsZzXrBwNPWZjdSa",
            "1AAuRETEcHDqL4VM3R97aZHP8DSUHxpkFV",
            "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD",
            "1VxsEDjo6ZLMT99dpcLu4RQonMDVEQQTG"
        ],
        "total": 3537488,
        "fees": 20000,
        "size": 438,
        "preference": "medium",
        "relayed_by": "",
        "confirmed": "2014-03-26T17:08:04Z",
        "received": "2014-03-26T17:08:04Z",
        "ver": 1,
        "lock_time": 0,
        "double_spend": false,
        "vin_sz": 2,
        "vout_sz": 2,
        "confirmations": 64492,
        "confidence": 1,
        "inputs": [
        {
            "prev_hash": "729f6469b59fea5da7...",
            "output_index": 0,
            "script": "483045022100d06cdad1a...",
            "output_value": 3500000,
            "sequence": 4294967295,
            "addresses": [
                "1VxsEDjo6ZLMT99dpcLu4RQonMDVEQQTG"
            ],
            "script_type": "pay-to-pubkey-hash"
        },
        ...
        ],
        "outputs": [
        {
             "value": 3500000,
             "script": "76a9148629647bd642a237...",
             "addresses": [
                 "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD"
             ],
             "script_type": "pay-to-pubkey-hash"
        }
        ]...

        Returns: An Object of type Transaction

        """

        inputs = []
        outputs = []
        addr_keys = set()
        for i in txn_json["inputs"]:
            # Chain doesn't return the stuff about script length etc, so
            # we need to prepend that.
            script, _ = Script.from_bytes(
                pack_var_str(bytes.fromhex(i["script"])))
            inputs.append(
                TransactionInput(Hash(i["prev_hash"]), i["output_index"],
                                 script, i["sequence"]))
            if "addresses" in i and i["addresses"]:
                addr_keys.add(i["addresses"][0])

        for i in txn_json["outputs"]:
            script, _ = Script.from_bytes(
                pack_var_str(bytes.fromhex(i["script"])))
            outputs.append(TransactionOutput(i["value"], script))
            if "addresses" in i and i["addresses"]:
                addr_keys.add(i["addresses"][0])

        txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs,
                          outputs, txn_json["lock_time"])

        return txn, addr_keys
Exemplo n.º 20
0
    def txn_from_json(txn_json):
        """ Returns a new Transaction from a JSON-serialized transaction

        Args:
            txn_json: JSON with the following format:

        {
        "hash": "0bf0de38c26195919179f...",
        "block_hash": "000000000000000...",
        "block_height": 303404,
        "block_time": "2014-05-30T23:54:55Z",
        "chain_received_at": "2015-08-13T10:52:21.718Z",
        "confirmations": 69389,
        "lock_time": 0,
        "inputs": [
          {
            "transaction_hash": "0bf0de38c2619...",
            "output_hash": "b84a66c46e24fe71f9...",
            "output_index": 0,
            "value": 300000,
            "addresses": [
              "3L7dKYQGNoZub928CJ8NC2WfrM8U8GGBjr"
            ],
            "script_signature": "03046022100de7b67b9...",
            "script_signature_hex": "00493046022100de7b...",
            "sequence": 4294967295
          }
        ],
        "outputs": [
          {
            "transaction_hash": "0bf0de38c261959...",
            "output_index": 0,
            "value": 290000,
            "addresses": [
              "1K4nPxBMy6sv7jssTvDLJWk1ADHBZEoUVb"
            ],
            "script": "OP_DUP OP_HASH160 c629680b8d...",
            "script_hex": "76a914c629680b8d13...",
            "script_type": "pubkeyhash",
            "required_signatures": 1,
            "spent": false,
            "spending_transaction": null
          }
        ],
        "fees": 10000,
        "amount": 290000
        },
        Transaction.DEFAULT_TRANSACTION_VERSION

        Returns:
            two1.lib.bitcoin.Transaction: a deserialized transaction derived
                from the provided json.

        """
        inputs = []
        outputs = []
        addr_keys = set()

        for i in sorted(txn_json["vin"], key=lambda i: i["n"]):
            if 'coinbase' in i:
                inputs.append(CoinbaseInput(height=0,
                                            raw_script=bytes.fromhex(i['coinbase']),
                                            sequence=i['sequence'],
                                            block_version=1))
            else:
                script = Script.from_hex(i["scriptSig"]["hex"])
                inputs.append(TransactionInput(Hash(i["txid"]),
                                               i["vout"],
                                               script,
                                               i["sequence"]))
            if "addr" in i:
                addr_keys.add(i["addr"])

        for o in sorted(txn_json["vout"], key=lambda o: o["n"]):
            script = Script.from_hex(o["scriptPubKey"]["hex"])
            value = int(decimal.Decimal(str(o["value"])) * decimal.Decimal('1e8'))
            outputs.append(TransactionOutput(value, script))

            if "addresses" in o["scriptPubKey"]:
                for a in o["scriptPubKey"]["addresses"]:
                    addr_keys.add(a)

        txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION,
                          inputs,
                          outputs,
                          txn_json["locktime"])

        assert txn.hash == Hash(txn_json['txid'])

        return txn, addr_keys
Exemplo n.º 21
0
def cmd_sign(id):
    body = request.data
    body_len = len(body)

    # get associated metadata
    try:
        cursor = connection.cursor()
        row = cursor.execute("SELECT * FROM metadata WHERE hd_index = ?",
                             (id, )).fetchone()
        if row is None:
            abort(404)

        hd_index = int(row[0])
        owner_key = PublicKey.from_bytes(row[3])
    except:
        abort(500)

    # check content-length
    clen_str = request.headers.get('content-length')
    if clen_str is None:
        abort(400)
    clen = int(clen_str)
    if clen != body_len:
        abort(400)

    # check content-type
    ctype = request.headers.get('content-type')
    if ctype is None or ctype != 'application/json':
        abort(400)

    # parse JSON body
    try:
        in_obj = json.loads(body)
        if (not 'msg' in in_obj or not 'sig' in in_obj
                or not 'hash_type' in in_obj or not 'input_idx' in in_obj
                or not 'script' in in_obj):
            abort(400)
        hash_type = int(in_obj['hash_type'])
        input_idx = int(in_obj['input_idx'])
        script = Script.from_bytes(binascii.unhexlify(in_obj['script']))
        tx_hex = binascii.unhexlify(in_obj['msg'])

        broadcast = False
        if 'broadcast' in in_obj and in_obj['broadcast'] == True:
            broadcast = True
    except:
        abort(400)

    # validate base64-encoded signature on hex-encoded transaction
    try:
        rc = PublicKey.verify_bitcoin(tx_hex, in_obj['sig'],
                                      owner_key.address())
        if not rc:
            abort(400)

        tx = Transaction.from_hex(tx_hex)
    except:
        abort(400)

    # get HD wallet account, privkey for this contract
    acct = wallet._check_and_get_accounts([SRV_ACCT])
    hd_privkey = acct.get_private_key(False, hd_index)

    # try to sign the input
    try:
        tx.sign_input(input_idx, hash_type, hd_privkey, script)
    except:
        abort(400)

    # broadcast transaction to network
    if broadcast:
        wallet.broadcast(tx)

    # return updated transaction
    output_data = tx.to_hex()

    return (output_data, 200, {
        'Content-length': len(output_data),
        'Content-type': 'text/plain',
    })