class ItemServer(): """ An issuer of items, among other things... It also maintains the heavy data structures and interfaces.""" def __init__(self, key_name, btc_proxy='http://*****:*****@localhost:19001', lineage_filename='lineage.pickle'): if pp_keys.ExportPubKey(key_name) == '': raise Exception('Unknown key name ' + key_name) self.key_name = key_name self.btc = ServiceProxy(btc_proxy) self.btc.getinfo() # Will raise an exception if we aren't connected # Load user accounts try: self.user_account = cPickle.load(file(USER_ACCOUNT_FILENAME)) except: logging.info('Starting with empty user accounts') self.user_account = {} # Load lineage try: self.lineage = cPickle.load(file(lineage_filename)) except: logging.info('Starting with empty lineage') self.lineage = pp_lineage.Lineage() logging.info('Loading block chain from' + BLOCK_DIRECTORY) self.lineage.UpdateDir(BLOCK_DIRECTORY) # Save the updated lineage (only at __init__). logging.info('Saving updated lineage...') cPickle.dump(self.lineage, file(lineage_filename, 'w'), -1) def CreateAccount(self, password): """ Clients create a new account by making a payment to an address. """ new_address = self.btc.getnewaddress() self.user_account[new_address] = password # Save the user accounts to disk. cPickle.dump(self.user_account, file('user_account.pickle', 'w'), -1) return new_address def VerifyAccount(self, btc_address, password, proof_sig): """ Clients log in by verifying their payment to a btc_address. """ # TODO: add a day-stamp to the text? if not btc_address in self.user_account: logging.warning('Unknown btc_address %s' % btc_address) return False if self.user_account[btc_address] != password: logging.warning('Password does not match for account %s' % btc_address) return False MIN_ACCOUNT_AMOUNT = 0.001 account_amount = self.btc.getreceivedbyaddress(btc_address, 1) if account_amount < MIN_ACCOUNT_AMOUNT: logging.warning('Address %s not sufficiently funded %f < %f' % (btc_address, account_amount, MIN_ACCOUNT_AMOUNT)) return False # TODO: actually verify that they can prove they made the (first?) payment. #return self.btc.verifymessage(btc_address, proof_sig, self.key_name) return True def Create(self, item_name, content): item = Item(item_name, content, self.key_name) return item def GrantToKey(self, item, key_name): """ Give an item to a particular owner: non-transferrable. """ if item.creator_key_name != self.key_name: logging.warning('This server is not the creator of the item %s' % item) return None if item.owner_key_name != '': logging.warning('This item has already been granted') return None item.owner_key_name = key_name # Sign the item to make it official. item.signature = pp_keys.Sign(item.signed_content(), self.key_name) return item def GrantToAddress(self, item, address, btc_value=0.01): """ Give an item to a bitcoin address: transferrable. """ if item.creator_key_name != self.key_name: logging.warning('This server is not the creator of the item %s' % item) return None if item.origin_tx_id != '': logging.warning('This item has already been granted') return None item.origin_tx_id = self.btc.sendtoaddress(address, btc_value) item.last_tx_id = item.origin_tx_id # Sign the item to make it official. item.signature = pp_keys.Sign(item.signed_content(), self.key_name) return item def Transfer(self, item, address, min_btc_confirmations=6, btc_fee=0.0005): if item.last_tx_id == '': print 'This item is not transferrable (no last tx id)' return False # NOTE: we assume the btc server knows of this this transaction because the # user is the owner of the item. last_tx = self.btc.gettransaction(item.last_tx_id) value = float(last_tx['amount']) confirmations = last_tx['confirmations'] if confirmations < min_btc_confirmations: print 'Not enough confirmations of last_tx:', print confirmations, '<', min_btc_confirmations return False # For the initial grant TX, vout will be 1, otherwise 0. vout = 0 if (item.origin_tx_id == item.last_tx_id): vout = 1 raw_tx = self.btc.createrawtransaction([{ "txid": item.last_tx_id, "vout": vout }], {address: value - btc_fee}) signed = self.btc.signrawtransaction(raw_tx) if signed['complete']: item.last_tx_id = self.btc.sendrawtransaction(signed['hex']) return True return False def Verify(self, item, proof_sig): """ Verify the integrity and ownership of the item: 1) The serialized item is properly signed, 2) and that the claimed owner also controls the heir bitcoin. """ # TODO: Check that the last tx has sufficient confirmations. # TODO: Support non-transferrable items. if item.origin_tx_id == '' or item.last_tx_id == '' or item.signature == '': print 'This item has not been granted' return False if not pp_keys.FindAndImportVerifiedKey(item.creator_key_name): print 'Could not find item creator key', item.creator_key_name return False if not pp_keys.Verify(item.signed_content(), item.signature): print 'Could not verify item signature' return False self.lineage.UpdateAll() if not self.lineage.VerifyLineage(item.last_tx_id, item.origin_tx_id): print 'Could not verify item lineage' return False last_address = self.lineage.GetOutputAddress(item.last_tx_id) if not last_address: print 'Could not find last tx output address' return False last_address_verified = self.btc.verifymessage(last_address, proof_sig, self.key_name) if not last_address_verified: print 'Could not verify ownership of last tx output address' return False return True def GenerateProofSig(self, item, target): """ Prove that this server owns the output of last_tx_id. """ self.lineage.UpdateAll() last_address = self.lineage.GetOutputAddress(item.last_tx_id) if not last_address: print 'Could not find last tx output address' return '' proof_sig = self.btc.signmessage(last_address, target) return proof_sig
def createrawtransaction(in_array,out_set): bitcoin = ServiceProxy(BITCOINRPC) try: data=bitcoin.createrawtransaction(in_array,out_set) except JSONRPCException, e: return (False, "Error: %s" % e.error['message'])
def createrawtransaction(in_array, out_set): bitcoin = ServiceProxy(BITCOINRPC) try: data = bitcoin.createrawtransaction(in_array, out_set) except JSONRPCException, e: return (False, "Error: %s" % e.error['message'])
print (' Script %s has %d txins and %s BTC value.'%(script,scripts[script][2],str(scripts[script][1]))) out={} na=amt-min_fee #One new output per 100 BTC of value to avoid consolidating too much value in too few addresses. # But don't add an extra output if it would have less than 10 BTC. while na>0: amount=min(Decimal(100),na) if ((na-amount)<10): amount=na addr=b.getnewaddress('consolidate') #omg wtf, this is awful. the python-bitcoin crap makes the argument be a float if (Decimal(str(float(amount)))>0): if addr not in out: out[addr]=float(0) out[addr]+=float(amount) na-=Decimal(str(float(amount))) print ('Paying %s BTC (%s fee) to:'%(sum([Decimal(str(out[k])) for k in out.keys()]),amt-sum([Decimal(str(out[k])) for k in out.keys()]))) for o in out.keys(): print (' %s %s'%(o,out[o])) txn=b.createrawtransaction(txouts,out) print ('\nRaw transaction, sign with signrawtransaction then send with sendrawtransaction:') print ('If, after signing, transaction is too large (e.g. >20,000 character) you may need to provide a fee or it will be rejected by bitcoin.\n') print (txn) #This could sign and send the transaction, but better to let the user do it. # txn=b.signrawtransaction(txn) # print (txn) # print ('Bytes: %d Fee: %s'%(len(txn['hex'])/2,amt-sum([Decimal(str(out[x])) for x in out.keys()])))
while na > 0: amount = min(Decimal(100), na) if ((na - amount) < 10): amount = na addr = b.getnewaddress('consolidate') #omg wtf, this is awful. the python-bitcoin crap makes the argument be a float if (Decimal(str(float(amount))) > 0): if addr not in out: out[addr] = float(0) out[addr] += float(amount) na -= Decimal(str(float(amount))) print('Paying %s BTC (%s fee) to:' % (sum([Decimal(str(out[k])) for k in out.keys() ]), amt - sum([Decimal(str(out[k])) for k in out.keys()]))) for o in out.keys(): print(' %s %s' % (o, out[o])) txn = b.createrawtransaction(txouts, out) print( '\nRaw transaction, sign with signrawtransaction then send with sendrawtransaction:' ) print( 'If, after signing, transaction is too large (e.g. >20,000 character) you may need to provide a fee or it will be rejected by bitcoin.\n' ) print(txn) #This could sign and send the transaction, but better to let the user do it. # txn=b.signrawtransaction(txn) # print (txn) # print ('Bytes: %d Fee: %s'%(len(txn['hex'])/2,amt-sum([Decimal(str(out[x])) for x in out.keys()])))
class ItemServer(): """ An issuer of items, among other things... It also maintains the heavy data structures and interfaces.""" def __init__(self, key_name, btc_proxy = 'http://*****:*****@localhost:19001', lineage_filename = 'lineage.pickle'): if pp_keys.ExportPubKey(key_name) == '': raise Exception('Unknown key name ' + key_name) self.key_name = key_name self.btc = ServiceProxy(btc_proxy) self.btc.getinfo() # Will raise an exception if we aren't connected # Load user accounts try: self.user_account = cPickle.load(file(USER_ACCOUNT_FILENAME)) except: logging.info('Starting with empty user accounts') self.user_account= {} # Load lineage try: self.lineage = cPickle.load(file(lineage_filename)) except: logging.info('Starting with empty lineage') self.lineage = pp_lineage.Lineage() logging.info('Loading block chain from' + BLOCK_DIRECTORY) self.lineage.UpdateDir(BLOCK_DIRECTORY) # Save the updated lineage (only at __init__). logging.info('Saving updated lineage...') cPickle.dump(self.lineage, file(lineage_filename, 'w'), -1) def CreateAccount(self, password): """ Clients create a new account by making a payment to an address. """ new_address = self.btc.getnewaddress() self.user_account[new_address] = password # Save the user accounts to disk. cPickle.dump(self.user_account, file('user_account.pickle', 'w'), -1) return new_address def VerifyAccount(self, btc_address, password, proof_sig): """ Clients log in by verifying their payment to a btc_address. """ # TODO: add a day-stamp to the text? if not btc_address in self.user_account: logging.warning('Unknown btc_address %s' % btc_address) return False if self.user_account[btc_address] != password: logging.warning('Password does not match for account %s' % btc_address) return False MIN_ACCOUNT_AMOUNT = 0.001 account_amount = self.btc.getreceivedbyaddress(btc_address, 1) if account_amount < MIN_ACCOUNT_AMOUNT: logging.warning('Address %s not sufficiently funded %f < %f' % (btc_address, account_amount, MIN_ACCOUNT_AMOUNT)) return False # TODO: actually verify that they can prove they made the (first?) payment. #return self.btc.verifymessage(btc_address, proof_sig, self.key_name) return True def Create(self, item_name, content): item = Item(item_name, content, self.key_name) return item def GrantToKey(self, item, key_name): """ Give an item to a particular owner: non-transferrable. """ if item.creator_key_name != self.key_name: logging.warning('This server is not the creator of the item %s' % item) return None if item.owner_key_name != '': logging.warning('This item has already been granted') return None item.owner_key_name = key_name # Sign the item to make it official. item.signature = pp_keys.Sign(item.signed_content(), self.key_name) return item def GrantToAddress(self, item, address, btc_value=0.01): """ Give an item to a bitcoin address: transferrable. """ if item.creator_key_name != self.key_name: logging.warning('This server is not the creator of the item %s' % item) return None if item.origin_tx_id != '': logging.warning('This item has already been granted') return None item.origin_tx_id = self.btc.sendtoaddress(address, btc_value) item.last_tx_id = item.origin_tx_id # Sign the item to make it official. item.signature = pp_keys.Sign(item.signed_content(), self.key_name) return item def Transfer(self, item, address, min_btc_confirmations=6, btc_fee=0.0005): if item.last_tx_id == '': print 'This item is not transferrable (no last tx id)' return False # NOTE: we assume the btc server knows of this this transaction because the # user is the owner of the item. last_tx = self.btc.gettransaction(item.last_tx_id) value = float(last_tx['amount']) confirmations = last_tx['confirmations'] if confirmations < min_btc_confirmations: print 'Not enough confirmations of last_tx:', print confirmations, '<', min_btc_confirmations return False # For the initial grant TX, vout will be 1, otherwise 0. vout = 0 if (item.origin_tx_id == item.last_tx_id): vout = 1 raw_tx = self.btc.createrawtransaction( [{"txid":item.last_tx_id, "vout":vout}], {address:value - btc_fee}) signed = self.btc.signrawtransaction(raw_tx) if signed['complete']: item.last_tx_id = self.btc.sendrawtransaction(signed['hex']) return True return False def Verify(self, item, proof_sig): """ Verify the integrity and ownership of the item: 1) The serialized item is properly signed, 2) and that the claimed owner also controls the heir bitcoin. """ # TODO: Check that the last tx has sufficient confirmations. # TODO: Support non-transferrable items. if item.origin_tx_id == '' or item.last_tx_id == '' or item.signature == '': print 'This item has not been granted' return False if not pp_keys.FindAndImportVerifiedKey(item.creator_key_name): print 'Could not find item creator key', item.creator_key_name return False if not pp_keys.Verify(item.signed_content(), item.signature): print 'Could not verify item signature' return False self.lineage.UpdateAll() if not self.lineage.VerifyLineage(item.last_tx_id, item.origin_tx_id): print 'Could not verify item lineage' return False last_address = self.lineage.GetOutputAddress(item.last_tx_id) if not last_address: print 'Could not find last tx output address' return False last_address_verified = self.btc.verifymessage( last_address, proof_sig, self.key_name) if not last_address_verified: print 'Could not verify ownership of last tx output address' return False return True def GenerateProofSig(self, item, target): """ Prove that this server owns the output of last_tx_id. """ self.lineage.UpdateAll() last_address = self.lineage.GetOutputAddress(item.last_tx_id) if not last_address: print 'Could not find last tx output address' return '' proof_sig = self.btc.signmessage(last_address, target) return proof_sig