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()
Пример #2
0
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()