def HundredSixBlockElementsTest(rpc: RPC) -> None: #Load the vectors. file: IO[Any] = open( "PythonTests/Vectors/Consensus/HundredSix/BlockElements.json", "r") vectors: Dict[str, Any] = json.loads(file.read()) file.close() #Blockchain. Solely used to get the genesis Block hash. blockchain: Blockchain = Blockchain() #Transactions. transactions: Transactions = Transactions.fromJSON(vectors["transactions"]) #Parse the Blocks from the vectors. blocks: List[Block] = [] for block in vectors["blocks"]: blocks.append(Block.fromJSON({}, block)) for block in blocks: #Handshake with the node. rpc.meros.connect(254, 254, blockchain.blocks[0].header.hash) #Send the Block. rpc.meros.blockHeader(block.header) #Flag of if the Block's Body synced. blockBodySynced: bool = False #Handle sync requests. reqHash: bytes = bytes() while True: try: msg: bytes = rpc.meros.recv() except TestError: if not blockBodySynced: raise TestError( "Node disconnected us before syncing the body.") #Verify the node didn't crash. try: if rpc.call("merit", "getHeight") != 1: raise Exception() except Exception: raise TestError( "Node crashed after being sent a malformed Element.") #Since the node didn't crash, break out of this loop to trigger the next test case. break if MessageType(msg[0]) == MessageType.Syncing: rpc.meros.syncingAcknowledged() elif MessageType(msg[0]) == MessageType.BlockBodyRequest: reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for a Block Body that didn't belong to the Block we just sent it." ) #Send the BlockBody. blockBodySynced = True rpc.meros.blockBody([], block) elif MessageType(msg[0]) == MessageType.SketchHashesRequest: if not block.body.packets: raise TestError( "Meros asked for Sketch Hashes from a Block without any." ) reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for Sketch Hashes that didn't belong to the Block we just sent it." ) #Create the haashes. hashes: List[int] = [] for packet in block.body.packets: hashes.append(Sketch.hash(block.header.sketchSalt, packet)) #Send the Sketch Hashes. rpc.meros.sketchHashes(hashes) elif MessageType(msg[0]) == MessageType.SketchHashRequests: if not block.body.packets: raise TestError( "Meros asked for Verification Packets from a Block without any." ) reqHash = msg[1:33] if reqHash != block.header.hash: raise TestError( "Meros asked for Verification Packets that didn't belong to the Block we just sent it." ) #Create a lookup of hash to packets. packets: Dict[int, VerificationPacket] = {} for packet in block.body.packets: packets[Sketch.hash(block.header.sketchSalt, packet)] = packet #Look up each requested packet and respond accordingly. for h in range(int.from_bytes(msg[33:37], byteorder="big")): sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 + (h * 8)], byteorder="big") if sketchHash not in packets: raise TestError( "Meros asked for a non-existent Sketch Hash.") rpc.meros.packet(packets[sketchHash]) elif MessageType(msg[0]) == MessageType.TransactionRequest: reqHash = msg[1:33] if reqHash not in transactions.txs: raise TestError( "Meros asked for a non-existent Transaction.") rpc.meros.transaction(transactions.txs[reqHash]) elif MessageType(msg[0]) == MessageType.SyncingOver: pass elif MessageType(msg[0]) == MessageType.BlockHeader: #Raise a TestError if the Block was added. raise TestError("Meros synced a Block with an invalid holder.") else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Reset the node. rpc.reset()
def HundredTwentyFourTest( rpc: RPC ) -> None: #Load the vectors. file: IO[Any] = open("PythonTests/Vectors/Merit/BlankBlocks.json", "r") vectors: List[Dict[str, Any]] = json.loads(file.read()) file.close() #Blockchain. Solely used to get the genesis Block hash. blockchain: Blockchain = Blockchain() #Parse the Blocks from the vectors. for i in range(2): blockchain.add(Block.fromJSON(vectors[i])) #Handshake with the node. rpc.meros.liveConnect(blockchain.blocks[0].header.hash) rpc.meros.syncConnect(blockchain.blocks[0].header.hash) def handleSync() -> None: #Handle sync requests. reqHash: bytes = bytes() bH: int = 0 bB: int = 1 while True: if bB == 3: break msg: bytes = rpc.meros.sync.recv() if MessageType(msg[0]) == MessageType.BlockListRequest: reqHash = msg[3 : 35] for b in range(len(blockchain.blocks)): if blockchain.blocks[b].header.hash == reqHash: blockList: List[bytes] = [] for bl in range(1, msg[2] + 2): if msg[1] == 0: if b - bl < 0: break blockList.append(blockchain.blocks[b - bl].header.hash) elif msg[1] == 1: blockList.append(blockchain.blocks[b + bl].header.hash) else: raise TestError("Meros asked for an invalid direction in a BlockListRequest.") if blockList == []: rpc.meros.dataMissing() break rpc.meros.blockList(blockList) break if b == len(blockchain.blocks): rpc.meros.dataMissing() elif MessageType(msg[0]) == MessageType.BlockHeaderRequest: reqHash = msg[1 : 33] if reqHash != blockchain.blocks[2 - bH].header.hash: raise TestError("Meros asked for a Block Header that didn't belong to the next Block.") #Send the BlockHeader. rpc.meros.syncBlockHeader(blockchain.blocks[2 - bH].header) bH += 1 elif MessageType(msg[0]) == MessageType.BlockBodyRequest: reqHash = msg[1 : 33] if reqHash != blockchain.blocks[bB].header.hash: raise TestError("Meros asked for a Block Body that didn't belong to the next Block.") #Send the Block. rpc.meros.blockBody(blockchain.blocks[bB]) bB += 1 else: raise TestError("Unexpected message sent: " + msg.hex().upper()) #Verify the Blockchain. verifyBlockchain(rpc, blockchain) #Send another Handshake with the latest block as the tip. rpc.meros.live.send( MessageType.Handshake.toByte() + (254).to_bytes(1, "big") + (254).to_bytes(1, "big") + b'\0\0\0' + blockchain.last(), False ) #Verify Meros responds with their tail (the genesis). if rpc.meros.live.recv() != MessageType.BlockchainTail.toByte() + blockchain.blocks[0].header.hash: raise TestError("Meros didn't respond with its Blockchain's Tail.") #Handle the sync. handleSync() #Reset Meros and do the same with Syncing. rpc.reset() rpc.meros.syncConnect(blockchain.blocks[0].header.hash) rpc.meros.sync.send( MessageType.Syncing.toByte() + (254).to_bytes(1, "big") + (254).to_bytes(1, "big") + b'\0\0\0' + blockchain.last(), False ) if rpc.meros.sync.recv() != MessageType.BlockchainTail.toByte() + blockchain.blocks[0].header.hash: raise TestError("Meros didn't respond with its Blockchain's Tail.") handleSync()