def _remove_block_by_hash(block_hash): """ Remove a block and restore it's transactions to the mempool. Parameters: block_hash -- hash of block to remove """ rs = RedisService() block_dal = BlockServiceDal() block = block_dal.find_by_hash(block_hash) # put all transaction types back into the mempool for transaction in block.transactions: TransactionService.add_to_mem_pool(transaction) for contract_transaction in block.contract_transactions: ContractTransactionService.add_to_mem_pool(contract_transaction) for pos_transaction in block.pos_transactions: PosTransactionService.add_to_mem_pool(pos_transaction) r = redis.StrictRedis() # remove from the sorted set of blocks r.zrem('blocks', block_hash) # remove from the set of blocks at it's height r.srem('block:' + str(block.height), block_hash) # delete the actual block rs.delete_by_key('block:' + block_hash)
def test_pos_author(): expected = 'c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34' r = redis.Redis() r.flushdb() genesis_block = { "height": 0, "prev_block": "", "_hash": "036850bec30839508bf16badc1efc5c0a31eb82f8b23c524c7ea8cd3d0c8b81f", "terminated_contracts": [], "signed_contracts": [], "contracts": [], "pos_transactions": [{ "from_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "82b2704e380f4bc55c214d44f4cdd698ec3ed5471882d0ae67d80462f13434f5", "amount": "100.00000000", "signature": "2b6f4ad89868f8a820f682fb580a20b3383e9889b50736a66c8ed441ac4ebb29b7f32d6efe929b05d66de7ac0e20d0ea471f7a1e482f505f2f0df3221d720ba4" }], "contract_transactions": [], "timestamp": 1520135639, "owner": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "transactions": [{ "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "f54029850ab8ffc3d3f1b210bee0008f1b42aa45e267925f42b80ed9eedb1c20", "amount": "1.00000000", "from_addr": "", "signature": "36a0131c4087dae1d0909baf5ea1b35c9955db7e775646df40d35ad6469469b21439e08263ab7a2fa03f3285fb13ce1b80b399bb6f254694e3f36b9ed5fa6a98" }, { "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "ac32ce4867f65d575d95109b59e713f180541cd5c76ca93dad7cea210ebfa26c", "amount": "10.00000000", "from_addr": "", "signature": "83abc47ca9ad48e91b63d6d4bba28786abfc7345f29f02dbf1c90b4e66f91413cf9a081314095d4bf30d508b9781d035a5816f13ea0c1f1d6b6dd59665697b15" }, { "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "e1e65c22699599507d2621b84a39b02ca525e5d3881c583d4d96cffdf3ceced7", "amount": "100.00000000", "from_addr": "", "signature": "998d03e220b28ad99b2b6d7a00cc1a06443ceea8a3a96acc896c6d8953b44d78f58a6cfbf699d5b4ed35f062cb05674d2f10718ecf44d07a300a781c21734220" }, { "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "b3cf3fba2d1b5e3ca6fee0b5d22a1b81f038ffd9e825119f1a7226e3e10a61ee", "amount": "1000.00000000", "from_addr": "", "signature": "556474088e1f4c75f24cb72db8b0be78134d10d0323c40569207baef1172c43b96596573a446389d2330d781109b76da8725d2ef29876cdd4a198fafc9cbf50f" }], "signature": "3a3a88935574c820fa70a2408f594585d03988df1980f6c0129b84ee129c322c683de1a7f8be6087d468abbbeb32f2a49eb0ac0c64a9b8de57d43a480ebf4dfc" } block = Block.from_dict(genesis_block) dal_block_service = DalBlockService() dal_block_service.store_block(block) actual = POSService.get_next_block_author(block) print(actual) assert actual == expected
def test_store_same_hash(): b = Block('block_service_test_1', '', '', 'LAST_BLOCK', 0, [], [], [], [], [], []) bs = BlockService() bs.store_block(b) new_b = bs.find_by_hash('block_service_test_1') assert b.get_sendable() != new_b.get_sendable() r = redis.Redis() r.flushdb()
def get_pos_pool(current_block): block_service_dal = BlockServiceDal() pos_transactions_before_block = block_service_dal.get_all_pos_transaction(current_block._hash) balances = {} # balances of all pos'ers for key, pos_transaction in pos_transactions_before_block.items(): # update address current balance balances[pos_transaction.from_addr] = pos_transaction.amount + balances.get(pos_transaction.from_addr, 0) if balances[pos_transaction.from_addr] == 0: balances.pop(pos_transaction.from_addr, None) return balances
def get_transaction_balances(): block_service_dal = BlockServiceDal() last_block_hash = BlockService.get_last_block_hash() transactions_before_block = block_service_dal.get_all_transaction_up_to_block( last_block_hash) balances = {} # update balances using all transaction from the past for key, transaction in transactions_before_block: balances[transaction.from_addr] = balances.get( transaction.from_addr, 0) - transaction.amount balances[transaction.to_addr] = balances.get( transaction.to_addr, 0) + transaction.amount return balances
def get_last_block_hash(): """ Gets the highest block's hash. Returns: string -- hash of the highest block """ block_dal = BlockServiceDal() max_height = block_dal.get_max_block_height() latest_blocks = block_dal.find_by_height(max_height) if len(latest_blocks) != 0: return latest_blocks[0]._hash else: return ''
def validate_incoming_block(block): block_dal = BlockServiceDal() objects = block_dal.get_all_objects_up_to_block(block) balances = BlockService.get_all_balances(objects) for key in balances.keys(): balance = balances[key] if key != '': if type(balance) is tuple: if balance[0] < 0 or balance[1] < 0: return False else: if balance < 0: print('insufficient funds on {}'.format(key)) return False return True
def verify_transactions(new_block): block_service_dal = BlockServiceDal() transactions_before_block = block_service_dal.get_all_transaction_up_to_block( new_block.prev_block) duplicate_transaction = False signatures_valid = True hashes_valid = True # balance for each from_addr in new block balances = {} for block_transaction in new_block.transactions: # update address current balance balances[block_transaction. from_addr] = block_transaction.amount + balances.get( block_transaction.from_addr, 0) # check that the transaction isnt used in earlier block if block_transaction._hash not in transactions_before_block: duplicate_transaction = True # TODO add logger # signature validation if new_block.prev_block and not block_transaction.valid_signature( ): signatures_valid = False if not block_transaction.valid_hash(): hashes_valid = False # update balances using all transaction from the past for key, transaction in transactions_before_block: if transaction.from_addr in balances: balances[transaction.from_addr] -= transaction.amount if transaction.to_addr in balances: balances[transaction.to_addr] += transaction.amount # not genesis block all_balance_positive = True if new_block.prev_block: # make sure each balance > 0 for key, balance in balances: if balance < 0: all_balance_positive = False # TODO add logger break return duplicate_transaction and all_balance_positive
def remove_stale_blocks(): """ Removes stale, unused blocks. Blocks are removed if starting from the newest block, they do not appear when following the chain of previous blocks. ie. []<-[]<-[]<-[]<-[]<-[]<-[]<-[]<-[]<-[] ^---[]<-[]<-[]<-[]<-[] In the above scenario, the bottom chain would be removed, moving all of those transactions back to the mempool. """ block_dal = BlockServiceDal() current_height = block_dal.get_max_block_height() highest_blocks = block_dal.find_by_height(current_height) # if there is only 1 block at the greatest height, we can prune old blocks if len(highest_blocks) == 1: # get all block hashes all_block_hashes = block_dal.get_all_block_hashes() correct_block_hashes = set() block = highest_blocks[0] # add current highest block to the set of correct blocks correct_block_hashes.add(block._hash) # TODO while there is still a previous block while block.prev_block != 'GENESIS_BLOCK': block = block_dal.find_by_hash(block.prev_block) # add to list of correct blocks correct_block_hashes.add(block._hash) print("correct_block_hashes len: " + str(len(correct_block_hashes))) print("\t" + str(correct_block_hashes)) # get the difference between the two sets of blocks to_remove = set(all_block_hashes) - correct_block_hashes print("to_remove: " + str(to_remove)) # remove each of the blocks for block_hash in to_remove: print("Removing block: " + block_hash) BlockService._remove_block_by_hash(block_hash)
def test_get_store_block(): test_time = int(time.time()) t1 = Transaction('transaction_test_1', '', 'matt', 'will', 45, 0, test_time) t2 = Transaction('transaction_test_2', '', 'matt', 'denys', 7, 0, test_time) t3 = Transaction('transaction_test_3', '', 'denys', 'steven', 33, 0, test_time) t4 = Transaction('transaction_test_4', '', 'steven', 'naween', 5040, 0, test_time) t5 = Transaction('transaction_test_5', '', 'will', 'naween', 22, 0, test_time) t6 = Transaction('transaction_test_6', '', 'naween', 'matt', 588, 0, test_time) b = Block('block_service_test_1', '', '', 'LAST_BLOCK', 0, [t1, t2, t3, t4, t5, t6], [], [], [], [], [], test_time) bs = BlockService() bs.store_block(b) new_b = bs.find_by_hash('block_service_test_1') b_send = b.get_sendable() new_send = new_b.get_sendable() assert b_send == new_send
def get_max_height(): """ Method Comment """ block_service_dal = BlockServiceDal() return block_service_dal.get_max_block_height()
def get_all_balances(objects=None): if objects == None: block_dal = BlockServiceDal() last_block_hash = BlockService.get_last_block_hash() block = block_dal.find_by_hash(last_block_hash) objects = block_dal.get_all_objects_up_to_block(block) balances = {} print('------------TRANSACTION PAYOUT------------') # Transactions transaction_dict = objects.get('transactions', {}) for transaction_hash in transaction_dict: transaction = transaction_dict.get(transaction_hash) balances[transaction.from_addr] = balances.get( transaction.from_addr, 0) - transaction.amount balances[transaction.to_addr] = balances.get( transaction.to_addr, 0) + transaction.amount print('------------POS TRANSACTION PAYOUT------------') # Proof of Stake Transactions pos_transaction_dict = objects.get('pos_transactions', {}) for pos_transaction_hash in pos_transaction_dict: pos_transaction = pos_transaction_dict.get(pos_transaction_hash) balances[pos_transaction.from_addr] = balances.get( pos_transaction.from_addr, 0) - pos_transaction.amount print('------------SIGNED CONTRACT PAYOUT------------') # Signed Contracts signed_contract_dict = objects.get('signed_contracts', {}) for signed_contract_hash in signed_contract_dict: signed_contract = signed_contract_dict[signed_contract_hash] balances[signed_contract.from_addr] = balances.get( signed_contract.from_addr, 0) - signed_contract.amount print('sc|| from:\t' + signed_contract.from_addr + ": balance:" + str(balances[signed_contract.from_addr])) balances[signed_contract._hash] = ( balances.get(signed_contract._hash, (0, 0))[0] + signed_contract.amount, 0) print('sc|| parent:\t' + signed_contract._hash + ": balance:" + str(balances[signed_contract._hash])) print('------------CONTRACT TRANSACTION PAYOUT------------') # Contract Transactions contract_transaction_dict = objects.get('contract_transactions', {}) temp_contracts = {} for key, contract_transaction in contract_transaction_dict.items(): temp_contracts[contract_transaction. signed_contract_addr] = temp_contracts.get( contract_transaction.signed_contract_addr, list()) temp_contracts[contract_transaction.signed_contract_addr].append( contract_transaction) unspent_cts = {} for signed_contract_addr in temp_contracts.keys(): # sort by signed_contract_addr first, then to_symbol, then from_symbol, then price contract_transactions = sorted( temp_contracts[signed_contract_addr], key=lambda ct: (ct.signed_contract_addr, ct.timestamp)) print('owner:' + signed_contract_addr + " len=" + str(len(contract_transactions))) for contract_transaction in contract_transactions: if contract_transaction.from_symbol == 'TPS': # remove from balance print('\tFROM TPS| amount: ' + str(contract_transaction.amount) + ' @ ' + str(contract_transaction.price) + ' ct hash:' + contract_transaction._hash) balances[contract_transaction.signed_contract_addr] = ( balances.get(contract_transaction.signed_contract_addr, (0, 0))[0] - contract_transaction.amount, balances.get( contract_transaction.signed_contract_addr)[1] + contract_transaction.amount) print('\t\t' + contract_transaction.signed_contract_addr + ": balance:" + str(balances[ contract_transaction.signed_contract_addr])) unspent_cts[signed_contract_addr] = unspent_cts.get( signed_contract_addr, list()) unspent_cts[signed_contract_addr].append( contract_transaction) elif contract_transaction.to_symbol == 'TPS': print('\tTO TPS| amount: ' + str(contract_transaction.amount) + ' @ ' + str(contract_transaction.price) + ' ct hash:' + contract_transaction._hash) # sort by price first unspent_cts[signed_contract_addr].sort( key=lambda ct: ct.price) amount_remaining = contract_transaction.amount # iterate through copy of unspent_cts, removing as they are used up for unspent_ct in unspent_cts[signed_contract_addr]: # if took place before current contract transaction if amount_remaining == 0: break if unspent_ct.timestamp <= contract_transaction.timestamp and unspent_ct.amount != 0: if amount_remaining - unspent_ct.amount == 0: print('\t\t->B:S') # sell contract is used up, buy contract is used up amount_remaining -= unspent_ct.amount profit = contract_transaction.price / unspent_ct.price * unspent_ct.amount print('\t\t' + str(contract_transaction.price) + "/" + str(unspent_ct.price) + "*" + str(unspent_ct.amount) + "=" + str(profit)) balances[ contract_transaction. signed_contract_addr] = ( balances[contract_transaction. signed_contract_addr][0] + profit, balances[contract_transaction. signed_contract_addr][1] - unspent_ct.amount) print( '\t\t' + contract_transaction.signed_contract_addr + ' amount: ' + str( balances.get(contract_transaction. signed_contract_addr)) + ' (added: ' + str(profit) + ")") unspent_ct.amount = 0 break elif amount_remaining - unspent_ct.amount > 0: print('\t\t->B') # sell contract is not used up, buy contract is used up profit = contract_transaction.price / unspent_ct.price * unspent_ct.amount print('\t\t' + str(contract_transaction.price) + "/" + str(unspent_ct.price) + "*" + str(unspent_ct.amount) + "=" + str(profit)) balances[ contract_transaction. signed_contract_addr] = ( balances[contract_transaction. signed_contract_addr][0] + profit, balances[contract_transaction. signed_contract_addr][1] - unspent_ct.amount) print( '\t\t' + contract_transaction.signed_contract_addr + ' amount: ' + str( balances.get(contract_transaction. signed_contract_addr)) + ' (added: ' + str(profit) + ")") amount_remaining -= unspent_ct.amount unspent_ct.amount = 0 continue elif amount_remaining - unspent_ct.amount < 0: print('\t\t->S') # sell contract is used up, buy contract is not profit = contract_transaction.price / unspent_ct.price * amount_remaining print('\t\t' + str(contract_transaction.price) + "/" + str(unspent_ct.price) + "*" + str(amount_remaining) + "=" + str(profit)) balances[ contract_transaction. signed_contract_addr] = ( balances[contract_transaction. signed_contract_addr][0] + profit, balances[contract_transaction. signed_contract_addr][1] - amount_remaining) print( '\t\t' + contract_transaction.signed_contract_addr + ' amount: ' + str( balances.get(contract_transaction. signed_contract_addr)) + ' (added: ' + str(profit) + ")") unspent_ct.amount -= amount_remaining amount_remaining = 0 break # Terminated Contracts print('------------TERMINATED CONTRACT PAYOUT------------') term_contract_dict = objects.get('terminated_contracts', {}) for signed_contract_addr in term_contract_dict.keys(): print(signed_contract_addr + "||unspent cts len: " + str(len(unspent_cts.get(signed_contract_addr, [])))) terminated_contract = term_contract_dict.get(signed_contract_addr) for unspent_ct in unspent_cts.get(signed_contract_addr, []): print('\thash:' + unspent_ct._hash + ' -> amount:' + str(unspent_ct.amount)) if unspent_ct.timestamp <= terminated_contract.timestamp and unspent_ct.amount != 0: profit = terminated_contract.price / unspent_ct.price * unspent_ct.amount print('\t\t' + str(terminated_contract.price) + "/" + str(unspent_ct.price) + "*" + str(unspent_ct.amount) + "=" + str(profit)) balances[signed_contract_addr] = ( balances[signed_contract_addr][0] + profit, balances[signed_contract_addr][1] - unspent_ct.amount) unspent_ct.amount = 0 print('\t\t' + signed_contract_addr + ' amount: ' + str(balances.get(signed_contract_addr)) + ' (added: ' + str(profit) + ")") signed_contract = signed_contract_dict.get(signed_contract_addr, None) if signed_contract != None: base_amount = signed_contract.amount final_amount = balances[signed_contract_addr][0] profit = final_amount - base_amount print('----TOTAL PROFIT:' + str(profit)) from_addr_profit = 0 contract_owner_profit = 0 if profit > 0: # if profit was made, split profit among both accounts # contract owner gets the profit at the specified rate contract_owner_profit = profit * signed_contract.rate # account that signed gets remaining profit from_addr_profit = profit - contract_owner_profit else: # if no profit was made, from_addr gets all of the money remaining contract_owner_profit = 0 from_addr_profit = final_amount balances[signed_contract.parent_owner] = balances.get( signed_contract.parent_owner, 0) + contract_owner_profit print('-----' + signed_contract.parent_owner + ' amount: ' + str(balances.get(signed_contract.parent_owner)) + ' (added: ' + str(contract_owner_profit) + ")") balances[signed_contract.from_addr] = balances.get( signed_contract.from_addr, 0) + from_addr_profit print('-----' + signed_contract.from_addr + ' amount: ' + str(balances.get(signed_contract.from_addr)) + ' (added: ' + str(from_addr_profit) + ")") balances[signed_contract._hash] = (0, 0) # Contracts contract_dict = objects.get('contracts', {}) # Owners # print('------------MINER PAYOUT------------') owners = objects.get('owners', []) for owner in owners: balances[owner] = balances.get(owner, 0) + 10 # print('owner: ' + owner + ' amount: ' + str(balances[owner]) + ' (added: 10)') return balances
def add_block_to_chain(block): """ Method Comment """ block_service_dal = BlockServiceDal() return block_service_dal.store_block(block)
def test_pos_author_two_blocks(): expected = '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0' r = redis.Redis() r.flushdb() genesis_block = { "height": 0, "prev_block": "", "_hash": "036850bec30839508bf16badc1efc5c0a31eb82f8b23c524c7ea8cd3d0c8b81f", "terminated_contracts": [], "signed_contracts": [], "contracts": [], "pos_transactions": [{ "from_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "82b2704e380f4bc55c214d44f4cdd698ec3ed5471882d0ae67d80462f13434f5", "amount": "100.00000000", "signature": "2b6f4ad89868f8a820f682fb580a20b3383e9889b50736a66c8ed441ac4ebb29b7f32d6efe929b05d66de7ac0e20d0ea471f7a1e482f505f2f0df3221d720ba4" }], "contract_transactions": [], "timestamp": 1520135639, "owner": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "transactions": [{ "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "f54029850ab8ffc3d3f1b210bee0008f1b42aa45e267925f42b80ed9eedb1c20", "amount": "1.00000000", "from_addr": "", "signature": "36a0131c4087dae1d0909baf5ea1b35c9955db7e775646df40d35ad6469469b21439e08263ab7a2fa03f3285fb13ce1b80b399bb6f254694e3f36b9ed5fa6a98" }, { "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "ac32ce4867f65d575d95109b59e713f180541cd5c76ca93dad7cea210ebfa26c", "amount": "10.00000000", "from_addr": "", "signature": "83abc47ca9ad48e91b63d6d4bba28786abfc7345f29f02dbf1c90b4e66f91413cf9a081314095d4bf30d508b9781d035a5816f13ea0c1f1d6b6dd59665697b15" }, { "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "e1e65c22699599507d2621b84a39b02ca525e5d3881c583d4d96cffdf3ceced7", "amount": "100.00000000", "from_addr": "", "signature": "998d03e220b28ad99b2b6d7a00cc1a06443ceea8a3a96acc896c6d8953b44d78f58a6cfbf699d5b4ed35f062cb05674d2f10718ecf44d07a300a781c21734220" }, { "to_addr": "c8fdd9558e4e36d3549c449986c587aa16be67439ed70b8bf1f7e47e8586572f4c821059e4077a94d3e31f1cfa8bccc5c2acf86e955d30ef93633bcabcdc9f34", "timestamp": 1520135639, "_hash": "b3cf3fba2d1b5e3ca6fee0b5d22a1b81f038ffd9e825119f1a7226e3e10a61ee", "amount": "1000.00000000", "from_addr": "", "signature": "556474088e1f4c75f24cb72db8b0be78134d10d0323c40569207baef1172c43b96596573a446389d2330d781109b76da8725d2ef29876cdd4a198fafc9cbf50f" }], "signature": "3a3a88935574c820fa70a2408f594585d03988df1980f6c0129b84ee129c322c683de1a7f8be6087d468abbbeb32f2a49eb0ac0c64a9b8de57d43a480ebf4dfc" } second_block = { '_hash': '1048eb4638a45b140a51e7a6d92e972010878d9f05be6fe5c0d20d17b4c26e7a', 'height': 1, 'contract_transactions': [], 'transactions': [{ 'amount': '1.00000000', 'to_addr': '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0', 'timestamp': 1520135639, '_hash': '188b1e41db5661c87777d7ea3d96cbe0b8858df2cd9c020abb4a424f91c22087', 'from_addr': '', 'signature': 'c3d5bdf941cf4a4a95483174e085da38cc4f7decb59cf07ce3ac80623de7e842f46b1d7f6880c358fe4b0ead324ba5af4176743bfd390daf34f79a6ed5e51de8' }, { 'amount': '10.00000000', 'to_addr': '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0', 'timestamp': 1520135639, '_hash': '004186e14438ea30c3d6ee69dfdc4b66d589e6d5d85c751bfae1220ecdbe8954', 'from_addr': '', 'signature': '8d02e40b4923aa1e9869ab48c8de423a510f966e6edb3def1013cf243fe9b7c6ab9c77fa485a02ff03fc769f9e1c36f9085210058d729ed4d71194d7e6c98335' }, { 'amount': '100.00000000', 'to_addr': '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0', 'timestamp': 1520135639, '_hash': '9463a74fa3e79a5a7f0dee4c8b0d06cdf5624dc529b2d1915cdffabfcdece8ff', 'from_addr': '', 'signature': '26962120d2621f61ce4281169d97a06fc508d0246e9779dc3d50a04382f469389166b040d54fab4f00b45fa4ef9ff69296709b1165afb1e695ff893124325e47' }, { 'amount': '1000.00000000', 'to_addr': '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0', 'timestamp': 1520135639, '_hash': '79ba95186cf2068aa7868057661e315856e44d43a7b3e1fdebfdd9cf7e9679d1', 'from_addr': '', 'signature': '5b8dfb857bbee98edc869948bcd90b361d2a9ac48704981cd4a4697ae090b22bf3389b2a0d17ed198f7c9aaa98baa68db5d869279a5065c6ebb44dcb628d06f7' }], 'timestamp': 1520135642, 'terminated_contracts': [], 'signed_contracts': [], 'contracts': [], 'prev_block': '036850bec30839508bf16badc1efc5c0a31eb82f8b23c524c7ea8cd3d0c8b81f', 'signature': '829ac7859ca675ea410a781cf30b39fd7864daeda054c50893001da164d04cfacab103dc57cb9d39e545b8533dbd8d54954c3399c01bc356c06801e48242d531', 'owner': '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0', 'pos_transactions': [{ '_hash': '1d1d4247b7611a28e66b114a14445e894dfb7086accb8d02f6f1ac06ff15e049', 'amount': '100.00000000', 'from_addr': '23f48768a8e871db2ed721a1e0d250ce41a1fe49765e01e798db0816b781169115e01d3a702934276fa4536bb59527ba0cd7c2fd9eb9e3c13785750c4a9c31d0', 'signature': 'b7e348c8ebe6e483279a22d1426d31122f14a4ea46b27b9fa85d2cd91b533abc463cafd85ddf524f3677daabf888a146f91721cac26a17568a768a3c18956a15', 'timestamp': 1520135639 }] } dal_block_service = DalBlockService() block = Block.from_dict(genesis_block) dal_block_service.store_block(block) block = Block.from_dict(second_block) dal_block_service.store_block(block) actual = POSService.get_next_block_author(block) assert actual == expected