Example #1
0
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))
Example #2
0
def cosign(master_xpriv, recovery_package):
    raw_txs = recovery_package['txs']
    print "Signing %d transactions" % len(raw_txs)
    for tx_index, tx_raw in enumerate(raw_txs):
        print "\nTransaction #", tx_index
        hex_tx = tx_raw['bytes']
        tx = bitcoin.transaction.deserialize(unhexlify(hex_tx))
        keypaths = tx_raw['input_paths']
        keypairs = {}
        for p in keypaths:
            xpriv = seedlib.bip32_child(master_xpriv, p)
            priv = bitcoin.bip32_extract_key(xpriv)
            pub = bitcoin.privtopub(priv)
            keypairs[pub] = priv
        for i, inp in enumerate(tx['ins']):
            (sigs, pubkeys, redeemScript, M,
             N) = multisig.decode_multisig_script(inp['script'])
            for p in pubkeys:
                if p in keypairs:
                    sig_new = bitcoin.multisign(hex_tx, i, redeemScript,
                                                keypairs[p])
                    sigs.append(sig_new)
                    tx_new = bitcoin.apply_multisignatures(
                        unhexlify(hex_tx), i, redeemScript, sigs)
                    print "Signed transaction %d input %d" % (tx_index, i)

                    # replace tx with newly signed transaction
                    hex_tx = hexlify(tx_new)
        recovery_package['txs'][tx_index]['bytes'] = hex_tx
    return recovery_package
Example #3
0
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
Example #4
0
	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)
Example #5
0
 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)
Example #6
0
            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'])
Example #7
0
def tx_sign_multisig(blockstack_tx,
                     idx,
                     redeem_script,
                     private_keys,
                     hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2sh multisig input.
    Return the signed transaction
    """

    # sign in the right order
    privs = dict([
        (virtualchain.BitcoinPrivateKey(str(pk_str)).public_key().to_hex(),
         str(pk_str)) for pk_str in private_keys
    ])
    m, public_keys = virtualchain.parse_multisig_redeemscript(
        str(redeem_script))

    used_keys = []
    sigs = []

    for ki in xrange(0, len(public_keys)):
        if not privs.has_key(public_keys[ki]):
            continue

        if len(used_keys) == m:
            break

        assert public_keys[
            ki] not in used_keys, "Tried to reuse key %s" % public_keys[ki]

        pk_str = privs[public_keys[ki]]
        used_keys.append(public_keys[ki])

        pk_hex = virtualchain.BitcoinPrivateKey(str(pk_str)).to_hex()
        sig = bitcoin.multisign(blockstack_tx,
                                idx,
                                str(redeem_script),
                                pk_hex,
                                hashcode=hashcode)
        sigs.append(sig)

    assert len(used_keys) == m, "Missing private keys"

    return bitcoin.apply_multisignatures(blockstack_tx, idx,
                                         str(redeem_script), sigs)
Example #8
0
def main():
    locktime = args.locktime
    privkey = args.privkey
    address = args.address

    script = getRedeemScript(locktime, privkey)
    ins, balance = getBalance(scriptaddr(script, 50))
    len_inputs = len(ins)

    tx = ''

    if balance > 0 and check_addr(address) and is_privkey(privkey):
        # Fee
        fee = round(base_fee + fee_per_input * len_inputs, 8)

        # Outputs
        out_value = int((balance - fee) * COIN)
        outs = [{'address' : address, 'value' : out_value}]

        # Make unsigned transaction
        tx = mktx(ins, outs)

        # Append nLockTime and reset nSequence
        unpacked = deserialize(tx)
        unpacked['locktime'] = locktime
        for i in range(len_inputs):
            unpacked['ins'][i]['sequence'] = 0
        tx = serialize(unpacked)

        # get all signatures
        sigs = []
        for i in range(len_inputs):
            sigs.append(multisign(tx, i, script, privkey))

        # sign inputs
        unpacked = deserialize(tx)
        for i in range(len_inputs):
            unpacked['ins'][i]['script'] = getLen(sigs[i]) + sigs[i]
            unpacked['ins'][i]['script'] += getLen(script) + script
        tx = serialize(unpacked)

    print('> BALANCE (%s): %f' % (scriptaddr(script, 50), balance))

    if len(tx) > 0:
        txid = broadcast(tx)
        print('> RESPONSE: %s' % txid.text)
Example #9
0
            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')
                )
Example #10
0
            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'))
Example #11
0
    def sign( self, privkey ):
	if( self.tx is None or self.redeemScript is None ):
            raise RuntimeError( "You have not entered in a tx to sign" )

        try:
            pub = bitcoin.privtopub( privkey )
            if pub not in self.pubs:
                pub = bitcoin.encode_pubkey( pub, 'hex_compressed' )
                if pub not in self.pubs: 
                    raise ValueError( "Key doesn't match any public keys in redeemscript" )
            
            stx = bitcoin.serialize( self.tx )
            sigs = self.extract_sigs( self.tx ) 
            sigs.append( bitcoin.multisign( stx, 0, self.redeemScript, privkey ) )
            sigs = self.reorder_sigs( sigs )
            stx = bitcoin.apply_multisignatures( stx, 0, self.redeemScript, sigs )
            return stx, ( len(sigs) >= self.neededSigs )
        except ValueError as e:
            raise RuntimeError( "Key Error", str( e ) )
        except Exception as e: 
            raise RuntimeError( "Unexpected Error", "Unexpected error formating key: " + str( e ) )
Example #12
0
            def cb(ec, history, order):
                if ec is not None:
                    self.log.error("Error fetching history: %s", ec)
                    # TODO: Send error message to GUI
                    return

                unspent = [row[:4] for row in history if row[4] is None]

                # Send all unspent outputs (everything in the address) minus
                # the fee
                inputs = []
                for row in unspent:
                    assert len(row) == 4
                    inputs.append(
                        str(row[0].encode('hex')) + ":" + str(row[1])
                    )

                seller_signatures = []
                print 'private key ', self.transport.settings['privkey']
                for x in range(0, len(inputs)):
                    ms = multisign(
                        tx, x, script, self.transport.settings['privkey']
                    )
                    print 'seller sig', ms
                    seller_signatures.append(ms)

                tx2 = apply_multisignatures(
                    tx, 0, script, seller_signatures[0], msg['signatures'][0]
                )

                print 'FINAL SCRIPT: %s' % tx2
                print 'Sent', eligius_pushtx(tx2)

                self.send_to_client(
                    None,
                    {
                        "type": "order_notify",
                        "msg": "Funds were released for your sale."
                    }
                )
Example #13
0
            def cb(ec, history, order):
                if ec is not None:
                    self.log.error("Error fetching history: %s", ec)
                    # TODO: Send error message to GUI
                    return

                unspent = [row[:4] for row in history if row[4] is None]

                # Send all unspent outputs (everything in the address) minus
                # the fee
                inputs = []
                for row in unspent:
                    assert len(row) == 4
                    inputs.append(
                        str(row[0].encode('hex')) + ":" + str(row[1]))

                seller_signatures = []
                print 'private key ', self.transport.settings['privkey']
                for x in range(0, len(inputs)):
                    ms = multisign(tx, x, script,
                                   self.transport.settings['privkey'])
                    print 'seller sig', ms
                    seller_signatures.append(ms)

                tx2 = apply_multisignatures(tx, 0, script,
                                            seller_signatures[0],
                                            msg['signatures'][0])

                print 'FINAL SCRIPT: %s' % tx2
                print 'Sent', eligius_pushtx(tx2)

                self.send_to_client(
                    None, {
                        "type": "order_notify",
                        "msg": "Funds were released for your sale."
                    })
Example #14
0
    def add_order_confirmation(self,
                               payout_address,
                               comments=None,
                               shipper=None,
                               tracking_number=None,
                               est_delivery=None,
                               url=None,
                               password=None):
        """
        Add the vendor's order confirmation to the contract.
        """

        if not self.testnet and not (payout_address[:1] == "1" or payout_address[:1] == "3"):
            raise Exception("Bitcoin address is not a mainnet address")
        elif self.testnet and not \
                (payout_address[:1] == "n" or payout_address[:1] == "m" or payout_address[:1] == "2"):
            raise Exception("Bitcoin address is not a testnet address")
        try:
            bitcoin.b58check_to_hex(payout_address)
        except AssertionError:
            raise Exception("Invalid Bitcoin address")
        conf_json = {
            "vendor_order_confirmation": {
                "invoice": {
                    "ref_hash": digest(json.dumps(self.contract, indent=4)).encode("hex")
                }
            }
        }
        if self.contract["vendor_offer"]["listing"]["metadata"]["category"] == "physical good":
            shipping = {"shipper": shipper, "tracking_number": tracking_number, "est_delivery": est_delivery}
            conf_json["vendor_order_confirmation"]["invoice"]["shipping"] = shipping
        elif self.contract["vendor_offer"]["listing"]["metadata"]["category"] == "digital good":
            content_source = {"url": url, "password": password}
            conf_json["vendor_order_confirmation"]["invoice"]["content_source"] = content_source
        if comments:
            conf_json["vendor_order_confirmation"]["invoice"]["comments"] = comments
        confirmation = json.dumps(conf_json["vendor_order_confirmation"]["invoice"], indent=4)
        conf_json["vendor_order_confirmation"]["signature"] = \
            self.keychain.signing_key.sign(confirmation, encoder=nacl.encoding.HexEncoder)[:128]
        order_id = digest(json.dumps(self.contract, indent=4)).encode("hex")
        # apply signatures
        outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id))
        redeem_script = self.contract["buyer_order"]["order"]["payment"]["redeem_script"]
        value = 0
        for output in outpoints:
            value += output["value"]
            del output["value"]
        value -= TRANSACTION_FEE
        outs = [{'value': value, 'address': payout_address}]
        tx = bitcoin.mktx(outpoints, outs)
        signatures = []
        chaincode = self.contract["buyer_order"]["order"]["payment"]["chaincode"]
        masterkey_v = bitcoin.bip32_extract_key(self.keychain.bitcoin_master_privkey)
        vendor_priv = derive_childkey(masterkey_v, chaincode, bitcoin.MAINNET_PRIVATE)
        for index in range(0, len(outpoints)):
            sig = bitcoin.multisign(tx, index, redeem_script, vendor_priv)
            signatures.append({"input_index": index, "signature": sig})
        conf_json["vendor_order_confirmation"]["invoice"]["payout"] = {}
        conf_json["vendor_order_confirmation"]["invoice"]["payout"]["address"] = payout_address
        conf_json["vendor_order_confirmation"]["invoice"]["payout"]["value"] = value
        conf_json["vendor_order_confirmation"]["invoice"]["payout"]["signature(s)"] = signatures

        self.contract["vendor_order_confirmation"] = conf_json["vendor_order_confirmation"]
        self.db.Sales().update_status(order_id, 2)
        file_path = DATA_FOLDER + "store/listings/in progress/" + order_id + ".json"
        with open(file_path, 'w') as outfile:
            outfile.write(json.dumps(self.contract, indent=4))
Example #15
0
    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"]
Example #16
0
    def add_order_confirmation(self,
                               payout_address,
                               comments=None,
                               shipper=None,
                               tracking_number=None,
                               est_delivery=None,
                               url=None,
                               password=None):
        """
        Add the vendor's order confirmation to the contract.
        """

        if not self.testnet and not (payout_address[:1] == "1"
                                     or payout_address[:1] == "3"):
            raise Exception("Bitcoin address is not a mainnet address")
        elif self.testnet and not \
                (payout_address[:1] == "n" or payout_address[:1] == "m" or payout_address[:1] == "2"):
            raise Exception("Bitcoin address is not a testnet address")
        try:
            bitcoin.b58check_to_hex(payout_address)
        except AssertionError:
            raise Exception("Invalid Bitcoin address")
        conf_json = {
            "vendor_order_confirmation": {
                "invoice": {
                    "ref_hash":
                    digest(json.dumps(self.contract, indent=4)).encode("hex")
                }
            }
        }
        if self.contract["vendor_offer"]["listing"]["metadata"][
                "category"] == "physical good":
            shipping = {
                "shipper": shipper,
                "tracking_number": tracking_number,
                "est_delivery": est_delivery
            }
            conf_json["vendor_order_confirmation"]["invoice"][
                "shipping"] = shipping
        elif self.contract["vendor_offer"]["listing"]["metadata"][
                "category"] == "digital good":
            content_source = {"url": url, "password": password}
            conf_json["vendor_order_confirmation"]["invoice"][
                "content_source"] = content_source
        if comments:
            conf_json["vendor_order_confirmation"]["invoice"][
                "comments"] = comments
        confirmation = json.dumps(
            conf_json["vendor_order_confirmation"]["invoice"], indent=4)
        conf_json["vendor_order_confirmation"]["signature"] = \
            self.keychain.signing_key.sign(confirmation, encoder=nacl.encoding.HexEncoder)[:128]
        order_id = digest(json.dumps(self.contract, indent=4)).encode("hex")
        # apply signatures
        outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id))
        redeem_script = self.contract["buyer_order"]["order"]["payment"][
            "redeem_script"]
        value = 0
        for output in outpoints:
            value += output["value"]
            del output["value"]
        value -= TRANSACTION_FEE
        outs = [{'value': value, 'address': payout_address}]
        tx = bitcoin.mktx(outpoints, outs)
        signatures = []
        chaincode = self.contract["buyer_order"]["order"]["payment"][
            "chaincode"]
        masterkey_v = bitcoin.bip32_extract_key(
            self.keychain.bitcoin_master_privkey)
        vendor_priv = derive_childkey(masterkey_v, chaincode,
                                      bitcoin.MAINNET_PRIVATE)
        for index in range(0, len(outpoints)):
            sig = bitcoin.multisign(tx, index, redeem_script, vendor_priv)
            signatures.append({"input_index": index, "signature": sig})
        conf_json["vendor_order_confirmation"]["invoice"]["payout"] = {}
        conf_json["vendor_order_confirmation"]["invoice"]["payout"][
            "address"] = payout_address
        conf_json["vendor_order_confirmation"]["invoice"]["payout"][
            "value"] = value
        conf_json["vendor_order_confirmation"]["invoice"]["payout"][
            "signature(s)"] = signatures

        self.contract["vendor_order_confirmation"] = conf_json[
            "vendor_order_confirmation"]
        self.db.Sales().update_status(order_id, 2)
        file_path = DATA_FOLDER + "store/listings/in progress/" + order_id + ".json"
        with open(file_path, 'w') as outfile:
            outfile.write(json.dumps(self.contract, indent=4))
Example #17
0
 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"]