Пример #1
0
def HundredEightySevenTest(
  meros: Meros
) -> None:
  file: IO[Any] = open("e2e/Vectors/Merit/HundredEightySeven.json", "r")
  vectors: List[Dict[str, Any]] = json.loads(file.read())
  file.close()

  meros.liveConnect(Blockchain().last())
  meros.syncConnect(Blockchain().last())

  block: Block = Block.fromJSON(vectors[0])
  sent: bytes = meros.liveBlockHeader(block.header)
  if meros.sync.recv() != MessageType.BlockBodyRequest.toByte() + block.header.hash:
    raise TestError("Meros didn't request the matching BlockBody.")
  meros.blockBody(block)
  if meros.live.recv() != sent:
    raise TestError("Meros didn't broadcast a BlockHeader.")

  meros.liveBlockHeader(Block.fromJSON(vectors[1]).header)
  with raises(SuccessError):
    try:
      if len(meros.live.recv()) != 0:
        raise Exception()
    except TestError:
      sleep(1)
      if meros.process.poll() is not None:
        raise TestError("Node crashed trying to handle a BlockHeader which re-registers a key.")
      raise SuccessError("Node disconnected us after we sent a BlockHeader which re-registers a key.")
    except Exception:
      raise TestError("Meros didn't disconnect us after we sent a BlockHeader which re-registers a key; it also didn't crash.")
Пример #2
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."
        )
Пример #3
0
  def test() -> None:
    #Data.
    dataHash: str = rpc.call("personal", "data", {"data": "abc"})
    #Read the initial Data.
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.Data:
      raise TestError("Meros didn't broadcast the initial Data.")
    #Read the actual Data.
    serializedData: bytes = rpc.meros.live.recv()
    if serializedData[1:] != Data.fromJSON(rpc.call("transactions", "getTransaction", {"hash": dataHash})).serialize():
      raise TestError("Meros didn't broadcast the created Data.")
    res: Any = rpc.call("network", "broadcast", {"transaction": dataHash})
    if not (isinstance(res, bool) and res):
      raise TestError("Broadcast didn't return true.")
    if rpc.meros.live.recv() != serializedData:
      raise TestError("Meros didn't broadcast a Transaction when told to.")

    #Block.
    header: BlockHeader = Block.fromJSON(vectors["blockchain"][0]).header
    rpc.call("network", "broadcast", {"block": header.hash.hex()})
    if rpc.meros.live.recv() != (MessageType.BlockHeader.toByte() + header.serialize()):
      raise TestError("Meros didn't broadcast the Blockheader.")

    #Data and Block.
    rpc.call("network", "broadcast", {"block": header.hash.hex(), "transaction": dataHash})
    if rpc.meros.live.recv() != serializedData:
      raise TestError("Meros didn't broadcast a Transaction when told to.")
    if rpc.meros.live.recv() != (MessageType.BlockHeader.toByte() + header.serialize()):
      raise TestError("Meros didn't broadcast the Blockheader.")

    #Non-existent Transaction.
    try:
      rpc.call("network", "broadcast", {"transaction": bytes(32).hex()})
      raise TestError()
    except TestError as e:
      if str(e) != "-2 Transaction not found.":
        raise TestError("Meros didn't error when told to broadcast a non-existent Transaction.")

    #Non-existent Block.
    try:
      rpc.call("network", "broadcast", {"block": bytes(32).hex()})
      raise TestError()
    except TestError as e:
      if str(e) != "-2 Block not found.":
        raise TestError("Meros didn't error when told to broadcast a non-existent Block.")

    #Mint.
    try:
      rpc.call("network", "broadcast", {"transaction": mint.hex()})
      raise TestError()
    except TestError as e:
      if str(e) != "-3 Transaction is a Mint.":
        raise TestError("Meros didn't error when told to broadcast a Mint.")

    #Genesis Block.
    try:
      rpc.call("network", "broadcast", {"block": Blockchain().blocks[0].header.hash.hex()})
      raise TestError()
    except TestError as e:
      if str(e) != "-3 Block is the genesis Block.":
        raise TestError("Meros didn't error when told to broadcast the genesis Block.")
Пример #4
0
def MultiplePacketsTest(rpc: RPC) -> None:
    #Spawn a Blockchain just to set the RandomX key.
    _: Blockchain = Blockchain()

    vectors: Dict[str, Any]
    with open("e2e/Vectors/Merit/MultiplePackets.json", "r") as file:
        vectors = json.loads(file.read())

    data: Data = Data.fromJSON(vectors["data"])
    block: Block = Block.fromJSON(vectors["blockchain"][-1])

    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()

    with raises(SuccessError):
        Liver(rpc, vectors["blockchain"], callbacks={
            2: sendDataAndBlock
        }).live()
Пример #5
0
def TwoHundredThirtyFiveTest(rpc: RPC) -> None:
    blockchain: Blockchain = Blockchain()
    dataFilter: SpamFilter = SpamFilter(5)

    edPrivKey: ed25519.SigningKey = ed25519.SigningKey(b'\0' * 32)
    edPubKey: ed25519.VerifyingKey = edPrivKey.get_verifying_key()

    #Mine one Block to the node.
    blsPrivKey: PrivateKey = PrivateKey(
        bytes.fromhex(rpc.call("personal", "getMiner")))
    blsPubKey: bytes = blsPrivKey.toPublicKey().serialize()

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

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

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

    #Send Meros a Data and receive its Verification to make sure it's verifying Transactions in the first place.
    data: Data = Data(bytes(32), edPubKey.to_bytes())
    data.sign(edPrivKey)
    data.beat(dataFilter)

    rpc.meros.liveConnect(blockchain.blocks[0].header.hash)
    if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
        raise TestError("Meros didn't send back the Data.")
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification:
        raise TestError("Meros didn't send us its SignedVerification.")

    #Close our connection and mine 8 Blocks so its Merit is locked.
    rpc.meros.live.connection.close()
    for _ in range(8):
        block = Block(
            BlockHeader(0, blockchain.blocks[-1].header.hash, bytes(32), 1,
                        bytes(4), bytes(32), 0,
                        blockchain.blocks[-1].header.time + 1200, 0),
            BlockBody())
        #Reusing its key is fine as mining doesn't count as participation.
        block.mine(blsPrivKey, blockchain.difficulty())
        blockchain.add(block)

    #Sleep 30 seconds to make sure Meros noted we disconnected, and then reconnect.
    sleep(30)
    rpc.meros.liveConnect(blockchain.blocks[0].header.hash)
    rpc.meros.syncConnect(blockchain.blocks[0].header.hash)

    #Sync the Blocks.
    for b in range(8):
        header: bytes = rpc.meros.liveBlockHeader(blockchain.blocks[b +
                                                                    2].header)
        if rpc.meros.sync.recv() != (MessageType.BlockBodyRequest.toByte() +
                                     blockchain.blocks[b + 2].header.hash):
            raise TestError("Meros didn't request the BlockBody.")
        rpc.meros.blockBody(blockchain.blocks[b + 2])
        if rpc.meros.live.recv() != header:
            raise TestError("Meros didn't send back the header.")
        if MessageType(
                rpc.meros.live.recv()[0]) != MessageType.SignedVerification:
            raise TestError("Meros didn't verify this Block's data.")

    #Verify its Merit is locked.
    #Theoretically, all code after this check is unecessary.
    #Meros verifies a Block's Data after updating its State.
    #Therefore, if the above last Block had its Data verified, this issue should be closed.
    #That said, the timing is a bit too tight for comfort.
    #Better safe than sorry. Hence why the code after this check exists.
    if rpc.call("merit", "getMerit", [0])["status"] != "Locked":
        raise TestError("Merit wasn't locked when it was supposed to be.")

    #Send it a Transaction and make sure Meros verifies it, despite having its Merit locked.
    data = Data(data.hash, edPubKey.to_bytes())
    data.sign(edPrivKey)
    data.beat(dataFilter)

    if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
        raise TestError("Meros didn't send back the Data.")
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification:
        raise TestError("Meros didn't send us its SignedVerification.")
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()
Пример #7
0
    def finish(self, keepUnlocked: int, existing: Merit) -> Block:
        genesis: bytes = existing.blockchain.genesis
        prev: BlockHeader = existing.blockchain.blocks[-1].header
        diff: int = existing.blockchain.difficulty()

        #Create the signatures for every packet/element.
        signatures: List[Signature] = []
        for packet in self.packets:
            for holder in packet.holders:
                verif: SignedVerification = SignedVerification(
                    packet.hash, holder)
                verif.sign(holder, PrivateKey(holder))
                signatures.append(verif.signature)
        for element in self.elements:
            signatures.append(signElement(element))

        #Only add the Data Verification if:
        #1) We're supposed to make sure Merit Holders are always Unlocked
        #2) The last Block created a Data
        #3) The Merit Holder has Merit.
        if (keepUnlocked != 0) and (prev.last != genesis):
            #Create the Data from the last Block.
            blockData: Data = Data(genesis, prev.hash)

            #Create Verifications for said Data with every Private Key.
            #Ensures no one has their Merit locked.
            #pylint: disable=unnecessary-comprehension
            self.packets.append(VerificationPacket(blockData.hash, []))
            for i in range(keepUnlocked):
                if (
                        #Miners who are just being created don't have Merit.
                    ((i == (keepUnlocked - 1)) and
                     (isinstance(self.minerID, PrivateKey)))
                        or (existing.state.balances[i] == 0)):
                    continue

                self.packets[-1].holders.append(i)
                verif: SignedVerification = SignedVerification(
                    blockData.hash, i)
                verif.sign(i, PrivateKey(i))
                signatures.append(verif.signature)

            #Remove this packet if there's no holders.
            if not self.packets[-1].holders:
                del self.packets[-1]

        #Set the aggregate.
        aggregate = Signature.aggregate(signatures)

        #Create the actual Block.
        minerID: Union[bytes, int] = 0
        if isinstance(self.minerID, int):
            minerID = self.minerID
        else:
            minerID = self.minerID.toPublicKey().serialize()

        result: Block = Block(
            BlockHeader(
                0, prev.hash,
                BlockHeader.createContents(self.packets, self.elements),
                len(self.packets), bytes(4),
                BlockHeader.createSketchCheck(bytes(4), self.packets), minerID,
                self.time), BlockBody(self.packets, self.elements, aggregate))
        if isinstance(self.minerID, int):
            result.mine(PrivateKey(self.minerID), diff)
        else:
            result.mine(self.minerID, diff)
        return result
Пример #8
0
def HundredTwentyFourTest(
  rpc: RPC
) -> None:
  #Load the vectors.
  file: IO[Any] = open("e2e/Vectors/Merit/BlankBlocks.json", "r")
  vectors: List[Dict[str, Any]] = json.loads(file.read())
  file.close()

  #Blockchain. Solely used to get the genesis Block hash.
  blockchain: Blockchain = Blockchain()

  #Parse the Blocks from the vectors.
  for i in range(2):
    blockchain.add(Block.fromJSON(vectors[i]))

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

  def handleSync() -> None:
    #Handle sync requests.
    reqHash: bytes = bytes()
    bH: int = 0
    bB: int = 1
    while True:
      if bB == 3:
        break

      msg: bytes = rpc.meros.sync.recv()
      if MessageType(msg[0]) == MessageType.BlockListRequest:
        reqHash = msg[3 : 35]
        for b in range(len(blockchain.blocks)):
          if blockchain.blocks[b].header.hash == reqHash:
            blockList: List[bytes] = []
            for bl in range(1, msg[2] + 2):
              if msg[1] == 0:
                if b - bl < 0:
                  break
                blockList.append(blockchain.blocks[b - bl].header.hash)

              elif msg[1] == 1:
                blockList.append(blockchain.blocks[b + bl].header.hash)

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

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

            rpc.meros.blockList(blockList)
            break

          if b == len(blockchain.blocks):
            rpc.meros.dataMissing()

      elif MessageType(msg[0]) == MessageType.BlockHeaderRequest:
        reqHash = msg[1 : 33]
        if reqHash != blockchain.blocks[2 - bH].header.hash:
          raise TestError("Meros asked for a Block Header that didn't belong to the next Block.")

        #Send the BlockHeader.
        rpc.meros.syncBlockHeader(blockchain.blocks[2 - bH].header)
        bH += 1

      elif MessageType(msg[0]) == MessageType.BlockBodyRequest:
        reqHash = msg[1 : 33]
        if reqHash != blockchain.blocks[bB].header.hash:
          raise TestError("Meros asked for a Block Body that didn't belong to the next Block.")

        #Send the Block.
        rpc.meros.blockBody(blockchain.blocks[bB])
        bB += 1

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

    #Verify the Blockchain.
    verifyBlockchain(rpc, blockchain)

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

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

  #Handle the sync.
  handleSync()

  #Reset Meros and do the same with Syncing.
  rpc.reset()

  rpc.meros.syncConnect(blockchain.blocks[0].header.hash)
  rpc.meros.sync.send(
    MessageType.Syncing.toByte() +
    (254).to_bytes(1, "big") +
    (254).to_bytes(1, "big") +
    b'\0\0\0' +
    blockchain.last(),
    False
  )
  if rpc.meros.sync.recv() != MessageType.BlockchainTail.toByte() + blockchain.blocks[0].header.hash:
    raise TestError("Meros didn't respond with its Blockchain's Tail.")
  handleSync()
Пример #9
0
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)
Пример #10
0
def HundredFiftyFiveTest(rpc: RPC) -> None:
    edPrivKeys: List[ed25519.SigningKey] = [
        ed25519.SigningKey(b'\0' * 32),
        ed25519.SigningKey(b'\1' * 32)
    ]
    edPubKeys: List[ed25519.VerifyingKey] = [
        edPrivKeys[0].get_verifying_key(), edPrivKeys[1].get_verifying_key()
    ]

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

    blockchain: Blockchain = Blockchain()
    dataFilter: SpamFilter = SpamFilter(5)

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

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

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

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

    if MessageType(rpc.meros.live.recv()[0]) != MessageType.BlockHeader:
        raise TestError("Meros didn't broadcast the Block we just published.")
    #Ignore the Verification for the Block's Data.
    if MessageType(rpc.meros.live.recv()[0]) != MessageType.SignedVerification:
        raise TestError(
            "Meros didn't send the SignedVerification for the Block's Data.")

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

    for d in range(len(datas)):
        datas[d].sign(edPrivKeys[d])
        datas[d].beat(dataFilter)

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

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

        verif: SignedVerification = SignedVerification(datas[d].hash)
        verif.sign(0, blsPrivKey)
        if res[1:] != verif.signedSerialize():
            raise TestError(
                "Meros didn't send the correct SignedVerification.")
Пример #11
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)
Пример #12
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)
Пример #13
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()
Пример #14
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)
Пример #15
0
    def restOfTest() -> None:
        #Move expected into scope.
        expected: str = getAddress(mnemonic, password, 0)

        #Send to the new address, then call getAddress again. Verify a new address appears.
        last: Send = createSend(
            rpc,
            Claim.fromTransaction(iter(transactions.txs.values()).__next__()),
            expected)
        hashes: List[bytes] = [last.hash]

        expected = getAddress(mnemonic, password, 1)
        if rpc.call("personal", "getAddress") != expected:
            raise TestError(
                "Meros didn't move to the next address once the existing one was used."
            )

        #Send to the new unused address, spending the funds before calling getAddress again.
        #Checks address usage isn't defined as having an UTXO, yet rather any TXO.
        #Also confirm the spending TX with full finalization before checking.
        #Ensures the TXO isn't unspent by any definition.
        last = createSend(rpc, last, expected)
        hashes.append(last.hash)

        #Spending TX.
        send: Send = Send([(hashes[-1], 0)], [(bytes(32), 1)])
        send.signature = ed.sign(b"MEROS" + send.hash,
                                 getPrivateKey(mnemonic, password, 1))
        send.beat(SpamFilter(3))
        if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
            raise TestError("Meros didn't broadcast back the spending Send.")
        hashes.append(send.hash)

        #In order to finalize, we need to mine 6 Blocks once this Transaction and its parent have Verifications.
        for txHash in hashes:
            sv: SignedVerification = SignedVerification(txHash)
            sv.sign(0, PrivateKey(0))
            if rpc.meros.signedElement(sv) != rpc.meros.live.recv():
                raise TestError("Meros didn't broadcast back a Verification.")

        #Close the sockets while we mine.
        rpc.meros.live.connection.close()
        rpc.meros.sync.connection.close()

        #Mine these to the Wallet on the node so we can test getMeritHolderNick.
        privKey: PrivateKey = PrivateKey(
            bytes.fromhex(rpc.call("personal", "getMeritHolderKey")))
        blockchain: Blockchain = Blockchain.fromJSON(vectors["blockchain"])
        for _ in range(6):
            template: Dict[str, Any] = rpc.call(
                "merit", "getBlockTemplate",
                {"miner": privKey.toPublicKey().serialize().hex()})
            proof: int = -1
            tempHash: bytes = bytes()
            tempSignature: bytes = bytes()
            while ((proof == -1)
                   or ((int.from_bytes(tempHash, "little") *
                        (blockchain.difficulty() * 11 // 10)) > int.from_bytes(
                            bytes.fromhex("FF" * 32), "little"))):
                proof += 1
                tempHash = RandomX(
                    bytes.fromhex(template["header"]) +
                    proof.to_bytes(4, "little"))
                tempSignature = privKey.sign(tempHash).serialize()
                tempHash = RandomX(tempHash + tempSignature)

            rpc.call(
                "merit", "publishBlock", {
                    "id":
                    template["id"],
                    "header":
                    template["header"] + proof.to_bytes(4, "little").hex() +
                    tempSignature.hex()
                })
            blockchain.add(
                Block.fromJSON(
                    rpc.call("merit", "getBlock",
                             {"block": len(blockchain.blocks)})))

        #Verify a new address is returned.
        expected = getAddress(mnemonic, password, 2)
        if rpc.call("personal", "getAddress") != expected:
            raise TestError(
                "Meros didn't move to the next address once the existing one was used."
            )

        #Get a new address after sending to the address after it.
        #Use both, and then call getAddress.
        #getAddress should detect X is used, move to Y, detect Y is used, and move to Z.
        #It shouldn't assume the next address after an used address is unused.
        #Actually has two Ys as one iteration of the code only ran for the next address; not all future addresses.

        #Send to the next next addresses.
        for i in range(2):
            addy: str = getAddress(mnemonic, password, 3 + i)

            #Reopen the sockets. This isn't done outside of the loop due to the time deriving the final address can take.
            #Due to how slow the reference Python code is, it is necessary to redo the socket connections.
            sleep(65)
            rpc.meros.liveConnect(Blockchain().blocks[0].header.hash)
            rpc.meros.syncConnect(Blockchain().blocks[0].header.hash)

            last = createSend(rpc, last, addy)
            if MessageType(rpc.meros.live.recv()
                           [0]) != MessageType.SignedVerification:
                raise TestError(
                    "Meros didn't create and broadcast a SignedVerification for this Send."
                )

            if i == 0:
                #Close them again.
                rpc.meros.live.connection.close()
                rpc.meros.sync.connection.close()

        #Verify getAddress returns the existing next address.
        if rpc.call("personal", "getAddress") != expected:
            raise TestError(
                "Sending to the address after this address caused Meros to consider this address used."
            )

        #Send to the next address.
        last = createSend(rpc, last, expected)
        if MessageType(
                rpc.meros.live.recv()[0]) != MessageType.SignedVerification:
            raise TestError(
                "Meros didn't create and broadcast a SignedVerification for this Send."
            )

        #Verify getAddress returns the address after the next next addresses.
        expected = getAddress(mnemonic, password, 5)
        if rpc.call("personal", "getAddress") != expected:
            raise TestError(
                "Meros didn't return the correct next address after using multiple addresses in a row."
            )

        #Now that we have mined a Block as part of this test, ensure the Merit Holder nick is set.
        if rpc.call("personal", "getMeritHolderNick") != 1:
            raise TestError(
                "Merit Holder nick wasn't made available despite having one.")

        #Sanity check off Mnemonic.
        if rpc.call("personal", "getMnemonic") != mnemonic:
            raise TestError("getMnemonic didn't return the correct Mnemonic.")

        #Existing values used to test getMnemonic/getMeritHolderKey/getMeritHolderNick/getAccount/getAddress consistency.
        existing: Dict[str, Any] = {
            #Should be equal to the mnemonic variable, which is verified in a check above.
            "getMnemonic": rpc.call("personal", "getMnemonic"),
            "getMeritHolderKey": rpc.call("personal", "getMeritHolderKey"),
            "getMeritHolderNick": rpc.call("personal", "getMeritHolderNick"),
            "getAccount": rpc.call("personal", "getAccount"),
            #Should be equal to expected, which is also verified in a check above.
            "getAddress": rpc.call("personal", "getAddress")
        }

        #Set a new seed and verify the Merit Holder nick is cleared.
        rpc.call("personal", "setWallet")
        try:
            rpc.call("personal", "getMeritHolderNick")
            raise TestError("")
        except TestError as e:
            if str(
                    e
            ) != "-2 Wallet doesn't have a Merit Holder nickname assigned.":
                raise TestError(
                    "getMeritHolderNick returned something or an unexpected error when a new Mnemonic was set."
                )

        #Set back the old seed and verify consistency.
        rpc.call("personal", "setWallet", {
            "mnemonic": mnemonic,
            "password": password
        })
        for method in existing:
            if rpc.call("personal", method) != existing[method]:
                raise TestError(
                    "Setting an old seed caused the WalletDB to improperly reload."
                )

        #Verify calling getAddress returns the expected address.
        if rpc.call("personal", "getAddress") != expected:
            raise TestError(
                "Meros returned an address that wasn't next after reloading the seed."
            )

        #Reboot the node and verify consistency.
        rpc.quit()
        sleep(3)
        rpc.meros = Meros(rpc.meros.db, rpc.meros.tcp, rpc.meros.rpc)
        for method in existing:
            if rpc.call("personal", method) != existing[method]:
                raise TestError(
                    "Rebooting the node caused the WalletDB to improperly reload."
                )

        #Used so Liver doesn't run its own post-test checks.
        #Since we added our own Blocks, those will fail.
        raise SuccessError()
Пример #16
0
def HundredTwentyFourTest(rpc: RPC) -> None:
    vectors: List[Dict[str, Any]]
    with open("e2e/Vectors/Merit/BlankBlocks.json", "r") as file:
        vectors = json.loads(file.read())

    blockchain: Blockchain = Blockchain()
    for i in range(2):
        blockchain.add(Block.fromJSON(vectors[i]))

    rpc.meros.liveConnect(blockchain.blocks[0].header.hash)
    rpc.meros.syncConnect(blockchain.blocks[0].header.hash)

    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)

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

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

    #Handle the sync.
    handleSync()

    #Reset Meros and do the same with Syncing.
    rpc.reset()

    rpc.meros.syncConnect(blockchain.blocks[0].header.hash)
    rpc.meros.sync.send(MessageType.Syncing.toByte() +
                        (0).to_bytes(1, "little") +
                        (127).to_bytes(1, "little") + b'\0\0\0' +
                        blockchain.last())
    if rpc.meros.sync.recv() != MessageType.BlockchainTail.toByte(
    ) + blockchain.blocks[0].header.hash:
        raise TestError("Meros didn't respond with the genesis.")
    handleSync()