def test_spend_p2sh_utxos(setup_tx_creation): #make a multisig address from 3 privs privs = [chr(x) * 32 + '\x01' for x in range(1, 4)] pubs = [btc.privkey_to_pubkey(binascii.hexlify(priv)) for priv in privs] script = btc.mk_multisig_script(pubs, 2) msig_addr = btc.scriptaddr(script, magicbyte=196) #pay into it wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet'] jm_single().bc_interface.sync_wallet(wallet) amount = 350000000 ins_full = wallet.select_utxos(0, amount) txid = make_sign_and_push(ins_full, wallet, amount, output_addr=msig_addr) assert txid #wait for mining time.sleep(4) #spend out; the input can be constructed from the txid of previous msig_in = txid + ":0" ins = [msig_in] #random output address and change addr output_addr = wallet.get_new_addr(1, 1) amount2 = amount - 50000 outs = [{'value': amount2, 'address': output_addr}] tx = btc.mktx(ins, outs) sigs = [] for priv in privs[:2]: sigs.append(btc.multisign(tx, 0, script, binascii.hexlify(priv))) tx = btc.apply_multisignatures(tx, 0, script, sigs) txid = jm_single().bc_interface.pushtx(tx) assert txid
def make_multisig_info( m, pks ): """ Make a multisig address and redeem script. @m of the given @pks must sign. Return {'address': p2sh address, 'redeem_script': redeem script, 'private_keys': private keys} Return (p2sh address, redeem script) """ pubs = [] privkeys = [] for pk in pks: priv = BitcoinPrivateKey(pk) priv_hex = priv.to_hex() pub_hex = priv.public_key().to_hex() privkeys.append(priv_hex) pubs.append(pub_hex) script = bitcoin.mk_multisig_script( pubs, m ) addr = bitcoin.p2sh_scriptaddr(script, multisig_version_byte) return { 'address': addr, 'redeem_script': script, 'private_keys': privkeys }
def create_multisig_address(crypto, m, n, pub_key_list): if n != len(pub_key_list): raise Exception('n is not the same as length of pub_key_list') crypto_key_id_list = [] for pub_key in pub_key_list: c.execute('SELECT * FROM crypto_key WHERE public_key = ?', (pub_key, )) rows = c.fetchall() # create crypto_key entry if public key is not found in database if len(rows) == 0: c.execute( 'INSERT INTO crypto_key(crypto,public_key,private_key,encrypted_private_key,timestamp) VALUES(?,?,?,?,?)', (crypto, pub_key, 0, 0, datetime.datetime.now())) crypto_key_id_list.append(c.lastrowid) conn.commit() else: crypto_key_id_list.append(rows[0][0]) script = bitcoin.mk_multisig_script(pub_key_list, m) address = bitcoin.scriptaddr(script, SCRIPT_HASH_VERSION_BYTE[crypto]) c.execute( 'INSERT INTO multisig_addr(crypto,address,m,n,timestamp) VALUES(?,?,?,?,?)', (crypto, address, m, n, datetime.datetime.now())) multisig_addr_id = c.lastrowid conn.commit() #now we need to create multisig_own for crypto_key_id in crypto_key_id_list: c.execute( 'INSERT INTO multisig_own(crypto_key_id,multisig_addr_id) VALUES(?,?)', (crypto_key_id, multisig_addr_id)) conn.commit() return address
def make_multisig_info( m, pks ): """ Make a multisig address and redeem script. @m of the given @pks must sign. Return {'address': p2sh address, 'redeem_script': redeem script, 'private_keys': private keys} Return (p2sh address, redeem script) """ pubs = [] privkeys = [] for pk in pks: priv = BitcoinPrivateKey(pk) priv_wif = priv.to_wif() pub = priv.public_key().to_hex() privkeys.append(priv_wif) pubs.append(pub) script = bitcoin.mk_multisig_script( pubs, m ) addr = bitcoin.p2sh_scriptaddr(script, multisig_version_byte) return { 'address': addr, 'redeem_script': script, 'private_keys': privkeys }
def create_multisig_address(crypto,m,n,pub_key_list): if n!=len(pub_key_list): raise Exception('n is not the same as length of pub_key_list') crypto_key_id_list=[] for pub_key in pub_key_list: c.execute('SELECT * FROM crypto_key WHERE public_key = ?',(pub_key,)) rows=c.fetchall() # create crypto_key entry if public key is not found in database if len(rows) ==0: c.execute('INSERT INTO crypto_key(crypto,public_key,private_key,encrypted_private_key,timestamp) VALUES(?,?,?,?,?)', (crypto,pub_key,0,0,datetime.datetime.now())) crypto_key_id_list.append(c.lastrowid) conn.commit() else: crypto_key_id_list.append(rows[0][0]) script=bitcoin.mk_multisig_script(pub_key_list,m) address=bitcoin.scriptaddr(script,SCRIPT_HASH_VERSION_BYTE[crypto]) c.execute('INSERT INTO multisig_addr(crypto,address,m,n,timestamp) VALUES(?,?,?,?,?)', (crypto,address,m,n,datetime.datetime.now())) multisig_addr_id=c.lastrowid conn.commit() #now we need to create multisig_own for crypto_key_id in crypto_key_id_list: c.execute('INSERT INTO multisig_own(crypto_key_id,multisig_addr_id) VALUES(?,?)' ,(crypto_key_id,multisig_addr_id)) conn.commit() return address
def pushPayment(self): #compliantScript = bitcoin.mk_multisig_script([bitcoin.privtopub(self.privS), self.pubKeyClient], 2,2) # inversion!!!! compliantScript = bitcoin.mk_multisig_script([self.pubKeyClient, bitcoin.privtopub(self.privS)], 2,2) sigServer = bitcoin.multisign(self.lastpayment, 0, compliantScript, self.privS) signedPtx = bitcoin.apply_multisignatures(self.lastpayment, 0, compliantScript, [self.lastsig, sigServer]) print 'Broadcast the very last payment. Just got richer. Tx hash:', bitcoin.txhash(signedPtx) bitcoin.pushtx(signedPtx)
def compute_adr_P2SH(args): try: (priv_num, pubs, nkr, nkt) = args pub = bitcoin.privtopub(hexa(priv_num)) mscript = bitcoin.mk_multisig_script([pub] + pubs[1:], nkr, nkt) return bitcoin.p2sh_scriptaddr(mscript) except KeyboardInterrupt: return "x"
def compute_adr_P2SH(args): try: (priv_num, pubs, nkr, nkt) = args pub = coincurve.PrivateKey.from_int(priv_num).public_key.format( False).encode('hex') mscript = bitcoin.mk_multisig_script([pub] + pubs[1:], nkr, nkt) return bitcoin.p2sh_scriptaddr(mscript) except: return "x"
def test_create_p2sh_output_tx(setup_tx_creation, nw, wallet_structures, mean_amt, sdev_amt, amount, pubs, k): wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt) for w in wallets.values(): jm_single().bc_interface.sync_wallet(w['wallet']) for k, w in enumerate(wallets.values()): wallet = w['wallet'] ins_full = wallet.select_utxos(0, amount) script = btc.mk_multisig_script(pubs, k) #try the alternative argument passing pubs.append(k) script2 = btc.mk_multisig_script(*pubs) assert script2 == script output_addr = btc.scriptaddr(script, magicbyte=196) txid = make_sign_and_push(ins_full, wallet, amount, output_addr=output_addr) assert txid
def main(): ''' Our main function. ''' # Two of the three keys. The missing one: # 3347122612f83ad80517dfef41c8b6a6400eef1949df732ce60a4e7c9d00ccb0 priv_keys = [ fix_priv('93d716a849c4c215b3049670ef7c1eba9b19c0452caf37b8f3383dcdd5577440'), fix_priv('7b389eb21fb17ef293be410009d436a495e0942005b1e6845f64429a5ff13420'), ] # Same order that Counterparty uses. Order should not matter. pub_0 = priv2pub(fix_priv('3347122612f83ad80517dfef41c8b6a6400eef1949df732ce60a4e7c9d00ccb0')) pub_1 = priv2pub(priv_keys[0]) pub_2 = priv2pub(priv_keys[1]) script_not_real = bitcoin.mk_multisig_script(pub_0, pub_1, pub_2, 2, 3) for priv in priv_keys: check_priv_key_looks_good(priv) deserialized_txn = deserialize_tx(get_raw_tx()) print('The raw transaction: {}\n'.format(get_raw_tx())) print('The decoded transaction:\n{}\n'.format(pprint.pformat(deserialized_txn))) bitcoind_script = '52410427db4059d24bab05df3f6bcc768fb01bd976b973f93e72cce2dfbfbed5a32056c9040a2c2ea4c10c812a54fed7ff2e6a917dbc843362d398f6ace4000fafa5c641043e12a6cb1c7c156f789110abf8397b714047414b5a32c742f17ccf93ff23bdf3128f946207086bcef012558240cd16182c741123e93ed18327c4cd6ebac668a94104e4168c172283c7dfaa85d2004f763a28bf6d0f1602fc1452ccec62a7c8a66e422af1410fbf24a47355ddc43dfe3491cb1b806574ccd1c434680466dcff926f0153ae' # You might want to use _ for something. signatures_A = [] signatures_B = [] for tx_index, tx_input in enumerate(deserialized_txn['ins']): assert tx_index == 0 # Only once! script_real = tx_input['script'] assert script_real == bitcoind_script assert len(script_real) == len(script_not_real) signatures_A.append(bitcoin.multisign(get_raw_tx(), tx_index, script_real, priv_keys[0])) signatures_B.append(bitcoin.multisign(get_raw_tx(), tx_index, script_real, priv_keys[1])) fully_signed_tx = get_raw_tx() fully_signed_tx_before = fully_signed_tx for tx_index, tx_input in enumerate(deserialized_txn['ins']): assert tx_index == 0 # Only once! fully_signed_tx = bitcoin.apply_multisignatures( \ fully_signed_tx, tx_index, script_real, signatures_A[tx_index], signatures_B[tx_index]) assert fully_signed_tx_before != fully_signed_tx # may the bytes be with you print('Fully signed: {}'.format(fully_signed_tx))
def address(self): print 'pubkeys', self.pubkeys pubkeys = self.pubkeys for idx, pubkey in enumerate(pubkeys): pubkeys[idx] = pubkey.encode('hex') print 'pubkeys2', pubkeys script = bitcoin.mk_multisig_script(self.pubkeys, 2, 3) address = bitcoin.scriptaddr(script) print 'script',script return address
def pushPayment(self): #compliantScript = bitcoin.mk_multisig_script([bitcoin.privtopub(self.privS), self.pubKeyClient], 2,2) # inversion!!!! compliantScript = bitcoin.mk_multisig_script( [self.pubKeyClient, bitcoin.privtopub(self.privS)], 2, 2) sigServer = bitcoin.multisign(self.lastpayment, 0, compliantScript, self.privS) signedPtx = bitcoin.apply_multisignatures(self.lastpayment, 0, compliantScript, [self.lastsig, sigServer]) print 'Broadcast the very last payment. Just got richer. Tx hash:', bitcoin.txhash( signedPtx) bitcoin.pushtx(signedPtx)
def _bake(self): self.privates = [ hashlib.sha256('priv{}'.format(i).encode()).hexdigest() + '01' for i in range(0, 18) ] self._scripts = [ bitcoin.mk_multisig_script(bitcoin.privtopub(self.privates[x]), bitcoin.privtopub(self.privates[x + 1]), bitcoin.privtopub(self.privates[x + 2]), 2) for x in range(0, 18, 3) ] self.addresses = [ bitcoin.p2sh_scriptaddr(script, magicbyte=196) for script in self._scripts ]
def run(self): print 'Initialisation of MPC...' # exchange public keys pubKeyServer = bitcoin.privtopub(self.privS) print 'pubKeyServer: ', pubKeyServer self.pubKeyClient = txUtils.exchangePubKey(pubKeyServer, self.c) print 30 * '#', 'Handshake', 30 * '#' print 'Public Key received from client is: ', self.pubKeyClient # receive the signed Dtx and signedDtx = self.c.jrecv() print 'SignedDtx:', signedDtx #print pprint(bitcoin.deserialize(signedDtx)) scriptDtx = self.c.jrecv() print 'ScriptDtx: ', scriptDtx own = bitcoin.mk_multisig_script( [self.pubKeyClient, bitcoin.privtopub(self.privS)], 2, 2) # inversion!!!! if own != scriptDtx: print 'Anomalous ScriptDtx. Own is:', own # broadcast D bitcoin.pushtx(signedDtx) print 35 * '#', ' MPC initialised ', 35 * '#' self.balance += 1000000 # authorize use of the internet: hpUtils.allowFwd(self.ipClient) # set up Cashier (observed) self.cashier = cashier(self.c) self.cashier.addObserver(self) # obviously not the right way self.cashier.start() # start control spin self.controlSpin() # broadcast payment print 'Manager broadcasts payment' self.pushPayment() # terminate cashier print "Manager waiting for cashier's termination" self.cashier.join() #self.c.close() print 'Manager terminating'
def run(self): print 'Initialisation of MPC...' # exchange public keys pubKeyServer = bitcoin.privtopub(self.privS) print 'pubKeyServer: ', pubKeyServer self.pubKeyClient = txUtils.exchangePubKey(pubKeyServer, self.c) print 30*'#', 'Handshake', 30*'#' print 'Public Key received from client is: ', self.pubKeyClient # receive the signed Dtx and signedDtx = self.c.jrecv() print 'SignedDtx:' , signedDtx #print pprint(bitcoin.deserialize(signedDtx)) scriptDtx = self.c.jrecv() print 'ScriptDtx: ', scriptDtx own = bitcoin.mk_multisig_script([self.pubKeyClient, bitcoin.privtopub(self.privS)], 2,2) # inversion!!!! if own != scriptDtx: print 'Anomalous ScriptDtx. Own is:', own # broadcast D bitcoin.pushtx(signedDtx) print 35*'#',' MPC initialised ', 35*'#' self.balance += 1000000 # authorize use of the internet: hpUtils.allowFwd(self.ipClient) # set up Cashier (observed) self.cashier = cashier(self.c) self.cashier.addObserver(self) # obviously not the right way self.cashier.start() # start control spin self.controlSpin() # broadcast payment print 'Manager broadcasts payment' self.pushPayment() # terminate cashier print "Manager waiting for cashier's termination" self.cashier.join() #self.c.close() print 'Manager terminating'
def make_multisig_info(m, pks): """ Make a multisig address and redeem script """ pubs = [] prikeys = [] for pk in pks: priv = BitcoinPrivateKey(pk) priv_wif = priv.to_wif() pub = priv.public_key().to_hex() prikeys.append(priv_wif) pubs.append(pub) script = bitcoin.mk_multisig_script( pubs, m) addr = bitcoin.p2sh_scriptaddr(script, multisig_version_byte) return { 'address': addr, 'redeem_script': script, 'private_keys': prikeys }
def get_order(self, order_id, by_buyer_id=False): notary_fee = "" if not by_buyer_id: _order = self.db_connection.select_entries("orders", {"order_id": order_id})[0] else: _order = self.db_connection.select_entries("orders", {"buyer_order_id": order_id})[0] total_price = 0 offer_data_json = self.get_offer_json(_order['signed_contract_body'], _order['state']) buyer_data_json = self.get_buyer_json(_order['signed_contract_body'], _order['state']) if _order['state'] != Orders.State.SENT: notary_json = self.get_notary_json(_order['signed_contract_body'], _order['state']) notary = notary_json['Notary']['notary_GUID'] else: notary = "" if _order['state'] in (Orders.State.NEED_TO_PAY, Orders.State.NOTARIZED, Orders.State.WAITING_FOR_PAYMENT, Orders.State.WAITING_FOR_MERCHANT, Orders.State.PAID, Orders.State.BUYER_PAID, Orders.State.SHIPPED, Orders.State.COMPLETED): def send_to_client_callback(total): if self.transport.handler is not None: self.transport.handler.send_to_client(None, {"type": "order_payment_amount", "order_id": order_id, "value": total}) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], buyer_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], notary_json['Notary']['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) payment_address = scriptaddr(script) def get_unspent(): trust.get_unspent(payment_address, send_to_client_callback) threading.Thread(target=get_unspent).start() if 'shipping_price' in _order: shipping_price = _order['shipping_price'] if _order['shipping_price'] != '' else 0 else: shipping_price = 0 try: total_price = str((Decimal(shipping_price) + Decimal(_order['item_price']))) \ if 'item_price' in _order else _order['item_price'] except Exception as exc: self.log.error('Probably not a number %s', exc) notary_fee = notary_json['Notary']['notary_fee'] # Generate QR code qr_code = self.get_qr_code(offer_data_json['Contract']['item_title'], _order['address'], total_price) merchant_bitmessage = offer_data_json.get('Seller', '').get('seller_Bitmessage') buyer_bitmessage = buyer_data_json.get('Buyer', '').get('buyer_Bitmessage') self.log.debug('Shipping Address: %s', _order.get('shipping_address')) if _order.get('buyer') == self.transport.guid: shipping_address = self.get_shipping_address() else: shipping_address = _order.get('shipping_address') # Get order prototype object before storing order = {"id": _order['id'], "state": _order.get('state'), "address": _order.get('address'), "buyer": _order.get('buyer'), "merchant": _order.get('merchant'), "order_id": _order.get('order_id'), "item_quantity": _order.get('item_quantity'), "item_price": _order.get('item_price'), "shipping_price": _order.get('shipping_price'), "shipping_address": shipping_address, "total_price": total_price, "merchant_bitmessage": merchant_bitmessage, "buyer_bitmessage": buyer_bitmessage, "notary": notary, "notary_fee": notary_fee, "payment_address": _order.get('payment_address'), "payment_address_amount": _order.get('payment_address_amount'), "qrcode": 'data:image/png;base64,' + qr_code, "item_title": offer_data_json['Contract']['item_title'], "item_desc": offer_data_json['Contract']['item_desc'], "signed_contract_body": _order.get('signed_contract_body'), "note_for_merchant": _order.get('note_for_merchant'), "merchant_tx": _order.get('merchant_tx'), "merchant_sigs": _order.get('merchant_sigs'), "merchant_script": _order.get('merchant_script'), "updated": _order.get('updated')} if len(offer_data_json['Contract']['item_remote_images']): order['item_images'] = offer_data_json['Contract']['item_remote_images'] else: order['item_images'] = [] self.log.datadump('FULL ORDER: %s', order) return order
def client_release_payment(self, socket_handler, msg): self.log.info('Releasing payment to Merchant %s', msg) order = self.market.orders.get_order(msg['orderId']) contract = order['signed_contract_body'] # Find Seller Data in Contract offer_data = ''.join(contract.split('\n')[8:]) index_of_seller_signature = offer_data.find( '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data) ) offer_data_json = offer_data[0:index_of_seller_signature] offer_data_json = json.loads(offer_data_json) self.log.info('Offer Data: %s', offer_data_json) # Find Buyer Data in Contract bid_data_index = offer_data.find( '"Buyer"', index_of_seller_signature, len(offer_data) ) end_of_bid_index = offer_data.find( '- -----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data) ) bid_data_json = "{" bid_data_json += offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) # Find Notary Data in Contract notary_data_index = offer_data.find( '"Notary"', end_of_bid_index, len(offer_data) ) end_of_notary_index = offer_data.find( '-----BEGIN PGP SIGNATURE', notary_data_index, len(offer_data) ) notary_data_json = "{" notary_data_json += offer_data[notary_data_index:end_of_notary_index] notary_data_json = json.loads(notary_data_json) self.log.info('Notary Data: %s', notary_data_json) try: client = obelisk.ObeliskOfLightClient( 'tcp://obelisk.coinkite.com:9091' ) seller = offer_data_json['Seller'] buyer = bid_data_json['Buyer'] notary = notary_data_json['Notary'] pubkeys = [ seller['seller_BTC_uncompressed_pubkey'], buyer['buyer_BTC_uncompressed_pubkey'], notary['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) multi_address = scriptaddr(script) def cb(ec, history, order): settings = self.market.get_settings() private_key = settings.get('privkey') if ec is not None: self.log.error("Error fetching history: %s", ec) # TODO: Send error message to GUI return # Create unsigned transaction unspent = [row[:4] for row in history if row[4] is None] # Send all unspent outputs (everything in the address) minus # the fee total_amount = 0 inputs = [] for row in unspent: assert len(row) == 4 inputs.append( str(row[0].encode('hex')) + ":" + str(row[1]) ) value = row[3] total_amount += value # Constrain fee so we don't get negative amount to send fee = min(total_amount, 10000) send_amount = total_amount - fee payment_output = order['payment_address'] tx = mktx( inputs, [str(payment_output) + ":" + str(send_amount)] ) signatures = [] for x in range(0, len(inputs)): ms = multisign(tx, x, script, private_key) signatures.append(ms) print signatures self.market.release_funds_to_merchant( buyer['buyer_order_id'], tx, script, signatures, order.get('merchant') ) def get_history(): client.fetch_history( multi_address, lambda ec, history, order=order: cb(ec, history, order) ) reactor.callFromThread(get_history) except Exception as e: self.log.error('%s', e)
import bitcoin as bt #1st Sig private_key1 = bt.random_key() public_key1 = bt.privttopub(private_key1) #2nd Sig private_key2 = bt.random_key() public_key2 = bt.privttopub(private_key2) #3rd Sig private_key3 = bt.random_key() public_key3 = bt.privttopub(private_key3) multi_sig = bt.mk_multisig_script(public_key1, public_key2, public_key3, 2,3) btc_address = scriptaddr(multi_sig) #with open('data.txt', 'w') as fob: # fob.write('Private Key1: ' + private_key1 + '\nPrivate Key2: ' + private_key2 + '\nPrivate Key3: ' + private_key3 + 'nPublic Key1: ' + public_key1 + '\nPublic Key2: ' + public_key2 + '\nPublic Key3: ' + public_key3 + '\nBTC Address: '+bitcoin_address+'\n') # fob.close() print('Private Key1:', private_key1) print('Private Key2:', private_key2) print('Private Key3:', private_key3) print('BTC Address:', btc_address)
assert npubinput < nkeystotal P2SH = True except: raise ValueError( "Error in arguments\nUse : SigVanity.py [ <1xFirstBits> |\nm (<KeysReq> <KeysTot>) |\n<3xFirstBits> (<KeysReq> <KeysTot>) [<PubKeyHex> [<PubKeyHex> ...]]\n]" ) load_gtable('lib/G_Table') if P2SH: privs = [randomforkey() for x in range(nkeystotal - npubinput)] pubs = [bitcoin.privtopub(hexa(priv)) for priv in privs] pubinputlist = [] for item in rawpubinputlist: pubinputlist.append(item.lower()) pubs = pubs + pubinputlist addresses = [bitcoin.pubtoaddr(pub) for pub in pubs] mscript = bitcoin.mk_multisig_script(pubs, nkeysneeded, nkeystotal) address = bitcoin.p2sh_scriptaddr(mscript) foundprivkeynum = privs[0] else: privkeynum = randomforkey() address = compute_adr(privkeynum) foundprivkeynum = privkeynum if vanity: address = None if P2SH: newprivkeynum = privs[0] print "\nVanity Mode, please Wait ..." print "Press CTRL+C to stop searching" nstart = privs[0] startTime = time.time() try:
def test_P2SH_P2WSH_ALL_SIGHASH(self): tx = TEST_CASES[3] VIN_AMOUNT = int(9.87654321 * 10**8) deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][0]) priv1 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][1]) priv2 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][2]) priv3 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][3]) priv4 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][4]) priv5 = self.append_compressed_flag_to_privkey(tx['ins'][0]['privkeys'][5]) witness_script = mk_multisig_script(privtopub(priv0), privtopub(priv1), privtopub(priv2), privtopub(priv3), privtopub(priv4), privtopub(priv5), 6) self.assertEqual(witness_script, tx['ins'][0]['witness_script']) sign0 = segwit_multisign(generated_tx, 0, witness_script, priv0, VIN_AMOUNT, hashcode=SIGHASH_ALL) sign1 = segwit_multisign(generated_tx, 0, witness_script, priv1, VIN_AMOUNT, hashcode=SIGHASH_NONE) sign2 = segwit_multisign(generated_tx, 0, witness_script, priv2, VIN_AMOUNT, hashcode=SIGHASH_SINGLE) sign3 = segwit_multisign(generated_tx, 0, witness_script, priv3, VIN_AMOUNT, hashcode=SIGHASH_ALL|SIGHASH_ANYONECANPAY) sign4 = segwit_multisign(generated_tx, 0, witness_script, priv4, VIN_AMOUNT, hashcode=SIGHASH_NONE|SIGHASH_ANYONECANPAY) sign5 = segwit_multisign(generated_tx, 0, witness_script, priv5, VIN_AMOUNT, hashcode=SIGHASH_SINGLE|SIGHASH_ANYONECANPAY) signed = apply_segwit_multisignatures(stripped_tx, 0, witness_script, [sign0, sign1, sign2, sign3, sign4, sign5], nested=True) self.assertEqual(signed, tx['signed']) print('[P2WSH 6-of-6 multisig NESTED in P2SH] SIGHASH_SINGLE\SIGHASH_ALL\SIGHASH_NONE & ANYONECANPAY')
def handle_bid_order(self, bid): self.log.info('Bid Order: %s', bid) new_peer = self.transport.get_crypto_peer(bid.get('merchantGUID'), bid.get('merchantURI'), bid.get('merchantPubkey')) # Generate unique id for this bid order_id = random.randint(0, 1000000) while len(self.db.selectEntries("contracts", {"id": order_id})) > 0: order_id = random.randint(0, 1000000) # Add to contract and sign contract = bid.get('rawContract') contract_stripped = "".join(contract.split('\n')) bidder_pgp_start_index = contract_stripped.find("buyer_pgp", 0, len(contract_stripped)) bidder_pgp_end_index = contract_stripped.find("buyer_GUID", 0, len(contract_stripped)) bidder_pgp = contract_stripped[bidder_pgp_start_index + 13:bidder_pgp_end_index] self.gpg.import_keys(bidder_pgp) v = self.gpg.verify(contract) if v: self.log.info('Sellers contract verified') notary_section = {} notary_section['Notary'] = { 'notary_GUID': self.transport.guid, 'notary_BTC_uncompressed_pubkey': privkey_to_pubkey(self.transport.settings['privkey']), 'notary_pgp': self.transport.settings['PGPPubKey'], 'notary_fee': "", 'notary_order_id': order_id } offer_data_json = self.get_offer_json(contract, Orders.State.SENT) bid_data_json = self.get_buyer_json(contract, Orders.State.SENT) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], privkey_to_pubkey(self.transport.settings['privkey']) ] script = mk_multisig_script(pubkeys, 2, 3) multisig_address = scriptaddr(script) notary_section['Escrow'] = { 'multisig_address': multisig_address, 'redemption_script': script } self.log.debug('Notary: %s', notary_section) gpg = self.gpg # Prepare contract body notary_json = json.dumps(notary_section, indent=0) seg_len = 52 out_text = "\n".join( notary_json[x:x + seg_len] for x in range(0, len(notary_json), seg_len) ) # Append new data to contract out_text = "%s\n%s" % (contract, out_text) signed_data = gpg.sign(out_text, passphrase='P@ssw0rd', keyid=self.transport.settings.get('PGPPubkeyFingerprint')) self.log.debug('Double-signed Contract: %s', signed_data) # Hash the contract for storage contract_key = hashlib.sha1(str(signed_data)).hexdigest() hash_value = hashlib.new('ripemd160') hash_value.update(contract_key) contract_key = hash_value.hexdigest() self.log.info('Order ID: %s', order_id) # Push buy order to DHT and node if available # self.transport.store(contract_key, str(signed_data), self.transport.guid) # self.update_listings_index() # Find Seller Data in Contract offer_data = ''.join(contract.split('\n')[8:]) index_of_seller_signature = offer_data.find('- -----BEGIN PGP SIGNATURE-----', 0, len(offer_data)) offer_data_json = "{\"Seller\": {" + offer_data[0:index_of_seller_signature] self.log.info('Offer Data: %s', offer_data_json) offer_data_json = json.loads(str(offer_data_json)) # Find Buyer Data in Contract bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature, len(offer_data)) end_of_bid_index = offer_data.find('-----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data)) bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) self.log.info('Bid Data: %s', bid_data_json) buyer_order_id = "%s-%s" % ( bid_data_json['Buyer']['buyer_GUID'], bid_data_json['Buyer']['buyer_order_id'] ) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], privkey_to_pubkey(self.transport.settings['privkey']) ] script = mk_multisig_script(pubkeys, 2, 3) multisig_address = scriptaddr(script) self.db.insertEntry( "orders", { 'market_id': self.transport.market_id, 'contract_key': contract_key, 'signed_contract_body': str(signed_data), 'state': Orders.State.NOTARIZED, 'buyer_order_id': buyer_order_id, 'order_id': order_id, 'merchant': offer_data_json['Seller']['seller_GUID'], 'buyer': bid_data_json['Buyer']['buyer_GUID'], 'address': multisig_address, 'item_price': offer_data_json['Contract'].get('item_price', 0), 'shipping_price': offer_data_json['Contract']['item_delivery'].get('shipping_price', ""), 'note_for_merchant': bid_data_json['Buyer']['note_for_seller'], "updated": time.time() } ) # Send order to seller and buyer self.log.info('Sending notarized contract to buyer and seller %s', bid) if self.transport.handler is not None: self.transport.handler.send_to_client(None, {"type": "order_notify", "msg": "You just auto-notarized a contract."}) notarized_order = { "type": "order", "state": "Notarized", "rawContract": str(signed_data) } if new_peer is not None: new_peer.send(notarized_order) self.transport.send(notarized_order, bid_data_json['Buyer']['buyer_GUID']) self.log.info('Sent notarized contract to Seller and Buyer')
def handle_notarized_order(self, msg): self.log.info('Handling notarized order') contract = msg['rawContract'] # Find Seller Data in Contract offer_data = ''.join(contract.split('\n')[8:]) index_of_seller_signature = offer_data.find('- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data)) offer_data_json = offer_data[0:index_of_seller_signature] self.log.info('Offer Data: %s', offer_data_json) offer_data_json = json.loads(str(offer_data_json)) # Find Buyer Data in Contract bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature, len(offer_data)) end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data)) bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) self.log.info('Bid Data: %s', bid_data_json) # Find Notary Data in Contract notary_data_index = offer_data.find('"Notary"', end_of_bid_index, len(offer_data)) end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE', notary_data_index, len(offer_data)) notary_data_json = "{" + offer_data[notary_data_index:end_of_notary_index] notary_data_json = json.loads(notary_data_json) self.log.info('Notary Data: %s', notary_data_json) # Generate multi-sig address pubkeys = [offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], notary_data_json['Notary']['notary_BTC_uncompressed_pubkey']] script = mk_multisig_script(pubkeys, 2, 3) multisig_address = scriptaddr(script) seller_GUID = offer_data_json['Seller']['seller_GUID'] order_id = bid_data_json['Buyer']['buyer_order_id'] contract_key = hashlib.sha1(str(contract)).hexdigest() hash_value = hashlib.new('ripemd160') hash_value.update(contract_key) contract_key = hash_value.hexdigest() if seller_GUID == self.transport.guid: self.log.info('I am the seller!') state = 'Waiting for Payment' merchant_order_id = random.randint(0, 1000000) while len(self.db.selectEntries("orders", {"id": order_id})) > 0: merchant_order_id = random.randint(0, 1000000) buyer_id = "%s-%s" % ( bid_data_json['Buyer']['buyer_GUID'], bid_data_json['Buyer']['buyer_order_id'] ) self.db.insertEntry( "orders", { 'market_id': self.transport.market_id, 'contract_key': contract_key, 'order_id': merchant_order_id, 'signed_contract_body': str(contract), 'state': state, 'buyer_order_id': buyer_id, 'merchant': offer_data_json['Seller']['seller_GUID'], 'buyer': bid_data_json['Buyer']['buyer_GUID'], 'notary': notary_data_json['Notary']['notary_GUID'], 'address': multisig_address, 'shipping_address': self.transport.cryptor.decrypt( bid_data_json['Buyer']['buyer_deliveryaddr'].decode('hex')), 'item_price': offer_data_json['Contract'].get('item_price', 0), 'shipping_price': offer_data_json['Contract']['item_delivery'].get('shipping_price', 0), 'note_for_merchant': bid_data_json['Buyer']['note_for_seller'], "updated": time.time() } ) self.transport.handler.send_to_client(None, {"type": "order_notify", "msg": "You just received a new order."}) else: self.log.info('I am the buyer') state = 'Need to Pay' self.db.updateEntries( "orders", { 'market_id': self.transport.market_id, 'contract_key': contract_key, 'signed_contract_body': str(contract), 'state': state, 'merchant': offer_data_json['Seller']['seller_GUID'], 'buyer': bid_data_json['Buyer']['buyer_GUID'], 'notary': notary_data_json['Notary']['notary_GUID'], 'address': multisig_address, 'shipping_address': json.dumps(self.get_shipping_address()), 'item_price': offer_data_json['Contract'].get('item_price', 0), 'shipping_price': offer_data_json['Contract']['item_delivery'].get('shipping_price', ''), 'note_for_merchant': bid_data_json['Buyer']['note_for_seller'], "updated": time.time() }, { 'order_id': order_id } ) self.transport.handler.send_to_client(None, {"type": "order_notify", "msg": "Your order requires payment now."})
def add_purchase_info( self, quantity, ship_to=None, shipping_address=None, city=None, state=None, postal_code=None, country=None, moderator=None, options=None, ): """ Update the contract with the buyer's purchase information. """ profile = Profile(self.db).get() order_json = { "buyer_order": { "order": { "ref_hash": digest(json.dumps(self.contract, indent=4)).encode("hex"), "quantity": quantity, "id": { "guid": self.keychain.guid.encode("hex"), "pubkeys": { "guid": self.keychain.guid_signed_pubkey[64:].encode("hex"), "bitcoin": bitcoin.bip32_extract_key(self.keychain.bitcoin_master_pubkey), "encryption": self.keychain.encryption_pubkey.encode("hex"), }, }, "payment": {}, } } } if profile.HasField("handle"): order_json["buyer_order"]["order"]["id"]["blockchain_id"] = profile.handle if self.contract["vendor_offer"]["listing"]["metadata"]["category"] == "physical good": order_json["buyer_order"]["order"]["shipping"] = {} order_json["buyer_order"]["order"]["shipping"]["ship_to"] = ship_to order_json["buyer_order"]["order"]["shipping"]["address"] = shipping_address order_json["buyer_order"]["order"]["shipping"]["city"] = city order_json["buyer_order"]["order"]["shipping"]["state"] = state order_json["buyer_order"]["order"]["shipping"]["postal_code"] = postal_code order_json["buyer_order"]["order"]["shipping"]["country"] = country if options is not None: order_json["buyer_order"]["order"]["options"] = options if moderator: # TODO: Handle direct payments chaincode = sha256(str(random.getrandbits(256))).digest().encode("hex") order_json["buyer_order"]["order"]["payment"]["chaincode"] = chaincode valid_mod = False for mod in self.contract["vendor_offer"]["listing"]["moderators"]: if mod["guid"] == moderator: order_json["buyer_order"]["order"]["moderator"] = moderator masterkey_m = mod["pubkeys"]["bitcoin"]["key"] valid_mod = True if not valid_mod: return False masterkey_b = bitcoin.bip32_extract_key(self.keychain.bitcoin_master_pubkey) masterkey_v = self.contract["vendor_offer"]["listing"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) vendor_key = derive_childkey(masterkey_v, chaincode) moderator_key = derive_childkey(masterkey_m, chaincode) redeem_script = "75" + bitcoin.mk_multisig_script([buyer_key, vendor_key, moderator_key], 2) order_json["buyer_order"]["order"]["payment"]["redeem_script"] = redeem_script if self.testnet: payment_address = bitcoin.p2sh_scriptaddr(redeem_script, 196) else: payment_address = bitcoin.p2sh_scriptaddr(redeem_script) order_json["buyer_order"]["order"]["payment"]["address"] = payment_address price_json = self.contract["vendor_offer"]["listing"]["item"]["price_per_unit"] if "bitcoin" in price_json: order_json["buyer_order"]["order"]["payment"]["amount"] = price_json["bitcoin"] else: currency_code = price_json["fiat"]["currency_code"] fiat_price = price_json["fiat"]["price"] try: request = Request("https://api.bitcoinaverage.com/ticker/" + currency_code.upper() + "/last") response = urlopen(request) conversion_rate = response.read() except URLError: return False order_json["buyer_order"]["order"]["payment"]["amount"] = float( "{0:.8f}".format(float(fiat_price) / float(conversion_rate)) ) self.contract["buyer_order"] = order_json["buyer_order"] order = json.dumps(self.contract["buyer_order"]["order"], indent=4) self.contract["buyer_order"]["signature"] = self.keychain.signing_key.sign( order, encoder=nacl.encoding.HexEncoder )[:128] return self.contract["buyer_order"]["order"]["payment"]["address"]
def get_order(self, order_id, by_buyer_id=False): if not by_buyer_id: _order = self.db.selectEntries("orders", {"order_id": order_id})[0] else: _order = self.db.selectEntries("orders", {"buyer_order_id": order_id})[0] total_price = 0 offer_data_json = self.get_offer_json(_order['signed_contract_body'], _order['state']) buyer_data_json = self.get_buyer_json(_order['signed_contract_body'], _order['state']) if _order['state'] != Orders.State.SENT: notary_json = self.get_notary_json(_order['signed_contract_body'], _order['state']) notary = notary_json['Notary']['notary_GUID'] else: notary = "" if _order['state'] in (Orders.State.NEED_TO_PAY, Orders.State.NOTARIZED, Orders.State.WAITING_FOR_PAYMENT, Orders.State.PAID, Orders.State.BUYER_PAID, Orders.State.SHIPPED): def cb(total): if self.transport.handler is not None: self.transport.handler.send_to_client(None, {"type": "order_payment_amount", "value": total}) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], buyer_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], notary_json['Notary']['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) payment_address = scriptaddr(script) trust.get_unspent(payment_address, cb) if 'shipping_price' in _order: shipping_price = _order['shipping_price'] if _order['shipping_price'] != '' else 0 else: shipping_price = 0 try: total_price = str((Decimal(shipping_price) + Decimal(_order['item_price']))) \ if 'item_price' in _order else _order['item_price'] except Exception as e: self.log.error('Probably not a number %s', e) # Generate QR code qr = self.get_qr_code(offer_data_json['Contract']['item_title'], _order['address'], total_price) merchant_bitmessage = offer_data_json.get('Seller', '').get('seller_Bitmessage') buyer_bitmessage = buyer_data_json.get('Buyer', '').get('buyer_Bitmessage') # Get order prototype object before storing order = {"id": _order['id'], "state": _order.get('state'), "address": _order.get('address'), "buyer": _order.get('buyer'), "merchant": _order.get('merchant'), "order_id": _order.get('order_id'), "item_price": _order.get('item_price'), "shipping_price": _order.get('shipping_price'), "shipping_address": str(_order.get('shipping_address')), "total_price": total_price, "merchant_bitmessage": merchant_bitmessage, "buyer_bitmessage": buyer_bitmessage, "notary": notary, "payment_address": _order.get('payment_address'), "payment_address_amount": _order.get('payment_address_amount'), "qrcode": 'data:image/png;base64,' + qr, "item_title": offer_data_json['Contract']['item_title'], "signed_contract_body": _order.get('signed_contract_body'), "note_for_merchant": _order.get('note_for_merchant'), "updated": _order.get('updated')} if 'item_images' in offer_data_json['Contract'] and offer_data_json['Contract']['item_images'] != {}: order['item_image'] = offer_data_json['Contract']['item_images'] else: order['item_image'] = "img/no-photo.png" self.log.datadump('FULL ORDER: %s', order) return order
def verify(self, sender_key): """ Validate that an order sent over by a buyer is filled out correctly. """ try: contract_dict = json.loads(json.dumps(self.contract, indent=4), object_pairs_hook=OrderedDict) del contract_dict["buyer_order"] contract_hash = digest(json.dumps(contract_dict, indent=4)) ref_hash = unhexlify(self.contract["buyer_order"]["order"]["ref_hash"]) # verify that the reference hash matches the contract and that the contract actually exists if contract_hash != ref_hash or not self.db.HashMap().get_file(ref_hash): raise Exception("Order for contract that doesn't exist") # verify the signature on the order verify_key = nacl.signing.VerifyKey(sender_key) verify_key.verify( json.dumps(self.contract["buyer_order"]["order"], indent=4), unhexlify(self.contract["buyer_order"]["signature"]), ) # verify buyer included the correct bitcoin amount for payment price_json = self.contract["vendor_offer"]["listing"]["item"]["price_per_unit"] if "bitcoin" in price_json: asking_price = price_json["bitcoin"] else: currency_code = price_json["fiat"]["currency_code"] fiat_price = price_json["fiat"]["price"] request = Request("https://api.bitcoinaverage.com/ticker/" + currency_code.upper() + "/last") response = urlopen(request) conversion_rate = response.read() asking_price = float("{0:.8f}".format(float(fiat_price) / float(conversion_rate))) if asking_price > self.contract["buyer_order"]["order"]["payment"]["amount"]: raise Exception("Insuffient Payment") # verify a valid moderator was selected # TODO: handle direct payments valid_mod = False for mod in self.contract["vendor_offer"]["listing"]["moderators"]: if mod["guid"] == self.contract["buyer_order"]["order"]["moderator"]: valid_mod = True if not valid_mod: raise Exception("Invalid moderator") # verify all the shipping fields exist if self.contract["vendor_offer"]["listing"]["metadata"]["category"] == "physical good": shipping = self.contract["buyer_order"]["order"]["shipping"] keys = ["ship_to", "address", "postal_code", "city", "state", "country"] for value in map(shipping.get, keys): if value is None: raise Exception("Missing shipping field") # verify buyer ID pubkeys = self.contract["buyer_order"]["order"]["id"]["pubkeys"] keys = ["guid", "bitcoin", "encryption"] for value in map(pubkeys.get, keys): if value is None: raise Exception("Missing pubkey field") # verify redeem script chaincode = self.contract["buyer_order"]["order"]["payment"]["chaincode"] for mod in self.contract["vendor_offer"]["listing"]["moderators"]: if mod["guid"] == self.contract["buyer_order"]["order"]["moderator"]: masterkey_m = mod["pubkeys"]["bitcoin"]["key"] masterkey_v = bitcoin.bip32_extract_key(self.keychain.bitcoin_master_pubkey) masterkey_b = self.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) vendor_key = derive_childkey(masterkey_v, chaincode) moderator_key = derive_childkey(masterkey_m, chaincode) redeem_script = "75" + bitcoin.mk_multisig_script([buyer_key, vendor_key, moderator_key], 2) if redeem_script != self.contract["buyer_order"]["order"]["payment"]["redeem_script"]: raise Exception("Invalid redeem script") # verify the payment address if self.testnet: payment_address = bitcoin.p2sh_scriptaddr(redeem_script, 196) else: payment_address = bitcoin.p2sh_scriptaddr(redeem_script) if payment_address != self.contract["buyer_order"]["order"]["payment"]["address"]: raise Exception("Incorrect payment address") return True except Exception: return False
def test_P2SH_P2WSH_ALL_SIGHASH(self): tx = TEST_CASES[3] VIN_AMOUNT = int(9.87654321 * 10**8) deserialized = deserialize(tx['unsigned']) serialized = serialize(deserialized) self.assertEqual(serialized, tx['unsigned']) self.assertEqual(deserialized['locktime'], tx['locktime']) ins = self.get_pybtc_vins(tx) outs = self.get_pybtc_outs(tx) generated_tx = mktx(ins, outs) stripped_tx = strip_witness_data(generated_tx) self.assertEqual(stripped_tx, serialized) priv0 = self.append_compressed_flag_to_privkey( tx['ins'][0]['privkeys'][0]) priv1 = self.append_compressed_flag_to_privkey( tx['ins'][0]['privkeys'][1]) priv2 = self.append_compressed_flag_to_privkey( tx['ins'][0]['privkeys'][2]) priv3 = self.append_compressed_flag_to_privkey( tx['ins'][0]['privkeys'][3]) priv4 = self.append_compressed_flag_to_privkey( tx['ins'][0]['privkeys'][4]) priv5 = self.append_compressed_flag_to_privkey( tx['ins'][0]['privkeys'][5]) witness_script = mk_multisig_script(privtopub(priv0), privtopub(priv1), privtopub(priv2), privtopub(priv3), privtopub(priv4), privtopub(priv5), 6) self.assertEqual(witness_script, tx['ins'][0]['witness_script']) sign0 = segwit_multisign(generated_tx, 0, witness_script, priv0, VIN_AMOUNT, hashcode=SIGHASH_ALL) sign1 = segwit_multisign(generated_tx, 0, witness_script, priv1, VIN_AMOUNT, hashcode=SIGHASH_NONE) sign2 = segwit_multisign(generated_tx, 0, witness_script, priv2, VIN_AMOUNT, hashcode=SIGHASH_SINGLE) sign3 = segwit_multisign(generated_tx, 0, witness_script, priv3, VIN_AMOUNT, hashcode=SIGHASH_ALL | SIGHASH_ANYONECANPAY) sign4 = segwit_multisign(generated_tx, 0, witness_script, priv4, VIN_AMOUNT, hashcode=SIGHASH_NONE | SIGHASH_ANYONECANPAY) sign5 = segwit_multisign(generated_tx, 0, witness_script, priv5, VIN_AMOUNT, hashcode=SIGHASH_SINGLE | SIGHASH_ANYONECANPAY) signed = apply_segwit_multisignatures( stripped_tx, 0, witness_script, [sign0, sign1, sign2, sign3, sign4, sign5], nested=True) self.assertEqual(signed, tx['signed']) print( '[P2WSH 6-of-6 multisig NESTED in P2SH] SIGHASH_SINGLE\SIGHASH_ALL\SIGHASH_NONE & ANYONECANPAY' )
def verify(self, sender_key): """ Validate that an order sent over by a buyer is filled out correctly. """ try: contract_dict = json.loads(json.dumps(self.contract, indent=4), object_pairs_hook=OrderedDict) del contract_dict["buyer_order"] contract_hash = digest(json.dumps(contract_dict, indent=4)) ref_hash = unhexlify( self.contract["buyer_order"]["order"]["ref_hash"]) # verify that the reference hash matches the contract and that the contract actually exists if contract_hash != ref_hash or not self.db.HashMap().get_file( ref_hash): raise Exception("Order for contract that doesn't exist") # verify the signature on the order verify_key = nacl.signing.VerifyKey(sender_key) verify_key.verify( json.dumps(self.contract["buyer_order"]["order"], indent=4), unhexlify(self.contract["buyer_order"]["signature"])) # TODO: verify the bitcoin signature after we add it # verify buyer included the correct bitcoin amount for payment price_json = self.contract["vendor_offer"]["listing"]["item"][ "price_per_unit"] if "bitcoin" in price_json: asking_price = price_json["bitcoin"] else: currency_code = price_json["fiat"]["currency_code"] fiat_price = price_json["fiat"]["price"] request = Request('https://api.bitcoinaverage.com/ticker/' + currency_code.upper() + '/last') response = urlopen(request) conversion_rate = response.read() asking_price = float("{0:.8f}".format( float(fiat_price) / float(conversion_rate))) if asking_price > self.contract["buyer_order"]["order"]["payment"][ "amount"]: raise Exception("Insuffient Payment") # verify a valid moderator was selected # TODO: handle direct payments valid_mod = False for mod in self.contract["vendor_offer"]["listing"]["moderators"]: if mod["guid"] == self.contract["buyer_order"]["order"][ "moderator"]: valid_mod = True if not valid_mod: raise Exception("Invalid moderator") # verify all the shipping fields exist if self.contract["vendor_offer"]["listing"]["metadata"][ "category"] == "physical good": shipping = self.contract["buyer_order"]["order"]["shipping"] keys = [ "ship_to", "address", "postal_code", "city", "state", "country" ] for value in map(shipping.get, keys): if value is None: raise Exception("Missing shipping field") # verify buyer ID pubkeys = self.contract["buyer_order"]["order"]["id"]["pubkeys"] keys = ["guid", "bitcoin", "encryption"] for value in map(pubkeys.get, keys): if value is None: raise Exception("Missing pubkey field") # verify redeem script chaincode = self.contract["buyer_order"]["order"]["payment"][ "chaincode"] for mod in self.contract["vendor_offer"]["listing"]["moderators"]: if mod["guid"] == self.contract["buyer_order"]["order"][ "moderator"]: masterkey_m = mod["pubkeys"]["bitcoin"]["key"] masterkey_b = self.contract["buyer_order"]["order"]["id"][ "pubkeys"]["bitcoin"] masterkey_v = bitcoin.bip32_extract_key( self.keychain.bitcoin_master_pubkey) buyer_key = derive_childkey(masterkey_b, chaincode) vendor_key = derive_childkey(masterkey_v, chaincode) moderator_key = derive_childkey(masterkey_m, chaincode) redeem_script = bitcoin.mk_multisig_script( [buyer_key, vendor_key, moderator_key], 2) if redeem_script != self.contract["buyer_order"]["order"][ "payment"]["redeem_script"]: raise Exception("Invalid redeem script") # verify the payment address if self.testnet: payment_address = bitcoin.p2sh_scriptaddr(redeem_script, 196) else: payment_address = bitcoin.p2sh_scriptaddr(redeem_script) if payment_address != self.contract["buyer_order"]["order"][ "payment"]["address"]: raise Exception("Incorrect payment address") return True except Exception: return False
def handle_notarized_order(self, msg): self.log.info('Handling notarized order') contract = msg['rawContract'] # Find Seller Data in Contract offer_data = ''.join(contract.split('\n')[8:]) index_of_seller_signature = offer_data.find( '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data)) offer_data_json = offer_data[0:index_of_seller_signature] self.log.info('Offer Data: %s', offer_data_json) offer_data_json = json.loads(str(offer_data_json)) # Find Buyer Data in Contract bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature, len(offer_data)) end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data)) bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) self.log.info('Bid Data: %s', bid_data_json) # Find Notary Data in Contract notary_data_index = offer_data.find('"Notary"', end_of_bid_index, len(offer_data)) end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE', notary_data_index, len(offer_data)) notary_data_json = "{" + offer_data[ notary_data_index:end_of_notary_index] notary_data_json = json.loads(notary_data_json) self.log.info('Notary Data: %s', notary_data_json) # Generate multi-sig address pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], notary_data_json['Notary']['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) multisig_address = scriptaddr(script) seller_GUID = offer_data_json['Seller']['seller_GUID'] order_id = bid_data_json['Buyer']['buyer_order_id'] contract_key = hashlib.sha1(str(contract)).hexdigest() hash_value = hashlib.new('ripemd160') hash_value.update(contract_key) contract_key = hash_value.hexdigest() if seller_GUID == self.transport.guid: self.log.info('I am the seller!') state = 'Waiting for Payment' merchant_order_id = random.randint(0, 1000000) while len(self.db.selectEntries("orders", {"id": order_id})) > 0: merchant_order_id = random.randint(0, 1000000) buyer_id = "%s-%s" % (bid_data_json['Buyer']['buyer_GUID'], bid_data_json['Buyer']['buyer_order_id']) self.db.insertEntry( "orders", { 'market_id': self.transport.market_id, 'contract_key': contract_key, 'order_id': merchant_order_id, 'signed_contract_body': str(contract), 'state': state, 'buyer_order_id': buyer_id, 'merchant': offer_data_json['Seller']['seller_GUID'], 'buyer': bid_data_json['Buyer']['buyer_GUID'], 'notary': notary_data_json['Notary']['notary_GUID'], 'address': multisig_address, 'shipping_address': self.transport.cryptor.decrypt( bid_data_json['Buyer']['buyer_deliveryaddr'].decode( 'hex')), 'item_price': offer_data_json['Contract'].get('item_price', 0), 'shipping_price': offer_data_json['Contract']['item_delivery'].get( 'shipping_price', 0), 'note_for_merchant': bid_data_json['Buyer']['note_for_seller'], "updated": time.time() }) self.transport.handler.send_to_client( None, { "type": "order_notify", "msg": "You just received a new order." }) else: self.log.info('I am the buyer') state = 'Need to Pay' self.db.updateEntries( "orders", { 'market_id': self.transport.market_id, 'contract_key': contract_key, 'signed_contract_body': str(contract), 'state': state, 'merchant': offer_data_json['Seller']['seller_GUID'], 'buyer': bid_data_json['Buyer']['buyer_GUID'], 'notary': notary_data_json['Notary']['notary_GUID'], 'address': multisig_address, 'shipping_address': json.dumps(self.get_shipping_address()), 'item_price': offer_data_json['Contract'].get('item_price', 0), 'shipping_price': offer_data_json['Contract']['item_delivery'].get( 'shipping_price', ''), 'note_for_merchant': bid_data_json['Buyer']['note_for_seller'], "updated": time.time() }, {'order_id': order_id}) self.transport.handler.send_to_client( None, { "type": "order_notify", "msg": "Your order requires payment now." })
def handle_bid_order(self, bid): self.log.info('Bid Order: %s', bid) new_peer = self.transport.get_crypto_peer(bid.get('merchantGUID'), bid.get('merchantURI'), bid.get('merchantPubkey')) # Generate unique id for this bid order_id = random.randint(0, 1000000) while len(self.db.selectEntries("contracts", {"id": order_id})) > 0: order_id = random.randint(0, 1000000) # Add to contract and sign contract = bid.get('rawContract') contract_stripped = "".join(contract.split('\n')) bidder_pgp_start_index = contract_stripped.find( "buyer_pgp", 0, len(contract_stripped)) bidder_pgp_end_index = contract_stripped.find("buyer_GUID", 0, len(contract_stripped)) bidder_pgp = contract_stripped[bidder_pgp_start_index + 13:bidder_pgp_end_index] self.gpg.import_keys(bidder_pgp) v = self.gpg.verify(contract) if v: self.log.info('Sellers contract verified') notary_section = {} notary_section['Notary'] = { 'notary_GUID': self.transport.guid, 'notary_BTC_uncompressed_pubkey': privkey_to_pubkey(self.transport.settings['privkey']), 'notary_pgp': self.transport.settings['PGPPubKey'], 'notary_fee': "", 'notary_order_id': order_id } offer_data_json = self.get_offer_json(contract, Orders.State.SENT) bid_data_json = self.get_buyer_json(contract, Orders.State.SENT) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], privkey_to_pubkey(self.transport.settings['privkey']) ] script = mk_multisig_script(pubkeys, 2, 3) multisig_address = scriptaddr(script) notary_section['Escrow'] = { 'multisig_address': multisig_address, 'redemption_script': script } self.log.debug('Notary: %s', notary_section) gpg = self.gpg # Prepare contract body notary_json = json.dumps(notary_section, indent=0) seg_len = 52 out_text = "\n".join(notary_json[x:x + seg_len] for x in range(0, len(notary_json), seg_len)) # Append new data to contract out_text = "%s\n%s" % (contract, out_text) signed_data = gpg.sign( out_text, passphrase='P@ssw0rd', keyid=self.transport.settings.get('PGPPubkeyFingerprint')) self.log.debug('Double-signed Contract: %s', signed_data) # Hash the contract for storage contract_key = hashlib.sha1(str(signed_data)).hexdigest() hash_value = hashlib.new('ripemd160') hash_value.update(contract_key) contract_key = hash_value.hexdigest() self.log.info('Order ID: %s', order_id) # Push buy order to DHT and node if available # self.transport.store(contract_key, str(signed_data), self.transport.guid) # self.update_listings_index() # Find Seller Data in Contract offer_data = ''.join(contract.split('\n')[8:]) index_of_seller_signature = offer_data.find( '- -----BEGIN PGP SIGNATURE-----', 0, len(offer_data)) offer_data_json = "{\"Seller\": {" + offer_data[ 0:index_of_seller_signature] self.log.info('Offer Data: %s', offer_data_json) offer_data_json = json.loads(str(offer_data_json)) # Find Buyer Data in Contract bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature, len(offer_data)) end_of_bid_index = offer_data.find('-----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data)) bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) self.log.info('Bid Data: %s', bid_data_json) buyer_order_id = "%s-%s" % (bid_data_json['Buyer']['buyer_GUID'], bid_data_json['Buyer']['buyer_order_id']) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], privkey_to_pubkey(self.transport.settings['privkey']) ] script = mk_multisig_script(pubkeys, 2, 3) multisig_address = scriptaddr(script) self.db.insertEntry( "orders", { 'market_id': self.transport.market_id, 'contract_key': contract_key, 'signed_contract_body': str(signed_data), 'state': Orders.State.NOTARIZED, 'buyer_order_id': buyer_order_id, 'order_id': order_id, 'merchant': offer_data_json['Seller']['seller_GUID'], 'buyer': bid_data_json['Buyer']['buyer_GUID'], 'address': multisig_address, 'item_price': offer_data_json['Contract'].get('item_price', 0), 'shipping_price': offer_data_json['Contract']['item_delivery'].get( 'shipping_price', ""), 'note_for_merchant': bid_data_json['Buyer']['note_for_seller'], "updated": time.time() }) # Send order to seller and buyer self.log.info('Sending notarized contract to buyer and seller %s', bid) if self.transport.handler is not None: self.transport.handler.send_to_client( None, { "type": "order_notify", "msg": "You just auto-notarized a contract." }) notarized_order = { "type": "order", "state": "Notarized", "rawContract": str(signed_data) } if new_peer is not None: new_peer.send(notarized_order) self.transport.send(notarized_order, bid_data_json['Buyer']['buyer_GUID']) self.log.info('Sent notarized contract to Seller and Buyer')
def ship_order(self, order, order_id, payment_address): self.log.info('Shipping order %s', order) del order['qrcode'] del order['item_images'] del order['total_price'] del order['item_title'] del order['item_desc'] del order['buyer_bitmessage'] del order['merchant_bitmessage'] del order['payment_address_amount'] order['state'] = Orders.State.SHIPPED order['payment_address'] = payment_address order['type'] = 'order' self.db_connection.update_entries("orders", order, {"order_id": order_id}) # Find Seller Data in Contract offer_data = ''.join(order['signed_contract_body'].split('\n')[8:]) index_of_seller_signature = offer_data.find('- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data)) offer_data_json = offer_data[0:index_of_seller_signature] self.log.info('Offer Data: %s', offer_data_json) offer_data_json = json.loads(str(offer_data_json)) # Find Buyer Data in Contract self.log.info(offer_data) bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature, len(offer_data)) end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data)) bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) self.log.info('Bid Data: %s', bid_data_json) # Find Notary Data in Contract notary_data_index = offer_data.find( '"Notary"', end_of_bid_index, len(offer_data) ) end_of_notary_index = offer_data.find( '-----BEGIN PGP SIGNATURE', notary_data_index, len(offer_data) ) notary_data_json = "{" notary_data_json += offer_data[notary_data_index:end_of_notary_index] notary_data_json = json.loads(notary_data_json) self.log.info('Notary Data: %s', notary_data_json) # TODO: Check to ensure the OBelisk server is listening first try: client = obelisk.ObeliskOfLightClient( 'tcp://%s' % self.transport.settings['obelisk'] ) seller = offer_data_json['Seller'] buyer = bid_data_json['Buyer'] notary = notary_data_json['Notary'] pubkeys = [ seller['seller_BTC_uncompressed_pubkey'], buyer['buyer_BTC_uncompressed_pubkey'], notary['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) multi_address = scriptaddr(script) def cb(ec, history, order): self.log.debug('Callback for history %s', history) private_key = self.get_signing_key(seller['seller_contract_id']) if ec is not None: self.log.error("Error fetching history: %s", ec) # TODO: Send error message to GUI return # Create unsigned transaction unspent = [row[:4] for row in history if row[4] is None] # Send all unspent outputs (everything in the address) minus # the fee total_amount = 0 inputs = [] for row in unspent: assert len(row) == 4 inputs.append( str(row[0].encode('hex')) + ":" + str(row[1]) ) value = row[3] total_amount += value # Constrain fee so we don't get negative amount to send fee = min(total_amount, 10000) send_amount = total_amount - fee payment_output = order['payment_address'] tx = mktx( inputs, [str(payment_output) + ":" + str(send_amount)] ) # Sign all the inputs signatures = [] for x in range(0, len(inputs)): ms = multisign(tx, x, script, private_key) signatures.append(ms) self.log.debug('Merchant TX Signatures: %s', signatures) order['merchant_tx'] = tx order['merchant_script'] = script order['buyer_order_id'] = buyer['buyer_order_id'] order['merchant_sigs'] = signatures self.transport.send(order, bid_data_json['Buyer']['buyer_GUID']) def get_history(): self.log.debug('Getting history') client.fetch_history( multi_address, lambda ec, history, order=order: cb(ec, history, order) ) reactor.callFromThread(get_history) except Exception as e: self.log.debug('Error: %s', e)
def add_purchase_info(self, quantity, ship_to=None, shipping_address=None, city=None, state=None, postal_code=None, country=None, moderator=None, options=None): """ Update the contract with the buyer's purchase information. """ profile = Profile(self.db).get() order_json = { "buyer_order": { "order": { "ref_hash": digest(json.dumps(self.contract, indent=4)).encode("hex"), "quantity": quantity, "id": { "guid": self.keychain.guid.encode("hex"), "pubkeys": { "guid": self.keychain.guid_signed_pubkey[64:].encode( "hex"), "bitcoin": bitcoin.bip32_extract_key( self.keychain.bitcoin_master_pubkey), "encryption": self.keychain.encryption_pubkey.encode("hex") } }, "payment": {} } } } if profile.HasField("handle"): order_json["buyer_order"]["order"]["id"][ "blockchain_id"] = profile.handle if self.contract["vendor_offer"]["listing"]["metadata"][ "category"] == "physical good": order_json["buyer_order"]["order"]["shipping"] = {} order_json["buyer_order"]["order"]["shipping"]["ship_to"] = ship_to order_json["buyer_order"]["order"]["shipping"][ "address"] = shipping_address order_json["buyer_order"]["order"]["shipping"]["city"] = city order_json["buyer_order"]["order"]["shipping"]["state"] = state order_json["buyer_order"]["order"]["shipping"][ "postal_code"] = postal_code order_json["buyer_order"]["order"]["shipping"]["country"] = country if options is not None: order_json["buyer_order"]["order"]["options"] = options if moderator: # TODO: Handle direct payments chaincode = sha256(str( random.getrandbits(256))).digest().encode("hex") order_json["buyer_order"]["order"]["payment"][ "chaincode"] = chaincode valid_mod = False for mod in self.contract["vendor_offer"]["listing"]["moderators"]: if mod["guid"] == moderator: order_json["buyer_order"]["order"]["moderator"] = moderator masterkey_m = mod["pubkeys"]["bitcoin"]["key"] valid_mod = True if not valid_mod: return False masterkey_b = bitcoin.bip32_extract_key( self.keychain.bitcoin_master_pubkey) masterkey_v = self.contract["vendor_offer"]["listing"]["id"][ "pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) vendor_key = derive_childkey(masterkey_v, chaincode) moderator_key = derive_childkey(masterkey_m, chaincode) redeem_script = bitcoin.mk_multisig_script( [buyer_key, vendor_key, moderator_key], 2) order_json["buyer_order"]["order"]["payment"][ "redeem_script"] = redeem_script if self.testnet: payment_address = bitcoin.p2sh_scriptaddr(redeem_script, 196) else: payment_address = bitcoin.p2sh_scriptaddr(redeem_script) order_json["buyer_order"]["order"]["payment"][ "address"] = payment_address price_json = self.contract["vendor_offer"]["listing"]["item"][ "price_per_unit"] if "bitcoin" in price_json: order_json["buyer_order"]["order"]["payment"][ "amount"] = price_json["bitcoin"] else: currency_code = price_json["fiat"]["currency_code"] fiat_price = price_json["fiat"]["price"] try: request = Request('https://api.bitcoinaverage.com/ticker/' + currency_code.upper() + '/last') response = urlopen(request) conversion_rate = response.read() except URLError: return False order_json["buyer_order"]["order"]["payment"]["amount"] = float( "{0:.8f}".format(float(fiat_price) / float(conversion_rate))) self.contract["buyer_order"] = order_json["buyer_order"] order = json.dumps(self.contract["buyer_order"]["order"], indent=4) # TODO: This should also be signed with the bitcoin key. It's the only way a moderator # will have to link this contract to a bitcoin transaction. self.contract["buyer_order"]["signature"] = \ self.keychain.signing_key.sign(order, encoder=nacl.encoding.HexEncoder)[:128] return (self.contract["buyer_order"]["order"]["payment"]["address"], order_json["buyer_order"]["order"]["payment"]["amount"])
def client_release_payment(self, socket_handler, msg): self.log.info('Releasing payment to Merchant %s', msg) order = self.market.orders.get_order(msg['orderId']) contract = order['signed_contract_body'] # Find Seller Data in Contract offer_data = ''.join(contract.split('\n')[8:]) index_of_seller_signature = offer_data.find( '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data)) offer_data_json = offer_data[0:index_of_seller_signature] offer_data_json = json.loads(offer_data_json) self.log.info('Offer Data: %s', offer_data_json) # Find Buyer Data in Contract bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature, len(offer_data)) end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE', bid_data_index, len(offer_data)) bid_data_json = "{" bid_data_json += offer_data[bid_data_index:end_of_bid_index] bid_data_json = json.loads(bid_data_json) # Find Notary Data in Contract notary_data_index = offer_data.find('"Notary"', end_of_bid_index, len(offer_data)) end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE', notary_data_index, len(offer_data)) notary_data_json = "{" notary_data_json += offer_data[notary_data_index:end_of_notary_index] notary_data_json = json.loads(notary_data_json) self.log.info('Notary Data: %s', notary_data_json) try: client = obelisk.ObeliskOfLightClient( 'tcp://obelisk.coinkite.com:9091') seller = offer_data_json['Seller'] buyer = bid_data_json['Buyer'] notary = notary_data_json['Notary'] pubkeys = [ seller['seller_BTC_uncompressed_pubkey'], buyer['buyer_BTC_uncompressed_pubkey'], notary['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) multi_address = scriptaddr(script) def cb(ec, history, order): settings = self.market.get_settings() private_key = settings.get('privkey') if ec is not None: self.log.error("Error fetching history: %s", ec) # TODO: Send error message to GUI return # Create unsigned transaction unspent = [row[:4] for row in history if row[4] is None] # Send all unspent outputs (everything in the address) minus # the fee total_amount = 0 inputs = [] for row in unspent: assert len(row) == 4 inputs.append( str(row[0].encode('hex')) + ":" + str(row[1])) value = row[3] total_amount += value # Constrain fee so we don't get negative amount to send fee = min(total_amount, 10000) send_amount = total_amount - fee payment_output = order['payment_address'] tx = mktx(inputs, [str(payment_output) + ":" + str(send_amount)]) signatures = [] for x in range(0, len(inputs)): ms = multisign(tx, x, script, private_key) signatures.append(ms) print signatures self.market.release_funds_to_merchant(buyer['buyer_order_id'], tx, script, signatures, order.get('merchant')) def get_history(): client.fetch_history( multi_address, lambda ec, history, order=order: cb(ec, history, order)) reactor.callFromThread(get_history) except Exception as e: self.log.error('%s', e)
def get_order(self, order_id, by_buyer_id=False): if not by_buyer_id: _order = self.db.selectEntries("orders", {"order_id": order_id})[0] else: _order = self.db.selectEntries("orders", {"buyer_order_id": order_id})[0] total_price = 0 offer_data_json = self.get_offer_json(_order['signed_contract_body'], _order['state']) buyer_data_json = self.get_buyer_json(_order['signed_contract_body'], _order['state']) if _order['state'] != Orders.State.SENT: notary_json = self.get_notary_json(_order['signed_contract_body'], _order['state']) notary = notary_json['Notary']['notary_GUID'] else: notary = "" if _order['state'] in (Orders.State.NEED_TO_PAY, Orders.State.NOTARIZED, Orders.State.WAITING_FOR_PAYMENT, Orders.State.PAID, Orders.State.BUYER_PAID, Orders.State.SHIPPED): def cb(total): if self.transport.handler is not None: self.transport.handler.send_to_client( None, { "type": "order_payment_amount", "value": total }) pubkeys = [ offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'], buyer_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'], notary_json['Notary']['notary_BTC_uncompressed_pubkey'] ] script = mk_multisig_script(pubkeys, 2, 3) payment_address = scriptaddr(script) trust.get_unspent(payment_address, cb) if 'shipping_price' in _order: shipping_price = _order[ 'shipping_price'] if _order['shipping_price'] != '' else 0 else: shipping_price = 0 try: total_price = str((Decimal(shipping_price) + Decimal(_order['item_price']))) \ if 'item_price' in _order else _order['item_price'] except Exception as e: self.log.error('Probably not a number %s', e) # Generate QR code qr = self.get_qr_code(offer_data_json['Contract']['item_title'], _order['address'], total_price) merchant_bitmessage = offer_data_json.get('Seller', '').get('seller_Bitmessage') buyer_bitmessage = buyer_data_json.get('Buyer', '').get('buyer_Bitmessage') # Get order prototype object before storing order = { "id": _order['id'], "state": _order.get('state'), "address": _order.get('address'), "buyer": _order.get('buyer'), "merchant": _order.get('merchant'), "order_id": _order.get('order_id'), "item_price": _order.get('item_price'), "shipping_price": _order.get('shipping_price'), "shipping_address": str(_order.get('shipping_address')), "total_price": total_price, "merchant_bitmessage": merchant_bitmessage, "buyer_bitmessage": buyer_bitmessage, "notary": notary, "payment_address": _order.get('payment_address'), "payment_address_amount": _order.get('payment_address_amount'), "qrcode": 'data:image/png;base64,' + qr, "item_title": offer_data_json['Contract']['item_title'], "signed_contract_body": _order.get('signed_contract_body'), "note_for_merchant": _order.get('note_for_merchant'), "updated": _order.get('updated') } if 'item_images' in offer_data_json['Contract'] and offer_data_json[ 'Contract']['item_images'] != {}: order['item_image'] = offer_data_json['Contract']['item_images'] else: order['item_image'] = "img/no-photo.png" self.log.datadump('FULL ORDER: %s', order) return order