def add_signature(self, nick, sigb64): if nick not in self.nonrespondants: debug('add_signature => nick=' + nick + ' not in nonrespondants ' + str(self.nonrespondants)) return sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False txhex = btc.serialize(self.latest_tx) #batch retrieval of utxo data utxo = {} ctr = 0 for index, ins in enumerate(self.latest_tx['ins']): utxo_for_checking = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if ins['script'] != '' or utxo_for_checking in self.input_utxos.keys(): continue utxo[ctr] = [index, utxo_for_checking] ctr += 1 utxo_data = common.bc_interface.query_utxo_set([x[1] for x in utxo.values()]) #insert signatures for i,u in utxo.iteritems(): if utxo_data[i] == None: continue sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (u[0])) self.latest_tx['ins'][u[0]]['script'] = sig inserted_sig = True #check if maker has sent everything possible self.utxos[nick].remove(u[1]) if len(self.utxos[nick]) == 0: debug('nick = ' + nick + ' sent all sigs, removing from nonrespondant list') self.nonrespondants.remove(nick) break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return self.end_timeout_thread = True self.all_responded = True with self.timeout_lock: self.timeout_lock.notify() debug('all makers have sent their signatures') for index, ins in enumerate(self.latest_tx['ins']): #remove placeholders if ins['script'] == 'deadbeef': ins['script'] = '' if self.finishcallback != None: self.finishcallback(self)
def reorder_sigs( self, sigs ): reorderedSigs = [] stx = bitcoin.serialize( self.tx ) for pub in self.pubs: for sig in sigs: if bitcoin.verify_tx_input( stx, 0, self.redeemScript, sig, pub ): reorderedSigs.append( sig ) break return reorderedSigs
def add_signature(self, sigb64): sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False txhex = btc.serialize(self.latest_tx) #batch retrieval of utxo data utxo = {} ctr = 0 for index, ins in enumerate(self.latest_tx['ins']): utxo_for_checking = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) if ins['script'] != '' or utxo_for_checking in self.input_utxos.keys(): continue utxo[ctr] = [index, utxo_for_checking] ctr += 1 utxo_data = common.bc_interface.query_utxo_set([x[1] for x in utxo.values()]) #insert signatures for i,u in utxo.iteritems(): if utxo_data[i] == None: continue sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (u[0])) self.latest_tx['ins'][u[0]]['script'] = sig inserted_sig = True break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return debug('the entire tx is signed, ready to pushtx()') txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) #TODO send to a random maker or push myself #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) self.txid = common.bc_interface.pushtx(txhex) debug('pushed tx ' + str(self.txid)) if self.txid == None: debug('unable to pushtx') if self.finishcallback != None: self.finishcallback(self)
def add_signature(self, sigb64): sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): if ins['script'] != '': continue utxo = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) utxo_data = common.bc_interface.query_utxo_set(utxo) if utxo_data[0] == None: continue sig_good = btc.verify_tx_input(tx, index, utxo_data[0]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (index)) ins['script'] = sig inserted_sig = True break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return debug('the entire tx is signed, ready to pushtx()') txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) #TODO send to a random maker or push myself #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) txid = common.bc_interface.pushtx(txhex) debug('pushed tx ' + str(txid)) if self.finishcallback != None: self.finishcallback(self)
def add_signature(self, sigb64): sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False tx = btc.serialize(self.latest_tx) for index, ins in enumerate(self.latest_tx['ins']): if ins['script'] != '': continue utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) utxo_data = common.bc_interface.query_utxo_set(utxo) if utxo_data[0] == None: continue sig_good = btc.verify_tx_input(tx, index, utxo_data[0]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (index)) ins['script'] = sig inserted_sig = True break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return debug('the entire tx is signed, ready to pushtx()') txhex = btc.serialize(self.latest_tx) debug('\n' + txhex) #TODO send to a random maker or push myself #self.msgchan.push_tx(self.active_orders.keys()[0], txhex) txid = common.bc_interface.pushtx(txhex) debug('pushed tx ' + str(txid)) if self.finishcallback != None: self.finishcallback(self)
def add_signature(self, nick, sigb64): if nick not in self.nonrespondants: debug('add_signature => nick=' + nick + ' not in nonrespondants ' + str(self.nonrespondants)) return sig = base64.b64decode(sigb64).encode('hex') inserted_sig = False txhex = btc.serialize(self.latest_tx) #batch retrieval of utxo data utxo = {} ctr = 0 for index, ins in enumerate(self.latest_tx['ins']): utxo_for_checking = ins['outpoint']['hash'] + ':' + str( ins['outpoint']['index']) if ins['script'] != '' or utxo_for_checking in self.input_utxos.keys( ): continue utxo[ctr] = [index, utxo_for_checking] ctr += 1 utxo_data = common.bc_interface.query_utxo_set( [x[1] for x in utxo.values()]) #insert signatures for i, u in utxo.iteritems(): if utxo_data[i] == None: continue sig_good = btc.verify_tx_input(txhex, u[0], utxo_data[i]['script'], *btc.deserialize_script(sig)) if sig_good: debug('found good sig at index=%d' % (u[0])) self.latest_tx['ins'][u[0]]['script'] = sig inserted_sig = True #check if maker has sent everything possible self.utxos[nick].remove(u[1]) if len(self.utxos[nick]) == 0: debug('nick = ' + nick + ' sent all sigs, removing from nonrespondant list') self.nonrespondants.remove(nick) break if not inserted_sig: debug('signature did not match anything in the tx') #TODO what if the signature doesnt match anything # nothing really to do except drop it, carry on and wonder why the # other guy sent a failed signature tx_signed = True for ins in self.latest_tx['ins']: if ins['script'] == '': tx_signed = False if not tx_signed: return self.end_timeout_thread = True self.all_responded = True with self.timeout_lock: self.timeout_lock.notify() debug('all makers have sent their signatures') for index, ins in enumerate(self.latest_tx['ins']): #remove placeholders if ins['script'] == 'deadbeef': ins['script'] = '' if self.finishcallback != None: self.finishcallback(self)
def accept_receipt(self, ws, blockchain, receipt_json=None): """ Process the final receipt sent over by the buyer. If valid, broadcast the transaction to the bitcoin network. """ self.ws = ws self.blockchain = blockchain try: if receipt_json: self.contract["buyer_receipt"] = json.loads( receipt_json, object_pairs_hook=OrderedDict) contract_dict = json.loads(json.dumps(self.contract, indent=4), object_pairs_hook=OrderedDict) del contract_dict["buyer_receipt"] contract_hash = digest(json.dumps(contract_dict, indent=4)).encode("hex") ref_hash = self.contract["buyer_receipt"]["receipt"]["ref_hash"] if ref_hash != contract_hash: raise Exception("Order number doesn't match") # The buyer may have sent over this whole contract, make sure the data we added wasn't manipulated. verify_key = self.keychain.signing_key.verify_key verify_key.verify( json.dumps( self.contract["vendor_order_confirmation"]["invoice"], indent=4), unhexlify( self.contract["vendor_order_confirmation"]["signature"])) order_id = self.contract["vendor_order_confirmation"]["invoice"][ "ref_hash"] outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id)) payout_address = self.contract["vendor_order_confirmation"][ "invoice"]["payout"]["address"] redeem_script = str(self.contract["buyer_order"]["order"] ["payment"]["redeem_script"]) for output in outpoints: del output["value"] value = self.contract["vendor_order_confirmation"]["invoice"][ "payout"]["value"] outs = [{'value': value, 'address': payout_address}] tx = bitcoin.mktx(outpoints, outs) chaincode = self.contract["buyer_order"]["order"]["payment"][ "chaincode"] masterkey_b = self.contract["buyer_order"]["order"]["id"][ "pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) vendor_sigs = self.contract["vendor_order_confirmation"][ "invoice"]["payout"]["signature(s)"] buyer_sigs = self.contract["buyer_receipt"]["receipt"]["payout"][ "signature(s)"] for index in range(0, len(outpoints)): for s in vendor_sigs: if s["input_index"] == index: sig1 = str(s["signature"]) for s in buyer_sigs: if s["input_index"] == index: sig2 = str(s["signature"]) if bitcoin.verify_tx_input(tx, index, redeem_script, sig2, buyer_key): tx = bitcoin.apply_multisignatures(tx, index, str(redeem_script), sig1, sig2) else: raise Exception("Buyer sent invalid signature") d = defer.Deferred() def on_broadcast_complete(success): if success: d.callback(order_id) else: d.callback(False) def on_validate(success): def on_fetch(ec, result): if ec: # if it's not in the blockchain, let's try broadcasting it. self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx, cb=on_broadcast_complete) else: d.callback(order_id) if success: # broadcast anyway but don't wait for callback self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx) d.callback(order_id) else: # check to see if the tx is already in the blockchain self.blockchain.fetch_transaction( unhexlify(bitcoin.txhash(tx)), on_fetch) if "txid" in self.contract["buyer_receipt"]["receipt"]["payout"] \ and bitcoin.txhash(tx) == self.contract["buyer_receipt"]["receipt"]["payout"]["txid"]: # check mempool and blockchain for tx self.blockchain.validate(tx, cb=on_validate) else: # try broadcasting self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx, cb=on_broadcast_complete) # TODO: update db and file system if successful # TODO: broadcast over websocket return d except Exception: return defer.succeed(False)
def add_receipt(self, received, libbitcoin_client, feedback=None, quality=None, description=None, delivery_time=None, customer_service=None, review="", dispute=False, claim=None, payout=True): """ Add the final piece of the contract that appends the review and payout transaction. """ self.blockchain = libbitcoin_client receipt_json = { "buyer_receipt": { "receipt": { "ref_hash": digest(json.dumps(self.contract, indent=4)).encode("hex"), "listing": { "received": received, "listing_hash": self.contract["buyer_order"]["order"]["ref_hash"] }, "dispute": { "dispute": dispute } } } } if None not in (feedback, quality, description, delivery_time, customer_service): receipt_json["buyer_receipt"]["receipt"]["rating"] = {} receipt_json["buyer_receipt"]["receipt"]["rating"][ "feedback"] = feedback receipt_json["buyer_receipt"]["receipt"]["rating"][ "quality"] = quality receipt_json["buyer_receipt"]["receipt"]["rating"][ "description"] = description receipt_json["buyer_receipt"]["receipt"]["rating"][ "delivery_time"] = delivery_time receipt_json["buyer_receipt"]["receipt"]["rating"][ "customer_service"] = customer_service receipt_json["buyer_receipt"]["receipt"]["rating"][ "review"] = review if payout: order_id = self.contract["vendor_order_confirmation"]["invoice"][ "ref_hash"] outpoints = pickle.loads( self.db.Purchases().get_outpoint(order_id)) payout_address = self.contract["vendor_order_confirmation"][ "invoice"]["payout"]["address"] redeem_script = str(self.contract["buyer_order"]["order"] ["payment"]["redeem_script"]) for output in outpoints: del output["value"] value = self.contract["vendor_order_confirmation"]["invoice"][ "payout"]["value"] outs = [{'value': value, 'address': payout_address}] tx = bitcoin.mktx(outpoints, outs) signatures = [] chaincode = self.contract["buyer_order"]["order"]["payment"][ "chaincode"] masterkey_b = bitcoin.bip32_extract_key( self.keychain.bitcoin_master_privkey) buyer_priv = derive_childkey(masterkey_b, chaincode, bitcoin.MAINNET_PRIVATE) masterkey_v = self.contract["vendor_offer"]["listing"]["id"][ "pubkeys"]["bitcoin"] vendor_key = derive_childkey(masterkey_v, chaincode) valid_inputs = 0 for index in range(0, len(outpoints)): sig = bitcoin.multisign(tx, index, redeem_script, buyer_priv) signatures.append({"input_index": index, "signature": sig}) for s in self.contract["vendor_order_confirmation"]["invoice"][ "payout"]["signature(s)"]: if s["input_index"] == index: if bitcoin.verify_tx_input(tx, index, redeem_script, s["signature"], vendor_key): tx = bitcoin.apply_multisignatures( tx, index, str(redeem_script), sig, str(s["signature"])) valid_inputs += 1 receipt_json["buyer_receipt"]["receipt"]["payout"] = {} if valid_inputs == len(outpoints): self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx) receipt_json["buyer_receipt"]["receipt"]["payout"][ "txid"] = bitcoin.txhash(tx) receipt_json["buyer_receipt"]["receipt"]["payout"][ "signature(s)"] = signatures receipt_json["buyer_receipt"]["receipt"]["payout"]["value"] = value if claim: receipt_json["buyer_receipt"]["receipt"]["dispute"][ "claim"] = claim receipt = json.dumps(receipt_json["buyer_receipt"]["receipt"], indent=4) receipt_json["buyer_receipt"]["signature"] = \ self.keychain.signing_key.sign(receipt, encoder=nacl.encoding.HexEncoder)[:128] self.contract["buyer_receipt"] = receipt_json["buyer_receipt"]
def accept_receipt(self, ws, blockchain, receipt_json=None): """ Process the final receipt sent over by the buyer. If valid, broadcast the transaction to the bitcoin network. """ self.ws = ws self.blockchain = blockchain try: if receipt_json: self.contract["buyer_receipt"] = json.loads(receipt_json, object_pairs_hook=OrderedDict) contract_dict = json.loads(json.dumps(self.contract, indent=4), object_pairs_hook=OrderedDict) del contract_dict["buyer_receipt"] contract_hash = digest(json.dumps(contract_dict, indent=4)).encode("hex") ref_hash = self.contract["buyer_receipt"]["receipt"]["ref_hash"] if ref_hash != contract_hash: raise Exception("Order number doesn't match") # The buyer may have sent over this whole contract, make sure the data we added wasn't manipulated. verify_key = self.keychain.signing_key.verify_key verify_key.verify(json.dumps(self.contract["vendor_order_confirmation"]["invoice"], indent=4), unhexlify(self.contract["vendor_order_confirmation"]["signature"])) order_id = self.contract["vendor_order_confirmation"]["invoice"]["ref_hash"] outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id)) payout_address = self.contract["vendor_order_confirmation"]["invoice"]["payout"]["address"] redeem_script = str(self.contract["buyer_order"]["order"]["payment"]["redeem_script"]) for output in outpoints: del output["value"] value = self.contract["vendor_order_confirmation"]["invoice"]["payout"]["value"] outs = [{'value': value, 'address': payout_address}] tx = bitcoin.mktx(outpoints, outs) chaincode = self.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = self.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) vendor_sigs = self.contract["vendor_order_confirmation"]["invoice"]["payout"]["signature(s)"] buyer_sigs = self.contract["buyer_receipt"]["receipt"]["payout"]["signature(s)"] for index in range(0, len(outpoints)): for s in vendor_sigs: if s["input_index"] == index: sig1 = str(s["signature"]) for s in buyer_sigs: if s["input_index"] == index: sig2 = str(s["signature"]) if bitcoin.verify_tx_input(tx, index, redeem_script, sig2, buyer_key): tx = bitcoin.apply_multisignatures(tx, index, str(redeem_script), sig1, sig2) else: raise Exception("Buyer sent invalid signature") d = defer.Deferred() def on_broadcast_complete(success): if success: d.callback(order_id) else: d.callback(False) def on_validate(success): def on_fetch(ec, result): if ec: # if it's not in the blockchain, let's try broadcasting it. self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx, cb=on_broadcast_complete) else: d.callback(order_id) if success: # broadcast anyway but don't wait for callback self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx) d.callback(order_id) else: # check to see if the tx is already in the blockchain self.blockchain.fetch_transaction(unhexlify(bitcoin.txhash(tx)), on_fetch) if "txid" in self.contract["buyer_receipt"]["receipt"]["payout"] \ and bitcoin.txhash(tx) == self.contract["buyer_receipt"]["receipt"]["payout"]["txid"]: # check mempool and blockchain for tx self.blockchain.validate(tx, cb=on_validate) else: # try broadcasting self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx, cb=on_broadcast_complete) # TODO: update db and file system if successful # TODO: broadcast over websocket return d except Exception: return defer.succeed(False)
def add_receipt(self, received, libbitcoin_client, feedback=None, quality=None, description=None, delivery_time=None, customer_service=None, review="", dispute=False, claim=None, payout=True): """ Add the final piece of the contract that appends the review and payout transaction. """ self.blockchain = libbitcoin_client receipt_json = { "buyer_receipt": { "receipt": { "ref_hash": digest(json.dumps(self.contract, indent=4)).encode("hex"), "listing": { "received": received, "listing_hash": self.contract["buyer_order"]["order"]["ref_hash"] }, "dispute": { "dispute": dispute } } } } if None not in (feedback, quality, description, delivery_time, customer_service): receipt_json["buyer_receipt"]["receipt"]["rating"] = {} receipt_json["buyer_receipt"]["receipt"]["rating"]["feedback"] = feedback receipt_json["buyer_receipt"]["receipt"]["rating"]["quality"] = quality receipt_json["buyer_receipt"]["receipt"]["rating"]["description"] = description receipt_json["buyer_receipt"]["receipt"]["rating"]["delivery_time"] = delivery_time receipt_json["buyer_receipt"]["receipt"]["rating"]["customer_service"] = customer_service receipt_json["buyer_receipt"]["receipt"]["rating"]["review"] = review if payout: order_id = self.contract["vendor_order_confirmation"]["invoice"]["ref_hash"] outpoints = pickle.loads(self.db.Purchases().get_outpoint(order_id)) payout_address = self.contract["vendor_order_confirmation"]["invoice"]["payout"]["address"] redeem_script = str(self.contract["buyer_order"]["order"]["payment"]["redeem_script"]) for output in outpoints: del output["value"] value = self.contract["vendor_order_confirmation"]["invoice"]["payout"]["value"] outs = [{'value': value, 'address': payout_address}] tx = bitcoin.mktx(outpoints, outs) signatures = [] chaincode = self.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = bitcoin.bip32_extract_key(self.keychain.bitcoin_master_privkey) buyer_priv = derive_childkey(masterkey_b, chaincode, bitcoin.MAINNET_PRIVATE) masterkey_v = self.contract["vendor_offer"]["listing"]["id"]["pubkeys"]["bitcoin"] vendor_key = derive_childkey(masterkey_v, chaincode) valid_inputs = 0 for index in range(0, len(outpoints)): sig = bitcoin.multisign(tx, index, redeem_script, buyer_priv) signatures.append({"input_index": index, "signature": sig}) for s in self.contract["vendor_order_confirmation"]["invoice"]["payout"]["signature(s)"]: if s["input_index"] == index: if bitcoin.verify_tx_input(tx, index, redeem_script, s["signature"], vendor_key): tx = bitcoin.apply_multisignatures(tx, index, str(redeem_script), sig, str(s["signature"])) valid_inputs += 1 receipt_json["buyer_receipt"]["receipt"]["payout"] = {} if valid_inputs == len(outpoints): self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx)) self.blockchain.broadcast(tx) receipt_json["buyer_receipt"]["receipt"]["payout"]["txid"] = bitcoin.txhash(tx) receipt_json["buyer_receipt"]["receipt"]["payout"]["signature(s)"] = signatures receipt_json["buyer_receipt"]["receipt"]["payout"]["value"] = value if claim: receipt_json["buyer_receipt"]["receipt"]["dispute"]["claim"] = claim receipt = json.dumps(receipt_json["buyer_receipt"]["receipt"], indent=4) receipt_json["buyer_receipt"]["signature"] = \ self.keychain.signing_key.sign(receipt, encoder=nacl.encoding.HexEncoder)[:128] self.contract["buyer_receipt"] = receipt_json["buyer_receipt"]