Beispiel #1
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
Beispiel #2
0
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  
Beispiel #6
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)
Beispiel #7
0
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"
Beispiel #8
0
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"
Beispiel #9
0
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
Beispiel #10
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))
Beispiel #11
0
    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
Beispiel #12
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)
 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
     ]
Beispiel #14
0
    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'
Beispiel #15
0
	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
    }
Beispiel #17
0
    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
Beispiel #18
0
    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)
Beispiel #20
0
         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:
Beispiel #21
0
 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')
Beispiel #22
0
    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')
Beispiel #23
0
    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."})
Beispiel #24
0
    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"]
Beispiel #25
0
    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
Beispiel #26
0
    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
Beispiel #27
0
 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'
     )
Beispiel #28
0
    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
Beispiel #29
0
    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."
                })
Beispiel #30
0
    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')
Beispiel #31
0
    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)
Beispiel #32
0
    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"])
Beispiel #33
0
    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)
Beispiel #34
0
    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