コード例 #1
0
  def serialize(
    self,
    sketchSalt: bytes,
    capacityArg: int = -1
  ) -> bytes:
    capacity: int = capacityArg
    if capacity == -1:
      capacity = len(self.packets) // 5 + 1 if len(self.packets) != 0 else 0

    sketch: Sketch = Sketch(capacity)
    for packet in self.packets:
      sketch.add(sketchSalt, packet)

    result: bytes = (
      self.packetsContents +
      capacity.to_bytes(4, "big") +
      sketch.serialize() +
      len(self.elements).to_bytes(4, "big")
    )

    for elem in self.elements:
      result += elem.prefix + elem.serialize()

    result += self.aggregate.serialize()
    return result
コード例 #2
0
    def sendDataAndBlock() -> None:
        #Send the Data.
        if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
            raise TestError("Meros didn't send back the Data.")

        rpc.meros.liveBlockHeader(block.header)
        rpc.meros.handleBlockBody(block)
        msg: bytes = rpc.meros.sync.recv()
        if MessageType(msg[0]) != MessageType.SketchHashRequests:
            raise TestError("Meros didn't request the packets for this Block.")

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

        try:
            if MessageType(
                    rpc.meros.live.recv()[0]) == MessageType.BlockHeader:
                raise TestError("Meros added the Block.")
        except Exception as e:
            if str(e) != "Meros added the Block.":
                raise SuccessError()
コード例 #3
0
        def checkFail() -> None:
            #Grab the Block.
            #pylint: disable=cell-var-from-loop
            block: Block = merit.blockchain.blocks[12]

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

            #Handle sync requests.
            while True:
                msg: bytes = rpc.meros.sync.recv()
                if MessageType(msg[0]) == MessageType.SketchHashRequests:
                    if msg[1:33] != 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.")
                        rpc.meros.packet(packets[sketchHash])

                elif MessageType(msg[0]) == MessageType.TransactionRequest:
                    reqHash: bytes = msg[1:33]
                    #pylint: disable=cell-var-from-loop
                    if reqHash not in transactions.txs:
                        raise TestError(
                            "Meros asked for a non-existent Transaction.")

                    #pylint: disable=cell-var-from-loop
                    rpc.meros.syncTransaction(transactions.txs[reqHash])

                    #Try receiving from the Live socket, where Meros sends keep-alives.
                    try:
                        if len(rpc.meros.live.recv()) != 0:
                            raise Exception()
                    except TestError:
                        raise SuccessError(
                            "Node disconnected us after we sent an invalid Transaction."
                        )
                    except Exception:
                        raise TestError("Meros sent a keep-alive.")

                else:
                    raise TestError("Unexpected message sent: " +
                                    msg.hex().upper())
コード例 #4
0
def TwoHundredFourTest(rpc: RPC) -> None:
    vectors: Dict[str, Any]
    with open("e2e/Vectors/Consensus/TwoHundredFour.json", "r") as file:
        vectors = json.loads(file.read())

    #Instantiate a Blockchain to set the RandomX key.
    chain: Blockchain = Blockchain()
    blank: Block = Block.fromJSON(vectors["blank"])

    if len(vectors["blocks"]) != 1:
        raise Exception(
            "Misread this test's vectors, creating an invalid test due to that."
        )
    block: Block = Block.fromJSON(vectors["blocks"][0])

    rpc.meros.liveConnect(chain.last())
    rpc.meros.syncConnect(chain.last())

    #Send a blank block so Meros acknowledges a holder.
    sentHeader: bytes = rpc.meros.liveBlockHeader(blank.header)
    rpc.meros.handleBlockBody(blank)
    if rpc.meros.live.recv() != sentHeader:
        raise TestError(
            "Meros didn't rebroadcast the header for a blank Block.")

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

    msg: bytes = rpc.meros.sync.recv()
    if MessageType(msg[0]) != MessageType.SketchHashRequests:
        raise TestError("Unexpected message sent: " + msg.hex().upper())
    if msg[1:33] != block.header.hash:
        raise TestError(
            "Meros asked for Verification Packets that didn't belong to the Block we just sent it."
        )
    if int.from_bytes(msg[33:37], byteorder="little") != 1:
        raise TestError("Meros didn't ask for one VerificationPacket.")
    if int.from_bytes(msg[37:45], byteorder="little") != Sketch.hash(
            block.header.sketchSalt, block.body.packets[0]):
        raise TestError("Meros didn't ask for the VerificationPacket.")
    rpc.meros.packet(block.body.packets[0])

    #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 node didn't crash.
        sleep(1)
        if rpc.meros.process.poll() is not None:
            raise TestError(
                "Node crashed trying to handle a VerificationPacket with no holders."
            )
    except Exception:
        raise TestError(
            "Meros didn't disconnect us after sending a VerificationPacket with no holders; it also didn't crash."
        )
コード例 #5
0
ファイル: BlockBody.py プロジェクト: frozenghozt/Meros
    def serialize(self, sketchSalt: bytes, capacity: int) -> bytes:
        sketch: Sketch = Sketch(capacity)
        for packet in self.packets:
            sketch.add(sketchSalt, packet)

        result: bytes = (self.packetsContents +
                         capacity.to_bytes(4, "little") + sketch.serialize() +
                         len(self.elements).to_bytes(4, "little"))

        for elem in self.elements:
            result += elem.prefix + elem.serialize()

        result += self.aggregate.serialize()
        return result
コード例 #6
0
 def sendBlock(
   toSend: Block
 ) -> None:
   rpc.meros.liveBlockHeader(toSend.header)
   rpc.meros.handleBlockBody(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])
コード例 #7
0
ファイル: BlockHeader.py プロジェクト: Tesconanopay/MerosDeFi
    def createSketchCheck(salt: bytes = bytes(4),
                          packets: List[VerificationPacket] = []) -> bytes:
        sketchHashes: List[int] = []
        for packet in packets:
            sketchHashes.append(Sketch.hash(salt, packet))
        sketchHashes.sort()

        #Hash each sketch hash to leaf length.
        leaves: List[bytes] = []
        for sketchHash in sketchHashes:
            leaves.append(
                blake2b(sketchHash.to_bytes(8, byteorder="little"),
                        digest_size=32).digest())

        return merkle(leaves)
コード例 #8
0
ファイル: PinsketchTest.py プロジェクト: frozenghozt/Meros
def PinsketchTest() -> None:
    for _ in range(100):
        capacity: int = getrandbits(7) + 1
        sketches: List[Sketch] = [Sketch(capacity) for _ in range(2)]
        differences: List[int] = []

        for _ in range(capacity + getrandbits(7)):
            sketches[0].hashes.append(getrandbits(64))
            MinisketchLib.minisketch_add_uint64(
                sketches[0].sketch, c_uint64(sketches[0].hashes[-1]))

            if (getrandbits(2) == 0) and (len(differences) < capacity):
                differences.append(sketches[0].hashes[-1])
            else:
                sketches[1].hashes.append(sketches[0].hashes[-1])
                MinisketchLib.minisketch_add_uint64(
                    sketches[1].sketch, c_uint64(sketches[1].hashes[-1]))
        differences = sorted(differences)

        miniSerialized: List[bytes] = [
            sketch.serialize() for sketch in sketches
        ]
        pythonSerialized: List[bytes] = [
            encodeSketch(sketch.hashes, capacity) for sketch in sketches
        ]
        for i in range(len(miniSerialized)):
            if miniSerialized[i] != pythonSerialized[i]:
                raise TestError(
                    "Pure Python Pinsketch encoded the sketch to a different serialization than Minisketch."
                )

        sketches[1].merge(miniSerialized[0])
        mergedArr: bytearray = bytearray()
        for i in range(len(pythonSerialized[0])):
            mergedArr.append(pythonSerialized[0][i] ^ pythonSerialized[1][i])
        merged: bytes = bytes(mergedArr)
        if merged != sketches[1].serialize():
            raise TestError(
                "The merged Python sketch serialization is different than the Minisketch serialization of its merged Sketch."
            )

        if differences != sketches[1].decode():
            raise TestError("Minisketch didn't decode the differences.")
        if differences != decodeSketch(merged):
            raise TestError(
                "Pure Python Pinsketch didn't decode the differences.")
コード例 #9
0
ファイル: UnknownTest.py プロジェクト: vporton/Meros
    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())
コード例 #10
0
def TwoHundredFourTest(
  rpc: RPC
) -> None:
  file: IO[Any] = open("e2e/Vectors/Consensus/TwoHundredFour.json", "r")
  vectors: Dict[str, Any] = json.loads(file.read())
  file.close()

  #Instantiate a Blockchain to set the RandomX key.
  chain: Blockchain = Blockchain()
  blank: Block = Block.fromJSON(vectors["blank"])

  for blockJSON in vectors["blocks"]:
    block: Block = Block.fromJSON(blockJSON)

    rpc.meros.liveConnect(chain.last())
    rpc.meros.syncConnect(chain.last())

    #Send a blank block so Meros acknowledges a holder.
    sentHeader: bytes = rpc.meros.liveBlockHeader(blank.header)
    if rpc.meros.sync.recv() != MessageType.BlockBodyRequest.toByte() + blank.header.hash:
      raise TestError("Meros didn't request the body for a blank Block.")
    rpc.meros.blockBody(blank)
    if rpc.meros.live.recv() != sentHeader:
      raise TestError("Meros didn't rebroadcast the header for a blank Block.")

    with raises(SuccessError):
      rpc.meros.liveBlockHeader(block.header)
      sentProblem: bool = False
      while True:
        if sentProblem:
          #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 node didn't crash.
            sleep(1)
            if rpc.meros.process.poll() is not None:
              raise TestError("Node crashed trying to handle a VerificationPacket with no holders.")
            raise SuccessError("Node disconnected us after we sent a VerificationPacket with no holders.")
          except Exception:
            raise TestError("Meros didn't disconnect us after sending a VerificationPacket with no holders; it also didn't crash.")

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

        if MessageType(msg[0]) == MessageType.BlockBodyRequest:
          if msg[1 : 33] != 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)

          #If this Block has no packets, we've already sent the problem.
          sentProblem = not block.body.packets

        elif MessageType(msg[0]) == MessageType.SketchHashRequests:
          if msg[1 : 33] != block.header.hash:
            raise TestError("Meros asked for Verification Packets that didn't belong to the Block we just sent it.")
          if int.from_bytes(msg[33 : 37], byteorder="little") != 1:
            raise TestError("Meros didn't ask for one VerificationPacket.")
          if int.from_bytes(msg[37 : 45], byteorder="little") != Sketch.hash(block.header.sketchSalt, block.body.packets[0]):
            raise TestError("Meros didn't ask for the VerificationPacket.")

          rpc.meros.packet(block.body.packets[0])
          sentProblem = True

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

    #Reset the node for the next test case.
    rpc.reset()
コード例 #11
0
    def verifyBeaten() -> None:
        #Verify beaten was set. The fourth Transaction is also beaten, yet should be pruned.
        #That's why we don't check its status.
        for send in sends[1:3]:
            if not rpc.call("consensus", "getStatus",
                            {"hash": send.hash.hex()})["beaten"]:
                raise TestError(
                    "Meros didn't mark a child and its descendant as beaten.")

        #Check the pending Verification for the beaten descendant was deleted.
        if ((rpc.call("consensus", "getStatus",
                      {"hash": sends[2].hash.hex()})["verifiers"] != [0])
                or (bytes.fromhex(
                    rpc.call("merit", "getBlockTemplate",
                             {"miner": blsPubKey})["header"])[36:68] !=
                    bytes(32))):
            raise TestError("Block template still has the Verification.")

        #Verify the fourth Transaction was pruned.
        with raises(TestError):
            rpc.call("transactions", "getTransaction",
                     {"hash": sends[3].hash.hex()})

        #Verify neither the second or third Transaction tree can be appended to.
        #Publishes a never seen-before Send for the descendant.
        #Re-broadcasts the pruned Transaction for the parent.
        for send in sends[3:]:
            #Most of these tests use a socket connection for this.
            #This has identical effects, returns an actual error instead of a disconnect,
            #and doesn't force us to wait a minute for our old socket to be cleared.
            with raises(TestError):
                rpc.call("transactions", "publishTransaction", {
                    "type": "Send",
                    "transaction": send.serialize().hex()
                })

        #Not loaded above as it can only be loqaded after the chain starts, which is done by the Liver.
        #RandomX cache keys and all that.
        blockWBeatenVerif: Block = Block.fromJSON(
            vectors["blockWithBeatenVerification"])

        #The following code used to test behavior which was removed, in order to be more forgiving for nodes a tad behind.

        #Verify we can't add that SignedVerification now.
        #rpc.meros.signedElement(verif)
        #try:
        #  rpc.meros.live.recv()
        #  #Hijacks a random Exception type for our purposes.
        #  raise MessageException("Meros didn't disconnect us after we sent a Verification for a beaten Transaction.")
        #except TestError:
        #  pass
        #except MessageException as e:
        #  raise TestError(e.message)
        #sleep(65)
        #rpc.meros.liveConnect(blockWBeatenVerif.header.last)

        #Verify we can't add a Block containing that Verification.
        rpc.meros.liveBlockHeader(blockWBeatenVerif.header)

        #BlockBody sync request.
        rpc.meros.handleBlockBody(blockWBeatenVerif)

        #Sketch hash sync request.
        hashReqs: bytes = rpc.meros.sync.recv()[37:]
        for h in range(0, len(hashReqs), 8):
            for packet in blockWBeatenVerif.body.packets:
                if int.from_bytes(hashReqs[h:h + 8],
                                  byteorder="little") == Sketch.hash(
                                      blockWBeatenVerif.header.sketchSalt,
                                      packet):
                    rpc.meros.packet(packet)
                    break

        try:
            rpc.meros.live.recv()
            raise MessageException(
                "Meros didn't disconnect us after we sent a Block containing a Verification of a beaten Transaction."
            )
        except TestError:
            pass
        except MessageException as e:
            raise TestError(e.message)

        sleep(65)
        rpc.meros.liveConnect(blockWBeatenVerif.header.last)
        rpc.meros.syncConnect(blockWBeatenVerif.header.last)
コード例 #12
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()
コード例 #13
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()
コード例 #14
0
def HundredSixBlockElementsTest(rpc: RPC) -> None:
    vectors: Dict[str, Any]
    with open("e2e/Vectors/Consensus/HundredSix/BlockElements.json",
              "r") as file:
        vectors = json.loads(file.read())

    #Solely used to get the genesis Block hash.
    blockchain: Blockchain = Blockchain()
    transactions: Transactions = Transactions.fromJSON(vectors["transactions"])

    blocks: List[Block] = []
    for block in vectors["blocks"]:
        blocks.append(Block.fromJSON(block))

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

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

        #Flag of if the Block's Body synced.
        doneSyncing: bool = len(block.body.packets) == 0

        #Handle sync requests.
        reqHash: bytes = bytes()
        while True:
            if doneSyncing:
                #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 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
                except Exception:
                    raise TestError("Meros sent a keep-alive.")

            msg: bytes = rpc.meros.sync.recv()
            if 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="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.")
                    rpc.meros.packet(packets[sketchHash])

                doneSyncing = True

            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.syncTransaction(transactions.txs[reqHash])

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

        #Reset the node so we can test the next invalid Block.
        rpc.reset()
コード例 #15
0
ファイル: OOOPackets.py プロジェクト: Vyryn/Meros
from e2e.Classes.Transactions.Data import Data
from e2e.Classes.Transactions.Transactions import Transactions

from e2e.Classes.Consensus.VerificationPacket import VerificationPacket

from e2e.Vectors.Generation.PrototypeChain import PrototypeChain

edPrivKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32)
edPubKey: bytes = edPrivKey.get_verifying_key()

proto: PrototypeChain = PrototypeChain(1, keepUnlocked=False)
datas: List[Data] = [Data(bytes(32), edPubKey)]

counter: int = 0
datas.append(Data(datas[0].hash, counter.to_bytes(4, byteorder="little")))
while (Sketch.hash(bytes(4), VerificationPacket(datas[0].hash, [0])) <=
       Sketch.hash(bytes(4), VerificationPacket(datas[1].hash, [0]))):
    counter += 1
    datas[1] = Data(datas[0].hash, counter.to_bytes(4, byteorder="little"))

proto.add(packets=[
    VerificationPacket(datas[1].hash, [0]),
    VerificationPacket(datas[0].hash, [0])
])

transactions: Transactions = Transactions()
for data in datas:
    data.sign(edPrivKey)
    transactions.add(data)

with open("e2e/Vectors/Merit/OutOfOrder/Packets.json", "w") as vectors:
コード例 #16
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()
コード例 #17
0
def MatchesHeaderQuantityTest(meros: Meros) -> None:
    #Create an instance of Merit to make sure the RandomX VM key was set.
    Merit()

    blocks: List[Block]
    txs: List[Data] = []
    verifs: List[SignedVerification] = []
    with open(
            "e2e/Vectors/Merit/TwoHundredSeventyFour/MatchesHeaderQuantity.json",
            "r") as file:
        vectors: Dict[str, Any] = json.loads(file.read())
        blocks = [Block.fromJSON(block) for block in vectors["blocks"]]
        txs = [Data.fromJSON(tx) for tx in vectors["transactions"]]
        verifs = [
            SignedVerification.fromSignedJSON(verif)
            for verif in vectors["verifications"]
        ]

    #Connect.
    meros.liveConnect(blocks[0].header.last)
    meros.syncConnect(blocks[0].header.last)

    #Send a single Block to earn Merit.
    meros.liveBlockHeader(blocks[0].header)
    meros.handleBlockBody(blocks[0])

    #Send the header.
    meros.liveBlockHeader(blocks[1].header)

    #Fail Sketch Resolution, and send a different amount of sketch hashes.
    meros.handleBlockBody(blocks[1], 0)
    if MessageType(meros.sync.recv()[0]) != MessageType.SketchHashesRequest:
        raise TestError(
            "Meros didn't request the hashes after failing sketch resolution.")

    #Send a quantity of sketch hashes that doesn't match the header.
    meros.sketchHashes([
        Sketch.hash(blocks[1].header.sketchSalt,
                    VerificationPacket(tx.hash, [0])) for tx in txs
    ])
    try:
        if len(meros.sync.recv()) == 0:
            raise TestError()
        raise Exception()
    except TestError:
        pass
    except Exception:
        raise TestError("Meros tried to further sync an invalid Block Body.")

    #Sleep so we can reconnect.
    sleep(65)

    #Repeat setup.
    meros.liveConnect(blocks[0].header.last)
    meros.syncConnect(blocks[0].header.last)

    #Send two Transactions.
    for i in range(2):
        meros.liveTransaction(txs[i])
        meros.signedElement(verifs[i])

    #Send the header and a large enough sketch to cause resolution.
    meros.liveBlockHeader(blocks[1].header)
    meros.handleBlockBody(blocks[1], 3)

    #Should now have been disconnected thanks to having 5 hashes.
    try:
        if len(meros.sync.recv()) == 0:
            raise TestError()
        raise Exception()
    except TestError:
        pass
    except Exception:
        raise TestError("Meros tried to further sync an invalid Block Body.")