def lithium_instance(self, run_event, rpc_from, rpc_to, from_account, to_account, lock, link, batch_size): ionlock = rpc_from.proxy("abi/IonLock.abi", lock, from_account) batch = [] prev_root = merkle_hash("merkle-tree-extra") print("Starting block iterator") print("Latest Block: ", ionlock.LatestBlock) for is_latest, block_group in self.iter_blocks(run_event, rpc_from, ionlock.LatestBlock()): items, group_tx_count, group_log_count, transfers = self.process_block_group( rpc_from, block_group) if items: for value in items: self.leaves.append(value) pack_items(self.leaves) print("blocks %d-%d (%d tx, %d events)" % (min(block_group), max(block_group), group_tx_count, group_log_count)) tree, root = merkle_tree(self.leaves) batch.append((block_group[0], root, transfers[0])) if is_latest or len(batch) >= batch_size: print("Submitting batch of", len(batch), "blocks") prev_root = self.lithium_submit(batch, prev_root, rpc_to, link, to_account, self.checkpoints, self.leaves) batch = [] return 0
def api_proof(): """ POST: Arguments: JSON with leaf, blockid in the form {'leaf': <some_leaf>, 'blockid': <some_blockid>} Return: If passed valid information returns merkle proof to supplied leaf of relevant blockid """ if request.method == 'POST': json = request.get_json() leaf = json[u'leaf'] blockid = json[u'blockid'] else: return "Please POST leaf data." if leaf is not None and blockid is not None: nleaves = app.lithium.checkpoints[blockid] tree, root = merkle_tree(app.lithium.leaves[:nleaves]) hex_leaf = leaf.decode('hex') path = merkle_path(hex_leaf, tree) string_path = [str(x) for x in path] dict = {u'proof': string_path} return jsonify(dict) else: return "No valid leaf received."
def api_root(): """ GET: Return: The root for the merkle tree of all leaves """ byte_leaves = app.lithium.leaves tree, root = merkle_tree(byte_leaves) dict = {u'root': root} return jsonify(dict)
def test_merkle_tree(self): """ Test merkle tree generation """ print("\nTest: Merkle tree generation") tree, root = merkle_tree(TEST_DATA) self.assertTrue(tree == EXPECTED_TREE) self.assertTrue(root == EXPECTED_ROOT) print("Test: Merkle tree generation success")
def api_verify_proof(): """ POST: Arguments: JSON with leaf, proof, blockid in the form {'leaf': <some_leaf>, 'proof': [<array_of_path>] 'blockid': <some_blockid>} Return: If passed valid information returns a boolean verifying in the supplied leaf is part of the merkle tree """ if request.method == 'POST': json = dict(request.get_json()) leaf = json[u'leaf'] proof = json[u'proof'] blockid = json[u'blockid'] else: return "Please POST leaf and path data." if leaf is not None and proof is not None and blockid is not None: nleaves = app.lithium.checkpoints[blockid] leaves = app.lithium.leaves[0:nleaves] tree, root = merkle_tree(leaves) hex_leaf = leaf.decode('hex') proof = merkle_proof(hex_leaf, proof, root) return jsonify({"verified": proof}) else: return "No valid leaf or path provided."
def test_integration(self): print("\nTest: Integration") totalSupply_a = 1000 totalSupply_b = 1000 value_a = 10 value_b = 10 rawRef_a = 'Hello world!' rawRef_b = 'Hello world!' # Assert that both testrpc A and B are live sockA = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sockA.settimeout(2) self.assertFalse(sockA.connect_ex(('127.0.0.1', 8545)), "Please run testrpc on 127.0.0.1:8545") sockB = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sockB.settimeout(2) self.assertFalse(sockB.connect_ex(('127.0.0.1', 8546)), "Please run testrpc on 127.0.0.1:8546") # First iteration of block rpc_a = arg_ethrpc(None, None, '127.0.0.1:8545') rpc_b = arg_ethrpc(None, None, '127.0.0.1:8546') ionlock_a = rpc_a.proxy("abi/IonLock.abi", lock, owner) ionlock_b = rpc_b.proxy("abi/IonLock.abi", lock, owner) ionlink_a = rpc_a.proxy("abi/IonLink.abi", link, owner) ionlink_b = rpc_b.proxy("abi/IonLink.abi", link, owner) token_a = rpc_a.proxy("abi/Token.abi", tokAddr, send) token_b = rpc_b.proxy("abi/Token.abi", tokAddr, recv) batch_a = [] batch_b = [] transfers = [] prev_root = merkle_hash("merkle-tree-extra") ################################################################################ print("Starting block iterator: rpc_a") print("latest Block rpc_a: ", ionlock_a.LatestBlock()) # Note this is the un-wound infinite loop of iter_blocks start = rpc_a.eth_blockNumber() # Now deploy the tokens on the networks token_a.mint(totalSupply_a) token_a.metadataTransfer(lock, value_a, rawRef_a) obh = min(start + 1, max(1, rpc_a.eth_blockNumber() - 0)) print("Starting block header rpc_a: ", start) print("Previous block header rpc_a: ", obh) self.assertEqual(start, 8) obh -= obh % 1 blocks = [] is_latest = False # Pack the blocks into batches bh = rpc_a.eth_blockNumber() + 1 print("Current block header rpc_a: ", bh) for i in range(obh, bh): # XXX TODO: I think this is why the latest block info is not always in sync with geth if i == (bh - 1): is_latest = True blocks.append(i) obh = bh # Show the blocks to work on and then rename just to keep convention from lithium.py block_group = blocks self.assertEqual(len(blocks), 2) # Process the block on chain A items, group_tx_count, group_log_count, transfers = lithium_process_block_group( rpc_a, block_group) item_tree_a, root = merkle_tree(items) for i in range(0, len(block_group)): batch_a.append((block_group[i], root, transfers[i])) prev_root = lithium_submit(batch_a, prev_root, rpc_b, link, owner) latestBlockB = ionlink_b.GetLatestBlock() path_a = merkle_path(items[1], item_tree_a) leafHashB = sha3(items[1]) reference_a = sha3(rawRef_a) ionlock_b = rpc_b.proxy("abi/IonLock.abi", lock, send) # print(ionlink_b.Verify(latestBlockB, leafHashB, path_a)) ################################################################################ print("Starting block iterator: rpc_b") print("latest Block rpc_b: ", ionlock_b.LatestBlock()) # Note this is the un-wound infinite loop of iter_blocks start = rpc_b.eth_blockNumber() # Now deploy the tokens on the networks token_b.mint(totalSupply_b) token_b.metadataTransfer(lock, value_b, rawRef_b) obh = min(start + 1, max(1, rpc_b.eth_blockNumber() - 0)) print("Starting block header rpc_b: ", start) print("Previous block header rpc_b: ", obh) self.assertEqual(start, 9) obh -= obh % 1 blocks = [] is_latest = False # Pack the blocks into batches bh = rpc_b.eth_blockNumber() + 1 print("Current block header rpc_b: ", bh) for i in range(obh, bh): # XXX TODO: I think this is why the latest block info is not always in sync with geth if i == (bh - 1): is_latest = True blocks.append(i) obh = bh # Show the blocks to work on and then rename just to keep convention from lithium.py block_group = blocks self.assertEqual(len(blocks), 2) # Process the block on chain B items, group_tx_count, group_log_count, transfers = lithium_process_block_group( rpc_b, block_group) item_tree_b, root = merkle_tree(items) for i in range(0, len(block_group)): batch_b.append((block_group[i], root, transfers[i])) prev_root = lithium_submit(batch_b, prev_root, rpc_a, link, owner) latestBlockA = ionlink_a.GetLatestBlock() path_b = merkle_path(items[1], item_tree_b) leafHashA = sha3(items[1]) reference_b = sha3(rawRef_b) ionlock_a = rpc_a.proxy("abi/IonLock.abi", lock, recv) ################################################################################ self.assertEqual(token_a.balanceOf(lock), value_a) self.assertEqual(token_b.balanceOf(lock), value_b) self.assertEqual(token_a.balanceOf(recv), 0) self.assertEqual(token_b.balanceOf(send), 0) ionlock_b.Withdraw(value_a, reference_a, latestBlockB, path_a) ionlock_a.Withdraw(value_b, reference_b, latestBlockA, path_b) self.assertEqual(token_a.balanceOf(lock), 0) self.assertEqual(token_b.balanceOf(lock), 0) self.assertEqual(token_a.balanceOf(recv), value_a) self.assertEqual(token_b.balanceOf(send), value_b)