Esempio n. 1
0
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.")
Esempio n. 2
0
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.")
Esempio n. 3
0
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()
Esempio n. 4
0
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
Esempio n. 6
0
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()
Esempio n. 7
0
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.")
Esempio n. 8
0
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.")