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
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
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', })
def from_hex(h): return WalletTransaction.from_transaction( Transaction.from_hex(h))
def from_hex(h): return WalletTransaction.from_transaction(Transaction.from_hex(h))
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))