Esempio n. 1
0
    def release_funds(self, order_id):
        """
        This function should be called to release funds from a disputed contract after
        the moderator has resolved the dispute and provided his signature.
        """
        if os.path.exists(DATA_FOLDER + "purchases/in progress/" + order_id + ".json"):
            file_path = DATA_FOLDER + "purchases/trade receipts/" + order_id + ".json"
            outpoints = pickle.loads(self.db.Purchases().get_outpoint(order_id))
        elif os.path.exists(DATA_FOLDER + "store/contracts/in progress/" + order_id + ".json"):
            file_path = DATA_FOLDER + "store/contracts/in progress/" + order_id + ".json"
            outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id))

        with open(file_path, 'r') as filename:
            contract = json.load(filename, object_pairs_hook=OrderedDict)

        vendor_address = contract["vendor_order_confirmation"]["invoice"]["payout"]["address"]
        buyer_address = contract["buyer_order"]["order"]["refund_address"]

        for moderator in contract["vendor_offer"]["listing"]["moderators"]:
            if moderator["guid"] == contract["buyer_order"]["order"]["moderator"]:
                masterkey_m = moderator["pubkeys"]["bitcoin"]["key"]

        outputs = []

        outputs.append({'value': contract["dispute_resolution"]["resolution"]["moderator_fee"],
                        'address': contract["dispute_resolution"]["resolution"]["moderator_address"]})

        if "buyer_payout" in contract["dispute_resolution"]["resolution"]:
            outputs.append({'value': contract["dispute_resolution"]["resolution"]["buyer_payout"],
                            'address': buyer_address})

        if "vendor_payout" in contract["dispute_resolution"]["resolution"]:
            outputs.append({'value': contract["dispute_resolution"]["resolution"]["vendor_payout"],
                            'address': vendor_address})

        tx = bitcoin.mktx(outpoints, outputs)
        signatures = []
        chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"]
        redeem_script = str(contract["buyer_order"]["order"]["payment"]["redeem_script"])
        masterkey = bitcoin.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey)
        childkey = derive_childkey(masterkey, chaincode, bitcoin.MAINNET_PRIVATE)

        mod_key = derive_childkey(masterkey_m, chaincode)

        valid_inputs = 0
        for index in range(0, len(outpoints)):
            sig = bitcoin.multisign(tx, index, redeem_script, childkey)
            signatures.append({"input_index": index, "signature": sig})
            for s in contract["dispute_resolution"]["resolution"]["tx_signatures"]:
                if s["input_index"] == index:
                    if bitcoin.verify_tx_input(tx, index, redeem_script, s["signature"], mod_key):
                        tx = bitcoin.apply_multisignatures(tx, index, str(redeem_script),
                                                           sig, str(s["signature"]))
                        valid_inputs += 1

        if valid_inputs == len(outpoints):
            self.log.info("Broadcasting payout tx %s to network" % bitcoin.txhash(tx))
            self.protocol.multiplexer.blockchain.broadcast(tx)
        else:
            raise Exception("Failed to reconstruct transaction with moderator signature.")
Esempio n. 2
0
            def history_fetched(ec, history):
                outpoints = []
                satoshis = 0
                outputs = []
                dispute_json = {"dispute_resolution": {"resolution": {}}}
                if ec:
                    print ec
                else:
                    for tx_type, txid, i, height, value in history:  # pylint: disable=W0612
                        if tx_type == obelisk.PointIdent.Output:
                            satoshis += value
                            outpoint = txid.encode("hex") + ":" + str(i)
                            if outpoint not in outpoints:
                                outpoints.append(outpoint)

                    satoshis -= TRANSACTION_FEE
                    moderator_fee = round(float(moderator_percentage * satoshis))
                    satoshis -= moderator_fee

                    outputs.append({'value': moderator_fee, 'address': moderator_address})
                    dispute_json["dispute_resolution"]["resolution"]["moderator_address"] = moderator_address
                    dispute_json["dispute_resolution"]["resolution"]["moderator_fee"] = moderator_fee
                    dispute_json["dispute_resolution"]["resolution"]["transaction_fee"] = TRANSACTION_FEE
                    if float(buyer_percentage) > 0:
                        amt = round(float(buyer_percentage * satoshis))
                        dispute_json["dispute_resolution"]["resolution"]["buyer_payout"] = amt
                        outputs.append({'value': amt,
                                        'address': buyer_address})
                    if float(vendor_percentage) > 0:
                        amt = round(float(vendor_percentage * satoshis))
                        dispute_json["dispute_resolution"]["resolution"]["vendor_payout"] = amt
                        outputs.append({'value': amt,
                                        'address': vendor_address})
                    tx = bitcoin.mktx(outpoints, outputs)
                    chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"]
                    redeem_script = str(contract["buyer_order"]["order"]["payment"]["redeem_script"])
                    masterkey_m = bitcoin.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey)
                    moderator_priv = derive_childkey(masterkey_m, chaincode, bitcoin.MAINNET_PRIVATE)
                    signatures = []
                    for index in range(0, len(outpoints)):
                        sig = bitcoin.multisign(tx, index, redeem_script, moderator_priv)
                        signatures.append({"input_index": index, "signature": sig})
                    dispute_json["dispute_resolution"]["resolution"]["order_id"] = order_id
                    dispute_json["dispute_resolution"]["resolution"]["tx_signatures"] = signatures
                    dispute_json["dispute_resolution"]["resolution"]["claim"] = self.db.Cases().get_claim(order_id)
                    dispute_json["dispute_resolution"]["resolution"]["decision"] = resolution
                    dispute_json["dispute_resolution"]["signature"] = \
                        base64.b64encode(KeyChain(self.db).signing_key.sign(json.dumps(
                            dispute_json["dispute_resolution"]["resolution"]))[:64])

                    def get_node(node_to_ask, recipient_guid, public_key):
                        def parse_response(response):
                            if not response[0]:
                                self.send_message(Node(unhexlify(recipient_guid)),
                                                  public_key,
                                                  objects.PlaintextMessage.Type.Value("DISPUTE_CLOSE"),
                                                  dispute_json,
                                                  order_id,
                                                  store_only=True)

                        if node_to_ask:
                            skephem = PrivateKey.generate()
                            pkephem = skephem.public_key.encode(nacl.encoding.RawEncoder)
                            box = Box(skephem, PublicKey(public_key, nacl.encoding.HexEncoder))
                            nonce = nacl.utils.random(Box.NONCE_SIZE)
                            ciphertext = box.encrypt(json.dumps(dispute_json, indent=4), nonce)
                            d = self.protocol.callDisputeClose(node_to_ask, pkephem, ciphertext)
                            return d.addCallback(parse_response)
                        else:
                            return parse_response([False])

                    self.kserver.resolve(unhexlify(vendor_guid)).addCallback(get_node, vendor_guid, vendor_enc_key)
                    self.kserver.resolve(unhexlify(buyer_guid)).addCallback(get_node, buyer_guid, buyer_enc_key)
                    self.db.Cases().update_status(order_id, 1)