Ejemplo n.º 1
0
def HundredTwentyFiveTest(rpc: RPC) -> None:
    #Meros allows connections from its own IP if they identify as 127.0.0.1.
    #We need to connect either through the LAN or through the public IP for this test to be valid.
    #The following code grabs the computer's 192 IP.
    lanIPFinder = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    lanIPFinder.connect(("meroscrypto.io", 443))
    lanIP = lanIPFinder.getsockname()[0]
    lanIPFinder.close()

    if not (lanIP.split(".")[0] in {"10", "172", "192"}):
        raise Exception("Failed to get the LAN IP.")

    #Blockchain. Solely used to get the genesis Block hash.
    blockchain: Blockchain = Blockchain()

    #Connect to Meros.
    connection: socket.socket = socket.socket(socket.AF_INET,
                                              socket.SOCK_STREAM)
    connection.connect((lanIP, rpc.meros.tcp))
    try:
        connection.send(
            MessageType.Syncing.toByte() + (254).to_bytes(1, "big") +
            (254).to_bytes(1, "big") + (128).to_bytes(1, "big") +
            (6000).to_bytes(2, "big") + blockchain.blocks[0].header.hash,
            False)
        if len(connection.recv(38)) == 0:
            raise Exception("")
    except Exception:
        raise SuccessError(
            "Meros closed a connection from the same IP as itself which wasn't 127.0.0.1."
        )
    raise TestError(
        "Meros allowed a connection from the same IP as itself which wasn't 127.0.0.1."
    )
Ejemplo n.º 2
0
def HundredTest(rpc: RPC) -> None:
    #Blocks.
    file: IO[Any] = open("PythonTests/Vectors/Merit/BlankBlocks.json", "r")
    blocks: List[Dict[str, Any]] = json.loads(file.read())
    file.close()

    #Grab only the first block.
    blocks = [blocks[0]]

    #Merit.
    merit: Merit = Merit.fromJSON(blocks)

    #The normal flow would be:
    #Handshake
    #BlockHeaderRequest

    #We need to delay the BlockHeader. Then, Meros should send:
    #Handshake
    #BlockHeaderRequest
    #Handshake

    #EXCEPT Meros can't handle sending Handshakes after Requests like that (see issue #100).
    #Therefore, Meros won't send a Handshake if it has a pending request (totally valid and acceptable behavior).
    #This test verifies we get disconnected without a Handshake attempt.

    #Handshake with the node.
    rpc.meros.connect(254, 254, merit.blockchain.blocks[1].header.hash)

    #Handle sync requests.
    reqHash: bytes = bytes()
    while True:
        msg: bytes = rpc.meros.recv()

        if MessageType(msg[0]) == MessageType.Syncing:
            rpc.meros.syncingAcknowledged()

        elif MessageType(msg[0]) == MessageType.BlockHeaderRequest:
            reqHash = msg[1:33]
            if reqHash != merit.blockchain.blocks[-1].header.hash:
                raise TestError(
                    "Meros asked for a BlockHeader other than the one in the Block from the Handshake."
                )

            #Wait until Meros disconnects us.
            try:
                rpc.meros.recv()
            except TestError:
                raise SuccessError(
                    "Meros didn't attempt to handshake with us while it had a pending sync request."
                )
            raise TestError(
                "Meros tried to handshake with us while it had a pending sync request."
            )
Ejemplo n.º 3
0
        def sendRepeatMeritRemoval() -> None:
            #Send the Block containing the modified Merit Removal.
            block: Block = Block.fromJSON(vectors["blockchains"][i][-1])
            rpc.meros.liveBlockHeader(block.header)

            #Flag of if the Block's Body synced.
            blockBodySynced: bool = False

            #Handle sync requests.
            reqHash: bytes = bytes()
            while True:
                if blockBodySynced:
                    #Sleep for a second so Meros handles the Block.
                    sleep(1)

                    #Try receiving from the Live socket, where Meros sends keep-alives.
                    try:
                        if len(rpc.meros.live.recv()) != 0:
                            raise Exception()
                    except TestError:
                        #Verify the height is 3.
                        #The genesis Block, the Block granting Merit, and the Block containing the MeritRemoval originally.
                        try:
                            if rpc.call("merit", "getHeight") != 3:
                                raise Exception()
                        except Exception:
                            raise TestError(
                                "Node added a Block containg a repeat MeritRemoval."
                            )

                        #Since the node didn't add the Block, raise SuccessError.
                        raise SuccessError(
                            "Node didn't add a Block containing a repeat MeritRemoval."
                        )
                    except Exception:
                        raise TestError("Meros sent a keep-alive.")

                msg: bytes = rpc.meros.sync.recv()
                if 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)

                else:
                    raise TestError("Unexpected message sent: " +
                                    msg.hex().upper())
Ejemplo n.º 4
0
    def checkFail() -> None:
        #Send the Send.
        rpc.meros.liveTransaction(send)

        #Handle sync requests.
        while True:
            #Try receiving from the Live socket, where Meros sends keep-alives.
            try:
                if len(rpc.meros.live.recv()) != 0:
                    raise Exception()
            except TestError:
                raise SuccessError("Node disconnected us after we sent an invalid Transaction.")
            except Exception:
                raise TestError("Meros sent a keep-alive.")
Ejemplo n.º 5
0
    def sendAlternateTip() -> None:
        header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)
        req: bytes = rpc.meros.sync.recv()
        if req != (MessageType.BlockBodyRequest.toByte() + alt.blocks[-1].header.hash):
            raise TestError("Meros didn't request the BlockBody.")
        rpc.meros.blockBody(alt.blocks[-1])

        if rpc.meros.live.recv() != header:
            raise TestError("Meros didn't send back the BlockHeader.")

        #Verify the alternate Blockchain.
        verifyBlockchain(rpc, alt)

        #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
        raise SuccessError("Meros re-organized to the alternate chain.")
Ejemplo n.º 6
0
        def sendMeritRemoval() -> None:
            #Send the Data.
            if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
                raise TestError("Meros didn't send back the Data.")

            rpc.meros.signedElement(removal)
            try:
                if len(rpc.meros.live.recv()) != 0:
                    raise Exception()
            except TestError:
                raise SuccessError(
                    "Meros rejected our MeritRemoval created from the same Element."
                )
            except Exception:
                raise TestError(
                    "Meros accepted our MeritRemoval created from the same Element."
                )
Ejemplo n.º 7
0
    def sendAlternateTip() -> None:
        header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)

        req: bytes = rpc.meros.sync.recv()
        if MessageType(req[0]) != MessageType.BlockListRequest:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders.")
        if req[3:35] != alt.blocks[-1].header.hash:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders for THIS header."
            )

        blockList: List[bytes] = []
        b: int = len(alt.blocks) - 2
        while b != -1:
            blockList.append(alt.blocks[b].header.hash)
            b -= 1
        rpc.meros.blockList(blockList)

        diff = -14
        while diff != -1:
            req = rpc.meros.sync.recv()
            if req != (MessageType.BlockHeaderRequest.toByte() +
                       alt.blocks[diff].header.hash):
                raise TestError("Meros didn't request a previous BlockHeader.")
            rpc.meros.syncBlockHeader(alt.blocks[diff].header)
            diff += 1

        diff = -14
        while diff != 0:
            req = rpc.meros.sync.recv()
            if req != (MessageType.BlockBodyRequest.toByte() +
                       alt.blocks[diff].header.hash):
                raise TestError("Meros didn't request a previous BlockBody.")
            rpc.meros.blockBody(alt.blocks[diff])
            diff += 1

        if rpc.meros.live.recv() != header:
            raise TestError("Meros didn't send back the BlockHeader.")

        #Verify the alternate Blockchain.
        verifyBlockchain(rpc, alt)

        #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
        raise SuccessError("Meros re-organized to the alternate chain.")
Ejemplo n.º 8
0
    def sendBlock() -> None:
        #Send the Block with the MeritRemoval archived again.
        block: Block = Block.fromJSON(keys, vectors[-1])
        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.")
                raise SuccessError(
                    "Meros didn't add the same MeritRemoval twice.")

            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.SyncingOver:
                pass

            elif MessageType(msg[0]) == MessageType.BlockHeader:
                #Raise a TestError if the Block was added.
                raise TestError(
                    "Meros synced a Block with a repeat MeritRemoval.")

            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())
Ejemplo n.º 9
0
    def sendBlock() -> None:
        #Send the Block with the MeritRemoval archived again.
        block: Block = Block.fromJSON(vectors[-1])
        rpc.meros.liveBlockHeader(block.header)

        #Flag of if the Block's Body synced.
        blockBodySynced: bool = False

        #Handle sync requests.
        reqHash: bytes = bytes()
        while True:
            if blockBodySynced:
                #Try receiving from the Live socket, where Meros sends keep-alives.
                try:
                    if len(rpc.meros.live.recv()) != 0:
                        raise Exception()
                except TestError:
                    raise SuccessError(
                        "Meros didn't add the same MeritRemoval twice.")
                except Exception:
                    raise TestError("Meros sent a keep-alive.")

            msg: bytes = rpc.meros.sync.recv()
            if 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)

            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())
Ejemplo n.º 10
0
    def checkFail() -> None:
        #This Block should cause the node to disconnect us AFTER it attempts to sync our Transaction.
        syncedTX: bool = False

        #Grab the Block.
        block: Block = merit.blockchain.blocks[2]

        #Send the Block.
        rpc.meros.liveBlockHeader(block.header)

        #Handle sync requests.
        reqHash: bytes = bytes()
        while True:
            if syncedTX:
                #Try receiving from the Live socket, where Meros sends keep-alives.
                try:
                    if len(rpc.meros.live.recv()) != 0:
                        raise Exception()
                except TestError:
                    raise SuccessError(
                        "Node disconnected us after we sent a parsable, yet invalid, Verification."
                    )
                except Exception:
                    raise TestError("Meros sent a keep-alive.")

            msg: bytes = rpc.meros.sync.recv()
            if 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.
                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:
                rpc.meros.dataMissing()
                syncedTX = True

            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())
Ejemplo n.º 11
0
    def checkFail() -> None:
        #This Block should cause the node to disconnect us AFTER it syncs our Transaction.
        syncedTX: bool = False

        #Grab the Block.
        block: Block = merit.blockchain.blocks[-1]

        #Send the Block.
        rpc.meros.blockHeader(block.header)

        #Handle sync requests.
        reqHash: bytes = bytes()
        while True:
            try:
                msg: bytes = rpc.meros.recv()
            except TestError:
                if syncedTX:
                    raise SuccessError("Node disconnected us after we sent an invalid Transaction.")
                raise TestError("Node errored before syncing our Transaction.")

            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.
                rpc.meros.blockBody(merit.state.nicks, 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])
                syncedTX = True

            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 Transaction which competed with a finalized Transaction.")

            else:
                raise TestError("Unexpected message sent: " + msg.hex().upper())
Ejemplo n.º 12
0
        continue
    testsToRun.remove(test.__name__)

    print("\033[0;37mRunning " + test.__name__ + ".")

    #Message to display on a Node crash.
    crash: str = "\033[5;31m" + test.__name__ + " caused the node to crash!\033[0;31m"

    #Meros instance.
    meros: Meros = Meros(test.__name__, port, port + 1)
    sleep(5)

    rpc: RPC = RPC(meros)
    try:
        test(rpc)
        raise SuccessError()
    except SuccessError as e:
        ress.append("\033[0;32m" + test.__name__ + " succeeded.")
    except EmptyError as e:
        ress.append("\033[0;33m" + test.__name__ + " is empty.")
    except NodeError as e:
        ress.append(crash)
    except TestError as e:
        ress.append("\033[0;31m" + test.__name__ + " failed: " + str(e))
    except Exception as e:
        ress.append("\033[0;31m" + test.__name__ + " is invalid.")
        ress.append(format_exc().rstrip())
    finally:
        try:
            rpc.quit()
            meros.quit()
Ejemplo n.º 13
0
 def verify() -> None:
     verifyMeritRemoval(rpc, 1, 1, removal.holder, False)
     verifyBlockchain(rpc, Blockchain.fromJSON(vectors["blockchain"]))
     raise SuccessError(
         "MeritRemoval and Blockchain were properly handled.")
Ejemplo n.º 14
0
def BusyTest(rpc: RPC) -> None:
    #Blockchain. Solely used to get the genesis Block hash.
    blockchain: Blockchain = Blockchain()

    #Handshake with the node.
    rpc.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 = rpc.meros.sync.recv()
        if MessageType(res[0]) == MessageType.Syncing:
            rpc.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.
    rpc.meros.sync.send(MessageType.Peers.toByte() +
                        bytes.fromhex("017F000001") +
                        busyServer.getsockname()[1].to_bytes(2, "big"))

    #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, "big") + (254).to_bytes(1, "big") +
                       (128).to_bytes(1, "big") +
                       (rpc.meros.tcp).to_bytes(2, "big") +
                       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, "big"))

        busy += 1
        if busy == 2:
            busyServer.close()
            break

    #Make sure Meros connects to the server we redirected to.
    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, "big") + (254).to_bytes(1, "big") +
                       (128).to_bytes(1, "big") +
                       (rpc.meros.tcp).to_bytes(2, "big") +
                       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.")