def recent_blockthings(key, size, length=0): storage = tools.local_get(key) def get_val(length): leng = str(length) if not leng in storage: block=tools.db_get(leng) if block==db.default_entry(): if leng==tools.local_get('length'): tools.local_put('length', int(leng)-1) block=tools.db_get(leng) else: error() #try: storage[leng] = tools.db_get(leng)[key[:-1]] tools.db_put(key, storage) return storage[leng] def clean_up(storage, end): if end<0: return if not str(end) in storage: return else: storage.pop(str(end)) return clean_up(storage, end-1) if length == 0: length = tools.local_get('length') start = max((length-size), 0) clean_up(storage, length-max(custom.mmm, custom.history_length)-100) return map(get_val, range(start, length))
def f(blocks_queue, txs_queue): def bb(): return blocks_queue.empty() def tb(): return txs_queue.empty() def ff(queue, g, b, s): while not b(): time.sleep(0.0001) try: g(queue.get(False)) except Exception as exc: tools.log('suggestions ' + s) tools.log(exc) while True: try: time.sleep(0.1) l=tools.local_get('length')+1 v=range(l-10, l) v=filter(lambda x: x>0, v) v=map(lambda x: tools.db_get(x), v) v=map(lambda x: x['block_hash'], v) if tools.local_get('stop'): tools.dump_out(blocks_queue) tools.dump_out(txs_queue) return while not bb() or not tb(): ff(blocks_queue, lambda x: add_block(x, v), bb, 'block') ff(txs_queue, add_tx, tb, 'tx') except Exception as exc: tools.log(exc)
def f(blocks_queue, txs_queue): def bb(): return blocks_queue.empty() def tb(): return txs_queue.empty() def ff(queue, g, b, s): while not b(): time.sleep(0.0001) try: g(queue.get(False)) except Exception as exc: tools.log('suggestions ' + s) tools.log(exc) while True: try: time.sleep(0.1) l = tools.local_get('length') + 1 v = range(l - 10, l) v = filter(lambda x: x > 0, v) v = map(lambda x: tools.db_get(x), v) v = map(lambda x: x['block_hash'], v) if tools.local_get('stop'): tools.dump_out(blocks_queue) tools.dump_out(txs_queue) return while not bb() or not tb(): ff(blocks_queue, lambda x: add_block(x, v), bb, 'block') ff(txs_queue, add_tx, tb, 'tx') except Exception as exc: tools.log(exc)
def delete_block(DB): """ Removes the most recent block from the blockchain. """ length=tools.local_get('length') if length < 0: return try: ts=tools.local_get('targets') ts.pop(str(length)) tools.local_put('targets', ts) except: pass try: ts=tools.local_get('times') ts.pop(str(length)) tools.local_put('times', ts) except: pass block = tools.db_get(length, DB) orphans = tools.local_get('txs') orphans=filter(lambda t: t['type']!='mint', orphans) tools.local_put('txs', []) for tx in block['txs']: orphans.append(tx) tools.local_put('add_block', False) transactions.update[tx['type']](tx, DB, False) tools.db_delete(length, DB) length-=1 tools.local_put('length', length) if length>=0: block=tools.db_get(length) tools.local_put('height', filter(lambda t: t['type']=='mint', block['txs'])[0]['height']) else: tools.local_put('height', -1) for orphan in orphans: add_tx(orphan, DB)
def create_reward_tx(): tx={} tx['type']='reward' length=tools.local_get('length') tx['on_block']=length-custom.long_time+random.randint(-custom.medium_time/2, custom.medium_time/2) if tx['on_block']<=0: time.sleep(1) return {'error':'no rewards to collect'} address=tools.local_get('address') acc=tools.db_get(address) if str(tx['on_block']) in acc['entropy']: return {'error':'already collected that reward'} zeroths=tools.local_get('txs') zeroths=filter(lambda t: tools.addr(t)==address, zeroths) zeroths=filter(lambda t: t['type']=='reward', zeroths) if len(zeroths)>0: {'error':'already made the tx to collect that reward'} txs=tools.db_get(tx['on_block'])['txs'] txs=filter(lambda t: t['type']=='sign', txs) #tools.log('on block: ' +str(tx['on_block'])) #tools.log('txs: ' +str(txs)) sign_tx=filter(lambda t: tools.addr(t)==address, txs)[0] #tools.log('txs: ' +str(sign_tx)) relative_reward=tools.relative_reward(tx['on_block'], address) tx['amount']=relative_reward+sign_tx['amount'] tx['reveal']=tools.local_get('secrets')[str(tx['on_block'])] tx['jackpots']=len(sign_tx['jackpots']) return tx
def recent_blockthings(key, size, length=0): storage = tools.local_get(key) def get_val(length): leng = str(length) if not leng in storage: block = tools.db_get(leng) if block == db.default_entry(): if leng == tools.local_get('length'): tools.local_put('length', int(leng) - 1) block = tools.db_get(leng) else: error() #try: storage[leng] = tools.db_get(leng)[key[:-1]] tools.db_put(key, storage) return storage[leng] def clean_up(storage, end): if end < 0: return if not str(end) in storage: return else: storage.pop(str(end)) return clean_up(storage, end - 1) if length == 0: length = tools.local_get('length') start = max((length - size), 0) clean_up(storage, length - max(custom.mmm, custom.history_length) - 100) return map(get_val, range(start, length))
def mint_tx(gap): txs = tools.local_get('txs') height = tools.local_get('height') on_block = int(tools.local_get('length')) + 1 return { 'type': 'mint', 'fee': tools.mint_cost(txs, gap), 'on_block': on_block, 'height': height + gap }
def easy_add_transaction(tx_orig, DB={}, privkey="default"): tx = copy.deepcopy(tx_orig) length = tools.local_get("length") if "recentHash" not in tx and length > 3: tx["recentHash"] = tools.db_get(length - 2)["block_hash"] if privkey in ["default", "Default"]: privkey = tools.local_get("privkey") tx = sign(tx_orig, privkey) custom.DB["suggested_txs"].put(tx) return "success" # blockchain.add_tx(tx, DB))#this is a mistake. It should append to the queue instead.
def easy_add_transaction(tx_orig, DB={}, privkey='default'): tx = copy.deepcopy(tx_orig) length=tools.local_get('length') if 'recentHash' not in tx and length>3: tx['recentHash']=tools.db_get(length-2)['block_hash'] if privkey in ['default', 'Default']: privkey=tools.local_get('privkey') tx=sign(tx_orig, privkey) custom.DB['suggested_txs'].put(tx) return('success')#blockchain.add_tx(tx, DB))#this is a mistake. It should append to the queue instead.
def easy_add_transaction(tx_orig, DB={}, privkey='default'): tx = copy.deepcopy(tx_orig) length = tools.local_get('length') if 'recentHash' not in tx and length > 3: tx['recentHash'] = tools.db_get(length - 2)['block_hash'] if privkey in ['default', 'Default']: privkey = tools.local_get('privkey') tx = sign(tx_orig, privkey) custom.DB['suggested_txs'].put(tx) return ( 'success' ) #blockchain.add_tx(tx, DB))#this is a mistake. It should append to the queue instead.
def mainloop(): while True: if tools.local_get('stop'): return time.sleep(1) txs=tools.local_get('txs') address=tools.local_get('address') txs=filter(lambda x: address==tools.addr(x), txs) txs=filter(lambda x: x['type']=='sign', txs) if len(txs)==0: tx=create_sign_tx() #tools.log('tx: ' +str(tx)) api.easy_add_transaction(tx) else: time.sleep(1)
def mainloop(): while True: time.sleep(1) tx=create_reward_tx() if tools.local_get('stop'): return if 'error' not in tx: api.easy_add_transaction(tx)
def add_recent_hash(tx): length = tools.local_get('length') if 'recent_hash' not in tx and length > 0: b = tools.db_get(max(1, length - 2))['block_hash'] tools.log('b: ' + str(b)) tx['recent_hash'] = b return tx
def add_recent_hash(tx): length = tools.local_get("length") if "recent_hash" not in tx and length > 0: b = tools.db_get(max(1, length - 2))["block_hash"] tools.log("b: " + str(b)) tx["recent_hash"] = b return tx
def reward_verify(tx, txs, out, DB): address = tools.addr(tx) acc = tools.db_get(address) relative_reward = tools.relative_reward(tx['on_block'], address) sign_tx = sign_transaction(tx['on_block'], address) length = tools.local_get('length') if len(sign_tx['jackpots']) != tx['jackpots']: tools.log('wrong number of jackpots') return False if length - custom.long_time + custom.medium_time / 2 < tx[ 'on_block'] or length - custom.long_time - custom.medium_time / 2 > tx[ 'on_block']: tools.log('you did not wait the correct amount of time') return False if acc['secrets'][str(tx['on_block'])]['slashed']: tools.log( 'you were slashed, or you already claimed your reward at this height' ) return False if tx['amount'] != relative_reward + sign_tx['amount']: tools.log('reward wrong size') return False if sign_tx['secret_hash'] != tools.det_hash(tx['reveal']): tools.log('entropy+salt does not match') return False if tx['reveal']['entropy'] not in [0, 1]: tools.log('entropy must be either 0 or 1') return False return True
def reward_verify(tx, txs, out, DB): address=tools.addr(tx) acc=tools.db_get(address) relative_reward=tools.relative_reward(tx['on_block'], address) sign_tx=sign_transaction(tx['on_block'], address) length=tools.local_get('length') if len(sign_tx['jackpots'])!=tx['jackpots']: tools.log('wrong number of jackpots') return False if length-custom.long_time+custom.medium_time/2<tx['on_block']or length-custom.long_time-custom.medium_time/2>tx['on_block']: tools.log('you did not wait the correct amount of time') return False if acc['secrets'][str(tx['on_block'])]['slashed']: tools.log('you were slashed, or you already claimed your reward at this height') return False if tx['amount']!=relative_reward+sign_tx['amount']: tools.log('reward wrong size') return False if sign_tx['secret_hash']!=tools.det_hash(tx['reveal']): tools.log('entropy+salt does not match') return False if tx['reveal']['entropy'] not in [0,1]: tools.log('entropy must be either 0 or 1') return False return True
def spend_verify(tx, txs, out, DB): txaddr=tools.addr(tx) h=tx['recent_hash'] l=tools.local_get('length') r=range(l-10, l) r=filter(lambda l: l>0, r) recent_blocks=map(lambda x:tools.db_get(x), r) recent_hashes=map(lambda x: x['block_hash'], recent_blocks) if h not in recent_hashes: tools.log('recent hash error') return False recent_txs=[] def f(b, recent_txs=recent_txs): recent_txs=recent_txs+b['txs'] map(f, recent_blocks) recent_txs=filter(lambda t: t['type']=='spend', recent_txs) recent_txs=filter(lambda t: t['recent_hash']==h, recent_txs) recent_txs=filter(lambda t: t['to']==tx['to'], recent_txs) recent_txs=filter(lambda t: t['amount']==tx['amount'], recent_txs) recent_txs=filter(lambda t: t['fee']==tx['fee'], recent_txs) recent_txs=filter(lambda t: tools.addr(t)==txaddr, recent_txs) if len(recent_txs)>0: out[0]+='no repeated spends' return False if not signature_check(tx): out[0]+='signature check' return False if len(tx['to'])<=30: out[0]+='that address is too short' out[0]+='tx: ' +str(tx) return False if not tools.fee_check(tx, txs, DB): out[0]+='fee check error' return False return True
def repeat_check(tx, txs): if tx['type']=='sign': return True l=tools.local_get('length') if l<=1: return True if 'recent_hash' not in tx: tools.log('no recent hash: ' +str(tx)) return False h=tx['recent_hash'] r=range(l-10, l) r=filter(lambda l: l>0, r) recent_blocks=map(lambda x:tools.db_get(x), r) recent_hashes=map(lambda x: x['block_hash'], recent_blocks) if h not in recent_hashes: tools.log('have : ' +str(h)) tools.log('need: ' +str(recent_hashes)) tools.log('recent hash error') return False recent_txs=[]#should be memoized? def f(b, recent_txs=recent_txs): recent_txs=recent_txs+b['txs'] map(f, recent_blocks) recent_txs+=txs def f(d): d=copy.deepcopy(d) d.pop('signatures') return tools.det_hash(d) if f(tx) in map(f, recent_txs): tools.log('no repeated tx') return False return True
def sign_verify(tx, txs, out, DB): #check the validity of a transaction of type sign. a = tools.addr(tx) B = tx[ 'B'] #verify a proof that addr(tx) actually owned that much money long*2-medium ago. M = custom.all_money address = tools.addr(tx) block = tools.db_get(tx['on_block']) num = max(0, tx['on_block'] - (custom.long_time * 2 - custom.medium_time)) election_block = tools.db_get(num) if not signature_check(tx): out[0] += 'signature check' return False if 'root_hash' not in election_block: out[0] += 'no root hash' return False v = tools.db_verify(election_block['root_hash'], address, tx['proof']) if v == False: tools.log('your address did not exist that long ago.') return False if v['amount'] != tx['B']: tools.log('that is not how much money you had that long ago') return False if 'secret_hash' not in tx: tools.log('need the hash of a secret') return False for t in txs: if tools.addr(t) == address and t['type'] == 'sign': #tools.log('can only have one sign tx per block') return False if len(tx['jackpots']) < 1: tools.log('insufficient jackpots') return False if not signature_check(tx): out[0] += 'signature check' return False length = tools.local_get('length') if int(tx['on_block']) != int(length + 1): out[0] += 'this tx is for the wrong block. have ' + str( length + 1) + ' need: ' + str(tx['on_block']) return False if tx['on_block'] > 0: if not tx['prev'] == tools.db_get(length)['block_hash']: tools.log('must give hash of previous block') return False ran = tools.det_random(tx['on_block']) for j in tx['jackpots']: if type(j) != int or j not in range(200): tools.log('bad jackpot') return False if len(filter(lambda x: x == j, tx['jackpots'])) != 1: tools.log('no repeated jackpots') return False if not tools.winner(B, M, ran, address, j): tools.log('that jackpot is not valid: ' + str(j)) return False if tx['amount'] < custom.minimum_deposit: tools.log('you have to deposit more than that') return False return True
def repeat_check(tx, txs): l = tools.local_get('length') if l <= 1: return True h = tx['recent_hash'] r = range(l - 10, l) r = filter(lambda l: l > 0, r) recent_blocks = map(lambda x: tools.db_get(x), r) recent_hashes = map(lambda x: x['block_hash'], recent_blocks) if h not in recent_hashes: tools.log('have : ' + str(h)) tools.log('need: ' + str(recent_hashes)) tools.log('recent hash error') return False recent_txs = [] for block in recent_blocks: recent_txs += block['txs'] def f(d): d = copy.deepcopy(d) d.pop('signatures') return tools.det_hash(d) if f(tx) in map(f, recent_txs): tools.log('no repeated tx') return False return True
def reward_verify(tx, txs, out, DB): address = tools.addr(tx) acc = tools.db_get(address) relative_reward = tools.relative_reward(tx["on_block"], address) sign_tx = sign_transaction(tx["on_block"], address) length = tools.local_get("length") if len(sign_tx["jackpots"]) != tx["jackpots"]: tools.log("wrong number of jackpots") return False if ( length - custom.long_time + custom.medium_time / 2 < tx["on_block"] or length - custom.long_time - custom.medium_time / 2 > tx["on_block"] ): tools.log("you did not wait the correct amount of time") return False if acc["secrets"][str(tx["on_block"])]["slashed"]: tools.log("you were slashed, or you already claimed your reward at this height") return False if tx["amount"] != relative_reward + sign_tx["amount"]: tools.log("reward wrong size") return False if sign_tx["secret_hash"] != tools.det_hash(tx["reveal"]): tools.log("entropy+salt does not match") return False if tx["reveal"]["entropy"] not in [0, 1]: tools.log("entropy must be either 0 or 1") return False return True
def create_sign_tx(): on_block=tools.local_get('length')+1 if on_block==0: time.sleep(1) return{'error':'not ready'} r=tools.det_random(on_block) jackpots=[] address=tools.local_get('address') l=max(-1, on_block-1-(custom.long_time*2-custom.medium_time)) election_block=tools.db_get(l+1) proof=tools.local_get('balance_proofs'+str(l)) if 'root_hash' not in election_block: return({'error':'database changed'}) a=tools.db_verify(election_block['root_hash'], address, proof) if a==False: #tools.log('election block: ' +str(election_block)) #tools.log('proof: ' +str(proof)) return({'error':'not valid proof'}) old_balance=a['amount'] M=custom.all_money for j in range(custom.jackpot_nonces): if tools.winner(old_balance, M, r, address, j): jackpots.append(j) if len(jackpots)>0: tx={'on_block':on_block, 'jackpots':jackpots, 'type':'sign', 'amount':M/3000/3} tx['B']=old_balance tx['proof']=proof if proof=='empty': time.sleep(1) return {'error':'not ready'} secrets=tools.local_get('secrets') if str(on_block) in secrets: secret=secrets[str(on_block)] else: secret=tools.unpackage(tools.package({'salt':str(random.random())+str(random.random()), 'entropy':random.randint(0,1)})) secrets[str(on_block)]=secret tools.local_put('secrets', secrets) tx['secret_hash']=tools.det_hash(secret) if on_block>0: block=tools.db_get(on_block-1) if 'amount' in block and block['amount']==0: return({'error':'database changed'}) #tools.log('on_block: ' +str(a)) tx['prev']=block['block_hash'] else: tx= {'error':'no jackpots'} return tx
def patty_info(DB, args): if len(args) < 1: return "not enough inputs" if args[0] == "my_address": address = tools.local_get("address") else: address = args[0] return tools.db_get(address, DB)
def patty_info(DB, args): if len(args) < 1: return ('not enough inputs') if args[0] == 'my_address': address = tools.local_get('address') else: address = args[0] return (tools.db_get(address, DB))
def buy_block(DB, args): gap=1#this should be an argument. #we should also let the user delete as many blocks first as they want, to build a fork from a point in history. length=tools.local_get('length') prev_block=tools.db_get(length) txs=tools.local_get('txs') privkey=tools.local_get('privkey') height=tools.local_get('height') block=default_block(length+1, height+gap, txs+[sign(mint_tx(gap), privkey)]) to_hash='' if length>-1: to_hash={'prev_hash':prev_block['block_hash'], 'txs':block['txs']} block['block_hash']=tools.det_hash(to_hash) block['root_hash']=tools.db_root() block=sign(block, privkey) block = tools.unpackage(tools.package(block)) DB['suggested_blocks'].put(block) return block
def give_block(peer, DB, block_count_peer): blocks=[] b=[max(block_count_peer-5, 0), min(tools.local_get('length'), block_count_peer+custom.download_many)] for i in range(b[0], b[1]+1): blocks.append(tools.db_get(i, DB)) cmd(peer, {'type': 'pushblock', 'blocks': blocks}) return 0
def patty_info(DB, args): if len(args)<1: return ('not enough inputs') if args[0]=='my_address': address=tools.local_get('address') else: address=args[0] return(tools.db_get(address, DB))
def sign_verify(tx, txs, out, DB):#check the validity of a transaction of type sign. a=tools.addr(tx) B=tx['B']#verify a proof that addr(tx) actually owned that much money long*2-medium ago. M=custom.all_money address=tools.addr(tx) block=tools.db_get(tx['on_block']) num=max(0,tx['on_block']-(custom.long_time*2-custom.medium_time)) election_block=tools.db_get(num) if not signature_check(tx): out[0]+='signature check' return False if 'root_hash' not in election_block: out[0]+='no root hash' return False v=tools.db_verify(election_block['root_hash'], address, tx['proof']) if v==False: tools.log('your address did not exist that long ago.') return False if v['amount']!=tx['B']: tools.log('that is not how much money you had that long ago') return False if 'secret_hash' not in tx: tools.log('need the hash of a secret') return False for t in txs: if tools.addr(t)==address and t['type']=='sign': #tools.log('can only have one sign tx per block') return False if len(tx['jackpots'])<1: tools.log('insufficient jackpots') return False if not signature_check(tx): out[0]+='signature check' return False length=tools.local_get('length') if int(tx['on_block'])!=int(length+1): out[0]+='this tx is for the wrong block. have '+str(length+1) +' need: ' +str(tx['on_block']) return False if tx['on_block']>0: if not tx['prev']==tools.db_get(length)['block_hash']: tools.log('must give hash of previous block') return False ran=tools.det_random(tx['on_block']) for j in tx['jackpots']: if type(j)!=int or j not in range(200): tools.log('bad jackpot') return False if len(filter(lambda x: x==j, tx['jackpots']))!=1: tools.log('no repeated jackpots') return False if not tools.winner(B, M, ran, address, j): tools.log('that jackpot is not valid: '+str(j)) return False if tx['amount']<custom.minimum_deposit: tools.log('you have to deposit more than that') return False return True
def info(DB, args): if len(args)<1: return ('not enough inputs') address=args[0] try: return(tools.local_get(address)) except Exception as exc: tools.log(exc) return(address+' is not in the local database. maybe you meant to do the command: "patty_info '+address+'"?')
def ask_for_count(peer): peers = tools.local_get('peers') block_count = cmd(peer, {'type': 'blockCount'}) if not isinstance(block_count, dict): return if 'error' in block_count.keys(): return peers[peer]['length'] = block_count['length'] tools.local_put('peers', peers)
def buy_block(DB, args): gap = 1 # this should be an argument. # we should also let the user delete as many blocks first as they want, to build a fork from a point in history. length = tools.local_get("length") prev_block = tools.db_get(length) txs = tools.local_get("txs") privkey = tools.local_get("privkey") height = tools.local_get("height") block = default_block(length + 1, height + gap, txs + [sign(mint_tx(gap), privkey)]) to_hash = "" if length > -1: to_hash = {"prev_hash": prev_block["block_hash"], "txs": block["txs"]} block["block_hash"] = tools.det_hash(to_hash) block["root_hash"] = tools.db_root() block = sign(block, privkey) block = tools.unpackage(tools.package(block)) DB["suggested_blocks"].put(block) return block
def ask_for_count(peer): peers=tools.local_get('peers') block_count = cmd(peer, {'type': 'blockCount'}) if not isinstance(block_count, dict): return if 'error' in block_count.keys(): return peers[peer]['length']=block_count['length'] tools.local_put('peers', peers)
def main(peers, DB): map(tools.add_peer, peers) try: while True: time.sleep(0.5)#changing this from 0.01 to 0.5 made blocks load way faster. the add_block queue was getting overfilled. if tools.local_get('stop'): return main_once(DB) except Exception as exc: tools.log(exc)
def block_check(block, DB): def log_(txt): pass #return tools.log(txt) def tx_check(txs): start = copy.deepcopy(txs) out = [] start_copy = [] invalid_because = [''] while start != start_copy: if start == []: return False # Block passes this test start_copy = copy.deepcopy(start) if transactions.tx_check[start[0]['type']](start[0], out, invalid_because, DB): out.append(start.pop()) else: tools.log('invalid tx: '+str(invalid_because[0])) return True # Block is invalid tools.log('block invalid because it has no txs') return True # Block is invalid if 'error' in block: log_('error in block') return False length =tools.local_get('length') if type(block['length'])!=type(1): log_('wrong length type') return False if int(block['length']) != int(length) + 1: log_('wrong longth') return False block_creator_address=tools.addr(block) mint_address=tools.addr(filter(lambda t: t['type']=='mint', block['txs'])[0]) if block_creator_address!=mint_address: log_('bad mint') return False if block['root_hash']!=tools.db_root(): log_('bad root, have: '+str(tools.db_root())+' need ' +str(block['root_hash'])) return False txs=filter(lambda x: x['type']=='mint', block['txs']) if len(txs)!=1: log_('wrong number of mint txs') return False txs=filter(lambda x: x['type']=='sign', block['txs']) txs=map(lambda x: len(x['jackpots']), txs) if sum(txs)<custom.signers*2/3 and length>-1: log_('not enough signatures') return False if length >= 0: prev_block=tools.db_get(length) to_hash={'prev_hash':prev_block['block_hash'], 'txs':block['txs']} if not block['block_hash']==tools.det_hash(to_hash): log_('det hash error') return False #total money spent must be less than the total amount of money in signed deposits for this block. if tx_check(block['txs']): log_('tx check') return False return True
def give_block(peer, DB, block_count_peer): blocks = [] b = [ max(block_count_peer - 5, 0), min(tools.local_get('length'), block_count_peer + custom.download_many) ] for i in range(b[0], b[1] + 1): blocks.append(tools.db_get(i, DB)) cmd(peer, {'type': 'pushblock', 'blocks': blocks}) return 0
def buy_block(DB, args): gap = 1 #this should be an argument. #we should also let the user delete as many blocks first as they want, to build a fork from a point in history. length = tools.local_get('length') prev_block = tools.db_get(length) txs = tools.local_get('txs') privkey = tools.local_get('privkey') height = tools.local_get('height') block = default_block(length + 1, height + gap, txs + [sign(mint_tx(gap), privkey)]) to_hash = '' if length > -1: to_hash = {'prev_hash': prev_block['block_hash'], 'txs': block['txs']} block['block_hash'] = tools.det_hash(to_hash) block['root_hash'] = tools.db_root() block = sign(block, privkey) block = tools.unpackage(tools.package(block)) DB['suggested_blocks'].put(block) return block
def main(peers, DB): map(tools.add_peer, peers) try: while True: time.sleep( 0.5 ) #changing this from 0.01 to 0.5 made blocks load way faster. the add_block queue was getting overfilled. if tools.local_get('stop'): return main_once(DB) except Exception as exc: tools.log(exc)
def sign_verify(tx, txs, out, DB): # check the validity of a transaction of type sign. a = tools.addr(tx) acc = tools.db_get(a) if a["amount"] < tx["B"]: tools.log("you do not have that much money") B = tx["B"] M = custom.all_money address = tools.addr(tx) block = tools.db_get(tx["on_block"]) num = max(0, tx["on_block"] - (custom.long_time * 2 - custom.medium_time)) election_block = tools.db_get(num) if "root_hash" not in election_block: out[0] += "no root hash" return False v = tools.db_verify(election_block["root_hash"], address, tx["proof"]) if v == False: tools.log("your address did not exist that long ago.") return False if v["amount"] != tx["B"]: tools.log("that is not how much money you had that long ago") return False if "secret_hash" not in tx: tools.log("need the hash of a secret") return False for t in txs: if tools.addr(t) == address and t["type"] == "sign": # tools.log('can only have one sign tx per block') return False if len(tx["jackpots"]) < 1: tools.log("insufficient jackpots") return False length = tools.local_get("length") if int(tx["on_block"]) != int(length + 1): out[0] += "this tx is for the wrong block. have " + str(length + 1) + " need: " + str(tx["on_block"]) return False if tx["on_block"] > 0: if not tx["prev"] == tools.db_get(length)["block_hash"]: tools.log("must give hash of previous block") return False ran = tools.det_random(tx["on_block"]) for j in tx["jackpots"]: if type(j) != int or j not in range(200): tools.log("bad jackpot") return False if len(filter(lambda x: x == j, tx["jackpots"])) != 1: tools.log("no repeated jackpots") return False if not tools.winner(B, M, ran, address, j): tools.log("that jackpot is not valid: " + str(j)) return False if tx["amount"] < custom.minimum_deposit: tools.log("you have to deposit more than that") return False return True
def info(DB, args): if len(args) < 1: return ('not enough inputs') address = args[0] try: return (tools.local_get(address)) except Exception as exc: tools.log(exc) return ( address + ' is not in the local database. maybe you meant to do the command: "patty_info ' + address + '"?')
def mint_verify(tx, txs, out, DB): length = tools.local_get("length") height = tools.local_get("height") custom.block_fee(tx["height"] - height) gap = tx["height"] - height for t in txs: if t["type"] == "mint": out[0] += "no mint repeats" if tx["on_block"] != length + 1: out[0] += "on wrong block" return False if len(filter(lambda x: x["type"] == "mint", txs)) > 0: out[0] += "too many mints" return False amount = tools.mint_cost(txs, gap) if tx["fee"] != amount: tools.log("have: " + str(tx["amount"])) tools.log("need: " + str(amount)) tools.log("that amount is too big") return False return True
def mint_verify(tx, txs, out, DB): length = tools.local_get('length') height = tools.local_get('height') custom.block_fee(tx['height'] - height) gap = tx['height'] - height for t in txs: if t['type'] == 'mint': out[0] += 'no mint repeats' if tx['on_block'] != length + 1: out[0] += 'on wrong block' return False if len(filter(lambda x: x['type'] == 'mint', txs)) > 0: out[0] += 'too many mints' return False amount = tools.mint_cost(txs, gap) if tx['fee'] != amount: tools.log('have: ' + str(tx['amount'])) tools.log('need: ' + str(amount)) tools.log('that amount is too big') return False return True
def ask_for_txs(peer, DB): txs = cmd(peer, {'type': 'txs'}) if not isinstance(txs, list): return -1 txs=filter(lambda t: t['type']!='mint', txs) for tx in txs: DB['suggested_txs'].put(tx) T=tools.local_get('txs') pushers = filter(lambda t: t not in txs, T) for push in pushers: cmd(peer, {'type': 'pushtx', 'tx': push}) return 0
def ask_for_txs(peer, DB): txs = cmd(peer, {'type': 'txs'}) if not isinstance(txs, list): return -1 txs = filter(lambda t: t['type'] != 'mint', txs) for tx in txs: DB['suggested_txs'].put(tx) T = tools.local_get('txs') pushers = filter(lambda t: t not in txs, T) for push in pushers: cmd(peer, {'type': 'pushtx', 'tx': push}) return 0
def peer_check(peer, DB): peers = tools.local_get('peers') if peers[peer]['length'] == 0 or random.random() < 0.1: ask_for_count(peer) out = trade_peers(peer) if type(out) == dict and 'error' in out: return 1 peers = tools.local_get('peers') length = tools.local_get('length') us = length them = peers[peer]['length'] if them < us: #tools.log('less than') return give_block(peer, DB, peers[peer]['length']) elif us == them: #tools.log('equal') try: return ask_for_txs(peer, DB) except Exception as exc: tools.log('ask for tx error') tools.log(exc) else: return download_blocks(peer, DB, peers[peer]['length'], length)
def peer_check(peer, DB): peers=tools.local_get('peers') if peers[peer]['length']==0 or random.random()<0.1: ask_for_count(peer) out=trade_peers(peer) if type(out)==dict and 'error' in out: return 1 peers=tools.local_get('peers') length = tools.local_get('length') us = length them = peers[peer]['length'] if them < us: #tools.log('less than') return give_block(peer, DB, peers[peer]['length']) elif us == them: #tools.log('equal') try: return ask_for_txs(peer, DB) except Exception as exc: tools.log('ask for tx error') tools.log(exc) else: return download_blocks(peer, DB, peers[peer]['length'], length)
def add_tx(tx, DB={}): # Attempt to add a new transaction into the pool. #print('top of add_tx') out = [''] if type(tx) != type({'a': 1}): return False address = tools.make_address(tx['pubkeys'], len(tx['signatures'])) ''' def verify_count(tx, txs): return tx['count'] != tools.count(address, DB) ''' def type_check(tx, txs): if not tools.E_check(tx, 'type', [str, unicode]): out[0] += 'blockchain type' return False if tx['type'] not in transactions.tx_check: out[0] += 'bad type' return False return True def too_big_block(tx, txs): return len( tools.package(txs + [tx])) > networking.MAX_MESSAGE_SIZE - 5000 def verify_tx(tx, txs, out): #do not allow tx which fail to reference one of the 10 most recent blocks. do not allow tx which have an identical copy in the last 10 blocks. if not type_check(tx, txs): out[0] += 'type error' return False if tx in txs: out[0] += 'no duplicates' return False #if verify_count(tx, txs): # out[0]+='count error' # return False if too_big_block(tx, txs): out[0] += 'too many txs' return False if not transactions.tx_check[tx['type']](tx, txs, out, DB): out[0] += 'tx: ' + str(tx) return False return True #tools.log('attempt to add tx: ' +str(tx)) T = tools.local_get('txs') if verify_tx(tx, T, out): T.append(tx) tools.local_put('txs', T) return ('added tx: ' + str(tx)) else: return ('failed to add tx because: ' + out[0])
def main_once(DB): pr = tools.local_get('peers') keys = filter(lambda x: pr[x]['blacklist'] < 500, pr.keys()) keys = sorted(keys, key=lambda r: pr[r]['lag']) if len(keys) < 1: time.sleep(0.5) return time.sleep(0.05) while not DB['suggested_blocks'].empty(): time.sleep(0.1) if tools.local_get('stop'): return 0 i = exponential_random(9.0 / 10) % len(keys) t1 = time.time() r = peer_check(keys[i], DB) t2 = time.time() a = 0.5 pr = tools.local_get('peers') pr[keys[i]]['lag'] *= (1 - a) if r == 0: a *= (t2 - t1) else: a *= 60 pr[keys[i]]['lag'] += a tools.local_put('peers', pr)
def get_val(length): leng = str(length) if not leng in storage: block = tools.db_get(leng) if block == db.default_entry(): if leng == tools.local_get('length'): tools.local_put('length', int(leng) - 1) block = tools.db_get(leng) else: error() #try: storage[leng] = tools.db_get(leng)[key[:-1]] tools.db_put(key, storage) return storage[leng]
def get_val(length): leng = str(length) if not leng in storage: block=tools.db_get(leng) if block==db.default_entry(): if leng==tools.local_get('length'): tools.local_put('length', int(leng)-1) block=tools.db_get(leng) else: error() #try: storage[leng] = tools.db_get(leng)[key[:-1]] tools.db_put(key, storage) return storage[leng]
def main_once(DB): pr=tools.local_get('peers') keys=filter(lambda x: pr[x]['blacklist']<500, pr.keys()) keys=sorted(keys, key=lambda r: pr[r]['lag']) if len(keys)<1: time.sleep(0.5) return time.sleep(0.05) while not DB['suggested_blocks'].empty(): time.sleep(0.1) if tools.local_get('stop'): return 0 i=exponential_random(9.0/10)%len(keys) t1=time.time() r=peer_check(keys[i], DB) t2=time.time() a=0.5 pr=tools.local_get('peers') pr[keys[i]]['lag']*=(1-a) if r==0: a*=(t2-t1) else: a*=60 pr[keys[i]]['lag']+=a tools.local_put('peers', pr)
def trade_peers(peer): peers=tools.local_get('peers') peer_length=peers[peer]['length'] their_peers=cmd(peer, {'type':'peers'}) if type(their_peers)!=dict: return {'error': 'cannot connect'} if 'error' in their_peers.keys(): return {'error': 'cannot connect'} def minus(a, b): return filter(lambda p: p not in b, a) to_them=minus(peers.keys(), their_peers.keys()) to_me=minus(their_peers.keys(), peers.keys()) for p in to_me: if not ':' in p: p=p+':'+str(their_peers[p]['port']) tools.log('peer: ' +str(p)) tools.add_peer(p) cmd(peer, {'type':'recieve_peer', 'peers':to_them})
def pushblock(dic, DB): length = tools.local_get('length') block = tools.db_get(length, DB) if 'peer' in dic: peer = dic['peer'] else: peer = False if 'blocks' in dic: if length >= 0: for i in range(20): if tools.fork_check(dic['blocks'], DB, length, block): blockchain.delete_block(DB) length -= 1 for block in dic['blocks']: DB['suggested_blocks'].put([block, peer]) else: DB['suggested_blocks'].put([dic['block'], peer]) return 'success'
def trade_peers(peer): peers = tools.local_get('peers') peer_length = peers[peer]['length'] their_peers = cmd(peer, {'type': 'peers'}) if type(their_peers) != dict: return {'error': 'cannot connect'} if 'error' in their_peers.keys(): return {'error': 'cannot connect'} def minus(a, b): return filter(lambda p: p not in b, a) to_them = minus(peers.keys(), their_peers.keys()) to_me = minus(their_peers.keys(), peers.keys()) for p in to_me: if not ':' in p: p = p + ':' + str(their_peers[p]['port']) tools.log('peer: ' + str(p)) tools.add_peer(p) cmd(peer, {'type': 'recieve_peer', 'peers': to_them})