def test_transaction_hashable_fail(): test_time = int(time.time()) block_time = int(time.time()) transaction_1 = Transaction('block_hash_test', '', 'to_steven_test', 'from_matt_test', 1, test_time) transaction_2 = Transaction('block_hash_test2', '', 'to_matt_test', 'from_steven_test', 1, test_time) block = Block('_hash_test', '','', 'LAST_BLOCK', 0, [ transaction_1, transaction_2 ], [], [], [], [], [], block_time) actual = block.get_hashable() expected = { 'owner': '', 'prev_block': 'LAST_BLOCK', 'height': 0, 'signature': '', 'transactions': [ transaction_1.get_sendable(), transaction_2.get_sendable() ], 'pos_transactions': [], 'contract_transactions': [], 'contracts': [], 'signed_contracts': [], 'terminated_contracts': [], 'timestamp': block_time } 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 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_hashable_fail(): test_time = int(time.time()) block = Block('block_hash_test', '', '', 'LAST_BLOCK', 0, [], [], [], [], [], [], test_time) actual = block.get_hashable() not_expected = { 'owner': '', 'prev_block': 'LAST_BLOCK', 'height': 1, 'signature': '', 'transactions': [], 'pos_transactions': [], 'contract_transactions': [], 'contracts': [], 'signed_contracts': [], 'terminated_contracts': [], 'timestamp': test_time } assert actual != not_expected
def test_sendable(): test_time = int(time.time()) block = Block('block_send_test', '', '', 'LAST_BLOCK', 0, [], [], [], [], [], [], test_time) actual = block.get_sendable() expected = { 'owner': '', 'prev_block': 'LAST_BLOCK', 'height': 0, 'signature': '', 'transactions': [], 'pos_transactions': [], 'contract_transactions': [], 'contracts': [], 'signed_contracts': [], 'terminated_contracts': [], 'timestamp': test_time, '_hash': 'block_send_test' } assert actual == expected
def generate_from_priv(private_key): time_now = 1520135639.4713802 public = EcdsaHashing.recover_public_key_str(private_key) transactions = [ Transaction('', '', public, '', 1, 1, time_now), Transaction('', '', public, '', 10, 1, time_now), Transaction('', '', public, '', 100, 1, time_now), Transaction('', '', public, '', 1000, 1, time_now), ] for tranaction in transactions: tranaction.update_signature(private_key) tranaction.update_hash() pos_transactions = [PosTransaction('', '', public, 100, 1, time_now)] for pos_transaction in pos_transactions: pos_transaction.update_signature(private_key) pos_transaction.update_hash() block = Block('', '', public, '', 0, transactions, pos_transactions, [], [], [], [], time_now) block.update_signature(private_key) block.update_hash() return block
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 mine_block(miner_priv_key, last_block): balances = BlockService.get_all_balances() transactions = BaseObjectService.get_all_mempool_objects(Transaction) transactions_to_add = [] for transaction in transactions: if len(transactions_to_add) == 100: break valid, balances = Miner.validate_transaction(balances, transaction) if valid: transactions_to_add.append(transaction) pos_transactions = BaseObjectService.get_all_mempool_objects( PosTransaction) pos_transactions_to_add = [] for pos_transaction in pos_transactions: if len(pos_transactions_to_add) == 10: break valid, balances = Miner.validate_pos_transaction( balances, pos_transaction) if valid: pos_transactions_to_add.append(pos_transaction) contract_transactions = BaseObjectService.get_all_mempool_objects( ContractTransaction) contract_transactions_to_add = [] for contract_transaction in contract_transactions: if len(contract_transactions_to_add) == 10: break valid, balances = Miner.validate_contract_transaction( balances, contract_transaction) if valid: contract_transactions_to_add.append(contract_transaction) contracts = BaseObjectService.get_all_mempool_objects(Contract) contracts_to_add = [] for contract in contracts: if len(contracts_to_add) == 20: break valid, balances = Miner.validate_contract(balances, contract) if valid: contracts_to_add.append(contract) signed_contracts = BaseObjectService.get_all_mempool_objects( SignedContract) signed_contracts_to_add = [] for signed_contract in signed_contracts: print('signed_contract:' + signed_contract._hash) if len(signed_contracts_to_add) == 20: break valid, balances = Miner.validate_signed_contract( balances, signed_contract) if valid: signed_contracts_to_add.append(signed_contract) terminated_contracts_to_add = [] signed_contracts_to_check = SignedContractService.get_all_open_signed_contracts( ) for sc_to_check in signed_contracts_to_check: print('signed_c to check: ' + sc_to_check._hash) end_time = sc_to_check.signed_timestamp + sc_to_check.duration now = int(time.time()) # print('signed_time=' + str(sc_to_check.signed_timestamp) + ' duration=' + str(sc_to_check.duration) + ' end time='+ str(end_time) + ' now=' + str(now) + ' end<=now=' + str(end_time<=now)) if end_time <= now: rs = RedisService() r = rs._connect() prices = r.zrangebyscore('price_stamps', end_time - 2000, end_time + 2000, withscores=True) if len(prices) != 0: price = min(prices, key=lambda x: abs(x[1] - end_time)) print('terminated contract: ' + sc_to_check._hash) tc = TerminatedContract(sc_to_check._hash, price[0], end_time) terminated_contracts_to_add.append(tc) else: print('no prices found') last_block_hash = last_block._hash miner_pub_key = EcdsaHashing.recover_public_key_str(miner_priv_key) height = last_block.height + 1 block = Block('', '', miner_pub_key, last_block_hash, height, transactions_to_add, pos_transactions_to_add, contract_transactions_to_add, contracts_to_add, signed_contracts_to_add, terminated_contracts_to_add, time.time()) block.update_signature(miner_priv_key) block.update_hash() return block
def regular_node_callback(data, peer_id=None): global kill_threads if kill_threads: return do_block_resend = False do_transaction_resend = True do_contract_resend = True sync_transaction = False sync_block = False sync_contract = False signed_contract_flag = False contract_transaction_flag = False pos_transaction_flag = False json_dic = json.loads(data) new_msg = message.Message.from_dict(json_dic) # sync block is the same as block, but they don't # need to be resend if new_msg.action == 'block_sync': new_msg.action = 'block' do_block_resend = False sync_block = True elif new_msg.action == 'transaction_sync' or new_msg.action == 'transaction_pos_sync' or new_msg.action == 'transaction_contract_sync': if new_msg.action == 'transaction_sync': new_msg.action = 'transaction' elif new_msg.action == 'transaction_pos_sync': new_msg.action = 'transaction_pos' elif new_msg.action == 'transaction_contract_sync': new_msg.action = 'transaction_contract' do_transaction_resend = False sync_transaction = True elif new_msg.action == 'contract_sync' or new_msg.action == 'contract_signed_sync': if new_msg.action == 'contract_sync': new_msg.action = 'contract' elif new_msg.action == 'contract_signed_sync': new_msg.action = 'contract_signed' do_contract_resend = False sync_contract = True # case to set flags for special types of transactions and contracts if new_msg.action == 'contract_signed': new_msg.action = 'contract' signed_contract_flag = True elif new_msg.action == 'transaction_contract': new_msg.action = 'transaction' contract_transaction_flag = True elif new_msg.action == 'transaction_pos': new_msg.action = 'transaction' pos_transaction_flag = True if new_msg.action == 'transaction': if contract_transaction_flag: print('\nContract Transaction') new_msg.data = ContractTransaction.from_dict(new_msg.data) object_to_check = ContractTransaction transaction_action = 'transaction_contract' elif pos_transaction_flag: print('\nPOS Transaction') new_msg.data = PosTransaction.from_dict(new_msg.data) object_to_check = PosTransaction transaction_action = 'transaction_pos' else: print('\nNormal Transaction') new_msg.data = Transaction.from_dict(new_msg.data) object_to_check = Transaction transaction_action = 'transaction' new_transaction = new_msg.data need_to_send = False transaction_lock.acquire() print('\nTransaction : {}'.format(new_transaction._hash)) if not check_if_object_exist(new_transaction._hash, object_to_check): if a_node.doing_transaction_sync and not sync_transaction: a_node.transaction_queue.append(new_transaction) print('Added transaction to the queue') else: rs = redis_service.RedisService() rs.store_object(new_transaction) need_to_send = True print('All good') else: print('Duplicate transaction') transaction_lock.release() if need_to_send and do_transaction_resend: send_a_transaction(new_transaction, action=transaction_action) elif new_msg.action == 'contract': if signed_contract_flag: print('\nSigned Contract') new_msg.data = SignedContract.from_dict(new_msg.data) object_to_check = SignedContract method_to_call = SignedContractService.store_signed_contract contract_action = 'contract_signed' else: print('\nNormal Contract') new_msg.data = Contract.from_dict(new_msg.data) object_to_check = Contract method_to_call = ContractService.store_contract contract_action = 'contract' new_contract = new_msg.data need_to_send = False contract_lock.acquire() print('Contract : {}'.format(new_contract._hash)) if not check_if_object_exist(new_contract._hash, object_to_check): if a_node.doing_contract_sync and not sync_contract: a_node.contract_queue.append([new_contract, method_to_call]) print('Added contract to the queue') else: method_to_call(new_contract) need_to_send = True print('All good') else: print('Duplicate contract') contract_lock.release() if need_to_send and do_contract_resend: send_a_contract(new_contract, action=contract_action) elif new_msg.action == 'transaction_sync_end': print('\n\nFinished transaction sync') a_node.doing_transaction_sync = False a_node.add_transactions_from_queue() elif new_msg.action == 'block_sync_end': print('\n\nFinished block sync') a_node.doing_blockchain_sync = False # after we have added all sync blocks # we need to add normal blocks # that were send while we where doing sync a_node.add_blocks_from_queue() elif new_msg.action == 'contract_sync_end': print('\n\nFinished contract sync') a_node.doing_contract_sync = False a_node.add_contracts_from_queue() elif new_msg.action == 'init_sync_contract': print('Contract sync request') mem_contracts = BaseObjectService.get_all_mempool_objects(Contract) print('I have {} contracts'.format(len(mem_contracts))) mem_signed_contracts = BaseObjectService.get_all_mempool_objects( SignedContract) print('I have {} signed contracts'.format(len(mem_signed_contracts))) contract_lock.acquire() for a_contract in mem_contracts: send_a_contract(a_contract, action='contract_sync', contract_target_peer_id=peer_id) for a_signed_contract in mem_signed_contracts: send_a_contract(a_signed_contract, action='contract_signed_sync', contract_target_peer_id=peer_id) ending_msg = message.Message(action='contract_sync_end', data='') json_dic = ending_msg.to_json(is_object=False) json_str = json.dumps(json_dic, sort_keys=True, separators=(',', ':')) a_node.connection_manager.send_msg(msg=json_str, target_peer_id=peer_id) contract_lock.release() elif new_msg.action == 'init_sync_trans': print('Transaction sync request') mem_transactions = TransactionService.get_all_mempool_transactions() print('I have {} mem transactions'.format(len(mem_transactions))) mem_pos_transactions = BaseObjectService.get_all_mempool_objects( PosTransaction) print('I have {} mem pos transactions'.format( len(mem_pos_transactions))) mem_contract_transactions = BaseObjectService.get_all_mempool_objects( ContractTransaction) print('I have {} mem contract transactions'.format( len(mem_contract_transactions))) transaction_lock.acquire() for a_transaction in mem_transactions: send_a_transaction(a_transaction, action='transaction_sync', transaction_target_peer_id=peer_id) for a_pos_transaction in mem_pos_transactions: send_a_transaction(a_pos_transaction, action='transaction_pos_sync', transaction_target_peer_id=peer_id) for a_contract_transaction in mem_contract_transactions: send_a_transaction(a_contract_transaction, action='transaction_contract_sync', transaction_target_peer_id=peer_id) ending_msg = message.Message(action='transaction_sync_end', data='') json_dic = ending_msg.to_json(is_object=False) json_str = json.dumps(json_dic, sort_keys=True, separators=(',', ':')) a_node.connection_manager.send_msg(msg=json_str, target_peer_id=peer_id) transaction_lock.release() elif new_msg.action == 'init_sync': print('\nGot init sync, height is {}'.format(new_msg.data)) peer_height = new_msg.data my_height = BlockService.get_max_height() # only do sync if we need to send blocks to a peer if peer_height < my_height: print('My height is higher, {}'.format(my_height)) bs = dal_service_block_service.BlockService() list_of_blocks = bs.get_blocks_after_height(peer_height) block_lock.acquire() for a_block in list_of_blocks: send_a_block(a_block, action='block_sync', block_target_peer_id=peer_id) ending_msg = message.Message(action='block_sync_end', data='') json_dic = ending_msg.to_json(is_object=False) json_str = json.dumps(json_dic, sort_keys=True, separators=(',', ':')) a_node.connection_manager.send_msg(msg=json_str, target_peer_id=peer_id) block_lock.release() else: print('Same height') ending_msg = message.Message(action='block_sync_end', data='') json_dic = ending_msg.to_json(is_object=False) json_str = json.dumps(json_dic, sort_keys=True, separators=(',', ':')) a_node.connection_manager.send_msg(msg=json_str, target_peer_id=peer_id) elif new_msg.action == 'block': block_service = BlockService() new_block = Block.from_dict(new_msg.data) bs = dal_service_block_service.BlockService() need_to_send = False need_to_mine_new = False block_lock.acquire() print('\nBlock : {}'.format(new_block._hash)) # if the node is doing blockchain sync # and this block is not sync block # we need to add it to the queue if a_node.doing_blockchain_sync and not sync_block: a_node.block_queue.append(new_block) result_list = [] else: if Miner.validate_incoming_block(new_block): result_list = block_service.add_block_to_chain(new_block) if result_list: need_to_mine_new = True else: result_list = [] if result_list: need_to_send = True print('All good') else: if a_node.doing_blockchain_sync and not sync_block: print('Added block to a queue') else: print('Duplicate block') block_lock.release() if need_to_send and do_block_resend: send_a_block(new_block) need_to_mine_new = False if need_to_mine_new: for new_block_callback in new_block_callbacks: new_block_callback(new_block)
def find_by_hash(self, block_hash): """ Find a block using it's hash. Will return the block object, fully populated with all of the objects encased in it. Arguments: block_hash -- hash of the block to retrieve Returns: block object -- Block object containing all of the objects included in the block """ r = self._connect() #rs = RedisService() # get key to retrieve list of block's fields name = self.key_suffix + block_hash if r.exists(name): # get all of the fields in the list hashes = r.lrange(name, 0, -1) # timestamp will always be first prev_block = hashes[0] # remove for iteration hashes.remove(prev_block) # timestamp will always be first height = hashes[0] # remove for iteration hashes.remove(height) # timestamp will always be first owner = hashes[0] # remove for iteration hashes.remove(owner) # timestamp will always be first signature = hashes[0] # remove for iteration hashes.remove(signature) # timestamp will always be first timestamp = hashes[0] # remove for iteration hashes.remove(timestamp) prefix = '' # list to hold all of the objects transactions = [] pos_transactions = [] contract_transactions = [] contracts = [] signed_contracts = [] terminated_contracts = [] # temporary list to copy from temp_list = [] obj = None contract_section = False signed_contract_section = False terminated_contract_section = False for h in hashes: # if at a new type of object, change some variables if h == 'transactions': prefix = Transaction._to_index()[-1] obj = Transaction continue elif h == 'pos_transactions': prefix = PosTransaction._to_index()[-1] obj = PosTransaction transactions = temp_list.copy() temp_list.clear() continue elif h == 'contract_transactions': prefix = ContractTransaction._to_index()[-1] obj = ContractTransaction pos_transactions = temp_list.copy() temp_list.clear() continue elif h == 'contracts': contract_section = True elif h == 'signed_contracts': contract_section = False signed_contract_section = True elif h == 'terminated_contracts': signed_contract_section = False terminated_contract_section = True # get the object from redis and add to the temporary list if contract_section: contract = ContractService.get_contract_by_hash(h) if contract != None: contracts.append(contract) elif signed_contract_section: signed_contract = SignedContractService.get_signed_contract_by_hash(h) if signed_contract != None: signed_contracts.append(signed_contract) elif terminated_contract_section: terminated_contract = self.rs.get_object_by_full_key('terminated_contract:' + h, TerminatedContract, r) if terminated_contract != None: terminated_contracts.append(terminated_contract) else: t = self.rs.get_object_by_full_key(prefix + ":" + h, obj, r) temp_list.append(t) contract_transactions = temp_list.copy() temp_list.clear() # create block object and return it block = Block(block_hash, signature, owner, prev_block, height, transactions, pos_transactions, contract_transactions, contracts, signed_contracts, terminated_contracts, timestamp) return block else: return None
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