Esempio n. 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.")
Esempio n. 2
0
  def test() -> None:
    recipient: Ristretto.SigningKey = Ristretto.SigningKey(b'\1' * 32)
    recipientPub: bytes = recipient.get_verifying_key()
    address: str = bech32_encode("mr", convertbits(bytes([0]) + recipientPub, 8, 5))

    #Create a Send.
    send: Send = Send.fromJSON(vectors["send"])
    if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
      raise TestError("Meros didn't broadcast back a Send.")
    verify(rpc, send.hash)
    if rpc.call("transactions", "getUTXOs", {"address": address}) != [{"hash": send.hash.hex().upper(), "nonce": 0}]:
      raise TestError("Meros didn't consider a confirmed Transaction's outputs as UTXOs.")
    #Spend it, with a newer Mint as an input as well so we can prune it without pruning the original.
    newerSend: Send = createSend(rpc, [Claim.fromJSON(vectors["newerMintClaim"])], recipientPub)
    _: Send = createSend(rpc, [send, newerSend], bytes(32), recipient)
    if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
      raise TestError("Meros thinks the recipient has UTXOs.")

    #Remove the spending Send by pruning its ancestor (a Mint).
    reorg(rpc, Blockchain.fromJSON(vectors["blocksWithoutNewerMint"]))
    #Meros should add back its parent as an UTXO.
    if rpc.call("transactions", "getUTXOs", {"address": address}) != [{"hash": send.hash.hex().upper(), "nonce": 0}]:
      raise TestError("Meros didn't consider a Transaction without spenders as an UTXO.")
    #Remove the original Send and verify its outputs are no longer considered UTXOs.
    reorg(rpc, Blockchain.fromJSON(vectors["blocksWithoutOlderMint"]))
    if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
      raise TestError("Meros didn't remove the outputs of a pruned Transaction as UTXOs.")

    raise SuccessError()
Esempio n. 3
0
    def verifyRecreation() -> None:
        template: Dict[str,
                       Any] = rpc.call("merit", "getBlockTemplate",
                                       [key.toPublicKey().serialize().hex()])
        if bytes.fromhex(
                template["header"])[36:68] != BlockHeader.createContents(
                    [VerificationPacket(data.hash, [1])]):
            raise TestError(
                "New Block template doesn't have a properly recreated packet.")

        #Mining it further verifies the internal state.
        header: bytes = bytes.fromhex(template["header"])
        proof: int = 0
        sig: bytes
        while True:
            initial: bytes = RandomX(header +
                                     proof.to_bytes(4, byteorder="little"))
            sig = key.sign(initial).serialize()
            final: bytes = RandomX(initial + sig)
            if (int.from_bytes(final, "little") *
                    template["difficulty"]) < int.from_bytes(
                        bytes.fromhex("FF" * 32), "little"):
                break
            proof += 1

        rpc.call("merit", "publishBlock", [
            template["id"],
            (header + proof.to_bytes(4, byteorder="little") + sig).hex()
        ])

        raise SuccessError(
            "Stop Liver from trying to verify the vector chain which doesn't have this Block."
        )
Esempio n. 4
0
def HundredTwentyFiveTest(rpc: RPC) -> None:
    #Meros allows connections from its own IP if they identify as 127.0.0.1.
    #We need to connect either through the LAN or through the public IP for this test to be valid.
    #The following code grabs the computer's 192 IP.
    lanIPFinder = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    lanIPFinder.connect(("meroscrypto.io", 443))
    lanIP = lanIPFinder.getsockname()[0]
    lanIPFinder.close()

    if not (lanIP.split(".")[0] in {"10", "172", "192"}):
        raise Exception("Failed to get the LAN IP.")

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

    #Connect to Meros.
    connection: socket.socket = socket.socket(socket.AF_INET,
                                              socket.SOCK_STREAM)
    connection.connect((lanIP, rpc.meros.tcp))
    try:
        connection.send(
            MessageType.Syncing.toByte() + (254).to_bytes(1, "big") +
            (254).to_bytes(1, "big") + (128).to_bytes(1, "big") +
            (6000).to_bytes(2, "big") + blockchain.blocks[0].header.hash,
            False)
        if len(connection.recv(38)) == 0:
            raise Exception("")
    except Exception:
        raise SuccessError(
            "Meros closed a connection from the same IP as itself which wasn't 127.0.0.1."
        )
    raise TestError(
        "Meros allowed a connection from the same IP as itself which wasn't 127.0.0.1."
    )
Esempio n. 5
0
  def sendBlock() -> None:
    #Send the Block with the MeritRemoval archived again.
    block: Block = Block.fromJSON(vectors[-1])
    rpc.meros.liveBlockHeader(block.header)

    #Flag of if the Block's Body synced.
    blockBodySynced: bool = False

    #Handle sync requests.
    reqHash: bytes = bytes()
    while True:
      if blockBodySynced:
        #Try receiving from the Live socket, where Meros sends keep-alives.
        try:
          if len(rpc.meros.live.recv()) != 0:
            raise Exception()
        except TestError:
          raise SuccessError("Meros didn't add the same MeritRemoval twice.")
        except Exception:
          raise TestError("Meros sent a keep-alive.")

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

        #Send the BlockBody.
        blockBodySynced = True
        rpc.meros.blockBody(block)

      else:
        raise TestError("Unexpected message sent: " + msg.hex().upper())
Esempio n. 6
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()
        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())
Esempio n. 8
0
        def sendMeritRemoval() -> None:
            #Send the Datas.
            for data in datas:
                if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
                    raise TestError("Meros didn't send us the Data.")

            #Send the Block containing the modified Merit Removal.
            block: Block = Block.fromJSON(vectors["blockchains"][i][-1])
            rpc.meros.liveBlockHeader(block.header)

            #Flag of if the Block's Body synced.
            blockBodySynced: bool = False

            #Handle sync requests.
            reqHash: bytes = bytes()
            while True:
                if blockBodySynced:
                    #Sleep for a second so Meros handles the Block.
                    sleep(1)

                    #Try receiving from the Live socket, where Meros sends keep-alives.
                    try:
                        if len(rpc.meros.live.recv()) != 0:
                            raise Exception()
                    except TestError:
                        #Verify the height is 2.
                        #The genesis Block and the Block granting Merit.
                        try:
                            if rpc.call("merit", "getHeight") != 2:
                                raise Exception()
                        except Exception:
                            raise TestError(
                                "Node added a Block containg a repeat MeritRemoval."
                            )

                        #Since the node didn't add the Block, raise SuccessError.
                        raise SuccessError(
                            "Node didn't add a Block containing a repeat MeritRemoval."
                        )
                    except Exception:
                        raise TestError("Meros sent a keep-alive.")

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

                    #Send the BlockBody.
                    blockBodySynced = True
                    rpc.meros.blockBody(block)

                else:
                    raise TestError("Unexpected message sent: " +
                                    msg.hex().upper())
Esempio n. 9
0
    def sendAlternateTip() -> None:
        rpc.meros.liveBlockHeader(alt.blocks[-1].header)

        req: bytes = rpc.meros.sync.recv()
        if MessageType(req[0]) != MessageType.BlockListRequest:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders.")
        if req[-32:] != alt.blocks[-2].header.hash:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders for THIS header."
            )

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

        diff = -14
        while diff != -1:
            if rpc.meros.sync.recv() != (
                    MessageType.BlockHeaderRequest.toByte() +
                    alt.blocks[diff].header.hash):
                raise TestError("Meros didn't request a previous BlockHeader.")
            rpc.meros.syncBlockHeader(alt.blocks[diff].header)
            diff += 1

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

        #Verify Meros at least went back to the fork point.
        #Ideally, it'd go back to the original chain.
        #Or if we synced enough blocks where we still have a chain with more work, we should remain on it.
        verifyBlockchain(rpc, forkPoint)
        raise SuccessError("Meros reverted back to the fork point.")
Esempio n. 10
0
    def test() -> None:
        recipient: ed25519.SigningKey = ed25519.SigningKey(b'\1' * 32)
        recipientPub: bytes = recipient.get_verifying_key().to_bytes()
        address: str = bech32_encode(
            "mr", convertbits(bytes([0]) + recipientPub, 8, 5))

        otherRecipient: bytes = ed25519.SigningKey(
            b'\2' * 32).get_verifying_key().to_bytes()
        otherAddress: str = bech32_encode(
            "mr", convertbits(bytes([0]) + otherRecipient, 8, 5))

        #Create a Send.
        send: Send = Send.fromJSON(vectors["send"])
        if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
            raise TestError("Meros didn't broadcast back a Send.")
        if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
            raise TestError(
                "Meros considered an unconfirmed Transaction's outputs as UTXOs."
            )
        verify(rpc, send.hash)

        #Spend it.
        spendingSend: Send = Send.fromJSON(vectors["spendingSend"])
        if rpc.meros.liveTransaction(spendingSend) != rpc.meros.live.recv():
            raise TestError("Meros didn't broadcast back a Send.")
        if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
            raise TestError(
                "Meros didn't consider a Transaction's inputs as spent.")

        #Verify with another party, so it won't be majority verified, yet will still have a Verification.
        mineBlock(rpc, 1)
        verify(rpc, spendingSend.hash, 1)
        #Verify it didn't create a UTXO.
        if rpc.call("transactions", "getUTXOs",
                    {"address": otherAddress}) != []:
            raise TestError("Unverified Transaction created a UTXO.")

        #Finalize.
        for _ in range(6):
            mineBlock(rpc)

        #Check the UTXOs were created.
        if rpc.call("transactions", "getUTXOs", {"address": otherAddress}) != [
            {
                "hash": spendingSend.hash.hex().upper(),
                "nonce": 0
            }
        ]:
            raise TestError(
                "Meros didn't consider a finalized Transaction's outputs as UTXOs."
            )

        raise SuccessError()
Esempio n. 11
0
  def sendAlternateTip() -> None:
    header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)
    rpc.meros.handleBlockBody(alt.blocks[-1])

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

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

    #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
    raise SuccessError("Meros re-organized to the alternate chain.")
Esempio n. 12
0
    def sendMeritRemoval() -> None:
      #Send the Data.
      if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
        raise TestError("Meros didn't send back the Data.")

      rpc.meros.signedElement(removal)
      try:
        if len(rpc.meros.live.recv()) != 0:
          raise Exception()
      except TestError:
        raise SuccessError("Meros rejected our MeritRemoval created from the same Element.")
      except Exception:
        raise TestError("Meros accepted our MeritRemoval created from the same Element.")
Esempio n. 13
0
  def checkFail() -> None:
    #Send the Send.
    rpc.meros.liveTransaction(send)

    #Handle sync requests.
    while True:
      #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.")
Esempio n. 14
0
    def sendAlternateTip() -> None:
        header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)
        req: bytes = rpc.meros.sync.recv()
        if req != (MessageType.BlockBodyRequest.toByte() +
                   alt.blocks[-1].header.hash):
            raise TestError("Meros didn't request the BlockBody.")
        rpc.meros.blockBody(alt.blocks[-1])

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

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

        #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
        raise SuccessError("Meros re-organized to the alternate chain.")
Esempio n. 15
0
    def sendAlternateTip() -> None:
        header: bytes = rpc.meros.liveBlockHeader(alt.blocks[-1].header)

        req: bytes = rpc.meros.sync.recv()
        if MessageType(req[0]) != MessageType.BlockListRequest:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders.")
        if req[3:35] != alt.blocks[-1].header.hash:
            raise TestError(
                "Meros didn't request the list of previous BlockHeaders for THIS header."
            )

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

        diff = -2
        while diff != -1:
            req = rpc.meros.sync.recv()
            if req != (MessageType.BlockHeaderRequest.toByte() +
                       alt.blocks[diff].header.hash):
                raise TestError("Meros didn't request a previous BlockHeader.")
            rpc.meros.syncBlockHeader(alt.blocks[diff].header)
            diff += 1

        diff = -2
        while diff != 0:
            req = rpc.meros.sync.recv()
            if req != (MessageType.BlockBodyRequest.toByte() +
                       alt.blocks[diff].header.hash):
                raise TestError("Meros didn't request a previous BlockBody.")
            rpc.meros.blockBody(alt.blocks[diff])
            diff += 1

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

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

        #Raise SuccessError so the Liver doesn't fail when verifying the original chain.
        raise SuccessError("Meros re-organized to the alternate chain.")
Esempio n. 16
0
    def test() -> None:
        #Send to the first address from outside the Wallet. First address is now funded.
        sendHash: bytes = createSend(
            rpc, claims[0], decodeAddress(rpc.call("personal", "getAddress")))

        #Send to the second address with all of the funds. Second address is now funded.
        #Tests send's minimal case (single input, no change).
        nextAddr: str = rpc.call("personal", "getAddress")
        sends: List[str] = [
            rpc.call(
                "personal", "send", {
                    "outputs": [{
                        "address": nextAddr,
                        "amount": str(claims[0].amount)
                    }]
                })
        ]
        checkSend(
            rpc, sends[-1], {
                "inputs": [{
                    "hash": sendHash.hex().upper(),
                    "nonce": 0
                }],
                "outputs": [{
                    "key": decodeAddress(nextAddr).hex().upper(),
                    "amount": str(claims[0].amount)
                }]
            })
        verify(rpc, bytes.fromhex(sends[-1]))

        #Send to the third address with some of the funds. Third and change addresses are now funded.
        #Tests send's capability to create a change output.
        mnemonic: str = rpc.call("personal", "getMnemonic")
        nextAddr = rpc.call("personal", "getAddress")
        sends.append(
            rpc.call(
                "personal", "send", {
                    "outputs": [{
                        "address": nextAddr,
                        "amount": str(claims[0].amount - 1)
                    }]
                }))
        checkSend(
            rpc, sends[-1], {
                "inputs": [{
                    "hash": sends[-2],
                    "nonce": 0
                }],
                "outputs":
                [{
                    "key": decodeAddress(nextAddr).hex().upper(),
                    "amount": str(claims[0].amount - 1)
                }, {
                    "key": getChangePublicKey(mnemonic, "", 0).hex().upper(),
                    "amount": "1"
                }]
            })
        verify(rpc, bytes.fromhex(sends[-1]))

        #Send all funds out of Wallet.
        #Tests MuSig signing and change UTXO detection.
        privKey: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32)
        pubKey: bytes = privKey.get_verifying_key()
        sends.append(
            rpc.call(
                "personal", "send", {
                    "outputs": [{
                        "address":
                        bech32_encode("mr",
                                      convertbits(bytes([0]) + pubKey, 8, 5)),
                        "amount":
                        str(claims[0].amount)
                    }]
                }))
        checkSend(
            rpc, sends[-1], {
                "inputs": [{
                    "hash": sends[-2],
                    "nonce": 0
                }, {
                    "hash": sends[-2],
                    "nonce": 1
                }],
                "outputs": [{
                    "key": pubKey.hex().upper(),
                    "amount": str(claims[0].amount)
                }]
            })
        verify(rpc, bytes.fromhex(sends[-1]))

        #Clear Wallet. Set a password this time around to make sure the password is properly carried.
        #Send two instances of funds to the first address.
        rpc.call("personal", "setWallet", {"password": "******"})
        mnemonic = rpc.call("personal", "getMnemonic")
        nodeKey: bytes = decodeAddress(rpc.call("personal", "getAddress"))
        send: Send = Send([(bytes.fromhex(sends[-1]), 0)],
                          [(nodeKey, claims[0].amount // 2),
                           (nodeKey, claims[0].amount // 2)])
        send.sign(Ristretto.SigningKey(b'\0' * 32))
        send.beat(SpamFilter(3))
        if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
            raise TestError("Meros didn't send back a Send.")
        verify(rpc, send.hash)
        sends = [send.hash.hex().upper()]

        #Send to self.
        #Tests send's capability to handle multiple UTXOs per key/lack of aggregation when all keys are the same/multiple output Sends.
        nextAddr = rpc.call("personal", "getAddress")
        changeKey: bytes = getChangePublicKey(mnemonic, "test", 0)
        sends.append(
            rpc.call(
                "personal", "send", {
                    "outputs": [{
                        "address": nextAddr,
                        "amount": str(claims[0].amount - 1)
                    }],
                    "password":
                    "******"
                }))
        checkSend(
            rpc, sends[-1], {
                "inputs": [{
                    "hash": sends[-2],
                    "nonce": 0
                }, {
                    "hash": sends[-2],
                    "nonce": 1
                }],
                "outputs": [{
                    "key": decodeAddress(nextAddr).hex().upper(),
                    "amount": str(claims[0].amount - 1)
                }, {
                    "key": changeKey.hex().upper(),
                    "amount": "1"
                }]
            })
        verify(rpc, bytes.fromhex(sends[-1]))

        #Externally send to the second/change address.
        #Enables entering multiple instances of each key into MuSig, which is significant as we originally only used the unique keys.
        sends.append(
            createSend(rpc, claims[1], decodeAddress(nextAddr)).hex().upper())
        sends.append(createSend(rpc, claims[2], changeKey).hex().upper())

        #Check personal_getUTXOs.
        utxos: List[Dict[str, Any]] = [{
            "hash": sends[-3],
            "nonce": 0,
            "address": nextAddr
        }, {
            "hash":
            sends[-3],
            "nonce":
            1,
            "address":
            bech32_encode("mr", convertbits(bytes([0]) + changeKey, 8, 5))
        }, {
            "hash": sends[-2],
            "nonce": 0,
            "address": nextAddr
        }, {
            "hash":
            sends[-1],
            "nonce":
            0,
            "address":
            bech32_encode("mr", convertbits(bytes([0]) + changeKey, 8, 5))
        }]
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError("personal_getUTXOs was incorrect.")
        for utxo in utxos:
            del utxo["address"]

        #Send to any address with all funds minus one.
        #Test MuSig signing, multiple inputs per key on account chains, change output creation to the next change key...
        sends.append(
            rpc.call(
                "personal", "send", {
                    "outputs": [{
                        "address":
                        nextAddr,
                        "amount":
                        str(claims[0].amount + claims[1].amount +
                            claims[2].amount - 1)
                    }],
                    "password":
                    "******"
                }))
        checkSend(
            rpc, sends[-1], {
                "inputs":
                utxos,
                "outputs": [{
                    "key":
                    decodeAddress(nextAddr).hex().upper(),
                    "amount":
                    str(claims[0].amount + claims[1].amount +
                        claims[2].amount - 1)
                }, {
                    "key":
                    getChangePublicKey(mnemonic, "test", 1).hex().upper(),
                    "amount":
                    "1"
                }]
            })
        verify(rpc, bytes.fromhex(sends[-1]))

        #Mine a Block so we can reboot the node without losing data.
        blsPrivKey: PrivateKey = PrivateKey(
            bytes.fromhex(rpc.call("personal", "getMeritHolderKey")))
        for _ in range(6):
            template: Dict[str, Any] = rpc.call(
                "merit", "getBlockTemplate",
                {"miner": blsPrivKey.toPublicKey().serialize().hex()})
            proof: int = -1
            tempHash: bytes = bytes()
            tempSignature: bytes = bytes()
            while ((proof == -1) or (
                (int.from_bytes(tempHash, "little") * template["difficulty"]) >
                    int.from_bytes(bytes.fromhex("FF" * 32), "little"))):
                proof += 1
                tempHash = RandomX(
                    bytes.fromhex(template["header"]) +
                    proof.to_bytes(4, "little"))
                tempSignature = blsPrivKey.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()
                })

        #Reboot the node and verify it still tracks the same change address.
        #Also reload the Wallet and verify it still tracks the same change address.
        #Really should be part of address discovery; we just have the opportunity right here.
        #Due to the timing of how the codebase was developed, and a personal frustration for how long this has taken...
        rpc.quit()
        sleep(3)
        rpc.meros = Meros(rpc.meros.db, rpc.meros.tcp, rpc.meros.rpc)
        if rpc.call("personal", "getTransactionTemplate",
                    {"outputs": [{
                        "address": nextAddr,
                        "amount": "1"
                    }]})["outputs"][1]["key"] != getChangePublicKey(
                        mnemonic, "test", 2).hex().upper():
            raise TestError(
                "Rebooting the node caused the WalletDB to stop tracking the next change address."
            )
        rpc.call("personal", "setAccount", rpc.call("personal", "getAccount"))
        if rpc.call("personal", "getTransactionTemplate",
                    {"outputs": [{
                        "address": nextAddr,
                        "amount": "1"
                    }]})["outputs"][1]["key"] != getChangePublicKey(
                        mnemonic, "test", 2).hex().upper():
            raise TestError(
                "Reloading the Wallet caused the WalletDB to stop tracking the next change address."
            )

        raise SuccessError()
Esempio n. 17
0
    def test() -> None:
        recipient: ed25519.SigningKey = ed25519.SigningKey(b'\1' * 32)
        recipientPub: bytes = recipient.get_verifying_key().to_bytes()
        address: str = bech32_encode(
            "mr", convertbits(bytes([0]) + recipientPub, 8, 5))

        otherRecipient: bytes = ed25519.SigningKey(
            b'\2' * 32).get_verifying_key().to_bytes()
        otherAddress: str = bech32_encode(
            "mr", convertbits(bytes([0]) + otherRecipient, 8, 5))

        #Create a Send.
        send: Send = Send.fromJSON(vectors["send"])
        if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
            raise TestError("Meros didn't broadcast back a Send.")
        if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
            raise TestError(
                "Meros considered an unconfirmed Transaction's outputs as UTXOs."
            )
        verify(rpc, send.hash)

        #Finalize the parent.
        for _ in range(6):
            mineBlock(rpc)

        #Spend it.
        spendingSend: Send = Send.fromJSON(vectors["spendingSend"])
        if rpc.meros.liveTransaction(spendingSend) != rpc.meros.live.recv():
            raise TestError("Meros didn't broadcast back a Send.")
        verify(rpc, spendingSend.hash)
        if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
            raise TestError(
                "Meros didn't consider a verified Transaction's inputs as spent."
            )
        if rpc.call("transactions", "getUTXOs", {"address": otherAddress}) != [
            {
                "hash": spendingSend.hash.hex().upper(),
                "nonce": 0
            }
        ]:
            raise TestError(
                "Meros didn't consider a verified Transaction's outputs as UTXOs."
            )

        #Unverify the spending Send. This would also unverify the parent if it wasn't finalized.
        #This is done via causing a Merit Removal.
        #Uses two competing Datas to not change the Send's status to competing.
        datas: List[Data] = [Data(bytes(32), recipientPub)]
        for _ in range(2):
            datas.append(Data(datas[0].hash, datas[-1].hash))
        for data in datas:
            data.sign(recipient)
            data.beat(SpamFilter(5))
            if rpc.meros.liveTransaction(data) != rpc.meros.live.recv():
                raise TestError("Meros didn't broadcast back a Data.")
            verify(rpc, data.hash, mr=(datas[-1].hash == data.hash))
        #Verify the MeritRemoval happened and the spending Send is no longer verified.
        #These first two checks are more likely to symbolize a failure in testing methodology than Meros.
        if not rpc.call("merit", "getMerit", {"nick": 0})["malicious"]:
            raise TestError("Meros didn't create a Merit Removal.")
        if not rpc.call("consensus", "getStatus",
                        {"hash": send.hash.hex()})["verified"]:
            raise TestError("Finalized Transaction became unverified.")
        if rpc.call("consensus", "getStatus",
                    {"hash": spendingSend.hash.hex()})["verified"]:
            raise TestError(
                "Meros didn't unverify a Transaction which is currently below the required threshold."
            )
        #Even after unverification, since the Transaction still exists, the input shouldn't be considered a UTXO.
        if rpc.call("transactions", "getUTXOs", {"address": address}) != []:
            raise TestError(
                "Meros didn't consider a unverified yet existing Transaction's inputs as spent."
            )
        #That said, its outputs should no longer be considered a UTXO.
        if rpc.call("transactions", "getUTXOs",
                    {"address": otherAddress}) != []:
            raise TestError(
                "Meros considered a unverified Transaction's outputs as UTXOs."
            )

        raise SuccessError()
Esempio n. 18
0
 def verify() -> None:
     verifyMeritRemoval(rpc, 1, 1, removal.holder, False)
     verifyBlockchain(rpc, Blockchain.fromJSON(vectors["blockchain"]))
     raise SuccessError(
         "MeritRemoval and Blockchain were properly handled.")
Esempio n. 19
0
def BusyTest(meros: Meros) -> None:
    #Solely used to get the genesis Block hash.
    blockchain: Blockchain = Blockchain()

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

    #Create two new server sockets.
    def createServerSocket() -> socket.socket:
        result: socket.socket = socket.socket(socket.AF_INET,
                                              socket.SOCK_STREAM)
        result.bind(("127.0.0.1", 0))
        result.listen(2)
        return result

    busyServer: socket.socket = createServerSocket()
    server: socket.socket = createServerSocket()

    #Receive Syncing until Meros asks for peers.
    while True:
        res = meros.sync.recv()
        if MessageType(res[0]) == MessageType.Syncing:
            meros.sync.send(MessageType.BlockchainTail.toByte() +
                            blockchain.blocks[0].header.hash)
        elif MessageType(res[0]) == MessageType.PeersRequest:
            break

    #Craft a Peers message of our own server.
    meros.sync.send(MessageType.Peers.toByte() + bytes.fromhex("017F000001") +
                    busyServer.getsockname()[1].to_bytes(2, "little"))

    #Use select to obtain a non-blocking accept.
    busy: int = 0
    buf: bytes
    for _ in select.select([busyServer], [], [], 5000):
        #Accept a new connection.
        client, _ = busyServer.accept()

        #Verify Meros's Handshake.
        buf = client.recv(38)
        if MessageType(
                buf[0]) not in {MessageType.Handshake, MessageType.Syncing}:
            busyServer.close()
            raise TestError(
                "Meros didn't start its connection with a Handshake.")

        if buf[1:] != (
            (254).to_bytes(1, "little") + (254).to_bytes(1, "little") +
            (128).to_bytes(1, "little") + meros.tcp.to_bytes(2, "little") +
                blockchain.blocks[0].header.hash):
            busyServer.close()
            raise TestError("Meros had an invalid Handshake.")

        #Send back Busy.
        client.send(MessageType.Busy.toByte() + bytes.fromhex("017F000001") +
                    server.getsockname()[1].to_bytes(2, "little"))

        busy += 1
        if busy == 2:
            busyServer.close()
            break

    #Make sure Meros connects to the server we redirected to.
    with raises(SuccessError):
        for _ in select.select([server], [], [], 5000):
            #Accept a new connection.
            client, _ = server.accept()

            #Verify Meros's Handshake.
            buf = client.recv(38)
            if MessageType(buf[0]) not in {
                    MessageType.Handshake, MessageType.Syncing
            }:
                server.close()
                raise TestError(
                    "Meros didn't start its connection with a Handshake.")

            if buf[1:] != (
                (254).to_bytes(1, "little") + (254).to_bytes(1, "little") +
                (128).to_bytes(1, "little") + meros.tcp.to_bytes(2, "little") +
                    blockchain.blocks[0].header.hash):
                server.close()
                raise TestError("Meros had an invalid Handshake.")

            server.close()
            raise SuccessError(
                "Meros connected to the server we redirected it to with a Busy message."
            )

        #Raise a TestError.
        busyServer.close()
        server.close()
        raise TestError("Meros didn't connect to the redirected server.")
Esempio n. 20
0
    def test() -> None:
        #Send to the new address and get the next address.
        dest: str = rpc.call("personal", "getAddress")
        last: Send = createSend(rpc, Claim.fromJSON(vectors["newerMintClaim"]),
                                dest)

        utxos: List[Dict[str, Any]] = rpc.call("personal", "getUTXOs")
        if utxos != [{
                "address": dest,
                "hash": last.hash.hex().upper(),
                "nonce": 0
        }]:
            raise TestError(
                "personal_getUTXOs didn't return the correct UTXOs.")

        #Set a different mnemonic to verify the tracked addresses is cleared.
        rpc.call("personal", "setWallet")
        if rpc.call("personal", "getUTXOs") != []:
            raise TestError(
                "Setting a new Mnemonic didn't clear the tracked addresses.")

        #Reload the Mnemonic and verify the UTXOs are correct.
        rpc.call("personal", "setWallet", {"mnemonic": mnemonic})
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            #This error message points out how no addresses are really being discovered yet; this is account zero's address.
            #That said, if the test started at the next address, there'd be a gap.
            #As that's an extra factor, this is tested before gaps are.
            raise TestError("Meros didn't recover the very first address.")

        #Now send to the next address and check accuracy.
        dest = rpc.call("personal", "getAddress")
        last = createSend(rpc, last, dest)
        utxos.append({
            "address": dest,
            "hash": last.hash.hex().upper(),
            "nonce": 0
        })
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError("Meros didn't track an implicitly gotten address.")
        rpc.call("personal", "setWallet", {"mnemonic": mnemonic})
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError(
                "Meros didn't recover the first address after the initial address."
            )

        #Send funds to the address after the next address; tests a gap when discovering addresses.
        last = createSend(rpc, last, getAddress(mnemonic, "", 3))
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError(
                "Meros magically recognized UTXOs as belonging to this Wallet or someone implemented an address cache."
            )
        utxos.append({
            "address": getAddress(mnemonic, "", 3),
            "hash": last.hash.hex().upper(),
            "nonce": 0
        })
        rpc.call("personal", "setWallet", {"mnemonic": mnemonic})
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError(
                "Meros didn't discover a used address in the Wallet when there was a gap."
            )

        #Finally, anything 10+ unused addresses out shouldn't be recovered.
        last = createSend(rpc, last, getAddress(mnemonic, "", 14))
        rpc.call("personal", "setWallet", {"mnemonic": mnemonic})
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError(
                "Meros recovered an address's UTXOs despite it being 10 unused addresses out."
            )

        #Explicitly generating this address should start tracking it though.
        rpc.call("personal", "getAddress",
                 {"index": getIndex(mnemonic, "", 14)})
        utxos.append({
            "address": getAddress(mnemonic, "", 14),
            "hash": last.hash.hex().upper(),
            "nonce": 0
        })
        if sortUTXOs(rpc.call("personal", "getUTXOs")) != sortUTXOs(utxos):
            raise TestError(
                "personal_getUTXOs didn't track an address explicitly indexed."
            )

        #If asked for an address, Meros should return the 5th (skip 4).
        #It's the first unused address AFTER used addresss EXCEPT ones explicitly requested.
        #This can, in the future, be juwst the first unused address/include ones explicitly requested (see DerivationTest for commentary on that).
        #This is really meant to ensure consistent behavior until we properly decide otherwise.
        if rpc.call("personal", "getAddress") != getAddress(mnemonic, "", 4):
            raise TestError(
                "Meros didn't return the next unused address (with conditions; see comment)."
            )

        #Mine a Block to flush the Transactions and Verifications to disk.
        sleep(65)
        rpc.meros.liveConnect(Blockchain().blocks[0].header.hash)
        mineBlock(rpc)

        #Existing values used to test getAddress/getUTXOs consistency.
        #The former is thoroughly tested elsewhere, making it quite redundant.
        existing: Dict[str, Any] = {
            "getAddress": rpc.call("personal", "getAddress"),
            "getUTXOs": rpc.call("personal", "getUTXOs")
        }

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

        #Used so Liver doesn't run its own post-test checks.
        #Since we added our own Blocks, those will fail.
        raise SuccessError()
Esempio n. 21
0
    continue
  testsToRun.remove(test.__name__)

  print("\033[0;37mRunning " + test.__name__ + ".")

  #Message to display on a Node crash.
  crash: str = "\033[5;31m" + test.__name__ + " caused the node to crash!\033[0;31m"

  #Meros instance.
  meros: Meros = Meros(test.__name__, port, port + 1)
  sleep(5)

  rpc: RPC = RPC(meros)
  try:
    test(rpc)
    raise SuccessError()
  except SuccessError as e:
    ress.append("\033[0;32m" + test.__name__ + " succeeded.")
  except EmptyError as e:
    ress.append("\033[0;33m" + test.__name__ + " is empty.")
  except NodeError as e:
    ress.append(crash)
  except TestError as e:
    ress.append("\033[0;31m" + test.__name__ + " failed: " + str(e))
  except Exception as e:
    ress.append("\033[0;31m" + test.__name__ + " is invalid.")
    ress.append(format_exc().rstrip())
  finally:
    try:
      rpc.quit()
      meros.quit()
Esempio n. 22
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()
Esempio n. 23
0
    def checkFail() -> None:
        #This Block should cause the node to disconnect us AFTER it attempts to sync our Transaction.
        syncedTX: bool = False

        #Grab the Block.
        block: Block = merit.blockchain.blocks[2]

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

        #Handle sync requests.
        reqHash: bytes = bytes()
        while True:
            if syncedTX:
                #Try receiving from the Live socket, where Meros sends keep-alives.
                try:
                    if len(rpc.meros.live.recv()) != 0:
                        raise Exception()
                except TestError:
                    raise SuccessError(
                        "Node disconnected us after we sent a parsable, yet invalid, Verification."
                    )
                except Exception:
                    raise TestError("Meros sent a keep-alive.")

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

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

            elif MessageType(msg[0]) == MessageType.SketchHashesRequest:
                if not block.body.packets:
                    raise TestError(
                        "Meros asked for Sketch Hashes from a Block without any."
                    )

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

                #Create the haashes.
                hashes: List[int] = []
                for packet in block.body.packets:
                    hashes.append(Sketch.hash(block.header.sketchSalt, packet))

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

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

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

                #Create a lookup of hash to packets.
                packets: Dict[int, VerificationPacket] = {}
                for packet in block.body.packets:
                    packets[Sketch.hash(block.header.sketchSalt,
                                        packet)] = packet

                #Look up each requested packet and respond accordingly.
                for h in range(int.from_bytes(msg[33:37], byteorder="big")):
                    sketchHash: int = int.from_bytes(msg[37 + (h * 8):45 +
                                                         (h * 8)],
                                                     byteorder="big")
                    if sketchHash not in packets:
                        raise TestError(
                            "Meros asked for a non-existent Sketch Hash.")
                    rpc.meros.packet(packets[sketchHash])

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

            else:
                raise TestError("Unexpected message sent: " +
                                msg.hex().upper())
Esempio n. 24
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()