Beispiel #1
0
    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)
Beispiel #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."
            )
Beispiel #3
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())
Beispiel #4
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())
    def sendMeritRemoval() -> None:
        #Send and verify the MeritRemoval.
        removalBytes: bytes = rpc.meros.signedElement(removal)

        done: bool = False
        while True:
            try:
                msg: bytes = rpc.meros.recv()
            except TestError:
                raise TestError("Node disconnected us.")

            if MessageType(msg[0]) == MessageType.Syncing:
                rpc.meros.syncingAcknowledged()
            elif MessageType(msg[0]) == MessageType.TransactionRequest:
                rpc.meros.transaction(transactions.txs[msg[1 : 33]])
            elif MessageType(msg[0]) == MessageType.SyncingOver:
                if done:
                    break
                done = True

        if removalBytes != rpc.meros.recv():
            raise TestError("Meros didn't send us the Merit Removal.")
        verifyMeritRemoval(rpc, 11, 11, removal.holder, True)
Beispiel #6
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.")
    def sendMeritRemoval() -> None:
        #Send and verify the MeritRemoval.
        removalBytes: bytes = rpc.meros.signedElement(removal)

        sent: int = 0
        while True:
            if sent == 2:
                break

            msg: bytes = rpc.meros.sync.recv()
            if MessageType(msg[0]) == MessageType.TransactionRequest:
                rpc.meros.syncTransaction(transactions.txs[msg[1:33]])
                sent += 1
            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())

        if removalBytes != rpc.meros.live.recv():
            raise TestError("Meros didn't send us the Merit Removal.")
        verifyMeritRemoval(rpc, 1, 1, removal.holder, True)
Beispiel #8
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())
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()
Beispiel #10
0
def EightyEightTest(rpc: RPC) -> None:
    #Ed25519 key.
    edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32)
    edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key()

    #BLS key.
    blsPrivKey: PrivateKey = PrivateKey(
        blake2b(b'\0', digest_size=32).digest())
    blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex()

    #Blocks.
    file: IO[Any] = open("PythonTests/Vectors/Merit/BlankBlocks.json", "r")
    blocks: List[Dict[str, Any]] = json.loads(file.read())
    file.close()

    #Merit.
    merit: Merit = Merit()
    #Spam Filter.
    dataFilter: SpamFilter = SpamFilter(bytes.fromhex("CC" * 32))

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

    #Send the first Block.
    block: Block = Block.fromJSON(merit.blockchain.keys, blocks[0])
    merit.blockchain.add(block)
    rpc.meros.blockHeader(block.header)

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

        elif MessageType(msg[0]) == MessageType.BlockHeader:
            break

        else:
            raise TestError("Unexpected message sent: " + msg.hex().upper())

    #Create two Datas.
    datas: List[Data] = [Data(bytes(32), edPubKey.to_bytes())]
    datas.append(Data(datas[0].hash, b"Hello there! General Kenobi."))

    for data in datas:
        #Sign them and have them beat the spam filter.
        data.sign(edPrivKey)
        data.beat(dataFilter)

        #Transmit them.
        rpc.meros.transaction(data)

    #Verify both.
    verifs: List[SignedVerification] = [
        SignedVerification(datas[0].hash),
        SignedVerification(datas[1].hash)
    ]
    for verif in verifs:
        verif.sign(0, blsPrivKey)

    #Only transmit the second.
    rpc.meros.signedElement(verifs[1])
    sleep(0.5)

    #Verify the block template has no verifications.
    if bytes.fromhex(
            rpc.call("merit", "getBlockTemplate",
                     [blsPubKey])["header"])[36:68] != bytes(32):
        raise TestError("Block template has Verification Packets.")

    #Transmit the first signed verification.
    rpc.meros.signedElement(verifs[0])
    sleep(0.5)

    #Verify the block template has both verifications.
    template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate",
                                        [blsPubKey])
    template["header"] = bytes.fromhex(template["header"])
    packets: List[VerificationPacket] = [
        VerificationPacket(datas[0].hash, [0]),
        VerificationPacket(datas[1].hash, [0])
    ]
    if template["header"][36:68] != BlockHeader.createContents(
            merit.state.nicks, packets):
        raise TestError(
            "Block template doesn't have both Verification Packets.")

    #Mine the Block.
    block = Block(
        BlockHeader(
            0,
            block.header.hash,
            BlockHeader.createContents(merit.state.nicks, packets),
            1,
            template["header"][-43:-39],
            BlockHeader.createSketchCheck(template["header"][-43:-39],
                                          packets),
            0,
            int.from_bytes(template["header"][-4:], byteorder="big"),
        ),
        BlockBody(
            packets, [],
            Signature.aggregate([verifs[0].signature, verifs[1].signature])))
    if block.header.serializeHash()[:-4] != template["header"]:
        raise TestError("Failed to recreate the header.")
    if block.body.serialize(merit.state.nicks, block.header.sketchSalt,
                            len(packets)) != bytes.fromhex(template["body"]):
        raise TestError("Failed to recreate the body.")

    block.mine(blsPrivKey, merit.blockchain.difficulty())
    merit.blockchain.add(block)

    #Publish it.
    rpc.call("merit", "publishBlock", [
        template["id"],
        (template["header"] + block.header.proof.to_bytes(4, byteorder="big") +
         block.header.signature + block.body.serialize(
             merit.state.nicks, block.header.sketchSalt, len(packets))).hex()
    ])

    #Verify the Blockchain.
    verifyBlockchain(rpc, merit.blockchain)
    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())
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.connect(254, 254, blockchain.blocks[0].header.hash)

    #Send another handshake with the latest block as the tip.
    rpc.meros.send(
        MessageType.Handshake.toByte() +
        (254).to_bytes(1, "big") +
        (254).to_bytes(1, "big") +
        b'\0' +
        blockchain.last(),
        False
    )

    #Verify Meros responds with their tail (the genesis).
    if rpc.meros.recv() != MessageType.BlockchainTail.toByte() + blockchain.blocks[0].header.hash:
        raise TestError("Meros didn't respond with its Blockchain's Tail.")

    #Handle sync requests.
    reqHash: bytes = bytes()
    bH: int = 0
    bB: int = 1
    while True:
        msg: bytes = rpc.meros.recv()

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

        elif MessageType(msg[0]) == MessageType.BlockListRequest:
            reqHash = msg[3 : 51]
            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.blockHeader(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

        elif MessageType(msg[0]) == MessageType.SyncingOver:
            if bB == 3:
                break

        else:
            raise TestError("Unexpected message sent: " + msg.hex().upper())

    #Verify the Blockchain.
    verifyBlockchain(rpc, blockchain)
Beispiel #13
0
    def live(self) -> None:
        #Handshake with the node.
        self.rpc.meros.connect(254, 254,
                               self.merit.blockchain.blocks[0].header.hash)

        #Send each Block.
        for b in range(1, len(self.merit.blockchain.blocks)):
            #Grab the Block.
            block: Block = self.merit.blockchain.blocks[b]

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

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

                if MessageType(msg[0]) == MessageType.Syncing:
                    self.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.
                    self.rpc.meros.blockBody(self.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.
                    self.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.")
                        self.rpc.meros.packet(packets[sketchHash])

                elif MessageType(msg[0]) == MessageType.TransactionRequest:
                    reqHash = msg[1:33]

                    if self.transactions is None:
                        raise TestError(
                            "Meros asked for a Transaction when we have none.")

                    if reqHash not in self.transactions.txs:
                        raise TestError(
                            "Meros asked for a non-existent Transaction.")

                    self.rpc.meros.transaction(self.transactions.txs[reqHash])

                elif MessageType(msg[0]) == MessageType.SyncingOver:
                    pass

                elif MessageType(msg[0]) == MessageType.BlockHeader:
                    break

                else:
                    raise TestError("Unexpected message sent: " +
                                    msg.hex().upper())

            #Add any new nicks to the lookup table.
            if self.merit.blockchain.blocks[b].header.newMiner:
                self.merit.state.nicks.append(
                    self.merit.blockchain.blocks[b].header.minerKey)

            #If there's a callback at this height, call it.
            if b in self.callbacks:
                self.callbacks[b]()

            #Execute the every-Block callback, if it exists.
            if self.everyBlock is not None:
                self.everyBlock(b)

        #Verify the Blockchain.
        verifyBlockchain(self.rpc, self.merit.blockchain)

        #Verify the Transactions.
        if self.transactions is not None:
            verifyTransactions(self.rpc, self.transactions)

        #Reset the node.
        self.rpc.reset()
Beispiel #14
0
    def live(self) -> None:
        #Handshake with the node.
        self.rpc.meros.connect(254, 254, 1)

        #Send each Block.
        for b in range(1, len(self.blockchain.blocks)):
            #Grab the Block.
            block: Block = self.blockchain.blocks[b]

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

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

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

                elif MessageType(msg[0]) == MessageType.BlockBodyRequest:
                    reqHash = msg[1:49]
                    if reqHash != block.header.hash:
                        raise TestError(
                            "Meros asked for a Block Body that didn't belong to the header we just sent it."
                        )

                    #Send the BlockBody.
                    self.rpc.meros.blockBody(block.body)

                elif MessageType(msg[0]) == MessageType.ElementRequest:
                    holder: bytes = msg[1:49]
                    nonce: int = int.from_bytes(msg[49:53], "big")

                    if self.consensus is None:
                        raise TestError(
                            "Meros asked for an Element when we have none.")

                    if holder not in self.consensus.holders:
                        raise TestError(
                            "Meros asked for an Element from a holder we don't have."
                        )

                    if nonce >= len(self.consensus.holders[holder]):
                        raise TestError(
                            "Meros asked for an Element we don't have.")

                    self.rpc.meros.element(
                        self.consensus.holders[holder][nonce])

                elif MessageType(msg[0]) == MessageType.TransactionRequest:
                    reqHash = msg[1:49]

                    if self.transactions is None:
                        raise TestError(
                            "Meros asked for a Transaction when we have none.")

                    if reqHash not in self.transactions.txs:
                        raise TestError(
                            "Meros asked for a Transaction we don't have.")

                    self.rpc.meros.transaction(self.transactions.txs[reqHash])

                elif MessageType(msg[0]) == MessageType.SyncingOver:
                    pass

                elif MessageType(msg[0]) == MessageType.BlockHeader:
                    break

                else:
                    raise TestError("Unexpected message sent: " +
                                    msg.hex().upper())

            #If there's a callback at this height, call it.
            if b in self.callbacks:
                self.callbacks[b]()

            #Execute the every-Block callback, if it exists.
            if self.everyBlock is not None:
                self.everyBlock(b)

        #Verify the Blockchain.
        verifyBlockchain(self.rpc, self.blockchain)

        #Verify the Consensus.
        if self.consensus is not None:
            verifyConsensus(self.rpc, self.consensus)

        #Verify the Transactions.
        if self.transactions is not None:
            verifyTransactions(self.rpc, self.transactions)

        #Reset the RPC.
        self.rpc.reset()
def HundredFiftyFiveTest(rpc: RPC) -> None:
    #Ed25519 keys.
    edPrivKeys: List[ed25519.SigningKey] = [
        ed25519.SigningKey(b'\0' * 32),
        ed25519.SigningKey(b'\1' * 32)
    ]
    edPubKeys: List[ed25519.VerifyingKey] = [
        edPrivKeys[0].get_verifying_key(), edPrivKeys[1].get_verifying_key()
    ]

    #BLS keys.
    blsPrivKey: PrivateKey = PrivateKey(
        bytes.fromhex(rpc.call("personal", "getMiner")))
    blsPubKey: bytes = blsPrivKey.toPublicKey().serialize()

    #Blockchain.
    blockchain: Blockchain = Blockchain()
    #Spam Filter.
    dataFilter: SpamFilter = SpamFilter(5)

    #Handshake with the node.
    rpc.meros.liveConnect(blockchain.blocks[0].header.hash)
    rpc.meros.syncConnect(blockchain.blocks[0].header.hash)

    #Call getBlockTemplate just to get an ID.
    #Skips the need to write a sync loop for the BlockBody.
    template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate",
                                        [blsPubKey.hex()])

    #Mine a Block.
    block = Block(
        BlockHeader(0, blockchain.blocks[0].header.hash, bytes(32), 1,
                    bytes(4), bytes(32), blsPubKey,
                    blockchain.blocks[0].header.time + 1200, 0), BlockBody())
    block.mine(blsPrivKey, blockchain.difficulty())
    blockchain.add(block)

    #Publish it.
    rpc.call("merit", "publishBlock",
             [template["id"], block.serialize().hex()])

    #Handle the fact Meros will now broadcast it to us.
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
        raise TestError("Meros didn't broadcast the Block it just published.")

    #Create the Datas.
    datas: List[Data] = [
        Data(bytes(32), edPubKeys[0].to_bytes()),
        Data(bytes(32), edPubKeys[1].to_bytes())
    ]

    for d in range(len(datas)):
        #Sign, and mine the Data.
        datas[d].sign(edPrivKeys[d])
        datas[d].beat(dataFilter)

        #Send the Data and verify Meros sends it back.
        if rpc.meros.liveTransaction(datas[d]) != rpc.meros.live.recv():
            raise TestError("Meros didn't send back the Data.")

        #Verify Meros sends back a Verification.
        res: bytes = rpc.meros.live.recv()
        if MessageType(res[0]) != MessageType.SignedVerification:
            raise TestError("Meros didn't send a SignedVerification.")

        verif: SignedVerification = SignedVerification(datas[d].hash)
        verif.sign(0, blsPrivKey)
        if res[1:] != verif.signedSerialize():
            raise TestError(
                "Meros didn't send the correct SignedVerification.")
Beispiel #16
0
    def live(self) -> None:
        #Handshake with the node.
        self.rpc.meros.liveConnect(self.merit.blockchain.blocks[0].header.hash)
        self.rpc.meros.syncConnect(self.merit.blockchain.blocks[0].header.hash)

        #Send each Block.
        for b in range(1, len(self.merit.blockchain.blocks)):
            #Grab the Block.
            block: Block = self.merit.blockchain.blocks[b]

            #Set loop variables with pending data.
            pendingBody: bool = True
            pendingPackets: List[bytes] = []
            pendingTXs: List[bytes] = []
            for packet in block.body.packets:
                pendingPackets.append(packet.hash)

                if packet.hash not in self.rpc.meros.sentTXs:
                    pendingTXs.append(packet.hash)

            for elem in block.body.elements:
                if isinstance(elem, MeritRemoval):
                    #pylint: disable=consider-merging-isinstance
                    if ((isinstance(elem.e1, Verification)
                         or isinstance(elem.e1, VerificationPacket))
                            and (elem.e1.hash not in self.rpc.meros.sentTXs)
                            and (elem.e1.hash not in pendingTXs)):
                        pendingTXs.append(elem.e1.hash)

                    if ((isinstance(elem.e2, Verification)
                         or isinstance(elem.e2, VerificationPacket))
                            and (elem.e2.hash not in self.rpc.meros.sentTXs)
                            and (elem.e2.hash not in pendingTXs)):
                        pendingTXs.append(elem.e2.hash)

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

            #Handle sync requests.
            reqHash: bytes = bytes()
            while True:
                #If we sent every bit of data, break.
                if ((not pendingBody) and (not pendingPackets)
                        and (not pendingTXs)):
                    break

                #Receive the next message.
                msg: bytes = self.rpc.meros.sync.recv()

                if MessageType(msg[0]) == MessageType.BlockBodyRequest:
                    #If we already sent the body, raise.
                    if not pendingBody:
                        raise TestError(
                            "Meros asked for the same Block Body multiple times."
                        )

                    #Verify Meros asked for the right Block Body.
                    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.
                    self.rpc.meros.blockBody(block)

                    #Mark the body as sent.
                    pendingBody = False

                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.
                    self.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.")
                        self.rpc.meros.packet(packets[sketchHash])

                        #Delete the VerificationPacket from pending.
                        del pendingPackets[pendingPackets.index(
                            packets[sketchHash].hash)]

                    #Make sure Meros asked for every packet.
                    if pendingPackets:
                        raise TestError(
                            "Meros didn't ask for every Verification Packet.")

                elif MessageType(msg[0]) == MessageType.TransactionRequest:
                    reqHash = msg[1:33]

                    if self.transactions is None:
                        raise TestError(
                            "Meros asked for a Transaction when we have none.")

                    if reqHash not in pendingTXs:
                        raise TestError(
                            "Meros asked for a non-existent Transaction, a Transaction part of a different Block, or an already sent Transaction."
                        )

                    self.rpc.meros.syncTransaction(
                        self.transactions.txs[reqHash])

                    #Delete the Transaction from pending.
                    del pendingTXs[pendingTXs.index(reqHash)]

                else:
                    raise TestError("Unexpected message sent: " +
                                    msg.hex().upper())

            #Receive the BlockHeader from Meros.
            if MessageType(
                    self.rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
                raise TestError("Meros didn't broadcast the new BlockHeader.")

            #Add any new nicks to the lookup table.
            if self.merit.blockchain.blocks[b].header.newMiner:
                self.merit.state.nicks.append(
                    self.merit.blockchain.blocks[b].header.minerKey)

            #If there's a callback at this height, call it.
            if b in self.callbacks:
                self.callbacks[b]()

            #Execute the every-Block callback, if it exists.
            if self.everyBlock is not None:
                self.everyBlock(b)

        #Verify the Blockchain.
        verifyBlockchain(self.rpc, self.merit.blockchain)

        #Verify the Transactions.
        if self.transactions is not None:
            verifyTransactions(self.rpc, self.transactions)

        #Reset the node.
        self.rpc.reset()
Beispiel #17
0
def TElementTest(rpc: RPC) -> None:
    #BLS key.
    blsPrivKey: PrivateKey = PrivateKey(
        blake2b(b'\0', digest_size=32).digest())
    blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex()

    #Blocks.
    file: IO[Any] = open("PythonTests/Vectors/Merit/BlankBlocks.json", "r")
    blocks: List[Dict[str, Any]] = json.loads(file.read())
    file.close()

    #Merit.
    merit: Merit = Merit()

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

    #Send the first Block.
    block: Block = Block.fromJSON(merit.blockchain.keys, blocks[0])
    merit.blockchain.add(block)
    rpc.meros.blockHeader(block.header)

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

        elif MessageType(msg[0]) == MessageType.BlockHeader:
            break

        else:
            raise TestError("Unexpected message sent: " + msg.hex().upper())

    #Create and transmit a DataDifficulty.
    dataDiff: SignedDataDifficulty = SignedDataDifficulty(
        bytes.fromhex("00" * 32), 0, 0)
    dataDiff.sign(0, blsPrivKey)
    rpc.meros.signedElement(dataDiff)
    sleep(0.5)

    #Verify the block template has the DataDifficulty.
    template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate",
                                        [blsPubKey])
    template["header"] = bytes.fromhex(template["header"])
    if template["header"][36:68] != BlockHeader.createContents(
            merit.state.nicks, [], [dataDiff]):
        raise TestError("Block template doesn't have the Data Difficulty.")

    #Mine the Block.
    block = Block(
        BlockHeader(
            0,
            block.header.hash,
            BlockHeader.createContents(merit.state.nicks, [], [dataDiff]),
            1,
            template["header"][-43:-39],
            BlockHeader.createSketchCheck(template["header"][-43:-39], []),
            0,
            int.from_bytes(template["header"][-4:], byteorder="big"),
        ), BlockBody([], [dataDiff], dataDiff.signature))
    if block.header.serializeHash()[:-4] != template["header"]:
        raise TestError("Failed to recreate the header.")
    if block.body.serialize(merit.state.nicks,
                            block.header.sketchSalt) != bytes.fromhex(
                                template["body"]):
        raise TestError("Failed to recreate the body.")

    block.mine(blsPrivKey, merit.blockchain.difficulty())
    merit.blockchain.add(block)

    #Publish it.
    rpc.call("merit", "publishBlock", [
        template["id"],
        (template["header"] + block.header.proof.to_bytes(4, byteorder="big") +
         block.header.signature + block.body.serialize(
             merit.state.nicks, block.header.sketchSalt)).hex()
    ])

    #Create and transmit a new DataDifficulty.
    dataDiff = SignedDataDifficulty(bytes.fromhex("AA" * 32), 1, 0)
    dataDiff.sign(0, blsPrivKey)
    rpc.meros.signedElement(dataDiff)
    sleep(0.5)

    #Verify the block template has the DataDifficulty.
    template = rpc.call("merit", "getBlockTemplate", [blsPubKey])
    template["header"] = bytes.fromhex(template["header"])
    if template["header"][36:68] != BlockHeader.createContents(
            merit.state.nicks, [], [dataDiff]):
        raise TestError("Block template doesn't have the new Data Difficulty.")

    #Create and transmit a new DataDifficulty reusing an existing nonce.
    signatures: List[Signature] = [dataDiff.signature]
    dataDiff = SignedDataDifficulty(bytes.fromhex("BB" * 32), 1, 0)
    dataDiff.sign(0, blsPrivKey)
    signatures.append(dataDiff.signature)
    rpc.meros.signedElement(dataDiff)
    sleep(0.5)

    #Verify the block template has a MeritRemoval.
    mr: MeritRemoval = MeritRemoval(
        SignedDataDifficulty(bytes.fromhex("AA" * 32), 1, 0),
        SignedDataDifficulty(bytes.fromhex("BB" * 32), 1, 0), False)
    template = rpc.call("merit", "getBlockTemplate", [blsPubKey])
    template["header"] = bytes.fromhex(template["header"])
    if template["header"][36:68] != BlockHeader.createContents(
            merit.state.nicks, [], [mr]):
        raise TestError("Block template doesn't have the Merit Removal.")

    #Mine the Block.
    block = Block(
        BlockHeader(
            0,
            block.header.hash,
            BlockHeader.createContents(merit.state.nicks, [], [mr]),
            1,
            template["header"][-43:-39],
            BlockHeader.createSketchCheck(template["header"][-43:-39], []),
            0,
            int.from_bytes(template["header"][-4:], byteorder="big"),
        ), BlockBody([], [mr], Signature.aggregate(signatures)))
    if block.header.serializeHash()[:-4] != template["header"]:
        raise TestError("Failed to recreate the header.")
    if block.body.serialize(merit.state.nicks,
                            block.header.sketchSalt) != bytes.fromhex(
                                template["body"]):
        raise TestError("Failed to recreate the body.")

    block.mine(blsPrivKey, merit.blockchain.difficulty())
    merit.blockchain.add(block)

    #Publish it.
    rpc.call("merit", "publishBlock", [
        template["id"],
        (template["header"] + block.header.proof.to_bytes(4, byteorder="big") +
         block.header.signature + block.body.serialize(
             merit.state.nicks, block.header.sketchSalt)).hex()
    ])

    #Verify the Blockchain.
    verifyBlockchain(rpc, merit.blockchain)
Beispiel #18
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.")
Beispiel #19
0
    def sync(self) -> None:
        #Handshake with the node.
        self.rpc.meros.connect(254, 254, self.settings["height"] + 1)

        #Handle sync requests.
        reqHash: bytes = bytes()
        lastBlock: int = 0
        hadTips: bool = False
        while True:
            msg: bytes = self.rpc.meros.recv()

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

            elif MessageType(msg[0]) == MessageType.GetBlockHash:
                height: int = int.from_bytes(msg[1:5], "big")

                if height == 0:
                    self.rpc.meros.blockHash(self.blockchain.blocks[
                        self.settings["height"]].header.hash)
                else:
                    if height > self.settings["height"]:
                        raise TestError(
                            "Meros asked for a Block Hash we don't have.")
                    self.rpc.meros.blockHash(
                        self.blockchain.blocks[height].header.hash)

            elif MessageType(msg[0]) == MessageType.BlockHeaderRequest:
                reqHash = msg[1:49]

                for block in self.blockchain.blocks:
                    if block.header.hash == reqHash:
                        self.rpc.meros.blockHeader(block.header)
                        break

                    if block.header.hash == self.blockchain.blocks[
                            self.settings["height"]].header.hash:
                        raise TestError(
                            "Meros asked for a Block Header we don't have.")

            elif MessageType(msg[0]) == MessageType.BlockBodyRequest:
                reqHash = msg[1:49]

                if self.tips != {}:
                    raise TestError(
                        "Meros requested a new BlockBody despite not finishing syncing the existing tips."
                    )

                for block in self.blockchain.blocks:
                    if block.header.hash == reqHash:
                        #Update the tips.
                        hadTips = self.updateTips(block.header.nonce,
                                                  block.body.records)

                        #Send the BlockBody.
                        self.rpc.meros.blockBody(block.body)
                        lastBlock = block.header.nonce + 1

                        #We check to load the tail tips AFTER an ElementRequest,
                        #Therefore, if there aren't any tips before in in the second to last block, we won't load them.
                        #This handles that case.
                        if ((not hadTips)
                                and (lastBlock == self.settings["height"])):
                            self.loadTailTips()
                        break

                    if block.header.hash == self.blockchain.blocks[
                            self.settings["height"]].header.hash:
                        raise TestError(
                            "Meros asked for a Block Body we don't have.")

            elif MessageType(msg[0]) == MessageType.ElementRequest:
                holder: bytes = msg[1:49]
                nonce: int = int.from_bytes(msg[49:53], "big")

                if self.consensus is None:
                    raise TestError(
                        "Meros asked for an Element when we have none.")

                if holder not in self.consensus.holders:
                    raise TestError(
                        "Meros asked for an Element from a holder we don't have."
                    )

                if nonce >= len(self.consensus.holders[holder]):
                    raise TestError(
                        "Meros asked for an Element we don't have.")

                if holder not in self.tips:
                    raise TestError(
                        "Meros asked for an Element from a holder we haven't mentioned/they already fully synced."
                    )

                self.rpc.meros.element(self.consensus.holders[holder][nonce])

                if nonce == self.tips[holder]:
                    del self.tips[holder]

                #If this is the Block before the tail, and tips is empty, correct the tips/TXs.
                if ((lastBlock == self.settings["height"])
                        and (self.tips == {})):
                    self.loadTailTips()

            elif MessageType(msg[0]) == MessageType.TransactionRequest:
                reqHash = msg[1:49]

                if self.transactions is None:
                    raise TestError(
                        "Meros asked for a Transaction when we have none.")

                if reqHash not in self.transactions.txs:
                    raise TestError(
                        "Meros asked for a Transaction we don't have.")

                if reqHash not in self.txs:
                    raise TestError(
                        "Meros asked for a Transaction we haven't mentioned/they already synced."
                    )

                self.rpc.meros.transaction(self.transactions.txs[reqHash])
                self.synced[reqHash] = True
                del self.txs[reqHash]

            elif MessageType(msg[0]) == MessageType.SyncingOver:
                #Break out of the foor loop if the sync finished.
                #This means we sent every Block, every Element, every Transaction...
                if ((lastBlock == self.settings["height"])
                        and (self.tips == {}) and (self.txs == {})):
                    #Make sure we handled the tail tips.
                    handled: bool = True
                    for holder in self.tailTips:
                        if holder not in self.allTips:
                            handled = False
                            break

                        if self.allTips[holder] != self.tailTips[holder]:
                            handled = False
                            break

                    if handled:
                        break

            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())

        #Verify the Blockchain.
        verifyBlockchain(self.rpc, self.blockchain)

        #Verify the Consensus.
        try:
            verifyConsensus(self.rpc, self.consensus)
        except AttributeError:
            pass

        #Verify the Transactions.
        try:
            verifyTransactions(self.rpc, self.transactions)
        except AttributeError:
            pass

        if self.settings["playback"]:
            #Playback their messages.
            self.rpc.meros.playback()
Beispiel #20
0
def VParsableTest(rpc: RPC) -> None:
    file: IO[Any] = open(
        "PythonTests/Vectors/Consensus/Verification/Parsable.json", "r")
    vectors: Dict[str, Any] = json.loads(file.read())
    file.close()

    #Blockchain.
    blockchain: Blockchain = Blockchain.fromJSON(
        b"MEROS_DEVELOPER_NETWORK", 60,
        int(
            "FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
            16), vectors["blockchain"])
    #Consensus.
    consensus: Consensus = Consensus(
        bytes.fromhex(
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
        ),
        bytes.fromhex(
            "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
        ),
    )
    consensus.add(SignedVerification.fromJSON(vectors["verification"]))
    #Transactions.
    transactions: Transactions = Transactions()
    transactions.add(Data.fromJSON(vectors["data"]))

    #Handshake with the node.
    rpc.meros.connect(254, 254, 3)

    sentLast: bool = False
    reqHash: bytes = bytes()
    msg: bytes = bytes()
    height: int = 0
    while True:
        try:
            msg = rpc.meros.recv()
        except TestError as e:
            if (not sentLast) or (str(e) != "Node disconnected us as a peer."):
                raise e
            break

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

        elif MessageType(msg[0]) == MessageType.GetBlockHash:
            height = int.from_bytes(msg[1:5], "big")
            if height == 0:
                rpc.meros.blockHash(blockchain.last())
            else:
                if height >= len(blockchain.blocks):
                    raise TestError(
                        "Meros asked for a Block Hash we do not have.")

                rpc.meros.blockHash(blockchain.blocks[height].header.hash)

        elif MessageType(msg[0]) == MessageType.BlockHeaderRequest:
            reqHash = msg[1:49]
            for block in blockchain.blocks:
                if block.header.hash == reqHash:
                    rpc.meros.blockHeader(block.header)
                    break

                if block.header.hash == blockchain.last():
                    raise TestError(
                        "Meros asked for a Block Header we do not have.")

        elif MessageType(msg[0]) == MessageType.BlockBodyRequest:
            reqHash = msg[1:49]
            for block in blockchain.blocks:
                if block.header.hash == reqHash:
                    rpc.meros.blockBody(block.body)
                    break

                if block.header.hash == blockchain.last():
                    raise TestError(
                        "Meros asked for a Block Body we do not have.")

        elif MessageType(msg[0]) == MessageType.ElementRequest:
            holder: bytes = msg[1:49]

            rpc.meros.element(consensus.holders[holder][int.from_bytes(
                msg[49:53], "big")])

        elif MessageType(msg[0]) == MessageType.TransactionRequest:
            sentLast = True
            rpc.meros.transaction(transactions.txs[msg[1:49]])

        elif MessageType(msg[0]) == MessageType.SyncingOver:
            pass

        else:
            raise TestError("Unexpected message sent: " + msg.hex().upper())
Beispiel #21
0
    def sync(self) -> None:
        #Handshake with the node.
        self.rpc.meros.syncConnect(
            self.merit.blockchain.blocks[self.settings["height"]].header.hash)

        #Handle sync requests.
        reqHash: bytes = bytes()
        while True:
            #Break out of the for loop if the sync finished.
            #This means we sent every Block, every Element, every Transaction...
            if ((self.blockHashes == set()) and (self.packets == {})
                    and (self.txs == set())):
                break

            msg: bytes = self.rpc.meros.sync.recv()

            if MessageType(msg[0]) == MessageType.BlockListRequest:
                reqHash = msg[3:35]
                for b in range(len(self.merit.blockchain.blocks)):
                    if self.merit.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(self.merit.blockchain.blocks[
                                    b - bl].header.hash)
                                if b - bl != 0:
                                    self.blocks.append(
                                        self.merit.blockchain.blocks[b - bl])

                            elif msg[1] == 1:
                                if b + bl > self.settings["height"]:
                                    break

                                blockList.append(self.merit.blockchain.blocks[
                                    b + bl].header.hash)
                                self.blocks.append(
                                    self.merit.blockchain.blocks[b + bl])

                            else:
                                raise TestError(
                                    "Meros asked for an invalid direction in a BlockListRequest."
                                )

                        if blockList == []:
                            self.rpc.meros.dataMissing()
                            break

                        self.rpc.meros.blockList(blockList)
                        break

                    if b == self.settings["height"]:
                        self.rpc.meros.dataMissing()

            elif MessageType(msg[0]) == MessageType.BlockHeaderRequest:
                if (self.txs != set()) or (self.packets != {}):
                    raise TestError(
                        "Meros asked for a new Block before syncing the last Block's Transactions and Packets."
                    )

                reqHash = msg[1:33]
                if reqHash != self.blocks[-1].header.hash:
                    raise TestError(
                        "Meros asked for a BlockHeader other than the next Block's on the last BlockList."
                    )

                self.rpc.meros.syncBlockHeader(self.blocks[-1].header)

            elif MessageType(msg[0]) == MessageType.BlockBodyRequest:
                reqHash = msg[1:33]
                if reqHash != self.blocks[-1].header.hash:
                    raise TestError(
                        "Meros asked for a BlockBody other than the next Block's on the last BlockList."
                    )

                self.rpc.meros.blockBody(self.blocks[-1])
                self.blockHashes.remove(self.blocks[-1].header.hash)

                #Set packets/transactions.
                self.packets = {}
                for packet in self.blocks[-1].body.packets:
                    if packet.hash not in self.synced:
                        self.txs.add(packet.hash)
                    self.packets[Sketch.hash(self.blocks[-1].header.sketchSalt,
                                             packet)] = packet

                #Update the list of mentioned Transactions.
                noVCMRs: bool = True
                for elem in self.blocks[-1].body.elements:
                    if isinstance(elem, MeritRemoval):
                        if isinstance(elem.e1,
                                      (Verification, VerificationPacket)):
                            self.txs.add(elem.e1.hash)
                            noVCMRs = False
                        if isinstance(elem.e2,
                                      (Verification, VerificationPacket)):
                            self.txs.add(elem.e2.hash)
                            noVCMRs = False

                if (self.packets == {}) and noVCMRs:
                    del self.blocks[-1]

            elif MessageType(msg[0]) == MessageType.SketchHashesRequest:
                reqHash = msg[1:33]
                if reqHash != self.blocks[-1].header.hash:
                    raise TestError(
                        "Meros asked for Sketch Hashes that didn't belong to the header we just sent it."
                    )

                #Get the haashes.
                hashes: List[int] = list(self.packets)

                #Send the Sketch Hashes.
                self.rpc.meros.sketchHashes(hashes)

            elif MessageType(msg[0]) == MessageType.SketchHashRequests:
                if not self.packets:
                    raise TestError(
                        "Meros asked for Verification Packets from a Block without any."
                    )

                reqHash = msg[1:33]
                if reqHash != self.blocks[-1].header.hash:
                    raise TestError(
                        "Meros asked for Verification Packets that didn't belong to the Block we just sent it."
                    )

                #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 self.packets:
                        raise TestError(
                            "Meros asked for a non-existent Sketch Hash.")
                    self.rpc.meros.packet(self.packets[sketchHash])
                    del self.packets[sketchHash]

            elif MessageType(msg[0]) == MessageType.TransactionRequest:
                reqHash = msg[1:33]

                if self.transactions is None:
                    raise TestError(
                        "Meros asked for a Transaction when we have none.")

                if reqHash not in self.transactions.txs:
                    raise TestError(
                        "Meros asked for a Transaction we don't have.")

                if reqHash not in self.txs:
                    raise TestError(
                        "Meros asked for a Transaction we haven't mentioned.")

                self.rpc.meros.syncTransaction(self.transactions.txs[reqHash])
                self.synced.add(reqHash)
                self.txs.remove(reqHash)

                if self.txs == set():
                    del self.blocks[-1]

            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())

        #Verify the Blockchain.
        verifyBlockchain(self.rpc, self.merit.blockchain)

        #Verify the Transactions.
        if self.transactions is not None:
            verifyTransactions(self.rpc, self.transactions)

        if self.settings["playback"]:
            #Playback their messages.
            self.rpc.meros.sync.playback()
Beispiel #22
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())
Beispiel #23
0
def VUnknownTest(
    rpc: RPC
) -> None:
    file: IO[Any] = open("PythonTests/Vectors/Consensus/Verification/Parsable.json", "r")
    vectors: Dict[str, Any] = json.loads(file.read())
    #SignedVerification.
    sv: SignedVerification = SignedVerification.fromJSON(vectors["verification"])
    #Blockchain.
    blockchain: Blockchain = Blockchain.fromJSON(
        b"MEROS_DEVELOPER_NETWORK",
        60,
        int("FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 16),
        vectors["blockchain"]
    )
    file.close()

    #Handshake with the node.
    rpc.meros.connect(254, 254, len(blockchain.blocks))

    sentLast: bool = False
    reqHash: bytes = bytes()
    while True:
        msg: bytes = rpc.meros.recv()

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

        elif MessageType(msg[0]) == MessageType.GetBlockHash:
            height: int = int.from_bytes(msg[1 : 5], "big")
            if height == 0:
                rpc.meros.blockHash(blockchain.last())
            else:
                if height >= len(blockchain.blocks):
                    raise TestError("Meros asked for a Block Hash we do not have.")

                rpc.meros.blockHash(blockchain.blocks[height].header.hash)

        elif MessageType(msg[0]) == MessageType.BlockHeaderRequest:
            reqHash = msg[1 : 49]
            for block in blockchain.blocks:
                if block.header.hash == reqHash:
                    rpc.meros.blockHeader(block.header)
                    break

                if block.header.hash == blockchain.last():
                    raise TestError("Meros asked for a Block Header we do not have.")

        elif MessageType(msg[0]) == MessageType.BlockBodyRequest:
            reqHash = msg[1 : 49]
            for block in blockchain.blocks:
                if block.header.hash == reqHash:
                    rpc.meros.blockBody(block.body)
                    break

                if block.header.hash == blockchain.last():
                    raise TestError("Meros asked for a Block Body we do not have.")

        elif MessageType(msg[0]) == MessageType.ElementRequest:
            rpc.meros.element(sv)

        elif MessageType(msg[0]) == MessageType.TransactionRequest:
            sentLast = True
            rpc.meros.dataMissing()

        elif MessageType(msg[0]) == MessageType.SyncingOver:
            if sentLast:
                break

        else:
            raise TestError("Unexpected message sent: " + msg.hex().upper())

    #Verify the Verification and Block were not added.
    if rpc.call("consensus", "getHeight", [sv.holder.hex()]) != 0:
        raise TestError("Meros added an unknown Verification.")

    if rpc.call("merit", "getHeight") != 2:
        raise TestError("Meros added a Block with an unknown Verification.")