Пример #1
0
def createSend(rpc: RPC, last: Union[Claim, Send], toAddress: str) -> Send:
    funded: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32)
    if isinstance(last, Claim):
        send: Send = Send([(last.hash, 0)],
                          [(decodeAddress(toAddress), 1),
                           (funded.get_verifying_key(), last.amount - 1)])
    else:
        send: Send = Send(
            [(last.hash, 1)],
            [(decodeAddress(toAddress), 1),
             (funded.get_verifying_key(), last.outputs[1][1] - 1)])

    send.sign(funded)
    send.beat(SpamFilter(3))
    sleep(65)
    rpc.meros.liveConnect(Blockchain().blocks[0].header.hash)
    if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
        raise TestError("Meros didn't broadcast back a Send.")

    sv: SignedVerification = SignedVerification(send.hash)
    sv.sign(0, PrivateKey(0))
    if rpc.meros.signedElement(sv) != rpc.meros.live.recv():
        raise TestError("Meros didn't broadcast back a Verification.")

    return send
Пример #2
0
def createSend(rpc: RPC, last: Union[Claim, Send], toAddress: str) -> Send:
    funded: Ristretto.SigningKey = Ristretto.SigningKey(b'\0' * 32)
    if isinstance(last, Claim):
        send: Send = Send([(last.hash, 0)],
                          [(decodeAddress(toAddress), 1),
                           (funded.get_verifying_key(), last.amount - 1)])
    else:
        send: Send = Send(
            [(last.hash, 1)],
            [(decodeAddress(toAddress), 1),
             (funded.get_verifying_key(), last.outputs[1][1] - 1)])
    send.sign(funded)
    send.beat(SpamFilter(3))
    if rpc.meros.liveTransaction(send) != rpc.meros.live.recv():
        raise TestError("Meros didn't broadcast back a Send.")
    return send
Пример #3
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()
Пример #4
0
def PersonalDataTest(rpc: RPC) -> None:
    #Create a Data.
    firstData: str = rpc.call("personal", "data", {"data": "a"})
    initial: str = checkData(rpc, firstData, b"a")

    #Meros should've also created an initial Data.
    if checkData(rpc, initial, decodeAddress(rpc.call(
            "personal", "getAddress"))) != bytes(32).hex():
        raise TestError("Initial Data didn't have a 0-hash input.")

    #Create a Data using hex data. Also tests upper case hex.
    if checkData(rpc,
                 rpc.call("personal", "data", {
                     "data": "AABBCC",
                     "hex": True
                 }), b"\xAA\xBB\xCC") != firstData:
        raise TestError(
            "Newly created Data wasn't a descendant of the existing Data.")

    #Should support using 256 bytes of Data. Also tests lower case hex.
    checkData(
        rpc,
        rpc.call("personal", "data", {
            "data": bytes([0xaa] * 256).hex(),
            "hex": True
        }), bytes([0xaa] * 256))

    #Should properly error when we input no data. All Datas must have at least 1 byte of Data.
    try:
        rpc.call("personal", "data", {"data": ""})
        raise Exception()
    except Exception as e:
        if str(e) != "-3 Data is too small or too large.":
            raise TestError("Meros didn't handle Data that was too small.")

    #Should properly error when we supply more than 256 bytes of data.
    try:
        rpc.call("personal", "data", {"data": "a" * 257})
        raise Exception()
    except Exception as e:
        if str(e) != "-3 Data is too small or too large.":
            raise TestError("Meros didn't handle Data that was too large.")

    #Should properly error when we supply non-hex data with the hex flag.
    try:
        rpc.call("personal", "data", {"data": "zz", "hex": True})
        raise Exception()
    except Exception as e:
        if str(e) != "-3 Invalid hex char `z` (ord 122).":
            raise TestError("Meros didn't properly handle invalid hex.")

    #Should properly error when we supply non-even hex data.
    try:
        rpc.call("personal", "data", {"data": "a", "hex": True})
        raise Exception()
    except Exception as e:
        if str(e) != "-3 Incorrect hex string len.":
            raise TestError("Meros didn't properly handle non-even hex.")

    #Test Datas when the Wallet has a password.
    rpc.call("personal", "setWallet", {"password": "******"})

    #Shouldn't work due to the lack of a password.
    try:
        rpc.call("personal", "data", {"data": "abc"})
        raise Exception()
    except Exception as e:
        if str(e) != "-3 Invalid password.":
            raise TestError(
                "Meros didn't properly handle creating a Data without a password."
            )

    #Should work due to the existence of a password.
    lastData: str = rpc.call("personal", "data", {
        "data": "abc",
        "password": "******"
    })
    checkData(rpc, lastData, b"abc")

    #Reboot the node and verify we can create a new Data without issue.
    rpc.quit()
    sleep(3)
    rpc.meros = Meros(rpc.meros.db, rpc.meros.tcp, rpc.meros.rpc)
    if checkData(
            rpc,
            rpc.call("personal", "data", {
                "data": "def",
                "password": "******"
            }), b"def") != lastData:
        raise TestError("Couldn't create a new Data after rebooting.")