Beispiel #1
0
    def run_test(self):
        self.nodes[1].generate(10)
        self.sync_blocks()
        self.nodes[0].generate(150)

        self.nodes[0].name_register("x/name", val("value"))
        self.nodes[0].generate(5)
        self.sync_blocks()
        self.checkName(0, "x/name", val("value"))

        # fundrawtransaction and friends does not support non-wallet provided
        # inputs.  Thus we have to first build up the funded transaction without
        # the name input and a slightly higher fee, and then combine it with the
        # name input to obtain the final raw transaction.
        addrNm = self.nodes[1].getnewaddress()
        addrPayment = self.nodes[0].getnewaddress()
        outs = [{addrNm: 0.01}, {addrPayment: 10}]
        part1 = self.nodes[1].createrawtransaction([], outs)
        options = {
            "feeRate": 0.001,
            "changePosition": 2,
        }
        part1 = self.nodes[1].fundrawtransaction(part1, options)["hex"]

        nmData = self.nodes[0].name_show("x/name")
        part2 = self.nodes[0].createrawtransaction([nmData], [])

        fullIns = []
        fullOuts = []
        for p in [part1, part2]:
            data = self.nodes[0].decoderawtransaction(p)
            fullIns.extend(data["vin"])
            for vout in data["vout"]:
                fullOuts.append(
                    {vout["scriptPubKey"]["addresses"][0]: vout["value"]})
        combined = self.nodes[1].createrawtransaction(fullIns, fullOuts)
        combined = self.nodes[1].converttopsbt(combined)

        nameOp = {
            "op": "name_update",
            "name": "x/name",
            "value": val("updated"),
        }
        combined = self.nodes[1].namepsbt(combined, 0, nameOp)["psbt"]

        # Sign and broadcast the partial tx.
        sign1 = self.nodes[0].walletprocesspsbt(combined)
        sign2 = self.nodes[1].walletprocesspsbt(combined)
        combined = self.nodes[1].combinepsbt([sign1["psbt"], sign2["psbt"]])
        tx = self.nodes[1].finalizepsbt(combined)
        assert_equal(tx["complete"], True)
        self.nodes[0].sendrawtransaction(tx["hex"])
        self.nodes[0].generate(1)
        data = self.checkName(0, "x/name", val("updated"))
        assert_equal(data["address"], addrNm)
Beispiel #2
0
    def run_test(self):
        node = self.nodes[0]
        node.generate(200)

        name = "x/testname"
        nameHex = name.encode("ascii").hex()
        singleHash = hashlib.new("sha256", name.encode("ascii")).digest()
        doubleHashHex = hashlib.new("sha256", singleHash).hexdigest()
        byHashOptions = {"nameEncoding": "hex", "byHash": "sha256d"}

        # Start by setting up a test name.
        node.name_register(name, val("value"))
        node.generate(1)

        # Check looking up "direct".
        res = node.name_show(name, {"byHash": "direct"})
        assert_equal(res["name"], name)
        assert_equal(res["value"], val("value"))

        # -namehashindex is not enabled yet.
        assert_raises_rpc_error(-1, 'namehashindex is not enabled',
                                node.name_show, doubleHashHex, byHashOptions)
        assert_equal(node.getindexinfo("namehash"), {})

        # Restart the node and enable indexing.
        self.restart_node(0, extra_args=["-namehashindex", "-namehistory"])
        self.wait_until(
            lambda: all(i["synced"] for i in node.getindexinfo().values()))
        assert_equal(
            node.getindexinfo("namehash"), {
                "namehash": {
                    "synced": True,
                    "best_block_height": node.getblockcount(),
                }
            })

        # Now the lookup by hash should work.
        res = node.name_show(doubleHashHex, byHashOptions)
        assert_equal(res["name"], nameHex)
        assert_equal(res["value"], val("value"))
        res = node.name_history(doubleHashHex, byHashOptions)
        assert_equal(len(res), 1)
        assert_equal(res[0]["name"], nameHex)

        # Unknown name by hash.
        assert_raises_rpc_error(-4, "name hash not found", node.name_show,
                                "42" * 32, byHashOptions)

        # General errors with the parameters.
        assert_raises_rpc_error(-8, "Invalid value for byHash", node.name_show,
                                doubleHashHex, {"byHash": "foo"})
        assert_raises_rpc_error(-8, "must be 32 bytes long", node.name_show,
                                "abcd", {"byHash": "sha256d"})
Beispiel #3
0
  def run_test (self):

    # Firstupdate the name and check that briefly.
    addrA = self.nodes[0].getnewaddress ()
    self.nodes[0].name_register ('x/testname', val ('value'),
                                 {"destAddress": addrA})
    self.nodes[0].generate (1)
    unspent = self.lookupName (0, "x/testname", includeNames=True)
    assert unspent is not None
    assert 'nameOp' in unspent
    assert_equal (unspent['nameOp']['op'], 'name_register')
    assert_equal (unspent['nameOp']['name'], 'x/testname')

    # Update the name, sending to another node.
    addrB = self.nodes[1].getnewaddress ()
    self.nodes[0].name_update ("x/testname", val ("value"),
                               {"destAddress": addrB})
    self.sync_mempools ()

    # Node 0 should no longer have the unspent output.
    assert self.lookupName (0, "x/testname",
                            allowUnconfirmed=True,
                            includeNames=True) is None
    assert self.lookupName (0, "x/testname",
                            allowUnconfirmed=True,
                            includeNames=True) is None

    # Node 1 should now see the output as unconfirmed.
    assert self.lookupName (1, "x/testname", allowUnconfirmed=True) is None
    assert self.lookupName (1, "x/testname", includeNames=True) is None
    unspent = self.lookupName (1, "x/testname",
                               addressFilter=[addrB],
                               allowUnconfirmed=True,
                               includeNames=True)
    assert unspent is not None
    assert_equal (unspent['confirmations'], 0)
    assert 'nameOp' in unspent
    assert_equal (unspent['nameOp']['op'], 'name_update')
    assert_equal (unspent['nameOp']['name'], 'x/testname')

    # Mine blocks and verify node 1 seeing the name correctly.
    self.nodes[1].generate (30)
    assert self.lookupName (1, "x/testname") is None
    assert self.lookupName (1, "x/testname",
                            addressFilter=[addrA],
                            includeNames=True) is None
    unspent = self.lookupName (1, "x/testname", includeNames=True)
    assert unspent is not None
    assert_equal (unspent['confirmations'], 30)
    assert 'nameOp' in unspent
    assert_equal (unspent['nameOp']['op'], 'name_update')
    assert_equal (unspent['nameOp']['name'], 'x/testname')
Beispiel #4
0
    def run_test(self):
        self.node = self.nodes[1]
        self.node.generate(110)

        # Register two names.  One of them is then sent to an address not owned
        # by the node and one is updated into a pending operation.  That then
        # gives us the basic setup to test the "ismine" field in all the
        # circumstances.
        self.node.name_register("d/a", val("value"))
        self.node.name_register("d/b", val("value"))
        self.node.generate(1)
        otherAddr = self.nodes[0].getnewaddress()
        self.node.name_update("d/b", val("new value"),
                              {"destAddress": otherAddr})
        self.node.generate(1)
        self.node.name_update("d/a", val("new value"))

        # name_show
        assert_equal(self.node.name_show("d/a")['ismine'], True)
        assert_equal(self.node.name_show("d/b")['ismine'], False)

        # name_history
        hist = self.node.name_history("d/a")
        assert_equal(len(hist), 1)
        assert_equal(hist[0]['ismine'], True)
        hist = self.node.name_history("d/b")
        assert_equal(len(hist), 2)
        assert_equal(hist[0]['ismine'], True)
        assert_equal(hist[1]['ismine'], False)

        # name_pending
        pending = self.node.name_pending()
        assert_equal(len(pending), 1)
        p = pending[0]
        assert_equal(p['name'], "d/a")
        assert_equal(p['ismine'], True)

        # name_scan, name_list
        self.verifyExpectedIsMineInList(self.node.name_scan())
        self.verifyExpectedIsMineInList(self.node.name_list())

        # Test the multiwallet situation.  If no wallet is specified for the RPC,
        # then ismine should not be set at all.
        self.node.createwallet("extra")
        defaultRpc = self.node.get_wallet_rpc("")
        extraRpc = self.node.get_wallet_rpc("extra")
        self.verifyExpectedIsMineInList(defaultRpc.name_list())
        for nm in ["d/a", "d/b"]:
            assert 'ismine' not in self.node.name_show(nm)
            assert_equal(extraRpc.name_show(nm)['ismine'], False)
Beispiel #5
0
    def run_test(self):

        # Send name_register with burn and verify it worked as expected.
        burn = {"foobar": 1, "baz baz baz": 2}
        txid = self.nodes[0].name_register("x/testname", val("value"),
                                           {"burn": burn})
        self.nodes[0].generate(1)
        self.verifyTx(txid, burn)

        # Test different variations (numbers of burns) with name_update.
        for n in range(5):
            burn = {"foo %d" % i: 42 + i for i in range(n)}
            txid = self.nodes[0].name_update("x/testname", val("value"),
                                             {"burn": burn})
            self.nodes[0].generate(1)
            self.verifyTx(txid, burn)

        # Test maximum length.
        burn = {"a" * MAX_DATA_LEN: 1, "b" * MAX_DATA_LEN: 2}
        txid = self.nodes[0].name_update("x/testname", val("value"),
                                         {"burn": burn})
        self.nodes[0].generate(1)
        self.verifyTx(txid, burn)

        # Verify the range check for amount and the data length verification.
        assert_raises_rpc_error(-3, 'Invalid amount for burn',
                                self.nodes[0].name_update, "x/testname",
                                val("value"), {"burn": {
                                    "foo": 0
                                }})
        assert_raises_rpc_error(-5, 'Burn data is too long',
                                self.nodes[0].name_update, "x/testname",
                                val("value"),
                                {"burn": {
                                    "x" * (MAX_DATA_LEN + 1): 1
                                }})

        # Verify the insufficient funds check, both where it fails a priori
        # and where we just don't have enough for the fee.
        balance = self.nodes[0].getbalance()
        assert_raises_rpc_error(-6, 'Insufficient funds',
                                self.nodes[0].name_update, "x/testname",
                                val("value"), {"burn": {
                                    "x": balance + 1
                                }})
        assert_raises_rpc_error(-6, 'Insufficient funds',
                                self.nodes[0].name_update, "x/testname",
                                val("value"), {"burn": {
                                    "x": balance
                                }})

        # Check that we can send a name_update that burns almost all funds in
        # the wallet.  We only need to keep a tiny amount to pay for the fee
        # (but less than the locked amount of 0.01).
        keep = Decimal("0.009")
        burn = {"some burn data": balance - keep}
        txid = self.nodes[0].name_update("x/testname", val("value"),
                                         {"burn": burn})
        self.nodes[0].generate(1)
        self.verifyTx(txid, burn)
  def run_test (self):
    addr = self.nodes[0].getnewaddress ()

    # Generate some blocks so that node 0 does not get fresh block rewards
    # anymore (similar to how it is in the upstream Namecoin test).
    self.nodes[0].generate (50)

    # It should be possible to use unconfirmed *currency* outputs in a name
    # firstupdate, though (so that multiple name registrations are possible
    # even if one has only a single currency output in the wallet).

    balance = self.nodes[0].getbalance ()
    self.nodes[0].sendtoaddress (addr, balance, None, None, True)
    assert_equal (1, len (self.nodes[0].listunspent (0)))
    firstC = self.nodes[0].name_register ("x/c", val ("value"))
    firstD = self.nodes[0].name_register ("x/d", val ("value"))
    assert self.dependsOn (0, firstD, firstC)
    self.nodes[0].generate (1)
    self.checkName (0, "x/c", val ("value"))
    self.checkName (0, "x/d", val ("value"))

    assert_equal (1, len (self.nodes[0].listunspent ()))
    updC = self.nodes[0].name_update ("x/c", val ("new value"))
    updD = self.nodes[0].name_update ("x/d", val ("new value"))
    assert self.dependsOn (0, updD, updC)
    self.nodes[0].generate (1)
    self.checkName (0, "x/c", val ("new value"))
    self.checkName (0, "x/d", val ("new value"))
Beispiel #7
0
    def run_test(self):
        self.node = self.nodes[0]

        # Register a test name to a bech32 pure-segwit address.
        addr = self.node.getnewaddress("test", "bech32")
        name = "d/test"
        value = "{}"
        self.node.name_register(name, value, {"destAddress": addr})
        self.node.generate(1)
        self.checkNameValueAddr(name, value, addr)

        # Before segwit activation, the script should behave as anyone-can-spend.
        # It will still fail due to non-mandatory flag checks when submitted
        # into the mempool.
        assert_greater_than(SEGWIT_ACTIVATION_HEIGHT,
                            self.node.getblockcount())
        assert_raises_rpc_error(-26,
                                'Script failed an OP_EQUALVERIFY operation',
                                self.tryUpdateSegwitName, name,
                                val("wrong value"), addr)
        self.node.generate(1)
        self.checkNameValueAddr(name, value, addr)

        # But directly in a block, the update should work with a dummy witness.
        assert_equal(
            self.tryUpdateInBlock(name, val("stolen"), addr,
                                  withWitness=False), None)
        self.checkNameValueAddr(name, val("stolen"), addr)

        # Activate segwit.  Restore original value for name.
        self.node.generate(400)
        self.node.name_update(name, value, {"destAddress": addr})
        self.node.generate(1)
        self.checkNameValueAddr(name, value, addr)

        # Verify that now trying to update the name without a proper signature
        # fails differently.
        assert_greater_than(self.node.getblockcount(),
                            SEGWIT_ACTIVATION_HEIGHT)
        assert_equal(
            self.tryUpdateInBlock(name,
                                  val("wrong value"),
                                  addr,
                                  withWitness=True),
            'non-mandatory-script-verify-flag' +
            ' (Script failed an OP_EQUALVERIFY operation)')
        self.checkNameValueAddr(name, value, addr)

        # Updating the name ordinarily (with signature) should work fine even
        # though it is at a segwit address.  Also spending from P2SH-segwit
        # should work fine.
        addrP2SH = self.node.getnewaddress("test", "p2sh-segwit")
        self.node.name_update(name, val("value 2"), {"destAddress": addrP2SH})
        self.node.generate(1)
        self.checkNameValueAddr(name, val("value 2"), addrP2SH)
        self.node.name_update(name, val("value 3"), {"destAddress": addr})
        self.node.generate(1)
        self.checkNameValueAddr(name, val("value 3"), addr)
Beispiel #8
0
    def run_test(self):
        self.nodes[1].generate(10)
        self.sync_blocks()
        self.nodes[0].generate(150)

        self.nodes[0].name_register("x/name", val("value"))
        self.nodes[0].generate(5)
        self.sync_blocks()
        self.checkName(0, "x/name", val("value"))

        # fundrawtransaction and friends does not support non-wallet provided
        # inputs.  Thus we have to first build up the funded transaction without
        # the name coins and a slightly higher fee, and then combine it with the
        # name input/output to obtain the final raw transaction.
        addrPayment = self.nodes[0].getnewaddress()
        outs = [{addrPayment: 10}]
        options = {
            "fee_rate": 100,
        }
        part1 = self.nodes[1].walletcreatefundedpsbt([], outs, 0,
                                                     options)["psbt"]

        addrNm = self.nodes[1].getnewaddress()
        nmData = self.nodes[0].name_show("x/name")
        part2 = self.nodes[0].createpsbt([nmData], [{addrNm: 0.01}])
        nameOp = {
            "op": "name_update",
            "name": "x/name",
            "value": val("updated"),
        }
        part2 = self.nodes[1].namepsbt(part2, 0, nameOp)["psbt"]
        combined = self.nodes[1].joinpsbts([part1, part2])

        # Sign and broadcast the partial tx.
        sign1 = self.nodes[0].walletprocesspsbt(combined)
        sign2 = self.nodes[1].walletprocesspsbt(combined)
        combined = self.nodes[1].combinepsbt([sign1["psbt"], sign2["psbt"]])
        tx = self.nodes[1].finalizepsbt(combined)
        assert_equal(tx["complete"], True)
        self.nodes[0].sendrawtransaction(tx["hex"])
        self.nodes[0].generate(1)
        data = self.checkName(0, "x/name", val("updated"))
        assert_equal(data["address"], addrNm)
Beispiel #9
0
    def run_test(self):

        # Send name_register with sendCoins option and verify it worked as expected.
        addr1 = self.nodes[0].getnewaddress()
        addr2 = self.nodes[0].getnewaddress()
        sendCoins = {addr1: 1, addr2: 2}
        txid = self.nodes[0].name_register("x/testname", val("value"),
                                           {"sendCoins": sendCoins})
        self.generate(0, 1)
        self.verifyTx(txid, sendCoins)

        # Test different variantions (numbers of target addresses) with name_update.
        for n in range(5):
            sendCoins = {}
            for i in range(n):
                sendCoins[self.nodes[0].getnewaddress()] = 42 + i
            txid = self.nodes[0].name_update("x/testname", val("value"),
                                             {"sendCoins": sendCoins})
            self.generate(0, 1)
            self.verifyTx(txid, sendCoins)

        # Verify the range check for amount and the address validation.
        assert_raises_rpc_error(-3, 'Invalid amount for send',
                                self.nodes[0].name_update, "x/testname",
                                val("value"), {"sendCoins": {
                                    addr1: 0
                                }})
        assert_raises_rpc_error(-5, 'Invalid address',
                                self.nodes[0].name_update, "x/testname",
                                val("value"), {"sendCoins": {
                                    "x": 1
                                }})

        # Verify the insufficient funds check, both where it fails a priori
        # and where we just don't have enough for the fee.
        balance = self.nodes[0].getbalance()
        assert_raises_rpc_error(-6, 'Insufficient funds',
                                self.nodes[0].name_update, "x/testname",
                                val("value"),
                                {"sendCoins": {
                                    addr1: balance + 1
                                }})
        assert_raises_rpc_error(-4, 'requires a transaction fee',
                                self.nodes[0].name_update, "x/testname",
                                val("value"), {"sendCoins": {
                                    addr1: balance
                                }})

        # Check that we can send a name_update that spends almost all funds in
        # the wallet.  We only need to keep a tiny amount to pay for the fee
        # (but less than the locked amount of 0.01).
        keep = Decimal("0.009")
        sendCoins = {addr1: balance - keep}
        txid = self.nodes[0].name_update("x/testname", val("value"),
                                         {"sendCoins": sendCoins})
        self.generate(0, 1)
        self.verifyTx(txid, sendCoins)
Beispiel #10
0
    def run_test(self):
        self.node = self.nodes[0]
        self.node.generate(110)

        # Register a test name.
        name = "d/test"
        self.node.name_register(name, val("first"))
        self.node.generate(1)
        self.checkName(0, name, val("first"))

        # Update the name (keep the transaction pending) and check that another
        # update is not allowed by the mempool.
        txid = self.node.name_update(name, val("second"))
        assert_raises_rpc_error(-25, "already a pending update",
                                self.node.name_update, name, val("wrong"))
        self.node.generate(1)
        self.checkName(0, name, val("second"))

        # Build two update transactions building on each other and try to
        # submit them both as transactions.
        blk = buildMultiUpdateBlock(self.node, name, val(["third", "wrong"]))
        assert_equal(len(blk.vtx), 3)
        self.node.sendrawtransaction(blk.vtx[1].serialize().hex())
        assert_raises_rpc_error(-26, "txn-mempool-name-error",
                                self.node.sendrawtransaction,
                                blk.vtx[2].serialize().hex())
        self.node.generate(1)
        self.checkName(0, name, val("third"))

        # Submitting two updates at once in a block is fine as long as that does
        # not go through the mempool.
        blk = buildMultiUpdateBlock(self.node, name, val(["fourth", "fifth"]))
        blkHex = blk.serialize(with_witness=False).hex()
        assert_equal(self.node.submitblock(blkHex), None)

        # Verify that the second update took effect, as well as the entire
        # history of the name.
        self.checkName(0, name, val("fifth"))
        values = [h["value"] for h in self.node.name_history(name)]
        assert_equal(values,
                     val(["first", "second", "third", "fourth", "fifth"]))
Beispiel #11
0
    def name_tests(self):
        """
        Run REST tests specific to names.
        """

        # Start by registering a test name.
        name = u"d/some weird.name++ä"
        value = names.val(u"correct value\nwith newlines\nand utf-8: äöü")
        hexValue = value.encode('ascii').hex()
        self.nodes[0].name_register(name, hexValue)
        self.nodes[0].generate(1)
        nameData = self.nodes[0].name_show(name)
        assert_equal(nameData['name_encoding'], 'utf8')
        assert_equal(nameData['name'], name)
        assert_equal(nameData['value_encoding'], 'hex')
        assert_equal(nameData['value'], hexValue)
        # The REST interface explicitly does not include the 'ismine' field
        # that the RPC interface has.  Thus remove the field for the comparison
        # below.
        del nameData['ismine']

        # Different variants of the encoded name that should all work.
        variants = [
            urllib.parse.quote_plus(name), "d/some+weird.name%2b%2B%C3%a4"
        ]

        for encName in variants:
            query = '/name/' + encName

            # Query JSON data of the name.
            data = self.test_rest_request(query, req_type=ReqType.JSON)
            assert_equal(data, nameData)

            # Query plain value.
            res = self.test_rest_request(query,
                                         req_type=ReqType.BIN,
                                         ret_type=RetType.BYTES)
            assert_equal(res.decode("ascii"), value)

            # Query hex value.
            res = self.test_rest_request(query,
                                         req_type=ReqType.HEX,
                                         ret_type=RetType.BYTES)
            assert_equal(res.decode('ascii'), hexValue + "\n")

        # Check invalid encoded names.
        invalid = ['%', '%2', '%2x', '%x2']
        for encName in invalid:
            query = '/name/' + encName
            res = self.test_rest_request(query,
                                         status=http.client.BAD_REQUEST,
                                         req_type=ReqType.BIN,
                                         ret_type=RetType.OBJ)
Beispiel #12
0
    def run_test(self):
        self.node = self.nodes[1]

        # Register two names.  One of them is then sent to an address not owned
        # by the node and one is updated into a pending operation.  That then
        # gives us the basic setup to test the "ismine" field in all the
        # circumstances.
        self.node.name_register("d/a", val("value"))
        self.node.name_register("d/b", val("value"))
        self.node.generate(1)
        otherAddr = self.nodes[0].getnewaddress()
        self.node.name_update("d/b", val("new value"),
                              {"destAddress": otherAddr})
        self.node.generate(1)
        self.node.name_update("d/a", val("new value"))

        # name_show
        assert_equal(self.node.name_show("d/a")['ismine'], True)
        assert_equal(self.node.name_show("d/b")['ismine'], False)

        # name_history
        hist = self.node.name_history("d/a")
        assert_equal(len(hist), 1)
        assert_equal(hist[0]['ismine'], True)
        hist = self.node.name_history("d/b")
        assert_equal(len(hist), 2)
        assert_equal(hist[0]['ismine'], True)
        assert_equal(hist[1]['ismine'], False)

        # name_pending
        pending = self.node.name_pending()
        assert_equal(len(pending), 1)
        p = pending[0]
        assert_equal(p['name'], "d/a")
        assert_equal(p['ismine'], True)

        # name_scan, name_filter, name_list
        self.verifyExpectedIsMineInList(self.node.name_scan())
        self.verifyExpectedIsMineInList(self.node.name_filter())
        self.verifyExpectedIsMineInList(self.node.name_list())
Beispiel #13
0
    def run_test(self):
        node = self.nodes[0]
        node.generate(200)

        node.name_register("d/name")
        node.generate(1)
        self.log.info("Name registered; no value provided.")

        self.checkName(0, "d/name", "{}")
        self.log.info("Value equals empty JSON.")

        node.name_update("d/name", val("1"))
        node.generate(1)
        self.log.info('Value changed to "1"; change is in chain.')

        self.checkName(0, "d/name", val("1"))
        self.log.info('Value equals "1".')

        node.name_update("d/name")
        node.generate(1)
        self.log.info("Updated; no value specified.")

        self.checkName(0, "d/name", val("1"))
        self.log.info('Name was updated. Value still equals "1".')

        node.name_update("d/name", val("2"))
        node.name_update("d/name")
        node.name_update("d/name", val("3"))
        node.generate(1)
        self.log.info('Stack of 3 registrations performed.')

        history = node.name_history("d/name")
        reference = ["{}"] + val(["1", "1", "2", "2", "3"])
        assert (list(map(lambda x: x['value'], history)) == reference)
        self.log.info('Updates correctly consider updates in the mempool.')
Beispiel #14
0
  def run_test (self):
    self.node = self.nodes[0]
    self.node.generate (110)

    # Register a test name.
    name = "d/test"
    new = self.node.name_register (name, val ("first"))

    # Building an update on top of a pending registration.
    self.node.name_update (name, val ("second"))

    # Finalise the registration.
    self.node.generate (1)
    self.checkName (0, name, val ("second"))
    assert_equal (self.node.name_pending (), [])

    # Build two update transactions building on each other.
    txn = []
    txn.append (self.node.name_update (name, val ("third")))
    txn.append (self.node.name_update (name, val ("fourth")))

    # Check that both are in the mempool.
    assert_equal (set (self.node.getrawmempool ()), set (txn))
    pending = self.node.name_pending (name)
    pendingNameVal = [(p["name"], p["value"]) for p in pending]
    assert_equal (pendingNameVal,
                  [(name, val ("third")), (name, val ("fourth"))])

    # Mine transactions and verify the effect.
    self.node.generate (1)
    self.checkName (0, name, val ("fourth"))
    values = [h["value"] for h in self.node.name_history (name)]
    assert_equal (values, val (["first", "second", "third", "fourth"]))

    # Detach the last block and check that both transactions are restored
    # to the mempool.
    self.node.invalidateblock (self.node.getbestblockhash ())
    self.checkName (0, name, val ("second"))
    assert_equal (self.node.name_pending (name), pending)
Beispiel #15
0
    def run_test(self):

        # Go through the full name "life cycle" (name_register and
        # name_update) with the PSBT interface.
        regOp = {
            "op": "name_register",
            "name": "d/my-name",
            "value": val("first value")
        }
        regAddr = self.nodes[0].getnewaddress()
        regOutp, regData = self.rawNameOp(0, None, regAddr, regOp)
        self.nodes[0].generate(1)
        self.checkName(0, "d/my-name", val("first value"))

        updOp = {
            "op": "name_update",
            "name": "d/my-name",
            "value": val("new value")
        }
        updAddr = self.nodes[0].getnewaddress()
        _, updData = self.rawNameOp(0, regOutp, updAddr, updOp)
        self.nodes[0].generate(1)
        self.checkName(0, "d/my-name", val("new value"))

        # Decode name_register.
        data = self.decodePsbt(self.nodes[0], regData["psbt"])
        assert_equal(data["op"], "name_register")
        assert_equal(data["name"], "d/my-name")
        assert_equal(data["value"], val("first value"))

        # Decode name_update.
        data = self.decodePsbt(self.nodes[0], updData["psbt"])
        assert_equal(data["op"], "name_update")
        assert_equal(data["name"], "d/my-name")
        assert_equal(data["value"], val("new value"))

        # Verify range check of vout in namepsbt.
        tx = self.nodes[0].createpsbt([], {})
        assert_raises_rpc_error(-8, "vout is out of range",
                                self.nodes[0].namepsbt, tx, 0, {})
        assert_raises_rpc_error(-8, "vout is out of range",
                                self.nodes[0].namepsbt, tx, -1, {})
Beispiel #16
0
  def test_2of2_multisig (self):
    """
    Tests that holding a name in a 2-of-2 multisig address works as expected.
    One key holder alone cannot sign, but both together can update the name.
    This verifies basic usage of P2SH multisig for names.
    """

    self.log.info ("Testing name held by 2-of-2 multisig...")

    # Construct a 2-of-2 multisig address shared between two nodes.
    pubkeyA = self.getNewPubkey (0)
    pubkeyB = self.getNewPubkey (1)
    multisig = self.nodes[0].addmultisigaddress (2, [pubkeyA, pubkeyB])
    multisig_ = self.nodes[1].addmultisigaddress (2, [pubkeyA, pubkeyB])
    assert_equal (multisig, multisig_)
    p2sh = multisig['address']

    # Register a new name to that address.
    self.nodes[0].name_register ("x/name", val ("value"), {"destAddress": p2sh})
    self.generate (0, 1, syncBefore=False)
    data = self.checkName (0, "x/name", val ("value"))
    assert_equal (data['address'], p2sh)

    # Straight-forward name updating should fail (for both nodes).
    assert_raises_rpc_error (-4, None,
                             self.nodes[0].name_update,
                             "x/name", val ("new value"))
    assert_raises_rpc_error (-4, None,
                             self.nodes[1].name_update,
                             "x/name", val ("new value"))

    # Find some other input to add as fee.
    unspents = self.nodes[0].listunspent ()
    assert len (unspents) > 0
    feeInput = unspents[0]
    changeAddr = self.nodes[0].getnewaddress ()
    nameAmount = Decimal ("0.01")
    changeAmount = feeInput['amount'] - nameAmount

    # Construct the name update as raw transaction.
    addr = self.nodes[1].getnewaddress ()
    inputs = [{"txid": data['txid'], "vout": data['vout']}, feeInput]
    outputs = {changeAddr: changeAmount, addr: nameAmount}
    txRaw = self.nodes[0].createrawtransaction (inputs, outputs)
    op = {"op": "name_update", "name": "x/name", "value": val ("it worked")}
    nameInd = self.rawtxOutputIndex (0, txRaw, addr)
    txRaw = self.nodes[0].namerawtransaction (txRaw, nameInd, op)

    # Sign it partially.
    partial = self.nodes[0].signrawtransactionwithwallet (txRaw['hex'])
    assert not partial['complete']
    assert_raises_rpc_error (-26, None,
                             self.nodes[0].sendrawtransaction, partial['hex'])

    # Sign it fully and transmit it.
    signed = self.nodes[1].signrawtransactionwithwallet (partial['hex'])
    assert signed['complete']
    tx = signed['hex']

    # Manipulate the signature to invalidate it.  This checks whether or
    # not the OP_MULTISIG is actually verified (vs just the script hash
    # compared to the redeem script).
    txData = bytearray (hex_str_to_bytes (tx))
    txData[44] = (txData[44] + 10) % 256
    txManipulated = txData.hex ()

    # Send the tx.  The manipulation should be caught (independently of
    # when strict P2SH checks are enabled, since they are enforced
    # mandatorily in the mempool).
    assert_raises_rpc_error (-26, None,
                             self.nodes[0].sendrawtransaction, txManipulated)
    self.nodes[0].sendrawtransaction (tx)
    self.generate (0, 1, syncBefore=False)

    # Check that it was transferred correctly.
    self.checkName (1, "x/name", val ("it worked"))
    self.nodes[1].name_update ("x/name", val ("changed"))
    self.nodes[1].generate (1)
    self.checkName (1, "x/name", val ("changed"))
Beispiel #17
0
  def run_test (self):
    # Note that the next 50 maturing blocks will be for nodes 0 and 1.
    # Thus we use 2 and 3 for the tests, because their balance
    # will stay constant over time except for our explicit transactions.

    self.checkBalances ()

    # Check that we use legacy addresses.
    # FIXME: Remove once we have segwit.
    addr = self.nodes[0].getnewaddress ()
    info = self.nodes[0].getaddressinfo (addr)
    assert not info['isscript']
    assert not info['iswitness']

    # Register and update a name.  Check changes to the balance.
    regA = self.nodes[2].name_register ("x/name-a", val ("value"))
    regFee = self.getFee (2, regA, nameFee)
    self.generate (0, 1)
    self.checkBalances (regFee)
    updA = self.nodes[2].name_update ("x/name-a", val ("new value"))
    updFee = self.getFee (2, updA)
    self.generate (0, 1)
    self.checkBalances (updFee)

    # Check the transactions.
    self.checkTx (2, regA, zero, -regFee,
                  [['send', 'update: x/name-a', zero, -regFee]])
    self.checkTx (2, updA, zero, -updFee,
                  [['send', 'update: x/name-a', zero, -updFee]])

    # Send a name from 1 to 2 by firstupdate and update.
    addrB = self.nodes[3].getnewaddress ()
    regB = self.nodes[2].name_register ("x/name-b", val ("value"),
                                        {"destAddress": addrB})
    fee = self.getFee (2, regB, nameFee)
    regC = self.nodes[2].name_register ("x/name-c", val ("value"))
    fee += self.getFee (2, regC, nameFee)
    self.generate (0, 1)
    self.checkBalances (fee)
    updC = self.nodes[2].name_update ("x/name-c", val ("new value"),
                                      {"destAddress": addrB})
    fee = self.getFee (2, updC)
    self.generate (0, 1)
    self.checkBalances (fee)

    # Check the receiving transactions on B.
    self.checkTx (3, regB, zero, None,
                  [['receive', 'update: x/name-b', zero, None]])
    self.checkTx (3, updC, zero, None,
                  [['receive', 'update: x/name-c', zero, None]])

    # Use the rawtx API to build a simultaneous name update and currency send.
    # This is done as an atomic name trade.  Note, though, that the
    # logic is a bit confused by "coin join" transactions and thus
    # possibly not exactly what one would expect.

    price = Decimal ("1.0")
    fee = Decimal ("0.01")
    txid = self.atomicTrade ("x/name-a", val ("enjoy"), price, fee, 2, 3)
    self.generate (0, 1)

    self.checkBalances (-price, price + fee)
    self.checkTx (2, txid, price, None,
                  [['receive', "none", price, None]])
    self.checkTx (3, txid, -price, -fee,
                  [['send', "none", -price, -fee],
                   ['send', 'update: x/name-a', zero, -fee]])

    # Test sendtoname RPC command.

    addrDest = self.nodes[2].getnewaddress ()
    self.nodes[0].name_register ("x/destination", val ("value"),
                                 {"destAddress": addrDest})
    self.generate (0, 1)
    self.checkName (3, "x/destination", val ("value"))

    assert_raises_rpc_error (-5, 'name not found',
                             self.nodes[3].sendtoname, "x/non-existant", 10)

    txid = self.nodes[3].sendtoname ("x/destination", 10)
    fee = self.getFee (3, txid)
    self.generate (0, 1)
    self.checkBalances (-10, 10 + fee)

    txid = self.nodes[3].sendtoname ("x/destination", 10, "foo", "bar", True)
    fee = self.getFee (3, txid)
    self.generate (0, 1)
    self.checkBalances (-10 + fee, 10)
Beispiel #18
0
class NameEncodingsTest(NameTestFramework):

    # A basic name that is valid as ASCII and used for tests with differently
    # encoded values.
    name = "d/test"

    # A basic value that is valid as ASCII and used for tests where the
    # name is encoded.
    value = val("test-value")

    # Running counter.  This is used to compute a suffix for registered names
    # to make sure they do not clash with names of previous tests.
    nameCounter = 0

    # Keep track of the currently set encodings.
    nameEncoding = 'ascii'
    valueEncoding = 'ascii'

    def set_test_params(self):
        # We need -namehistory for the test, so use node 1.  Thus we have to
        # have two nodes here.
        self.setup_name_test([[]] * 2)

    def setEncodings(self, nameEnc='ascii', valueEnc='ascii'):
        args = ["-nameencoding=%s" % nameEnc, "-valueencoding=%s" % valueEnc]
        self.restart_node(1, extra_args=args)

        self.nameEncoding = nameEnc
        self.valueEncoding = valueEnc

    def uniqueName(self, baseName, enc='ascii'):
        """
    Uses the running nameCounter to change the baseName into a unique
    name by adding some suffix (depending on the encoding).  The suffix
    will be valid for the encoding, so that a valid name stays valid and
    an invalid name is still invalid (due to the baseName itself).
    """

        suff = "%09d" % self.nameCounter
        if enc == 'hex':
            suff = strToHex(suff)

        self.nameCounter += 1

        return baseName + suff

    def nameRawTx(self, nameInp, nameOp):
        """
    Constructs, signs and sends a raw transaction using namerawtransaction
    with the given (if any) previous name input.

    Returned are the result of namerawtransaction (for name_new), to which the
    final txid and name vout are added.
    """

        ins = []
        if nameInp is not None:
            ins.append({"txid": nameInp['txid'], "vout": nameInp['vout']})
        addr = self.node.getnewaddress()
        out = {addr: Decimal('0.01')}

        rawTx = self.node.createrawtransaction(ins, out)
        nameOpData = self.node.namerawtransaction(rawTx, 0, nameOp)

        rawTx = self.node.fundrawtransaction(nameOpData['hex'])['hex']
        vout = self.rawtxOutputIndex(1, rawTx, addr)
        assert vout is not None

        signed = self.node.signrawtransactionwithwallet(rawTx)
        assert signed['complete']
        txid = self.node.sendrawtransaction(signed['hex'])

        nameOpData['txid'] = txid
        nameOpData['vout'] = vout
        return nameOpData

    def verifyAndMinePendingUpdate(self, name, value, txid):
        """
    Verifies that there is a pending transaction that (first)updates
    name to value with the given txid.  The tx is mined as well, and then
    all the read-only RPCs are checked for it (name_show, name_list, ...).
    """

        data = self.node.name_pending(name)
        assert_equal(len(data), 1)
        assert_equal(data[0]['name_encoding'], self.nameEncoding)
        assert_equal(data[0]['name'], name)
        assert_equal(data[0]['value_encoding'], self.valueEncoding)
        assert_equal(data[0]['value'], value)
        assert_equal(data[0]['txid'], txid)

        self.node.generate(1)
        data = self.node.name_show(name)
        assert_equal(data['name_encoding'], self.nameEncoding)
        assert_equal(data['name'], name)
        assert_equal(data['value_encoding'], self.valueEncoding)
        assert_equal(data['value'], value)
        assert_equal(data['txid'], txid)

        assert_equal(self.node.name_history(name)[-1], data)
        assert_equal(self.node.name_scan(name, 1)[0], data)
        assert_equal(self.node.name_list(name)[0], data)

    def validName(self, baseName, encoding):
        """
    Runs tests asserting that the given string is valid as name in the
    given encoding.
    """

        self.setEncodings(nameEnc=encoding)

        name = self.uniqueName(baseName, encoding)
        txid = self.node.name_register(name, self.value)
        self.verifyAndMinePendingUpdate(name, self.value, txid)

        txid = self.node.name_update(name, self.value)
        self.verifyAndMinePendingUpdate(name, self.value, txid)

        self.node.sendtoname(name, 1)

        # Redo the whole life-cycle now also with raw transactions (with a new
        # unique name).
        name = self.uniqueName(baseName, encoding)

        register = self.nameRawTx(None, {
            "op": "name_register",
            "name": name,
            "value": self.value,
        })
        self.verifyAndMinePendingUpdate(name, self.value, register['txid'])

        upd = self.nameRawTx(register, {
            "op": "name_update",
            "name": name,
            "value": self.value,
        })
        self.verifyAndMinePendingUpdate(name, self.value, upd['txid'])

    def validValue(self, value, encoding):
        """
    Runs tests asserting that the given string is valid as value in the
    given encoding.
    """

        self.setEncodings(valueEnc=encoding)

        name = self.uniqueName(self.name, encoding)
        txid = self.node.name_register(name, value)
        self.verifyAndMinePendingUpdate(name, value, txid)

        txid = self.node.name_update(name, value)
        self.verifyAndMinePendingUpdate(name, value, txid)

        # Redo the whole life-cycle now also with raw transactions (with a new
        # unique name).
        name = self.uniqueName(self.name, encoding)

        register = self.nameRawTx(None, {
            "op": "name_register",
            "name": name,
            "value": value,
        })
        self.verifyAndMinePendingUpdate(name, value, register['txid'])

        upd = self.nameRawTx(register, {
            "op": "name_update",
            "name": name,
            "value": value,
        })
        self.verifyAndMinePendingUpdate(name, value, upd['txid'])

    def invalidName(self, name, encoding):
        """
    Runs tests to check that the various RPC methods treat the given name
    as invalid in the encoding.
    """

        self.setEncodings(nameEnc=encoding)

        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_register, name, self.value)
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_update, name, self.value)

        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_pending, name)
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_show, name)
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_history, name)
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_scan, name)
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_list, name)

        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.sendtoname, name, 1)

        nameReg = {
            "op": "name_register",
            "name": name,
            "value": self.value,
        }
        assert_raises_rpc_error(-1000, "Name/value is invalid", self.nameRawTx,
                                None, nameReg)
        nameUpd = {
            "op": "name_update",
            "name": name,
            "value": self.value,
        }
        assert_raises_rpc_error(-1000, "Name/value is invalid", self.nameRawTx,
                                None, nameUpd)

    def invalidValue(self, value, encoding):
        """
    Runs tests to check that the various RPC methods treat the given value
    as invalid in the encoding.
    """

        self.setEncodings(valueEnc=encoding)

        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_register, self.name, value)
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_update, self.name, value)

        nameReg = {
            "op": "name_register",
            "name": self.name,
            "value": value,
        }
        assert_raises_rpc_error(-1000, "Name/value is invalid", self.nameRawTx,
                                None, nameReg)
        nameUpd = {
            "op": "name_update",
            "name": self.name,
            "value": value,
        }
        assert_raises_rpc_error(-1000, "Name/value is invalid", self.nameRawTx,
                                None, nameUpd)

    def run_test(self):
        self.node = self.nodes[1]

        # Note:  The tests here are mainly important to verify that strings
        # are encoded/decoded at all.  The different possibilities for valid
        # and invalid strings in detail are tested already in the unit test.
        # But since we have the utility methods available, we might just as well
        # call them with different values instead of just once or twice.

        self.log.info("Testing valid names...")
        self.validName("d/abc", "ascii")
        self.validName("d/äöü", "utf8")
        self.validName(strToHex("d/x"), "hex")

        self.log.info("Testing valid values...")
        self.validValue('{"foo":"bar"}', "ascii")
        self.validValue('{"foo":"\x20äöü\\n"}', "utf8")
        self.validValue(strToHex('{"foo":"\x20\x7f"}'), "hex")

        self.log.info("Testing invalid names...")
        self.invalidName("d/\n", "ascii")
        self.invalidName("d/äöü", "ascii")
        self.invalidName("d/\xff", "ascii")
        # We cannot actually test invalid UTF-8 on the "input side", because a
        # string with arbitrary bytes gets UTF-8 encoded when sending to JSON RPC.
        self.invalidName("d", "hex")
        self.invalidName("xx", "hex")

        self.log.info("Testing invalid values...")
        self.invalidValue('{"foo":"\n"}', "ascii")
        self.invalidValue('{"foo":"äöü"}', "ascii")
        self.invalidValue('{"foo":"\xff"}', "ascii")
        self.invalidValue('d', "hex")
        self.invalidValue('xx', "hex")

        self.test_outputSide()
        self.test_walletTx()
        self.test_rpcOption()

    def test_outputSide(self):
        """
    Tests encodings purely on the output-side.  This test registers some
    names/values using hex encoding, and then verifies how those names look like
    when queried with another encoding.
    """

        self.log.info("Different encodings on the output side...")

        nameAscii = self.uniqueName("d/test", "ascii")
        valueAscii = "{}"
        nameHex = self.uniqueName(strToHex("d/äöü"), "hex")
        valueHex = strToHex('{"msg":"äöü"}')

        self.setEncodings(nameEnc="hex", valueEnc="hex")
        txidAscii = self.node.name_register(strToHex(nameAscii), valueHex)
        txidHex = self.node.name_register(nameHex, strToHex(valueAscii))
        self.node.generate(1)

        # Test name_show with ASCII encoding.
        self.setEncodings(nameEnc="ascii", valueEnc="ascii")
        data = self.node.name_show(nameAscii)
        assert_equal(data['name_encoding'], 'ascii')
        assert_equal(data['name'], nameAscii)
        assert 'name_error' not in data
        assert_equal(data['value_encoding'], 'ascii')
        assert 'value' not in data
        assert_equal(data['value_error'], 'invalid data for ascii')
        assert_equal(data['txid'], txidAscii)

        # Test the non-ASCII name in name_scan output.
        found = False
        for data in self.node.name_scan():
            if data['txid'] != txidHex:
                continue
            assert not found
            found = True
            assert_equal(data['name_encoding'], 'ascii')
            assert 'name' not in data
            assert_equal(data['name_error'], 'invalid data for ascii')
            assert_equal(data['value_encoding'], 'ascii')
            assert_equal(data['value'], valueAscii)
            assert 'value_error' not in data
        assert found

        # Test script and transaction decoding.
        txHex = self.node.gettransaction(txidAscii)['hex']
        txAscii = self.node.decoderawtransaction(txHex)
        found = False
        for out in txAscii['vout']:
            if not 'nameOp' in out['scriptPubKey']:
                continue

            assert not found
            found = True

            op = out['scriptPubKey']['nameOp']
            assert_equal(op['op'], 'name_register')
            assert_equal(op['name_encoding'], 'ascii')
            assert_equal(op['name'], nameAscii)
            assert 'name_error' not in op
            assert_equal(op['value_encoding'], 'ascii')
            assert 'value' not in op
            assert_equal(op['value_error'], 'invalid data for ascii')

            script = self.node.decodescript(out['scriptPubKey']['hex'])
            assert_equal(script['nameOp'], op)
        assert found

    def testNameForWalletTx(self, baseName, enc, msgFmt):
        """
    Registers a name and then verifies that the value returned from
    gettransaction / listtransactions as "name operation" matches
    what we expect.

    The expected msgFmt is a format string where the actually used name
    is filled in for %s.
    """

        self.setEncodings(nameEnc=enc)
        name = self.uniqueName(baseName, enc)
        updMsg = msgFmt % name

        txid = self.node.name_register(name, self.value)
        self.node.generate(1)

        data = self.node.gettransaction(txid)
        assert_equal(len(data['details']), 1)
        assert_equal(data['details'][0]['name'], "update: %s" % updMsg)

        found = False
        for tx in self.node.listtransactions():
            if tx['txid'] != txid:
                continue
            assert not found
            found = True
            assert_equal(tx['name'], "update: %s" % updMsg)
        assert found

    def test_walletTx(self):
        """
    Tests the name displayed in listtransactions / gettransaction in the
    wallet when it is a name update.
    """

        self.log.info("Testing name update in wallet...")
        self.testNameForWalletTx("d/test", "ascii", "'%s'")
        self.testNameForWalletTx(strToHex("p/äöü"), "hex", "0x%s")

    def readRpcOption(self, nameAscii, nameUtf8, valueAscii, valueUtf8):
        """
    Tests overriding the name/value encoding through the "options" RPC
    argument for "read" methods.

    This is not a "standalone test" but rather called from test_rpcOption.
    This allows us to reuse the registered names/values from there.
    """

        self.log.info("Testing options-override for read RPCs...")
        self.setEncodings()

        # Helper function that tests a method that retrieves name data.
        # This method can be name_show, name_history or name_scan later on,
        # but the basic testing is always the same.
        def verifyReadMethod(func):
            assert_raises_rpc_error(-3, "Expected type string", func,
                                    nameAscii, {"nameEncoding": 42})
            assert_raises_rpc_error(-3, "Expected type string", func,
                                    nameAscii, {"valueEncoding": 42})
            assert_raises_rpc_error(-1000, "Name/value is invalid", func,
                                    nameUtf8)

            res = func(nameUtf8, {"nameEncoding": "utf8"})
            assert_equal(res['name_encoding'], 'utf8')
            assert_equal(res['name'], nameUtf8)
            assert_equal(res['value_encoding'], 'ascii')
            assert_equal(res['value'], valueAscii)

            res = func(nameAscii)
            assert_equal(res['name_encoding'], 'ascii')
            assert_equal(res['name'], nameAscii)
            assert_equal(res['value_encoding'], 'ascii')
            assert 'value' not in res
            assert_equal(res['value_error'], 'invalid data for ascii')

            res = func(nameAscii, {"valueEncoding": "utf8"})
            assert_equal(res['name_encoding'], 'ascii')
            assert_equal(res['name'], nameAscii)
            assert_equal(res['value_encoding'], 'utf8')
            assert_equal(res['value'], valueUtf8)

        # Verify the actual methods.
        verifyReadMethod(self.node.name_show)

        def nameHistoryWrapper(name, *opt):
            res = self.node.name_history(name, *opt)
            assert_greater_than(len(res), 0)
            return res[-1]

        verifyReadMethod(nameHistoryWrapper)

        def nameScanWrapper(name, *opt):
            res = self.node.name_scan(name, 1, *opt)
            assert_equal(len(res), 1)
            return res[0]

        verifyReadMethod(nameScanWrapper)

        def nameListWrapper(name, *opt):
            res = self.node.name_list(name, *opt)
            assert_equal(len(res), 1)
            return res[0]

        verifyReadMethod(nameListWrapper)

        # Helper function for testing name_list and name_pending without a name.
        # It verifies that an array returned from such a function contains the
        # given name with the given encoding.
        def resultContainsName(res, name, enc):
            for entry in res:
                if 'name' not in entry:
                    continue
                if entry['name'] == name and entry['name_encoding'] == enc:
                    return True
            return False

        # Test that name_list also supports the options argument if no name
        # is given.
        res = self.node.name_list(options={"nameEncoding": "utf8"})
        assert resultContainsName(res, nameUtf8, 'utf8')

        # Create a pending update for name_pending.
        self.node.name_update(nameAscii, valueUtf8, {"valueEncoding": "utf8"})
        self.node.name_update(nameUtf8, valueAscii, {"nameEncoding": "utf8"})

        def namePendingWrapper(name, *opt):
            res = self.node.name_pending(name, *opt)
            assert_equal(len(res), 1)
            return res[0]

        verifyReadMethod(namePendingWrapper)

        # Also test name_pending with options but without name.
        res = self.node.name_pending(options={"nameEncoding": "utf8"})
        assert resultContainsName(res, nameUtf8, 'utf8')

    def test_rpcOption(self):
        """
    Tests overriding the name/value encoding through the "options" RPC
    argument for "write" methods.

    The end of the function also calls a separate routine that verifies
    options overrides for "read" RPCs.
    """

        self.log.info("Testing options-override for write RPCs...")

        # We set the default encodings to ASCII and then use a name/value
        # that is not valid in ASCII with overrides to utf8 for the test.
        self.setEncodings()
        nameAscii = self.uniqueName("d/abc", "ascii")
        nameUtf8 = self.uniqueName("d/äöü", "utf8")
        valueAscii = "{}"
        valueUtf8 = '{"foo":"äöü"}'

        # Type check for the encoding options.
        assert_raises_rpc_error(-3, "Expected type string",
                                self.node.name_update, nameAscii, valueAscii,
                                {"nameEncoding": 42})
        assert_raises_rpc_error(-3, "Expected type string",
                                self.node.name_update, nameAscii, valueAscii,
                                {"valueEncoding": 42})

        # Register the names and verify expected behaviour.
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_register, nameAscii, valueUtf8)
        self.node.name_register(nameAscii, valueUtf8,
                                {"valueEncoding": "utf8"})
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_register, nameUtf8, valueAscii)
        self.node.name_register(nameUtf8, valueAscii, {"nameEncoding": "utf8"})
        self.node.generate(1)

        # update the names and verify also that.
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_update, nameAscii, valueUtf8)
        self.node.name_update(nameAscii, valueUtf8, {"valueEncoding": "utf8"})
        assert_raises_rpc_error(-1000, "Name/value is invalid",
                                self.node.name_update, nameUtf8, valueAscii)
        self.node.name_update(nameUtf8, valueAscii, {"nameEncoding": "utf8"})
        self.node.generate(1)

        # Verify using name_show just to make sure all worked as expected and did
        # not silently just do something wrong.  For this, we change the configured
        # encodings so that we can retrieve utf8 names and values.
        self.setEncodings(nameEnc="utf8", valueEnc="utf8")
        data = self.node.name_show(nameAscii)
        assert_equal(data["value"], valueUtf8)
        data = self.node.name_show(nameUtf8)
        assert_equal(data["value"], valueAscii)

        # Call tests for read-only RPCs.
        self.readRpcOption(nameAscii, nameUtf8, valueAscii, valueUtf8)
Beispiel #19
0
  def run_test (self):
    # Perform name_register's.  Check for too long names exception and
    # too long values.
    addrA = self.nodes[0].getnewaddress ()
    txidA = self.nodes[0].name_register ("x/node-0", val ("value-0"),
                                         {"destAddress": addrA})
    self.nodes[1].name_register ("x/node-1", valueOfLength (2048))
    assert_raises_rpc_error (-8, 'tx-value-too-long',
                             self.nodes[0].name_register,
                             "x/dummy name", valueOfLength (2049))
    self.nodes[0].name_register ("x/" + "x" * 254, val ("value"))
    assert_raises_rpc_error (-8, 'tx-name-too-long',
                             self.nodes[0].name_register,
                             "x/" + "x" * 255, val ("dummy value"))

    # Check for exception with name_history and without -namehistory.
    assert_raises_rpc_error (-1, 'namehistory is not enabled',
                             self.nodes[0].name_history, "x/node-0")

    # Check for mempool conflict detection with registration of "node-0".
    self.sync_with_mode ('both')
    assert_raises_rpc_error (-25, 'is already a pending registration',
                             self.nodes[1].name_register,
                             "x/node-0", val ("foo"))
    
    # Check that the name data appears when the tx are mined.
    self.generate (0, 1)
    data = self.checkName (1, "x/node-0", val ("value-0"))
    assert_equal (data['address'], addrA)
    assert_equal (data['txid'], txidA)
    assert_equal (data['height'], 201)

    self.checkNameHistory (1, "x/node-0", [val ("value-0")])
    self.checkNameHistory (1, "x/node-1", [valueOfLength (2048)])

    # Check for disallowed registration when the name is active.
    self.checkName (1, "x/node-0", val ("value-0"))
    assert_raises_rpc_error (-25, 'exists already',
                             self.nodes[1].name_register,
                             "x/node-0", val ("stolen"))

    # Check basic updating.
    self.nodes[0].name_register ("x/test-name", val ("test-value"))
    self.generate (0, 1)
    assert_raises_rpc_error (-8, 'tx-value-too-long',
                             self.nodes[0].name_update,
                             "x/test-name",
                             valueOfLength (2049))
    self.nodes[0].name_update ("x/test-name", valueOfLength (2048))
    self.checkName (0, "x/test-name", val ("test-value"))
    self.generate (0, 1)
    self.checkName (1, "x/test-name", valueOfLength (2048))
    self.checkNameHistory (1, "x/test-name",
                           [val ("test-value"), valueOfLength (2048)])

    addrB = self.nodes[1].getnewaddress ()
    self.nodes[0].name_update ("x/test-name", val ("sent"),
                               {"destAddress": addrB})
    self.generate (0, 1)
    data = self.checkName (0, "x/test-name", val ("sent"))
    assert_equal (data['address'], addrB)
    self.nodes[1].name_update ("x/test-name", val ("updated"))
    self.generate (0, 1)
    data = self.checkName (0, "x/test-name", val ("updated"))
    self.checkNameHistory (1, "x/test-name",
                           [val ("test-value"), valueOfLength (2048),
                            val ("sent"), val ("updated")])

    # Invalid updates.
    assert_raises_rpc_error (-25, 'this name can not be updated',
                             self.nodes[1].name_update,
                             "x/wrong-name", val ("foo"))
    assert_raises_rpc_error (-4, 'Input tx not found in wallet',
                             self.nodes[0].name_update,
                             "x/test-name", val ("stolen?"))

    # Reject update when another update is pending.
    self.nodes[1].name_update ("x/test-name", val ("value"))
    assert_raises_rpc_error (-25, 'is already a pending update for this name',
                             self.nodes[1].name_update,
                             "x/test-name", val ("new value"))
    self.generate (0, 1)
    data = self.checkName (0, "x/test-name", val ("value"))
    self.checkNameHistory (1, "x/test-name",
                           [val ("test-value"), valueOfLength (2048),
                            val ("sent"), val ("updated"), val ("value")])
    
    # Test that name updates are even possible with less balance in the wallet
    # than what is locked in a name (0.01 NMC).  There was a bug preventing
    # this from working.
    self.generate (0, 50)  # make node1 not get maturing rewards
    balance = self.nodes[1].getbalance ()
    keep = Decimal ("0.001")
    addr0 = self.nodes[0].getnewaddress ()
    self.nodes[1].sendtoaddress (addr0, balance - keep, "", "", True)
    addr1 = self.nodes[1].getnewaddress ()
    self.nodes[0].name_update ("x/node-0", val ("value"),
                               {"destAddress": addr1})
    self.generate (0, 1)
    assert_equal (self.nodes[1].getbalance (), keep)
    self.nodes[1].name_update ("x/node-0", val ("new value"))
    self.generate (0, 1)
    self.checkName (1, "x/node-0", val ("new value"))
    assert self.nodes[1].getbalance () < Decimal ("0.01")
Beispiel #20
0
    def run_test(self):
        # Register a name that can then be update'd in the mempool.
        self.nodes[1].name_register("x/a", val("old-value-a"))
        self.generate(0, 1)

        # Start a new name registration so we can first_update it.
        txb = self.nodes[2].name_register("x/b", val("value-b"))

        # Perform the unconfirmed updates.  Include a currency transaction
        # to check that it is not shown.
        txa = self.nodes[1].name_update("x/a", val("value-a"))
        addrC = self.nodes[3].getnewaddress()
        self.nodes[2].sendtoaddress(addrC, 1)

        # Check that name_show still returns the old value.
        self.checkName(0, "x/a", val("old-value-a"))

        # Check sizes of mempool against name_pending.
        self.sync_with_mode('mempool')
        mempool = self.nodes[0].getrawmempool()
        assert_equal(len(mempool), 3)
        pending = self.nodes[0].name_pending()
        assert_equal(len(pending), 2)

        # Check result of full name_pending (called above).
        for op in pending:
            assert op['txid'] in mempool
            assert not op['ismine']
            if op['name'] == 'x/a':
                assert_equal(op['op'], 'name_update')
                assert_equal(op['value'], val('value-a'))
                assert_equal(op['txid'], txa)
            elif op['name'] == 'x/b':
                assert_equal(op['op'], 'name_register')
                assert_equal(op['value'], val('value-b'))
                assert_equal(op['txid'], txb)
            else:
                assert False

        # Check name_pending with name filter that does not match any name.
        pending = self.nodes[0].name_pending('x/does not exist')
        assert_equal(pending, [])

        # Check name_pending with name filter and ismine.
        self.checkPendingName(1, 'x/a', 'name_update', val('value-a'), txa,
                              True)
        self.checkPendingName(2, 'x/a', 'name_update', val('value-a'), txa,
                              False)

        # We don't know the golden value for vout, as this is randomised.  But we
        # can store the output now and then verify it with name_show after the
        # update has been mined.
        pending = self.nodes[0].name_pending('x/a')
        assert_equal(len(pending), 1)
        pending = pending[0]
        assert 'vout' in pending

        # Mine a block and check that all mempool is cleared.
        self.generate(0, 1)
        assert_equal(self.nodes[3].getrawmempool(), [])
        assert_equal(self.nodes[3].name_pending(), [])

        # Verify vout from before against name_show.
        confirmed = self.nodes[0].name_show('x/a')
        assert_equal(pending['vout'], confirmed['vout'])

        # Send a name and check that ismine is handled correctly.
        tx = self.nodes[1].name_update('x/a', val('sent-a'),
                                       {"destAddress": addrC})
        self.sync_with_mode('mempool')
        self.checkPendingName(1, 'x/a', 'name_update', val('sent-a'), tx,
                              False)
        self.checkPendingName(3, 'x/a', 'name_update', val('sent-a'), tx, True)
Beispiel #21
0
    def run_test(self):
        node = self.nodes[0]
        node.generate(200)

        # Register a name prior to forking the chain.  This is used
        # to test unrolling of updates (as opposed to registrations).
        node.name_register("x/a", val("initial value"))
        node.generate(1)

        # Build a long chain that registers "b" (to clash with
        # the same registration on the short chain).
        node.name_register("x/b", val("b long"))
        undoBlk = node.generate(20)[0]
        self.checkName(0, "x/a", val("initial value"))
        self.checkName(0, "x/b", val("b long"))
        self.checkNameHistory(0, "x/a", val(["initial value"]))
        self.checkNameHistory(0, "x/b", val(["b long"]))
        node.invalidateblock(undoBlk)

        # Build a short chain with an update to "a" and registrations.
        assert_equal(node.getrawmempool(), [])
        node.generate(1)
        txidA = node.name_update("x/a", val("changed value"))
        txidB = node.name_register("x/b", val("b short"))
        txidC = node.name_register("x/c", val("c registered"))
        node.generate(1)
        self.checkName(0, "x/a", val("changed value"))
        self.checkName(0, "x/b", val("b short"))
        self.checkName(0, "x/c", val("c registered"))
        self.checkNameHistory(0, "x/a", val(["initial value",
                                             "changed value"]))
        self.checkNameHistory(0, "x/b", val(["b short"]))
        self.checkNameHistory(0, "x/c", val(["c registered"]))

        # Reconsider the long chain to reorg back to it.
        node.reconsiderblock(undoBlk)
        self.checkName(0, "x/a", val("initial value"))
        self.checkName(0, "x/b", val("b long"))
        self.checkNameHistory(0, "x/a", val(["initial value"]))
        self.checkNameHistory(0, "x/b", val(["b long"]))
        assert_raises_rpc_error(-4, 'name not found', node.name_show, "x/c")
        assert_raises_rpc_error(-4, 'name not found', node.name_history, "x/c")

        # Mine another block.  This should at least perform the
        # non-conflicting transactions.
        assert_equal(set(node.getrawmempool()), set([txidA, txidC]))
        node.generate(1)
        self.checkName(0, "x/a", val("changed value"))
        self.checkName(0, "x/b", val("b long"))
        self.checkName(0, "x/c", val("c registered"))
        self.checkNameHistory(0, "x/a", val(["initial value",
                                             "changed value"]))
        self.checkNameHistory(0, "x/b", val(["b long"]))
        self.checkNameHistory(0, "x/c", val(["c registered"]))

        # Check that the conflicting tx got handled properly.
        assert_equal(node.getrawmempool(), [])
        data = node.gettransaction(txidB)
        assert data['confirmations'] <= 0
Beispiel #22
0
  def run_test (self):
    self.node = self.nodes[0]

    # Mine a block so that we're no longer in initial download.
    self.node.generate (1)

    # Initially, all should be empty.
    assert_equal (self.node.name_scan (), [])
    assert_equal (self.node.name_scan ("foo", 10), [])
    assert_equal (self.node.name_filter (), [])
    assert_equal (self.node.name_filter ("", 0, 0, 0, "stat"),
                  {"blocks": 201,"count": 0})

    # Register some names with various data and heights.
    # Using both "aa" and "b" ensures that we can also check for the expected
    # comparison order between string length and lexicographic ordering.

    self.node.name_register ("x/a", val ("wrong value"))
    self.node.name_register ("x/aa", val ("value aa"))
    self.node.name_register ("x/b", val ("value b"))
    self.node.generate (15)
    self.node.name_register ("x/c", val ("value c"))
    self.node.name_update ("x/a", val ("value a"))
    self.node.generate (20)

    # Check the expected name_scan data values.
    scan = self.node.name_scan ()
    assert_equal (len (scan), 4)
    self.checkNameData (scan[0], "x/a", val ("value a"))
    self.checkNameData (scan[1], "x/b", val ("value b"))
    self.checkNameData (scan[2], "x/c", val ("value c"))
    self.checkNameData (scan[3], "x/aa", val ("value aa"))

    # Check for expected names in various name_scan calls.
    self.checkList (self.node.name_scan (), ["x/a", "x/b", "x/c", "x/aa"])
    self.checkList (self.node.name_scan ("", 0), [])
    self.checkList (self.node.name_scan ("", -1), [])
    self.checkList (self.node.name_scan ("x/b"), ["x/b", "x/c", "x/aa"])
    self.checkList (self.node.name_scan ("x/zz"), [])
    self.checkList (self.node.name_scan ("", 2), ["x/a", "x/b"])
    self.checkList (self.node.name_scan ("x/b", 1), ["x/b"])

    # Check the expected name_filter data values.
    scan = self.node.name_scan ()
    assert_equal (len (scan), 4)
    self.checkNameData (scan[0], "x/a", val ("value a"))
    self.checkNameData (scan[1], "x/b", val ("value b"))
    self.checkNameData (scan[2], "x/c", val ("value c"))
    self.checkNameData (scan[3], "x/aa", val ("value aa"))

    # Check for expected names in various name_filter calls.
    height = self.node.getblockcount ()
    self.checkList (self.node.name_filter (), ["x/a", "x/b", "x/c", "x/aa"])
    self.checkList (self.node.name_filter ("[ac]"), ["x/a", "x/c", "x/aa"])
    self.checkList (self.node.name_filter ("", 10), [])
    self.checkList (self.node.name_filter ("", 30), ["x/a", "x/c"])
    self.checkList (self.node.name_filter ("", 0, 0, 0),
                    ["x/a", "x/b", "x/c", "x/aa"])
    self.checkList (self.node.name_filter ("", 0, 0, 1), ["x/a"])
    self.checkList (self.node.name_filter ("", 0, 1, 4),
                    ["x/b", "x/c", "x/aa"])
    self.checkList (self.node.name_filter ("", 0, 4, 4), [])
    assert_equal (self.node.name_filter ("", 30, 0, 0, "stat"),
                  {"blocks": height, "count": 2})

    # Check test for "stat" argument.
    assert_raises_rpc_error (-8, "must be the literal string 'stat'",
                             self.node.name_filter, "", 0, 0, 0, "string")
Beispiel #23
0
  def run_test (self):
    self.node = self.nodes[0]
    self.node.generate (110)

    # Register a test name.
    name = "d/test"
    new = self.node.name_register (name, val ("first"))

    # Building an update on top of a pending registration.
    self.node.name_update (name, val ("second"))

    # Finalise the registration.
    self.node.generate (1)
    self.checkName (0, name, val ("second"))
    assert_equal (self.node.name_pending (), [])

    # Build two update transactions building on each other.
    txn = []
    txn.append (self.node.name_update (name, val ("third")))
    txn.append (self.node.name_update (name, val ("fourth")))

    # Check that both are in the mempool.
    assert_equal (set (self.node.getrawmempool ()), set (txn))
    pending = self.node.name_pending (name)
    pendingNameVal = [(p["name"], p["value"]) for p in pending]
    assert_equal (pendingNameVal,
                  [(name, val ("third")), (name, val ("fourth"))])

    # Mine transactions and verify the effect.
    self.node.generate (1)
    self.checkName (0, name, val ("fourth"))
    values = [h["value"] for h in self.node.name_history (name)]
    assert_equal (values, val (["first", "second", "third", "fourth"]))

    # Detach the last block and check that both transactions are restored
    # to the mempool.
    blk = self.node.getbestblockhash ()
    self.node.invalidateblock (blk)
    self.checkName (0, name, val ("second"))
    assert_equal (self.node.name_pending (name), pending)
    self.node.reconsiderblock (blk)
    assert_equal (self.node.name_pending (), [])

    # Perform a long chain of updates, which should run into the chain limit.
    for n in range (10):
      self.node.name_update (name, val ("value %d" % n))
    assert_equal (len (self.node.name_pending (name)), 10)
    assert_raises_rpc_error (-25, "too many pending operations",
                             self.node.name_update, name, val ("other update"))
Beispiel #24
0
    def run_test(self):
        # Register a name prior to forking the chain.  This is used
        # to test unrolling of updates (as opposed to registrations).
        self.nodes[3].name_register("x/a", val("initial value"))
        self.generate(0, 1)

        # Split the network.
        self.split_network()

        # Build a long chain that registers "b" (to clash with
        # the same registration on the short chain).
        self.generate(0, 2)
        self.nodes[0].name_register("x/b", val("b long"))
        self.generate(0, 2)
        self.checkName(0, "x/a", val("initial value"))
        self.checkName(0, "x/b", val("b long"))
        self.checkNameHistory(1, "x/a", [val("initial value")])
        self.checkNameHistory(1, "x/b", [val("b long")])

        # Build a short chain with an update to "a" and registrations.
        self.generate(3, 1)
        txidB = self.nodes[3].name_register("x/b", val("b short"))
        self.nodes[3].name_register("x/c", val("c registered"))
        self.nodes[3].name_update("x/a", val("changed value"))
        self.generate(3, 1)
        self.checkName(3, "x/a", val("changed value"))
        self.checkName(3, "x/b", val("b short"))
        self.checkName(3, "x/c", val("c registered"))
        self.checkNameHistory(
            2, "x/a",
            [val("initial value"), val("changed value")])
        self.checkNameHistory(2, "x/b", [val("b short")])
        self.checkNameHistory(2, "x/c", [val("c registered")])

        # Join the network and let the long chain prevail.
        self.join_network()
        self.checkName(3, "x/a", val("initial value"))
        self.checkName(3, "x/b", val("b long"))
        self.checkNameHistory(2, "x/a", [val("initial value")])
        self.checkNameHistory(2, "x/b", [val("b long")])
        assert_raises_rpc_error(-4, 'name not found', self.nodes[3].name_show,
                                "x/c")
        assert_raises_rpc_error(-4, 'name not found',
                                self.nodes[2].name_history, "x/c")

        # Mine another block.  This should at least perform the
        # non-conflicting transactions.  It is done on node 3 so
        # that these tx are actually in the mempool.
        self.generate(3, 1, False)
        self.checkName(3, "x/a", val("changed value"))
        self.checkName(3, "x/b", val("b long"))
        self.checkName(3, "x/c", val("c registered"))
        self.checkNameHistory(
            2, "x/a",
            [val("initial value"), val("changed value")])
        self.checkNameHistory(2, "x/b", [val("b long")])
        self.checkNameHistory(2, "x/c", [val("c registered")])

        # Check that the conflicting tx got pruned from the mempool properly.
        assert_equal(self.nodes[0].getrawmempool(), [])
        assert_equal(self.nodes[3].getrawmempool(), [])
        data = self.nodes[3].gettransaction(txidB)
        assert data['confirmations'] <= 0
Beispiel #25
0
  def test_namescript_p2sh (self):
    """
    Tests how name prefixes interact with P2SH outputs and redeem scripts.
    """

    self.log.info ("Testing name prefix and P2SH interactions...")

    # This test only needs a single node and no syncing.
    node = self.nodes[0]

    name = "d/p2sh"
    value = val ("value")
    node.name_register (name, value)
    node.generate (1)
    baseHeight = node.getblockcount ()
    self.checkNameWithHeight (0, name, value, baseHeight)

    # Prepare some scripts and P2SH addresses we use later.  We build the
    # name script prefix for an update to our testname, so that we can build
    # P2SH redeem scripts with (or without) it.

    nameBytes = codecs.encode (name, 'ascii')
    valueBytes = codecs.encode (value, 'ascii')
    updOps = [OP_NAME_UPDATE, nameBytes, valueBytes, OP_2DROP, OP_DROP]
    anyoneOps = [OP_TRUE]

    updScript = CScript (updOps)
    anyoneScript = CScript (anyoneOps)
    updAndAnyoneScript = CScript (updOps + anyoneOps)

    anyoneAddr = self.getP2SH (0, anyoneScript)
    updAndAnyoneAddr = self.getP2SH (0, updAndAnyoneScript)

    # Send the name to the anyone-can-spend name-update script directly.
    # This is expected to update the name (verifies the update script is good).

    tx = CTransaction ()
    data = node.name_show (name)
    tx.vin.append (CTxIn (COutPoint (int (data['txid'], 16), data['vout'])))
    tx.vout.append (CTxOut (COIN // 100, updAndAnyoneScript))
    txHex = tx.serialize ().hex ()

    txHex = node.fundrawtransaction (txHex)['hex']
    signed = node.signrawtransactionwithwallet (txHex)
    assert signed['complete']
    node.sendrawtransaction (signed['hex'])

    node.generate (1)
    self.checkNameWithHeight (0, name, value, baseHeight + 1)

    # Send the name to the anyone-can-spend P2SH address.  This should just
    # work fine and update the name.
    self.updateAnyoneCanSpendName (0, name, val ("value2"), anyoneAddr, [])
    node.generate (1)
    self.checkNameWithHeight (0, name, val ("value2"), baseHeight + 2)

    # Send a coin to the P2SH address with name prefix.  This should just
    # work fine but not update the name.  We should be able to spend the coin
    # again from that address.

    txid = node.sendtoaddress (updAndAnyoneAddr, 2)
    tx = node.getrawtransaction (txid)
    ind = self.rawtxOutputIndex (0, tx, updAndAnyoneAddr)
    node.generate (1)

    ins = [{"txid": txid, "vout": ind}]
    addr = node.getnewaddress ()
    out = {addr: 1}
    tx = node.createrawtransaction (ins, out)
    tx = self.setScriptSigOps (tx, 0, [updAndAnyoneScript])

    node.sendrawtransaction (tx, True)
    node.generate (1)
    self.checkNameWithHeight (0, name, val ("value2"), baseHeight + 2)

    found = False
    for u in node.listunspent ():
      if u['address'] == addr and u['amount'] == 1:
        found = True
        break
    if not found:
      raise AssertionError ("Coin not sent to expected address")

    # Send the name to the P2SH address with name prefix and then spend it
    # again.  Spending should work fine, and the name should just be updated
    # ordinarily; the name prefix of the redeem script should have no effect.
    self.updateAnyoneCanSpendName (0, name, val ("value3"), updAndAnyoneAddr,
                                   [anyoneScript])
    node.generate (1)
    self.checkNameWithHeight (0, name, val ("value3"), baseHeight + 5)
    self.updateAnyoneCanSpendName (0, name, val ("value4"), anyoneAddr,
                                   [updAndAnyoneScript])
    node.generate (1)
    self.checkNameWithHeight (0, name, val ("value4"), baseHeight + 6)
Beispiel #26
0
  def run_test (self):
    # Decode name_register.
    reg = self.nodes[0].name_register ("x/my-name", val ("initial value"))
    self.nodes[0].generate (1)
    data = self.decodeNameTx (0, reg)
    assert_equal (data['op'], "name_register")
    assert_equal (data['name'], "x/my-name")
    assert_equal (data['value'], val ("initial value"))

    # Decode name_update.
    upd = self.nodes[0].name_update ("x/my-name", val ("new value"))
    self.nodes[0].generate (1)
    data = self.decodeNameTx (0, upd)
    assert_equal (data['op'], "name_update")
    assert_equal (data['name'], "x/my-name")
    assert_equal (data['value'], val ("new value"))

    # Go through the full name "life cycle" (name_register and name_update)
    # with raw transactions.
    regOp = {"op": "name_register", "name": "x/raw-test-name",
             "value": val ("first value")}
    regAddr = self.nodes[0].getnewaddress ()
    regOutp, _ = self.rawNameOp (0, None, regAddr, regOp)
    self.nodes[0].generate (1)
    self.checkName (0, "x/raw-test-name", val ("first value"))

    updOp = {"op": "name_update", "name": "x/raw-test-name",
             "value": val ("new value")}
    updAddr = self.nodes[0].getnewaddress ()
    self.rawNameOp (0, regOutp, updAddr, updOp)
    self.nodes[0].generate (1)
    self.checkName (0, "x/raw-test-name", val ("new value"))

    # Verify range check of vout in namerawtransaction.
    tx = self.nodes[0].createrawtransaction ([], {})
    assert_raises_rpc_error (-8, "vout is out of range",
                             self.nodes[0].namerawtransaction, tx, 0, {})
    assert_raises_rpc_error (-8, "vout is out of range",
                             self.nodes[0].namerawtransaction, tx, -1, {})

    # Perform a rawtx name update together with an atomic currency transaction.
    # We send the test name from 0 to 1 and some coins from 1 to 0.  In other
    # words, perform an atomic name trade.
    self.sync_blocks ()
    balanceA = self.nodes[0].getbalance ()
    balanceB = self.nodes[1].getbalance ()
    price = Decimal ("1.0")
    fee = Decimal ("0.01")

    self.atomicTrade ("x/my-name", val ("enjoy"), price, fee, 0, 1)
    self.nodes[0].generate (1)
    self.sync_blocks ()

    data = self.checkName (0, "x/my-name", val ("enjoy"))
    info = self.nodes[1].getaddressinfo (data["address"])
    assert info['ismine']
    data = self.nodes[0].name_list ("x/my-name")
    assert_equal (len (data), 1)
    assert_equal (data[0]["name"], "x/my-name")
    assert_equal (data[0]["ismine"], False)
    data = self.nodes[1].name_list ("x/my-name")
    assert_equal (len (data), 1)
    assert_equal (data[0]["name"], "x/my-name")
    assert_equal (data[0]["ismine"], True)

    # Node 0 gets a block matured, take this into account.
    assert_equal (balanceA + price + Decimal ("50"),
                  self.nodes[0].getbalance ())
    assert_equal (balanceB - price - fee, self.nodes[1].getbalance ())

    # Try to construct and relay a transaction that updates two names at once.
    # This used to crash the client, #116.  It should lead to an error (as such
    # a transaction is invalid), but not a crash.
    self.nodes[0].name_register ("x/a", val ("value a"))
    self.nodes[0].name_register ("x/b", val ("value b"))
    self.nodes[0].generate (1)

    inA, outA = self.constructUpdateTx (0, "x/a", val ("new value a"))
    inB, outB = self.constructUpdateTx (0, "x/b", val ("new value b"))

    tx = outA[:8]      # version
    tx += '02'         # number of txin
    tx += inA[10:-10]  # first txin
    tx += inB[10:-10]  # second txin
    tx += '02'         # number of txout
    tx += outA[12:-8]  # first txout
    tx += outB[12:-8]  # second txout
    tx += '00' * 4     # locktime

    signed = self.nodes[0].signrawtransactionwithwallet (tx)
    assert_raises_rpc_error (-26, None,
                             self.nodes[0].sendrawtransaction, signed['hex'])
Beispiel #27
0
    def run_test(self):
        node = self.nodes[0]
        node.generate(50)
        self.generateToOther(150)

        # Perform name_register's.  Check for too long names exception and
        # too long values.
        addrA = node.getnewaddress()
        txidA = node.name_register("x/name-0", val("value-0"),
                                   {"destAddress": addrA})
        node.name_register("x/name-1", valueOfLength(2048))
        assert_raises_rpc_error(-8, 'tx-value-too-long', node.name_register,
                                "x/dummy name", valueOfLength(2049))
        node.name_register("x/" + "x" * 254, val("value"))
        assert_raises_rpc_error(-8, 'tx-name-too-long', node.name_register,
                                "x/" + "x" * 255, val("dummy value"))

        # Check for exception with name_history and without -namehistory.
        self.sync_blocks()
        assert_raises_rpc_error(-1, 'namehistory is not enabled',
                                self.nodes[1].name_history, "x/name-0")

        # Check for mempool conflict detection with registration of "name-0".
        assert_raises_rpc_error(-25, 'is already a pending registration',
                                node.name_register, "x/name-0", val("foo"))

        # Check that the name data appears when the tx are mined.
        assert_raises_rpc_error(-4, 'name not found', node.name_show,
                                "x/name-0")
        assert_raises_rpc_error(-4, 'name not found', node.name_history,
                                "x/name-0")
        self.generateToOther(1)
        data = self.checkName(1, "x/name-0", val("value-0"))
        assert_equal(data['address'], addrA)
        assert_equal(data['txid'], txidA)
        assert_equal(data['height'], 201)

        self.checkNameHistory(0, "x/name-0", [val("value-0")])
        self.checkNameHistory(0, "x/name-1", [valueOfLength(2048)])

        # Check for disallowed registration when the name is active.
        self.checkName(0, "x/name-0", val("value-0"))
        assert_raises_rpc_error(-25, 'exists already', node.name_register,
                                "x/name-0", val("stolen"))

        # Check basic updating.
        node.name_register("x/test-name", val("test-value"))
        self.generateToOther(1)
        assert_raises_rpc_error(-8, 'tx-value-too-long', node.name_update,
                                "x/test-name", valueOfLength(2049))
        node.name_update("x/test-name", valueOfLength(2048))
        self.checkName(0, "x/test-name", val("test-value"))
        self.generateToOther(1)
        self.checkName(0, "x/test-name", valueOfLength(2048))
        self.checkNameHistory(
            0, "x/test-name",
            [val("test-value"), valueOfLength(2048)])

        # In Xaya, we also verify that the value must be valid JSON.
        # It is specifically allowed to have JSON objects with duplicated keys.
        # Verify this is true.
        duplicateKeys = '{"x": 1, "x": 2}'
        node.name_update("x/test-name", duplicateKeys)
        self.generateToOther(1)
        self.checkName(0, "x/test-name", duplicateKeys)
        self.checkNameHistory(0, "x/test-name", [
            val("test-value"),
            valueOfLength(2048),
            duplicateKeys,
        ])

        addrOther = self.nodes[1].getnewaddress()
        node.name_update("x/test-name", val("sent"),
                         {"destAddress": addrOther})
        self.generateToOther(1)
        self.sync_blocks()
        data = self.checkName(0, "x/test-name", val("sent"))
        assert_equal(data['address'], addrOther)
        self.nodes[1].name_update("x/test-name", val("updated"))
        self.nodes[1].generate(1)
        self.sync_blocks()
        data = self.checkName(1, "x/test-name", val("updated"))
        self.checkNameHistory(0, "x/test-name", [
            val("test-value"),
            valueOfLength(2048),
            duplicateKeys,
            val("sent"),
            val("updated"),
        ])

        # Invalid updates.
        assert_raises_rpc_error(-25, 'this name can not be updated',
                                node.name_update, "x/wrong-name", val("foo"))
        assert_raises_rpc_error(-4, 'Input tx not found in wallet',
                                node.name_update, "x/test-name",
                                val("stolen?"))

        # Test that name updates are even possible with less balance in the wallet
        # than what is locked in a name (0.01 NMC).  There was a bug preventing
        # this from working.
        balance = node.getbalance()
        keep = Decimal("0.001")
        addrOther = self.nodes[1].getnewaddress()
        node.sendtoaddress(addrOther, balance - keep, "", "", True)
        self.generateToOther(1)
        assert_equal(node.getbalance(), keep)
        node.name_update("x/name-1", val("new value"))
        self.generateToOther(1)
        assert node.getbalance() < Decimal("0.01")
        self.checkName(0, "x/name-1", val("new value"))
Beispiel #28
0
  def run_test (self):
    self.nodes[0].createwallet ("")
    self.nodes[1].createwallet ("")
    addr1 = self.nodes[0].getnewaddress ()
    self.nodes[0].generatetoaddress (20, addr1)
    self.sync_blocks ()
    addr2 = self.nodes[1].getnewaddress ()
    self.nodes[1].generatetoaddress (120, addr2)
    self.sync_blocks ()

    # We perform an atomic name trade between our two nodes, and make sure
    # that the btxid changes with important tx details but not when the
    # parties sign the transaction.

    self.nodes[0].name_register ("p/test", val ("0"))
    self.nodes[0].generate (1)
    data = self.nodes[0].name_show ("p/test")
    assert_equal (data["address"][0], "c")
    assert not data["address"].startswith ("chirt")

    utxos = self.nodes[1].listunspent ()[:2]
    value = None
    for u in utxos:
      assert u["address"].startswith ("chirt")
      if value is None or value > u["amount"]:
        value = u["amount"]
    value -= 1
    assert_greater_than (value, 10)

    addr1 = self.nodes[0].getnewaddress ()
    addr1p = self.nodes[0].getnewaddress ()
    addr2 = self.nodes[1].getnewaddress ()

    unsigned = self.build_tx (utxos[0], {addr1: value},
                              "p/test", addr2, val ("1"))

    changed = self.build_tx (utxos[1], {addr1: value},
                             "p/test", addr2, val ("1"))
    assert changed["btxid"] != unsigned["btxid"]

    changed = self.build_tx (utxos[0], {addr1p: value},
                             "p/test", addr2, val ("1"))
    assert changed["btxid"] != unsigned["btxid"]

    changed = self.build_tx (utxos[0], {addr1: value - 1},
                             "p/test", addr2, val ("1"))
    assert changed["btxid"] != unsigned["btxid"]

    changed = self.build_tx (utxos[0], {addr1: value},
                             "p/test", addr2, val ("2"))
    assert changed["btxid"] != unsigned["btxid"]

    partial1 = self.sign (self.nodes[0], unsigned)
    assert_equal (partial1["complete"], False)
    assert_equal (partial1["btxid"], unsigned["btxid"])
    assert partial1["txid"] != unsigned["txid"]
    assert partial1["hash"] != unsigned["hash"]

    partial2 = self.sign (self.nodes[1], unsigned)
    assert_equal (partial2["complete"], False)
    assert_equal (partial2["btxid"], unsigned["btxid"])
    assert_equal (partial2["txid"], unsigned["txid"])
    assert partial2["hash"] != unsigned["hash"]

    full = self.sign (self.nodes[1], partial1)
    assert_equal (full["complete"], True)
    assert_equal (full["btxid"], unsigned["btxid"])
    assert full["txid"] != unsigned["txid"]
    assert full["hash"] != unsigned["hash"]
Beispiel #29
0
  def run_test (self):
    assert_equal (self.nodes[0].name_list (), [])
    assert_equal (self.nodes[1].name_list (), [])

    self.nodes[0].name_register ("x/name", val ("value"))
    self.nodes[0].generate (1)

    arr = self.nodes[0].name_list ()
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("value"), True)

    self.sync_blocks ()
    assert_equal (self.nodes[1].name_list ("x/name"), [])

    # Transfer the name away and check that name_list updates accordingly.
    addrB = self.nodes[1].getnewaddress ()
    self.nodes[0].name_update ("x/name", val ("enjoy"), {"destAddress":addrB})
    arr = self.nodes[0].name_list ()
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("value"), True)

    self.nodes[0].generate (1)
    arr = self.nodes[0].name_list ()
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("enjoy"), False)

    self.sync_blocks ()
    arr = self.nodes[1].name_list ()
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("enjoy"), True)

    # Updating the name in the new wallet shouldn't change the
    # old wallet's name_list entry.
    self.nodes[1].name_update ("x/name", val ("new value"))
    self.nodes[1].generate (1)
    arr = self.nodes[1].name_list ("x/name")
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("new value"), True)

    self.sync_blocks ()
    arr = self.nodes[0].name_list ()
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("enjoy"), False)

    # Transfer it back and see that it updates in wallet A.
    addrA = self.nodes[0].getnewaddress ()
    self.nodes[1].name_update ("x/name", val ("sent"), {"destAddress": addrA})
    self.nodes[1].generate (1)

    self.sync_blocks ()
    arr = self.nodes[0].name_list ()
    assert_equal (len (arr), 1)
    self.checkNameStatus (arr[0], "x/name", val ("sent"), True)
  def run_test (self):
    self.node = self.nodes[0]

    # Mine a block so that we're no longer in initial download.
    self.node.generate (1)

    # Initially, all should be empty.
    assert_equal (self.node.name_scan (), [])
    assert_equal (self.node.name_scan ("foo", 10), [])

    # Register some names with various data and heights.
    # Using both "aa" and "b" ensures that we can also check for the expected
    # comparison order between string length and lexicographic ordering.
    self.node.name_register ("d/a", val ("wrong value"))
    self.node.name_register ("d/aa", val ("value aa"))
    self.node.name_register ("d/b", val ("value b"))
    self.node.generate (15)
    self.node.name_register ("d/c", val ("value c"))
    self.node.name_update ("d/a", val ("value a"))
    self.node.generate (20)

    # Check the expected name_scan data values.
    scan = self.node.name_scan ()
    assert_equal (len (scan), 4)
    self.checkNameData (scan[0], "d/a", val ("value a"))
    self.checkNameData (scan[1], "d/b", val ("value b"))
    self.checkNameData (scan[2], "d/c", val ("value c"))
    self.checkNameData (scan[3], "d/aa", val ("value aa"))

    # Check for expected names in various basic name_scan calls.
    self.checkList (self.node.name_scan (), ["d/a", "d/b", "d/c", "d/aa"])
    self.checkList (self.node.name_scan ("", 0), [])
    self.checkList (self.node.name_scan ("", -1), [])
    self.checkList (self.node.name_scan ("d/b"), ["d/b", "d/c", "d/aa"])
    self.checkList (self.node.name_scan ("d/zz"), [])
    self.checkList (self.node.name_scan ("", 2), ["d/a", "d/b"])
    self.checkList (self.node.name_scan ("d/b", 1), ["d/b"])

    # Verify encoding for start argument.
    self.checkList (self.node.name_scan ("642f63", 10, {"nameEncoding": "hex"}),
                    ["642f63", "642f6161"])

    # Verify filtering based on number of confirmations.
    self.checkList (self.node.name_scan ("", 100, {"minConf": 35}),
                    ["d/b", "d/aa"])
    self.checkList (self.node.name_scan ("", 100, {"minConf": 36}), [])
    self.checkList (self.node.name_scan ("", 100, {"maxConf": 19}), [])
    self.checkList (self.node.name_scan ("", 100, {"maxConf": 20}),
                    ["d/a", "d/c"])

    # Verify interaction with filtering and count.
    self.checkList (self.node.name_scan ("", 1, {"maxConf": 20}), ["d/a"])
    self.checkList (self.node.name_scan ("", 2, {"maxConf": 20}),
                    ["d/a", "d/c"])

    # Error checks for confirmation options.
    assert_raises_rpc_error (-8, "minConf must be >= 1",
                             self.node.name_scan, "", 100, {"minConf": 0})
    assert_raises_rpc_error (-8, "minConf must be >= 1",
                             self.node.name_scan, "", 100, {"minConf": -42})
    self.node.name_scan ("", 100, {"minConf": 1})
    assert_raises_rpc_error (-8, "maxConf must not be negative",
                             self.node.name_scan, "", 100, {"maxConf": -1})
    self.node.name_scan ("", 100, {"maxConf": 0})

    # Verify filtering based on prefix.
    self.checkList (self.node.name_scan ("", 100, {"prefix": ""}),
                    ["d/a", "d/b", "d/c", "d/aa"])
    self.checkList (self.node.name_scan ("", 100, {"prefix": "d/a"}),
                    ["d/a", "d/aa"])

    # Check prefix and nameEncoding.
    options = {
        "prefix": "642f61",
        "nameEncoding": "hex",
    }
    self.checkList (self.node.name_scan ("", 100, options),
                    ["642f61", "642f6161"])
    assert_raises_rpc_error (-1000, "Name/value is invalid for encoding ascii",
                             self.node.name_scan, "", 100, {"prefix": "äöü"})

    # Verify filtering based on regexp.
    self.checkList (self.node.name_scan ("", 100, {"regexp": "[ac]"}),
                    ["d/a", "d/c", "d/aa"])

    # Multiple filters are combined using "and".
    options = {
        "prefix": "d/a",
        "maxConf": 20,
    }
    self.checkList (self.node.name_scan ("", 100, options), ["d/a"])