def HundredEightySevenTest( meros: Meros ) -> None: file: IO[Any] = open("e2e/Vectors/Merit/HundredEightySeven.json", "r") vectors: List[Dict[str, Any]] = json.loads(file.read()) file.close() meros.liveConnect(Blockchain().last()) meros.syncConnect(Blockchain().last()) block: Block = Block.fromJSON(vectors[0]) sent: bytes = meros.liveBlockHeader(block.header) if meros.sync.recv() != MessageType.BlockBodyRequest.toByte() + block.header.hash: raise TestError("Meros didn't request the matching BlockBody.") meros.blockBody(block) if meros.live.recv() != sent: raise TestError("Meros didn't broadcast a BlockHeader.") meros.liveBlockHeader(Block.fromJSON(vectors[1]).header) with raises(SuccessError): try: if len(meros.live.recv()) != 0: raise Exception() except TestError: sleep(1) if meros.process.poll() is not None: raise TestError("Node crashed trying to handle a BlockHeader which re-registers a key.") raise SuccessError("Node disconnected us after we sent a BlockHeader which re-registers a key.") except Exception: raise TestError("Meros didn't disconnect us after we sent a BlockHeader which re-registers a key; it also didn't crash.")
def OneHundredPercentSketchTest(meros: Meros) -> None: vectors: Dict[str, Any] with open("e2e/Vectors/Merit/Sketches/OneHundredPercent.json", "r") as file: vectors = json.loads(file.read()) blockchain: Blockchain = Blockchain.fromJSON(vectors["blockchain"]) meros.liveConnect(blockchain.blocks[0].header.hash) meros.syncConnect(blockchain.blocks[0].header.hash) header: bytes = meros.liveBlockHeader(blockchain.blocks[1].header) meros.handleBlockBody(blockchain.blocks[1]) if meros.live.recv() != header: raise TestError( "Meros didn't broadcast a BlockHeader for a Block it just added.") for data in vectors["datas"]: if meros.liveTransaction(Data.fromJSON(data)) != meros.live.recv(): raise TestError("Meros didn't broadcast back a Data Transaction.") for verif in vectors["verifications"]: if meros.signedElement( SignedVerification.fromSignedJSON(verif)) != meros.live.recv(): raise TestError("Meros didn't broadcast back a Verification.") header = meros.liveBlockHeader(blockchain.blocks[2].header) meros.handleBlockBody(blockchain.blocks[2]) if meros.live.recv() != header: raise TestError( "Meros didn't broadcast a BlockHeader for a Block it just added.")
def LANPeersTest(meros: Meros) -> None: #Solely used to get the genesis Block hash. blockchain: Blockchain = Blockchain() #Handshake with the node. meros.syncConnect(blockchain.blocks[0].header.hash) #Verify that sending a PeersRequest returns 0 peers. meros.peersRequest() if len(meros.sync.recv(True)) != 2: raise TestError("Meros sent peers.") #Create a new connection which identifies as a server. serverConnection: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serverConnection.connect(("127.0.0.1", meros.tcp)) serverConnection.send( MessageType.Syncing.toByte() + (254).to_bytes(1, "little") + (254).to_bytes(1, "little") + (128).to_bytes(1, "little") + (6000).to_bytes(2, "little") + blockchain.blocks[0].header.hash, False) serverConnection.recv(38) sleep(1) #Verify Meros ignores us as a peer since we're only available over the local network. meros.peersRequest() res: bytes = meros.sync.recv(True) if len(res) != 2: raise TestError("Meros sent peers.") #Close the new connection. serverConnection.close()
def MissingOneSketchTest(meros: Meros) -> None: vectors: Dict[str, Any] with open("e2e/Vectors/Merit/Sketches/MissingOne.json", "r") as file: vectors = json.loads(file.read()) blockchain: Blockchain = Blockchain.fromJSON(vectors["blockchain"]) meros.liveConnect(blockchain.blocks[0].header.hash) meros.syncConnect(blockchain.blocks[0].header.hash) header: bytes = meros.liveBlockHeader(blockchain.blocks[1].header) meros.handleBlockBody(blockchain.blocks[1]) if meros.live.recv() != header: raise TestError( "Meros didn't broadcast a BlockHeader for a Block it just added.") for data in vectors["datas"]: if meros.liveTransaction(Data.fromJSON(data)) != meros.live.recv(): raise TestError("Meros didn't broadcast back a Data Transaction.") for verif in vectors["verifications"]: if meros.signedElement( SignedVerification.fromSignedJSON(verif)) != meros.live.recv(): raise TestError("Meros didn't broadcast back a Verification.") header = meros.liveBlockHeader(blockchain.blocks[2].header) meros.handleBlockBody(blockchain.blocks[2], 1) if MessageType(meros.sync.recv()[0]) != MessageType.SketchHashRequests: raise TestError("Meros didn't request the packet it's missing.") meros.packet(VerificationPacket.fromJSON(vectors["packet"])) if meros.live.recv() != header: raise TestError( "Meros didn't broadcast a BlockHeader for a Block it just added.")
def TwoHundredSeventyThreeTest(meros: Meros) -> None: blockchain: Blockchain = Blockchain() vectors: Dict[str, Any] with open("e2e/Vectors/Merit/TwoHundredSeventyThree.json", "r") as file: vectors = json.loads(file.read()) header: BlockHeader = BlockHeader.fromJSON(vectors) meros.liveConnect(blockchain.last()) meros.syncConnect(blockchain.last()) #Sanity check on the behavior of select. readable, _, _ = select([meros.live.connection, meros.sync.connection], [], [], 65) if len(readable) != 1: raise Exception( "Misuse of select; multiple sockets reported readable.") if MessageType(meros.live.recv()[0]) != MessageType.Handshake: raise Exception( "Misuse of select; it didn't return the live socket trying to Handshake. Keep-alives could also be broken." ) meros.live.send(MessageType.BlockchainTail.toByte() + blockchain.last()) #Send the header. meros.liveBlockHeader(header) #Meros should disconnect us immediately. If it doesn't, it'll either send a keep-alive or a BlockBodyRequest. #One is inefficient as it doesn't properly protect against spam attacks. #One is invalid completely. readable, _, _ = select([meros.live.connection, meros.sync.connection], [], [], 65) #On Linux, both sockets immediately appear as readable. #That is why we iterate, instead of just checking length == 0. for s in readable: try: temp: str = s.recv(1) if len(temp) != 0: raise TestError( "Meros tried to send us something instead of immediately disconnecting us." ) except TestError as e: raise e except Exception: pass
def LANPeersTest(meros: Meros) -> None: #Solely used to get the genesis Block hash. blockchain: Blockchain = Blockchain() #Handshake with the node. meros.syncConnect(blockchain.blocks[0].header.hash) #Verify that sending a PeersRequest returns 0 peers. meros.peersRequest() if len(meros.sync.recv(True)) != 2: raise TestError("Meros sent peers.") #Create a server socket. server: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(("", 0)) server.listen(1) #Connect again. #Meros, if it doesn't realize we're a LAN peer, will try to connect to the above server to verify. #Since we're a LAN peer, it shouldn't bother. #Doesn't use MerosSocket so we can specify the port. serverConnection: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) serverConnection.connect(("127.0.0.1", meros.tcp)) serverConnection.send( MessageType.Syncing.toByte() + meros.protocol.to_bytes(1, "little") + meros.network.to_bytes(1, "little") + (0).to_bytes(1, "little") + server.getsockname()[1].to_bytes(2, "little") + blockchain.blocks[0].header.hash, False) serverConnection.recv(38) sleep(1) #Verify Meros ignores us as a peer since we're only available over the local network. meros.peersRequest() res: bytes = meros.sync.recv(True) if len(res) != 2: raise TestError("Meros sent peers.") #Close the new connection. serverConnection.close()
def BusyTest(meros: Meros) -> None: #Solely used to get the genesis Block hash. blockchain: Blockchain = Blockchain() #Handshake with the node. meros.syncConnect(blockchain.blocks[0].header.hash) #Create two new server sockets. def createServerSocket() -> socket.socket: result: socket.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) result.bind(("127.0.0.1", 0)) result.listen(2) return result busyServer: socket.socket = createServerSocket() server: socket.socket = createServerSocket() #Receive Syncing until Meros asks for peers. while True: res = meros.sync.recv() if MessageType(res[0]) == MessageType.Syncing: meros.sync.send(MessageType.BlockchainTail.toByte() + blockchain.blocks[0].header.hash) elif MessageType(res[0]) == MessageType.PeersRequest: break #Craft a Peers message of our own server. meros.sync.send(MessageType.Peers.toByte() + bytes.fromhex("017F000001") + busyServer.getsockname()[1].to_bytes(2, "little")) #Use select to obtain a non-blocking accept. busy: int = 0 buf: bytes for _ in select.select([busyServer], [], [], 5000): #Accept a new connection. client, _ = busyServer.accept() #Verify Meros's Handshake. buf = client.recv(38) if MessageType( buf[0]) not in {MessageType.Handshake, MessageType.Syncing}: busyServer.close() raise TestError( "Meros didn't start its connection with a Handshake.") if buf[1:] != ( (254).to_bytes(1, "little") + (254).to_bytes(1, "little") + (128).to_bytes(1, "little") + meros.tcp.to_bytes(2, "little") + blockchain.blocks[0].header.hash): busyServer.close() raise TestError("Meros had an invalid Handshake.") #Send back Busy. client.send(MessageType.Busy.toByte() + bytes.fromhex("017F000001") + server.getsockname()[1].to_bytes(2, "little")) busy += 1 if busy == 2: busyServer.close() break #Make sure Meros connects to the server we redirected to. with raises(SuccessError): for _ in select.select([server], [], [], 5000): #Accept a new connection. client, _ = server.accept() #Verify Meros's Handshake. buf = client.recv(38) if MessageType(buf[0]) not in { MessageType.Handshake, MessageType.Syncing }: server.close() raise TestError( "Meros didn't start its connection with a Handshake.") if buf[1:] != ( (254).to_bytes(1, "little") + (254).to_bytes(1, "little") + (128).to_bytes(1, "little") + meros.tcp.to_bytes(2, "little") + blockchain.blocks[0].header.hash): server.close() raise TestError("Meros had an invalid Handshake.") server.close() raise SuccessError( "Meros connected to the server we redirected it to with a Busy message." ) #Raise a TestError. busyServer.close() server.close() raise TestError("Meros didn't connect to the redirected server.")
def MatchesHeaderQuantityTest(meros: Meros) -> None: #Create an instance of Merit to make sure the RandomX VM key was set. Merit() blocks: List[Block] txs: List[Data] = [] verifs: List[SignedVerification] = [] with open( "e2e/Vectors/Merit/TwoHundredSeventyFour/MatchesHeaderQuantity.json", "r") as file: vectors: Dict[str, Any] = json.loads(file.read()) blocks = [Block.fromJSON(block) for block in vectors["blocks"]] txs = [Data.fromJSON(tx) for tx in vectors["transactions"]] verifs = [ SignedVerification.fromSignedJSON(verif) for verif in vectors["verifications"] ] #Connect. meros.liveConnect(blocks[0].header.last) meros.syncConnect(blocks[0].header.last) #Send a single Block to earn Merit. meros.liveBlockHeader(blocks[0].header) meros.handleBlockBody(blocks[0]) #Send the header. meros.liveBlockHeader(blocks[1].header) #Fail Sketch Resolution, and send a different amount of sketch hashes. meros.handleBlockBody(blocks[1], 0) if MessageType(meros.sync.recv()[0]) != MessageType.SketchHashesRequest: raise TestError( "Meros didn't request the hashes after failing sketch resolution.") #Send a quantity of sketch hashes that doesn't match the header. meros.sketchHashes([ Sketch.hash(blocks[1].header.sketchSalt, VerificationPacket(tx.hash, [0])) for tx in txs ]) try: if len(meros.sync.recv()) == 0: raise TestError() raise Exception() except TestError: pass except Exception: raise TestError("Meros tried to further sync an invalid Block Body.") #Sleep so we can reconnect. sleep(65) #Repeat setup. meros.liveConnect(blocks[0].header.last) meros.syncConnect(blocks[0].header.last) #Send two Transactions. for i in range(2): meros.liveTransaction(txs[i]) meros.signedElement(verifs[i]) #Send the header and a large enough sketch to cause resolution. meros.liveBlockHeader(blocks[1].header) meros.handleBlockBody(blocks[1], 3) #Should now have been disconnected thanks to having 5 hashes. try: if len(meros.sync.recv()) == 0: raise TestError() raise Exception() except TestError: pass except Exception: raise TestError("Meros tried to further sync an invalid Block Body.")