Exemple #1
0
    def handleSync() -> None:
        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[-32:]
                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 b - bl < 0:
                                break
                            blockList.append(blockchain.blocks[b -
                                                               bl].header.hash)

                        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."
                    )

                rpc.meros.rawBlockBody(blockchain.blocks[bB],
                                       len(blockchain.blocks[bB].body.packets))
                bB += 1

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

        #Verify the Blockchain.
        verifyBlockchain(rpc, blockchain)
Exemple #2
0
  def sendAlternateTip() -> None:
    header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)
    rpc.meros.handleBlockBody(alt.blocks[-1])

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

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

    #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
    raise SuccessError("Meros re-organized to the alternate chain.")
Exemple #3
0
    def sendAlternateTip() -> None:
        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[-32:] != alt.blocks[-2].header.hash:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders for THIS header."
            )

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

        diff = -14
        while diff != -1:
            if rpc.meros.sync.recv() != (
                    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

        #Meros will now attempt the re-org, having verified the work.
        #Break the chain early via a data missing.
        diff = -14
        while diff != 0:
            if diff == -2:
                if rpc.meros.sync.recv()[:-4] != (
                        MessageType.BlockBodyRequest.toByte() +
                        alt.blocks[diff].header.hash):
                    raise TestError(
                        "Meros didn't request a previous BlockBody.")
                rpc.meros.dataMissing()
                sleep(35)
                for socket in [rpc.meros.live, rpc.meros.sync]:
                    socket.connection.close()
                #We could just edit the condition above, yet this keeps parity with the other reorg tests.
                break
            else:
                rpc.meros.handleBlockBody(alt.blocks[diff])
            diff += 1

        #Verify Meros at least went back to the fork point.
        #Ideally, it'd go back to the original chain.
        #Or if we synced enough blocks where we still have a chain with more work, we should remain on it.
        verifyBlockchain(rpc, forkPoint)
        raise SuccessError("Meros reverted back to the fork point.")
Exemple #4
0
    def sendAlternateTip() -> None:
        header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)
        req: bytes = rpc.meros.sync.recv()
        if req != (MessageType.BlockBodyRequest.toByte() +
                   alt.blocks[-1].header.hash):
            raise TestError("Meros didn't request the BlockBody.")
        rpc.meros.blockBody(alt.blocks[-1])

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

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

        #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
        raise SuccessError("Meros re-organized to the alternate chain.")
    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 = -2
        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 = -2
        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.")
Exemple #6
0
def TwoHundredThirtyTwoTest(rpc: RPC) -> None:
    file: IO[Any] = open(
        "e2e/Vectors/Merit/Reorganizations/TwoHundredThirtyTwo.json", "r")
    chains: Dict[str, List[Dict[str, Any]]] = json.loads(file.read())
    main: Blockchain = Blockchain.fromJSON(chains["main"])
    alt: Blockchain = Blockchain.fromJSON(chains["alt"])
    file.close()

    def sendBlock(toSend: Block) -> None:
        rpc.meros.liveBlockHeader(toSend.header)
        if rpc.meros.sync.recv() != (MessageType.BlockBodyRequest.toByte() +
                                     toSend.header.hash):
            raise TestError("Meros didn't ask for this Block's body.")
        rpc.meros.blockBody(toSend)
        if toSend.body.packets:
            if rpc.meros.sync.recv() != (
                    MessageType.SketchHashRequests.toByte() +
                    toSend.header.hash +
                (1).to_bytes(4, byteorder="little") + Sketch.hash(
                    toSend.header.sketchSalt, toSend.body.packets[0]).to_bytes(
                        8, byteorder="little")):
                raise TestError(
                    "Meros didn't ask for this BlockBody's VerificationPacket."
                )
            rpc.meros.packet(toSend.body.packets[0])

    #Make the initial connection and sync the main chain.
    rpc.meros.liveConnect(main.blocks[0].header.hash)
    rpc.meros.syncConnect(main.blocks[0].header.hash)
    sendBlock(main.blocks[1])
    sendBlock(main.blocks[2])

    #Trigger the reorganization to the alternate chain.
    #We only want the revert aspect of this.
    rpc.meros.liveBlockHeader(alt.blocks[3].header)
    if rpc.meros.sync.recv()[0] != MessageType.BlockListRequest.toByte()[0]:
        raise TestError(
            "Meros didn't ask for the Block List of the alternate chain.")
    rpc.meros.blockList([alt.blocks[2].header.hash, alt.blocks[1].header.hash])
    if rpc.meros.sync.recv() != (MessageType.BlockHeaderRequest.toByte() +
                                 alt.blocks[2].header.hash):
        raise TestError(
            "Meros didn't ask for the other BlockHeader in this alternate chain."
        )
    rpc.meros.syncBlockHeader(alt.blocks[2].header)

    #Cause the re-organization to fail.
    rpc.meros.live.connection.close()
    rpc.meros.sync.connection.close()
    rpc.socket.close()
    sleep(35)

    #Reboot the node to reload the database.
    rpc.meros.quit()
    rpc.meros.calledQuit = False

    rpc.meros.process = Popen([
        "./build/Meros", "--data-dir", rpc.meros.dataDir, "--log-file",
        rpc.meros.log, "--db", rpc.meros.db, "--network", "devnet",
        "--tcp-port",
        str(rpc.meros.tcp), "--rpc-port",
        str(rpc.meros.rpc), "--no-gui"
    ])
    while True:
        try:
            connection: socket.socket = socket.socket(socket.AF_INET,
                                                      socket.SOCK_STREAM)
            connection.connect(("127.0.0.1", rpc.meros.rpc))
            connection.shutdown(socket.SHUT_RDWR)
            connection.close()
            break
        except ConnectionRefusedError:
            sleep(1)

    rpc.meros.liveConnect(main.blocks[0].header.hash)
    rpc.meros.syncConnect(main.blocks[0].header.hash)
    sendBlock(main.blocks[2])

    rpc.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    rpc.socket.connect(("127.0.0.1", rpc.meros.rpc))
    verifyBlockchain(rpc, main)
Exemple #7
0
    def live(self, ignorePackets: List[bytes] = []) -> 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)):
            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:
                if packet.hash in ignorePackets:
                    continue
                pendingPackets.append(packet.hash)

                #Don't include sent Transactions or independently created Block Data.
                if not ((packet.hash in self.rpc.meros.sentTXs) or
                        (packet.hash == (Data(self.merit.blockchain.genesis,
                                              block.header.last).hash))):
                    pendingTXs.append(packet.hash)

            for elem in block.body.elements:
                if isinstance(elem, MeritRemoval):
                    if (isinstance(elem.e1, (Verification, 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, VerificationPacket))
                            and (elem.e2.hash not in self.rpc.meros.sentTXs)
                            and (elem.e2.hash not in pendingTXs)):
                        pendingTXs.append(elem.e2.hash)

            self.rpc.meros.liveBlockHeader(block.header)

            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:
                    reqHash = msg[1:33]

                    if not pendingBody:
                        raise TestError(
                            "Meros asked for the same Block Body multiple times."
                        )
                    if reqHash != block.header.hash:
                        raise TestError(
                            "Meros asked for a Block Body that didn't belong to the Block we just sent it."
                        )

                    self.rpc.meros.blockBody(block)
                    pendingBody = False

                elif MessageType(msg[0]) == MessageType.SketchHashesRequest:
                    reqHash = msg[1:33]
                    if not block.body.packets:
                        raise TestError(
                            "Meros asked for Sketch Hashes from a Block without any."
                        )
                    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))

                    self.rpc.meros.sketchHashes(hashes)

                elif MessageType(msg[0]) == MessageType.SketchHashRequests:
                    reqHash = msg[1:33]
                    if not block.body.packets:
                        raise TestError(
                            "Meros asked for Verification Packets from a Block without any."
                        )
                    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="little")):
                        sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 +
                                                             (h * 8)],
                                                         byteorder="little")
                        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()
def EightyEightTest(
  rpc: RPC
) -> None:
  edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32)
  edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key()

  blsPrivKey: PrivateKey = PrivateKey(0)
  blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex()

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

  merit: Merit = Merit()
  dataFilter: SpamFilter = SpamFilter(5)

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

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

  #Handle sync requests.
  reqHash: bytes = bytes()
  while True:
    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)
      break

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

  if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
    raise TestError("Meros didn't broadcast the Block Header it just added.")

  #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.liveTransaction(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(packets):
    raise TestError("Block template doesn't have both Verification Packets.")

  #Mine the Block.
  block = Block(
    BlockHeader(
      0,
      block.header.hash,
      BlockHeader.createContents(packets),
      1,
      template["header"][-43 : -39],
      BlockHeader.createSketchCheck(template["header"][-43 : -39], packets),
      0,
      int.from_bytes(template["header"][-4:], byteorder="little")
    ),
    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(
    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)

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

  verifyBlockchain(rpc, merit.blockchain)
Exemple #9
0
 def verify() -> None:
     verifyMeritRemoval(rpc, 1, 1, removal.holder, False)
     verifyBlockchain(rpc, Blockchain.fromJSON(vectors["blockchain"]))
     raise SuccessError(
         "MeritRemoval and Blockchain were properly handled.")
Exemple #10
0
def TElementTest(
  rpc: RPC
) -> None:
  file: IO[Any] = open("e2e/Vectors/Merit/BlankBlocks.json", "r")
  blocks: List[Dict[str, Any]] = json.loads(file.read())
  file.close()
  merit: Merit = Merit()

  blsPrivKey: PrivateKey = PrivateKey(0)
  blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex()

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

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

  #Handle sync requests.
  reqHash: bytes = bytes()
  while True:
    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.")

      rpc.meros.blockBody(block)
      break

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

  if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
    raise TestError("Meros didn't broadcast the Block Header it just added.")

  #Create and transmit a DataDifficulty.
  dataDiff: SignedDataDifficulty = SignedDataDifficulty(0, 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([], [dataDiff]):
    raise TestError("Block template doesn't have the Data Difficulty.")

  #Mine the Block.
  block = Block(
    BlockHeader(
      0,
      block.header.hash,
      BlockHeader.createContents([], [dataDiff]),
      1,
      template["header"][-43 : -39],
      BlockHeader.createSketchCheck(template["header"][-43 : -39], []),
      0,
      int.from_bytes(template["header"][-4:], byteorder="little"),
    ),
    BlockBody([], [dataDiff], dataDiff.signature)
  )
  if block.header.serializeHash()[:-4] != template["header"]:
    raise TestError("Failed to recreate the header.")
  if block.body.serialize(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="little") +
        block.header.signature +
        block.body.serialize(block.header.sketchSalt)
      ).hex()
    ]
  )

  #Create and transmit a new DataDifficulty.
  dataDiff = SignedDataDifficulty(3, 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([], [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(4, 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(3, 1, 0),
    SignedDataDifficulty(4, 1, 0),
    False
  )
  template = rpc.call("merit", "getBlockTemplate", [blsPubKey])
  template["header"] = bytes.fromhex(template["header"])
  if template["header"][36 : 68] != BlockHeader.createContents([], [mr]):
    raise TestError("Block template doesn't have the Merit Removal.")

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

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

  rpc.call(
    "merit",
    "publishBlock",
    [
      template["id"],
      (
        template["header"] +
        block.header.proof.to_bytes(4, byteorder="little") +
        block.header.signature +
        block.body.serialize(block.header.sketchSalt)
      ).hex()
    ]
  )

  verifyBlockchain(rpc, merit.blockchain)
Exemple #11
0
def TElementTest(rpc: RPC) -> None:
    merit: Merit = Merit()

    blsPrivKey: PrivateKey = PrivateKey(0)
    blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex()

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

    #Send the first Block.
    block: Block
    with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file:
        block = Block.fromJSON(json.loads(file.read())[0])
    merit.blockchain.add(block)
    rpc.meros.liveBlockHeader(block.header)
    rpc.meros.handleBlockBody(block)
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
        raise TestError(
            "Meros didn't broadcast the Block Header it just added.")

    #Create and transmit a DataDifficulty.
    dataDiff: SignedDataDifficulty = SignedDataDifficulty(0, 0, 0)
    dataDiff.sign(0, blsPrivKey)
    rpc.meros.signedElement(dataDiff)
    sleep(1.5)

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

    #Mine the Block.
    block = Block(
        BlockHeader(
            0,
            block.header.hash,
            BlockHeader.createContents([], [dataDiff]),
            0,
            template["header"][-43:-39],
            BlockHeader.createSketchCheck(template["header"][-43:-39], []),
            0,
            int.from_bytes(template["header"][-4:], byteorder="little"),
        ), BlockBody([], [dataDiff], dataDiff.signature))
    if block.header.serializeHash()[:-4] != template["header"]:
        raise TestError("Failed to recreate the header.")

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

    #Publish it.
    rpc.call(
        "merit", "publishBlock", {
            "id":
            template["id"],
            "header": (template["header"] +
                       block.header.proof.to_bytes(4, byteorder="little") +
                       block.header.signature).hex()
        })

    #Create and transmit a new DataDifficulty.
    dataDiff = SignedDataDifficulty(3, 0, 0)
    dataDiff.sign(0, blsPrivKey)
    rpc.meros.signedElement(dataDiff)
    sleep(1.5)

    #Verify the block template has a MeritRemoval.
    #Thanks to implicit Merit Removals, this just means it has the new difficulty.
    template = rpc.call("merit", "getBlockTemplate", {"miner": blsPubKey})
    template["header"] = bytes.fromhex(template["header"])
    if template["header"][36:68] != BlockHeader.createContents([], [dataDiff]):
        raise TestError("Block template doesn't have the Merit Removal.")

    #Mine the Block.
    block = Block(
        BlockHeader(
            0, block.header.hash, BlockHeader.createContents([], [dataDiff]),
            0, template["header"][-43:-39],
            BlockHeader.createSketchCheck(template["header"][-43:-39], []), 0,
            int.from_bytes(template["header"][-4:], byteorder="little")),
        BlockBody([], [dataDiff], dataDiff.signature))
    if block.header.serializeHash()[:-4] != template["header"]:
        raise TestError("Failed to recreate the header.")

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

    rpc.call(
        "merit", "publishBlock", {
            "id":
            template["id"],
            "header": (template["header"] +
                       block.header.proof.to_bytes(4, byteorder="little") +
                       block.header.signature).hex()
        })

    verifyBlockchain(rpc, merit.blockchain)
Exemple #12
0
def EightyEightTest(rpc: RPC) -> None:
    edPrivKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32)
    edPubKey: bytes = edPrivKey.get_verifying_key()

    blsPrivKey: PrivateKey = PrivateKey(0)
    blsPubKey: str = blsPrivKey.toPublicKey().serialize().hex()

    merit: Merit = Merit()
    dataFilter: SpamFilter = SpamFilter(5)

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

    #Send the first Block.
    block: Block
    with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file:
        block = Block.fromJSON(json.loads(file.read())[0])
    merit.blockchain.add(block)
    rpc.meros.liveBlockHeader(block.header)
    rpc.meros.handleBlockBody(block)
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
        raise TestError(
            "Meros didn't broadcast the Block Header it just added.")

    #Create two Datas.
    datas: List[Data] = [Data(bytes(32), edPubKey)]
    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.liveTransaction(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(1.5)

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

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

    #Verify the block template has both verifications.
    template: Dict[str, Any] = rpc.call("merit", "getBlockTemplate",
                                        {"miner": 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(packets):
        raise TestError(
            "Block template doesn't have both Verification Packets.")

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

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

    rpc.call(
        "merit", "publishBlock", {
            "id":
            template["id"],
            "header": (template["header"] +
                       block.header.proof.to_bytes(4, byteorder="little") +
                       block.header.signature).hex()
        })

    verifyBlockchain(rpc, merit.blockchain)
Exemple #13
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()
Exemple #14
0
    def sync(self) -> None:
        self.rpc.meros.syncConnect(
            self.merit.blockchain.blocks[self.settings["height"]].header.hash)

        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[-32:]
                for b in range(len(self.merit.blockchain.blocks)):
                    if self.merit.blockchain.blocks[b].header.hash == reqHash:
                        if self.blocks[-1].header.hash != reqHash:
                            self.blocks.append(self.merit.blockchain.blocks[b])
                        blockList: List[bytes] = []
                        for bl in range(1, msg[1] + 2):
                            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])

                        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:
                reqHash = msg[1:33]
                if (self.txs != set()) or (self.packets != {}):
                    raise TestError(
                        "Meros asked for a new Block before syncing the last Block's Transactions and Packets."
                    )
                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."
                    )

                if int.from_bytes(msg[33:37], "little") != len(
                        self.blocks[-1].body.packets):
                    raise Exception(
                        "Meros didn't request 100% of packets in the BlockBody when syncing."
                    )
                self.rpc.meros.rawBlockBody(self.blocks[-1],
                                            len(self.blocks[-1].body.packets))
                self.blockHashes.remove(self.blocks[-1].header.hash)

                #Set the packets/transactions which should be synced.
                self.packets = {}
                for packet in self.blocks[-1].body.packets:
                    if not ((packet.hash in self.rpc.meros.sentTXs) or
                            (packet.hash == (Data(
                                self.merit.blockchain.genesis,
                                self.blocks[-1].header.last).hash))):
                        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
                if (self.packets == {}) and noVCMRs:
                    del self.blocks[-1]

            elif MessageType(msg[0]) == MessageType.SketchHashRequests:
                reqHash = msg[1:33]
                if not self.packets:
                    raise TestError(
                        "Meros asked for Verification Packets from a Block without any."
                    )
                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="little")):
                    sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 +
                                                         (h * 8)],
                                                     byteorder="little")
                    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]

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

            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.txs.remove(reqHash)

                if (self.packets == {}) and (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)

        #Playback their messages.
        #Verifies Meros can respond as it can receive.
        if self.settings["playback"]:
            self.rpc.meros.sync.playback()

        #Reset the node.
        self.rpc.reset()