Example #1
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
Example #2
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
Example #3
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',
    })
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',
    })
Example #5
0
 def from_hex(h):
     return WalletTransaction.from_transaction(
         Transaction.from_hex(h))
Example #6
0
 def from_hex(h):
     return WalletTransaction.from_transaction(Transaction.from_hex(h))
Example #7
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))