def run_test(self):
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress()
        zaddr2 = self.nodes[1].z_getnewaddress()

        self.nodes[0].sendtoaddress(taddr, Decimal('1.0'))
        self.generate_and_sync()

        # Send 1 ZEC to a zaddr
        wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(taddr, [{'address': zaddr1, 'amount': 1.0, 'memo': 'c0ffee01'}], 1, 0))
        self.generate_and_sync()

        # Check that we have received 1 note which is not change
        receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        listunspent = self.nodes[1].z_listunspent()
        assert_equal(1, len(receivedbyaddress), "Should have received 1 note")
        assert_false(receivedbyaddress[0]['change'], "Note should not be change")
        assert_equal(1, len(listunspent), "Should have 1 unspent note")
        assert_false(listunspent[0]['change'], "Unspent note should not be change")

        # Generate some change
        wait_and_assert_operationid_status(self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{'address': zaddr2, 'amount': 0.6, 'memo': 'c0ffee02'}], 1, 0))
        self.generate_and_sync()

        # Check zaddr1 received
        sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr1, 0), key = lambda received: received['amount'])
        assert_equal(2, len(sortedreceived1), "zaddr1 Should have received 2 notes")
        assert_equal(Decimal('0.4'), sortedreceived1[0]['amount'])
        assert_true(sortedreceived1[0]['change'], "Note valued at 0.4 should be change")
        assert_equal(Decimal('1.0'), sortedreceived1[1]['amount'])
        assert_false(sortedreceived1[1]['change'], "Note valued at 1.0 should not be change")
        # Check zaddr2 received
        sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(zaddr2, 0), key = lambda received: received['amount'])
        assert_equal(1, len(sortedreceived2), "zaddr2 Should have received 1 notes")
        assert_equal(Decimal('0.6'), sortedreceived2[0]['amount'])
        assert_false(sortedreceived2[0]['change'], "Note valued at 0.6 should not be change")
        # Check unspent
        sortedunspent = sorted(self.nodes[1].z_listunspent(), key = lambda received: received['amount'])
        assert_equal(2, len(sortedunspent), "Should have 2 unspent notes")
        assert_equal(Decimal('0.4'), sortedunspent[0]['amount'])
        assert_true(sortedunspent[0]['change'], "Unspent note valued at 0.4 should be change")
        assert_equal(Decimal('0.6'), sortedunspent[1]['amount'])
        assert_false(sortedunspent[1]['change'], "Unspent note valued at 0.6 should not be change")

        # Give node 0 a viewing key
        viewing_key = self.nodes[1].z_exportviewingkey(zaddr1)
        self.nodes[0].z_importviewingkey(viewing_key)
        received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(received_node0))
        unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True)
        assert_equal(2, len(unspent_node0))
        # node 0 only has a viewing key so does not see the change field
        assert_false('change' in received_node0[0])
        assert_false('change' in received_node0[1])
        assert_false('change' in unspent_node0[0])
        assert_false('change' in unspent_node0[1])
Exemple #2
0
    def run_test(self):
        # Generate shared state up to the network split
        logging.info("Generating initial blocks.")
        self.nodes[0].generate(13)
        block14 = self.nodes[0].generate(1)[0]
        logging.info("Syncing network after initial generation...")
        self.sync_all()  # Everyone is still on overwinter

        logging.info("Checking overwinter block propagation.")
        assert_equal(self.nodes[0].getbestblockhash(), block14)
        assert_equal(self.nodes[1].getbestblockhash(), block14)
        assert_equal(self.nodes[2].getbestblockhash(), block14)
        logging.info("All nodes are on overwinter.")

        logging.info("Generating network split...")
        self.is_network_split = True

        # generate past the boundary into sapling; this will become the "canonical" branch
        self.nodes[0].generate(50)
        expected = self.nodes[0].getbestblockhash()

        # generate blocks into sapling beyond the maximum rewind length (99 blocks)
        self.nodes[2].generate(120)
        self.sync_all()

        assert_true(expected != self.nodes[2].getbestblockhash(),
                    "Split chains have not diverged!")

        # Stop the overwinter node to ensure state is flushed to disk.
        logging.info("Shutting down lagging node...")
        self.nodes[2].stop()
        bitcoind_processes[2].wait()

        # Restart the nodes, reconnect, and sync the network. This succeeds if "-reindex" is passed.
        logging.info("Reconnecting the network...")

        # expect an exception; the node will refuse to fully start because its last point of
        # agreement with the rest of the network was prior to the network upgrade activation
        assert_start_raises_init_error(2, self.options.tmpdir, HAS_SAPLING,
                                       "roll back 120")

        # restart the node with -reindex to allow the test to complete gracefully,
        # otherwise the node shutdown call in test cleanup will throw an error since
        # it can't connect
        self.nodes[2] = start_node(2,
                                   self.options.tmpdir,
                                   extra_args=NO_SAPLING + ["-reindex"])
    def register_nft_reg_ticket(self, key1, key2):
        print("== Create the NFT registration ticket ==")

        self.create_nft_ticket_and_signatures(self.non_mn3, "HIJKLMNOP",
                                              "ABCDEFG", self.total_copies)
        nft_ticket_txid = \
            self.nodes[self.top_mns_index0].tickets("register", "nft",
                                                    self.ticket, json.dumps(self.signatures_dict),
                                                    self.top_mn_pastelid0, self.passphrase,
                                                    key1, key2, str(self.storage_fee))["txid"]
        print(nft_ticket_txid)
        assert_true(nft_ticket_txid, "No ticket was created")

        self.__wait_for_ticket_tnx()
        print(self.nodes[self.top_mns_index0].getblockcount())

        return nft_ticket_txid
Exemple #4
0
    def run_test(self):
        '''
        This test try to create a SC using the command create_sidechain using invalid parameters and valid parameters.
        '''
        #{"withdrawalEpochLength", "fromaddress", "toaddress", "amount", "minconf", "fee", "customData"};

        # network topology: (0)--(1)

        mark_logs("Node 1 generates 2 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates 220 block", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(220)
        self.sync_all()

        tx = []
        errorString = ""
        toaddress = "abcdef"

        #generate wCertVk and constant
        mcTest = MCTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params('sc1')
        constant = generate_random_field_element_hex()

        # create with wrong key in input
        #------------------------------------
        amount = 12.0
        fee = 0.000025

        cmdInput = {
            'wrong_key': 123,
            'toaddress': toaddress,
            'amount': amount,
            'fee': fee,
            'wCertVk': vk
        }

        mark_logs("\nNode 1 create SC with wrong key in input", self.nodes,
                  DEBUG_MODE)
        try:
            tx = self.nodes[1].create_sidechain(cmdInput)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true("wrong_key" in errorString)
def check_migration_status(node, destination_address, migration_state):
    status = node.z_getmigrationstatus()
    assert_equal(destination_address, status['destination_address'],
                 "Migration destination address; status=%r" % status)
    assert_true(migration_state in ALL_MIGRATION_STATES,
                "Unexpected migration state %r" % migration_state)

    expected_enabled = migration_state not in [
        DISABLED_NO_FUNDS, DISABLED_BEFORE_MIGRATION
    ]
    expected_sprout_funds = migration_state in [
        DISABLED_BEFORE_MIGRATION, ENABLED_BEFORE_MIGRATION
    ]
    positive_unfinalized_amount = migration_state == DURING_MIGRATION
    positive_finalized_amount = migration_state == AFTER_MIGRATION
    num_migration_txids = 1 if migration_state in [
        DURING_MIGRATION, AFTER_MIGRATION
    ] else 0
    num_finalized_migration_transactions = 1 if migration_state == AFTER_MIGRATION else 0

    assert_equal(expected_enabled, status['enabled'],
                 "Expected enabled: %s" % expected_enabled)
    # During and after the migration there may be no remaining sprout funds if
    # we have randomly picked to migrate them all at once, so we only check
    # this field in the one case.
    if expected_sprout_funds:
        assert_true(
            Decimal(status['unmigrated_amount']) > Decimal('0.00'),
            "Expected sprout funds; status=%r" % (status, ))
    # For the other two amount fields we know whether or not they will be positive
    unfinalized_msg = "Positive unfinalized amount: %s; status=%r " % (
        positive_unfinalized_amount, status)
    assert_equal(positive_unfinalized_amount,
                 Decimal(status['unfinalized_migrated_amount']) > Decimal('0'),
                 unfinalized_msg)
    finalized_msg = "Positive finalized amount: %s; status=%r " % (
        positive_finalized_amount, status)
    assert_equal(positive_finalized_amount,
                 Decimal(status['finalized_migrated_amount']) > Decimal('0'),
                 finalized_msg)
    assert_equal(num_finalized_migration_transactions,
                 status['finalized_migration_transactions'],
                 "Num finalized transactions; status=%r" % (status, ))
    assert_equal(num_migration_txids, len(status['migration_txids']),
                 "Num migration txids; status=%r" % (status, ))
Exemple #6
0
 def check_peers_info(self,
                      peers_info,
                      quorum_members,
                      is_iqr_conn,
                      inbound=False):
     for quorum_node in quorum_members:
         found = False
         for peer in peers_info:
             if "verif_mn_proreg_tx_hash" in peer and peer[
                     "verif_mn_proreg_tx_hash"] == quorum_node.proTx:
                 self.check_peer_info(peer, quorum_node, is_iqr_conn,
                                      inbound)
                 found = True
                 break
         if not found:
             print(peers_info)
         assert_true(
             found,
             "MN connection not found for ip: " + str(quorum_node.ipport))
Exemple #7
0
    def run_test(self):
        '''
        Create a few SCs having the same parameters, advance 2 epochs and then let half of them cease.
        For the SCs alive send a certificate, for the ceased ones send a csw, then mine a block, which 
        should contain all of cert and csw with related proofs.
        Restart the network and check DB integrity.
        '''
        #================================================================================
        # Modify these params for customizing the test:
        # -------------------------------------------------------------------------------
        # the number of sidechain to be used in the test (min 2)
        #TOT_NUM_OF_SIDECHAINS = 100
        TOT_NUM_OF_SIDECHAINS = 2
        # parameters for tuning the complexity (and the size) of the created proofs
        # These have impacts both in execution times and also on disk space
        # TO TEST:
        #      SEGMENT_SIZE = 1 << 17
        #   1) CERT_NUM_CONSTRAINTS = 1 << 19, CSW_NUM_CONSTRAINTS = 1 << 18;
        #   2) CERT_NUM_CONSTRAINTS = 1 << 20, CSW_NUM_CONSTRAINTS = 1 << 19;
        CERT_NUM_CONSTRAINTS = 1 << 13
        CSW_NUM_CONSTRAINTS = 1 << 13

        #        CERT_PROVING_SYSTEM = "darlin"
        #        CSW_PROVING_SYSTEM = "darlin"
        CERT_PROVING_SYSTEM = "cob_marlin"
        CSW_PROVING_SYSTEM = "cob_marlin"

        # Segment size should be  at most 2 powers less than number of constraints, otherwise out-of-size vk could be produced
        SEGMENT_SIZE = 1 << 11
        #================================================================================
        assert_true(TOT_NUM_OF_SIDECHAINS >= 2)

        def create_sc(cmdInput, node):
            try:
                res = node.sc_create(cmdInput)
                tx = res['txid']
                scid = res['scid']
            except JSONRPCException, e:
                errorString = e.error['message']
                mark_logs(errorString, self.nodes, DEBUG_MODE)
                assert_true(False)

            return tx, scid
Exemple #8
0
    def doTestJustBeforeScFork(self):

        node = self.nodes[0]

        tmpl = node.getblocktemplate()
        if 'coinbasetxn' not in tmpl:
            rawcoinbase = encodeUNum(tmpl['height'])
            rawcoinbase += b'\x01-'
            hexcoinbase = b2x(rawcoinbase)
            hexoutval = b2x(pack('<Q', tmpl['coinbasevalue']))
            tmpl['coinbasetxn'] = {
                'data':
                '01000000' + '01' +
                '0000000000000000000000000000000000000000000000000000000000000000ffffffff'
                + ('%02x' % (len(rawcoinbase), )) + hexcoinbase + 'fffffffe' +
                '01' + hexoutval + '00' + '00000000'
            }
        txlist = list(
            bytearray(a2b_hex(a['data']))
            for a in (tmpl['coinbasetxn'], ) + tuple(tmpl['transactions']))
        certlist = []

        # Test: set a non-zero 'hashReserved' field (32 bytes after mkl tree field); this is used from the sc fork on, renamed as 'scTxsCommitment'
        rawtmpl = template_to_bytes(tmpl, txlist, certlist)

        # a 32 null byte array string
        nb1 = b2x(bytearray(32))

        nb2 = b2x(rawtmpl[4 + 32 + 32:4 + 32 + 32 + 32])
        # check hashReserved field is currently null
        assert_true(nb1 == nb2)

        for j in range(0, 32):
            rawtmpl[4 + 32 + 32 + j] = j

        # hashReserved is not null now
        nb3 = b2x(rawtmpl[4 + 32 + 32:4 + 32 + 32 + 32])
        assert_false(nb3 == nb2)

        rsp = node.getblocktemplate({'data': b2x(rawtmpl), 'mode': 'proposal'})
        # assert block validity
        assert_equal(rsp, None)
Exemple #9
0
    def fake_nftsell_tnx_tests1(self):
        print(
            "== NFT Sell ticket transaction validation test (for activation ticket) =="
        )

        self.nodes[self.mining_node_num].sendtoaddress(self.nonmn3_address1,
                                                       200, "", "", False)
        time.sleep(2)
        self.sync_all(10, 30)
        self.nodes[self.mining_node_num].generate(1)
        self.sync_all(10, 30)

        self.nft_ticket1_act_ticket_txid = self.nodes[self.non_mn3].tickets(
            "register", "act", self.nft_ticket1_txid,
            str(self.creator_ticket_height), str(self.storage_fee),
            self.creator_pastelid1, "passphrase")["txid"]
        assert_true(self.nft_ticket1_act_ticket_txid, "No ticket was created")

        tickets = {
            # 1. check PastelID in this ticket matches PastelID in the referred Activation ticket
            "sell-bad-nfts-sign":
            self.nodes[self.non_mn3].tickets(
                "makefaketicket", "sell", self.nft_ticket1_act_ticket_txid,
                "100000", self.creator_pastelid1, "passphrase", "0", "0", "10",
                "1"
            ),  # Verb = 1 - will modify Act ticket signature to make it invalid (non matchig creator's PastelID)
        }

        # sync mempools
        self.sync_all()
        for n, t in tickets.items():
            try:
                self.nodes[0].sendrawtransaction(t)
            except JSONRPCException as e:
                self.errorString = e.error['message']
                print(n + ": " + self.errorString)
            assert_equal("bad-tx-invalid-ticket" in self.errorString, True)

        print(
            "== NFT Sell ticket transaction validation tested (for activation ticket) =="
        )
Exemple #10
0
        def advance_sidechains_epoch(num_of_scs):

            for i in range(0, num_of_scs):

                if i == 0:
                    self.nodes[0].generate(EPOCH_LENGTH)
                    self.sync_all()
                    # these parameters are valid for all scs since they share the same epoch length
                    epoch_number, epoch_cum_tree_hash = get_epoch_data(
                        scids[i], self.nodes[0], EPOCH_LENGTH)

                print "Generating cert proof..."
                t0 = time.time()
                scid_swapped = str(swap_bytes(scids[i]))

                proof = certMcTest.create_test_proof(
                    "scs", scid_swapped, epoch_number, q, MBTR_SC_FEE,
                    FT_SC_FEE, epoch_cum_tree_hash, constant, [], [],
                    proofCfeArray, CERT_NUM_CONSTRAINTS, SEGMENT_SIZE)
                assert_true(proof != None)
                t1 = time.time()
                print "...proof generated: {} secs".format(t1 - t0)

                try:
                    cert = self.nodes[0].sc_send_certificate(
                        scids[i], epoch_number, q, epoch_cum_tree_hash, proof,
                        [], FT_SC_FEE, MBTR_SC_FEE, CERT_FEE, "", vCfe, vCmt)
                except JSONRPCException, e:
                    errorString = e.error['message']
                    print "Send certificate failed with reason {}".format(
                        errorString)
                    assert (False)
                self.sync_all()

                mark_logs(
                    "==> certificate for SC{} epoch {} {} (chain height={})".
                    format(i, epoch_number, cert,
                           self.nodes[0].getblockcount()), self.nodes,
                    DEBUG_MODE)
    def check_genesis_balances(self, node, nodename, expected_keys_count,
                               expected_boxes_count):
        print("Genesis checks for {0}...".format(nodename))
        print(
            "-->Checking that each public key has a box assigned with a non-zero value... "
        )

        responce = node.wallet_allPublicKeys()
        public_keys = responce["result"]["propositions"]

        responce = node.wallet_allBoxes()
        boxes = responce["result"]["boxes"]

        responce = node.wallet_balance()
        balance = responce["result"]
        assert_equal(expected_keys_count, len(public_keys),
                     "Unexpected number of public keys")
        assert_equal(expected_boxes_count, len(boxes),
                     "Unexpected number of boxes")
        for key in public_keys:
            target = None
            for box in boxes:
                if box["proposition"]["publicKey"] == key["publicKey"]:
                    target = box
                    assert_true(
                        box["value"] > 0,
                        "Non positive value for box: {0} with public key: {1}".
                        format(box["id"], key))
                    break
            assert_true(target is not None,
                        "Box related to public key: {0} not found".format(key))
        print("-->Checking genesis balance...")
        assert_equal(10000000000, int(balance["balance"]),
                     "Unexpected balance")
        print("-->Total balance: {0}".format(json.dumps(balance["balance"])))
        print("OK\n")
Exemple #12
0
    def run_test(self):
        ''' Test verifying the fix of some corner cases in the implementation of cbh '''
        TARGET_H = 3
        FEE = Decimal('0.00005')

        self.mark_logs("Node1 generates %d blocks" %
                       (CBH_DELTA_HEIGHT + TARGET_H))
        self.nodes[1].generate(CBH_DELTA_HEIGHT + TARGET_H)
        self.sync_all()

        # create a Tx having a '-1' as height and genesys blockhash in its scriptPubKey CHECKBLOCKATHEIGHT part
        payment_1 = Decimal('10.0')
        raw_tx_1 = create_tampered_rawtx_cbh(self.nodes[1], self.nodes[2],
                                             payment_1, FEE, MODE_HEIGHT)

        try:
            self.mark_logs(
                "Node1 sending tx1 with tampered cbh script to Node2")
            tx_1 = self.nodes[1].sendrawtransaction(raw_tx_1['hex'])
            self.sync_all()
        except JSONRPCException, e:
            print " ==> Tx has been rejected! {}".format(e.error['message'])
            # before rp fix fork this is expected to succeed
            assert_true(False)
        def check_change_taddr_reuse(target, isTargetShielded):
            recipients = [{"address": target, "amount": Decimal('1')}]

            # Send funds to recipient address twice
            txid1 = self.nodes[0].shieldsendmany(taddrSource, recipients, 1)
            self.nodes[1].generate(1)
            self.sync_all()
            txid2 = self.nodes[0].shieldsendmany(taddrSource, recipients, 1)
            self.nodes[1].generate(1)
            self.sync_all()

            # Verify that the two transactions used different change addresses
            tx1 = self.nodes[0].getrawtransaction(txid1, 1)
            tx2 = self.nodes[0].getrawtransaction(txid2, 1)
            assert_true(len(tx1['vout']) >= 1)  # at least one output
            assert_true(len(tx2['vout']) >= 1)
            for i in range(len(tx1['vout'])):
                tx1OutAddrs = tx1['vout'][i]['scriptPubKey']['addresses']
                tx2OutAddrs = tx2['vout'][i]['scriptPubKey']['addresses']
                if tx1OutAddrs != [target]:
                    print('Source address:     %s' % taddrSource)
                    print('TX1 change address: %s' % tx1OutAddrs[0])
                    print('TX2 change address: %s' % tx2OutAddrs[0])
                    assert (tx1OutAddrs != tx2OutAddrs)
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(101)

        offline_node = start_node(1, self.options.tmpdir, ["-maxconnections=0", "-nuparams=5ba81b19:10"])
        self.nodes.append(offline_node)

        assert_equal(0, len(offline_node.getpeerinfo())) # make sure node 1 has no peers

        privkeys = [self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())]
        taddr = self.nodes[0].getnewaddress()

        tx = self.nodes[0].listunspent()[0]
        txid = tx['txid']
        scriptpubkey = tx['scriptPubKey']

        create_inputs = [{'txid': txid, 'vout': 0}]
        sign_inputs = [{'txid': txid, 'vout': 0, 'scriptPubKey': scriptpubkey, 'amount': 10}]

        create_hex = self.nodes[0].createrawtransaction(create_inputs, {taddr: 9.9999})

        # An offline regtest node does not rely on the approx release height of the software
        # to determine the consensus rules to be used for signing.
        try:
            signed_tx = offline_node.signrawtransaction(create_hex, sign_inputs, privkeys)
            self.nodes[0].sendrawtransaction(signed_tx['hex'])
            assert(False)
        except JSONRPCException:
            pass

        # Passing in the consensus branch id resolves the issue for offline regtest nodes.
        signed_tx = offline_node.signrawtransaction(create_hex, sign_inputs, privkeys, "ALL", "5ba81b19")

        # If we return the transaction hash, then we have have not thrown an error (success)
        online_tx_hash = self.nodes[0].sendrawtransaction(signed_tx['hex'])
        assert_true(len(online_tx_hash) > 0)
def parse_wallet_file(dump_path):
    file_lines = open(dump_path, "r", encoding="utf8").readlines()
    # We expect information about the HDSeed and fingerpring in the header
    assert_true("HDSeed" in file_lines[4], "Expected HDSeed")
    assert_true("fingerprint" in file_lines[4], "Expected fingerprint")
    seed_comment_line = file_lines[4][2:].split()  # ["HDSeed=...", "fingerprint=..."]
    assert_true(seed_comment_line[0].split("=")[1] != seed_comment_line[1].split("=")[1], "The seed should not equal the fingerprint")
    (t_keys, i) = parse_wallet_file_lines(file_lines, 0)
    (sapling_keys, i) = parse_wallet_file_lines(file_lines, i)

    return (t_keys, sapling_keys)
def parse_wallet_file(dump_path):
    file_lines = open(dump_path, "r").readlines()
    # We expect information about the HDSeed and fingerpring in the header
    assert_true("HDSeed" in file_lines[4], "Expected HDSeed")
    assert_true("fingerprint" in file_lines[4], "Expected fingerprint")
    seed_comment_line = file_lines[4][2:].split()  # ["HDSeed=...", "fingerprint=..."]
    assert_true(seed_comment_line[0].split("=")[1] != seed_comment_line[1].split("=")[1], "The seed should not equal the fingerprint")
    (t_keys, i) = parse_wallet_file_lines(file_lines, 0)
    (sprout_keys, i) = parse_wallet_file_lines(file_lines, i)
    (sapling_keys, i) = parse_wallet_file_lines(file_lines, i)

    return (t_keys, sprout_keys, sapling_keys)
def parse_wallet_file(dump_path):
    file_lines = open(dump_path, "r", encoding="utf8").readlines()
    # We expect information about the HDSeed and fingerpring in the header
    assert_true("recovery_phrase" in file_lines[5],
                "Expected emergency recovery phrase")
    assert_true("language" in file_lines[6], "Expected mnemonic seed language")
    assert_true("fingerprint" in file_lines[7],
                "Expected mnemonic seed fingerprint")
    mnemonic = file_lines[5].split("=")[1].replace("\"", "").strip()
    (t_keys, i) = parse_wallet_file_lines(file_lines, 0)
    (sprout_keys, i) = parse_wallet_file_lines(file_lines, i)
    (sapling_keys, i) = parse_wallet_file_lines(file_lines, i)

    return (mnemonic, t_keys, sprout_keys, sapling_keys)
    def run_test_release(self, release, height):
        self.generate_and_sync(height + 1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress(release)

        self.nodes[0].sendtoaddress(taddr, 2.0)
        self.generate_and_sync(height + 2)

        # Send 1 BLV to zaddr1
        opid = self.nodes[1].z_sendmany(taddr, [{
            'address': zaddr1,
            'amount': 1,
            'memo': my_memo
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid, r[0]['txid'])
        assert_equal(1, r[0]['amount'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])

        # Confirm transaction (1 BLV from taddr to zaddr1)
        self.generate_and_sync(height + 3)

        # Require one confirmation, note should be present
        assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1))

        # Generate some change by sending part of zaddr1 to zaddr2
        zaddr2 = self.nodes[1].z_getnewaddress(release)
        opid = self.nodes[1].z_sendmany(zaddr1, [{
            'address': zaddr2,
            'amount': 0.6
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        self.generate_and_sync(height + 4)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")

        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4') - fee, r[0]['amount'])
        assert_true(r[0]['change'],
                    "Note valued at (0.4-fee) should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('1.0'), r[1]['amount'])
        assert_false(r[1]['change'], "Note valued at 1.0 should not be change")
        assert_equal(my_memo, r[1]['memo'])

        # zaddr2 should not have change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(1, len(r), "zaddr2 Should have received 1 notes")
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.6'), r[0]['amount'])
        assert_false(r[0]['change'], "Note valued at 0.6 should not be change")
        assert_equal(no_memo, r[0]['memo'])
Exemple #19
0
    def validate_full_tx(self,endpoint,decodedTx,tx,shielded = False):
        if (endpoint['version'] == -5):
            assert_equal(endpoint['cert'],decodedTx['cert'])     
        assert_equal(endpoint['blockheight'],self.nodes[0].getblock(endpoint['blockhash'])['height'])
        assert_equal(endpoint['confirmations'],tx['confirmations'])
        assert_equal(endpoint['blocktime'],tx['blocktime']) 
        assert_equal(endpoint['txid'],decodedTx['txid'])
        assert_equal(endpoint['version'],decodedTx['version'])
        assert_equal(endpoint['blockhash'],tx['blockhash'])
        if('isCoinBase' in endpoint and endpoint['isCoinBase'] == True):
            assert_equal(len(endpoint['vin']),1)
            assert_equal(endpoint['vin'][0]['coinbase'],decodedTx['vin'][0]['coinbase'])
            assert_equal(endpoint['vin'][0]['sequence'],decodedTx['vin'][0]['sequence'])
            assert_equal(endpoint['vin'][0]['n'],0)
        else:
            assert_equal(len(endpoint['vin']),len(decodedTx['vin']))
            valueIn = 0
            for endpointVin in endpoint['vin']:
                decodedVin = None
                for vin in decodedTx['vin']:
                    if(vin['txid'] == endpointVin['txid'] and vin['vout'] == endpointVin['vout']):
                        decodedVin = vin
                        break;
                assert_equal(endpointVin['txid'],decodedVin['txid'])
                assert_equal(endpointVin['vout'],decodedVin['vout'])
                assert_equal(endpointVin['sequence'],decodedVin['sequence'])

                previousTx = self.nodes[0].gettransaction(endpointVin['txid'])
                decodedPreviousTx = self.nodes[0].decoderawtransaction(previousTx['hex'])
                previousUtxo = decodedPreviousTx['vout'][endpointVin['vout']]

                assert_equal(round(Decimal(endpointVin['value']),8),round(Decimal(previousUtxo['value']),8))
                assert_equal(endpointVin['valueSat'],previousUtxo['valueZat'])
                assert_equal(endpointVin['addr'],previousUtxo['scriptPubKey']['addresses'][0])
                assert_equal(endpointVin['scriptSig']['hex'],decodedVin['scriptSig']['hex'])
                assert_equal(endpointVin['scriptSig']['asm'],decodedVin['scriptSig']['asm'])
                valueIn += endpointVin['value']

            assert_equal(str(endpoint['valueIn']),str(valueIn))
            if(not shielded):
                assert_equal("{:.8f}".format(float(endpoint['fees'])),"{:.8f}".format(float(abs(tx['fee']))))
        assert_equal(len(endpoint['vout']),len(decodedTx['vout']))
        valueOut = 0
        for i in range (0,len(endpoint['vout'])):
            assert_equal(round(Decimal(endpoint['vout'][i]['value']),8),round(Decimal(decodedTx['vout'][i]['value']),8))
            assert_equal(endpoint['vout'][i]['n'],decodedTx['vout'][i]['n'])
            assert_equal(endpoint['vout'][i]['scriptPubKey']['hex'],decodedTx['vout'][i]['scriptPubKey']['hex'])
            assert_equal(endpoint['vout'][i]['scriptPubKey']['addresses'],decodedTx['vout'][i]['scriptPubKey']['addresses'])
            #The explorer doesn't distinguish from pubkeyhash and pubkeyhashreplay
            if (endpoint['vout'][i]['scriptPubKey']['type'] == "pubkeyhash"):
                    assert_true( (decodedTx['vout'][i]['scriptPubKey']['type'] == "pubkeyhashreplay") or (decodedTx['vout'][i]['scriptPubKey']['type'] == "pubkeyhash"))
            #The explorer doesn't distinguish from scripthash and scripthashreplay
            if (endpoint['vout'][i]['scriptPubKey']['type'] == "scripthash"):
                    assert_true( (decodedTx['vout'][i]['scriptPubKey']['type'] == "scripthashreplay") or (decodedTx['vout'][i]['scriptPubKey']['type'] == "scripthash"))
            if('asm' in endpoint['vout'][i]['scriptPubKey']):
                assert_equal(endpoint['vout'][i]['scriptPubKey']['asm'],decodedTx['vout'][i]['scriptPubKey']['asm'])
            valueOut += float(endpoint['vout'][i]['value'])

        assert_equal(round(Decimal(endpoint['valueOut']),8),round(Decimal(valueOut),8))
        #assert_equal(endpoint['time'],tx['blocktime']) TODO: add tollerance in the check
        #if(not shielded): Wait fix on zendoo
            #assert_equal(endpoint['size'],tx['details'][0]['size'])

        #Check joinsplit
        if(endpoint['version'] == -3):
            assert_equal(len(endpoint['vjoinsplit']),len(decodedTx['vjoinsplit']))
            for i in range (0,len(endpoint['vjoinsplit'])):
                assert_equal(round(Decimal(endpoint['vjoinsplit'][i]['vpub_old']),8),round(Decimal(decodedTx['vjoinsplit'][i]['vpub_old']),8))
                assert_equal(round(Decimal(endpoint['vjoinsplit'][i]['vpub_new']),8),round(Decimal(decodedTx['vjoinsplit'][i]['vpub_new']),8))
                assert_equal(endpoint['vjoinsplit'][i]['n'],i)

        #Check sc_params
        if(decodedTx['version'] == -4):
            #Vsc_ccout
            assert_equal(len(endpoint['vsc_ccout']),len(decodedTx['vsc_ccout']))
            for i in range (0,len(endpoint['vsc_ccout'])):
                assert_equal(endpoint['vsc_ccout'][i]['scid'],decodedTx['vsc_ccout'][i]['scid'])
                assert_equal(endpoint['vsc_ccout'][i]['withdrawalEpochLength'],decodedTx['vsc_ccout'][i]['withdrawalEpochLength'])
                assert_equal(endpoint['vsc_ccout'][i]['n'],decodedTx['vsc_ccout'][i]['n'])
                assert_equal(endpoint['vsc_ccout'][i]['address'],decodedTx['vsc_ccout'][i]['address'])
                assert_equal(endpoint['vsc_ccout'][i]['customData'],decodedTx['vsc_ccout'][i]['customData'])
                assert_equal(endpoint['vsc_ccout'][i]['version'],decodedTx['vsc_ccout'][i]['version'])
            #Vft_ccout
            assert_equal(len(endpoint['vft_ccout']),len(decodedTx['vft_ccout']))
            for i in range (0,len(endpoint['vft_ccout'])):
                assert_equal(endpoint['vft_ccout'][i]['scid'],decodedTx['vft_ccout'][i]['scid'])
                assert_equal(round(Decimal(endpoint['vft_ccout'][i]['value']),8),round(Decimal(decodedTx['vft_ccout'][i]['value']),8))
                assert_equal(endpoint['vft_ccout'][i]['address'],decodedTx['vft_ccout'][i]['address'])
                assert_equal(endpoint['vft_ccout'][i]['n'],decodedTx['vft_ccout'][i]['n'])
            #Vmbtr_out
            assert_equal(len(endpoint['vmbtr_out']),len(decodedTx['vmbtr_out']))
            for i in range (0,len(endpoint['vmbtr_out'])):
                assert_equal(endpoint['vmbtr_out'][i]['scid'],decodedTx['vmbtr_out'][i]['scid'])
                #assert_equal(endpoint['vmbtr_out'][i]['mcDestinationAddress']['pubkeyhash'],decodedTx['vmbtr_out'][i]['mcDestinationAddress'])
                assert_equal(endpoint['vmbtr_out'][i]['mcDestinationAddress'],decodedTx['vmbtr_out'][i]['mcDestinationAddress'])
                assert_equal(endpoint['vmbtr_out'][i]['n'],decodedTx['vmbtr_out'][i]['n'])
                assert_equal(round(Decimal(endpoint['vmbtr_out'][i]['scFee']),8),round(Decimal(decodedTx['vmbtr_out'][i]['scFee']),8))
                assert_equal(len(endpoint['vmbtr_out'][i]['vScRequestData']),len(decodedTx['vmbtr_out'][i]['vScRequestData']))

            #Vcsw_ccin
            assert_equal(len(endpoint['vcsw_ccin']),len(decodedTx['vcsw_ccin']))
            for i in range (0,len(endpoint['vcsw_ccin'])):
                assert_equal(endpoint['vcsw_ccin'][i]['scId'],decodedTx['vcsw_ccin'][i]['scId'])
                assert_equal(round(Decimal(endpoint['vcsw_ccin'][i]['value']),8),round(Decimal(decodedTx['vcsw_ccin'][i]['value']),8))
                assert_equal(endpoint['vcsw_ccin'][i]['nullifier'],decodedTx['vcsw_ccin'][i]['nullifier'])
                assert_equal(endpoint['vcsw_ccin'][i]['actCertDataHash'],decodedTx['vcsw_ccin'][i]['actCertDataHash'])
                assert_equal(endpoint['vcsw_ccin'][i]['ceasingCumScTxCommTree'],decodedTx['vcsw_ccin'][i]['ceasingCumScTxCommTree'])
                assert_equal(endpoint['vcsw_ccin'][i]['redeemScript']['hex'],decodedTx['vcsw_ccin'][i]['redeemScript']['hex'])
                assert_equal(endpoint['vcsw_ccin'][i]['redeemScript']['asm'],decodedTx['vcsw_ccin'][i]['redeemScript']['asm'])
                assert_equal(endpoint['vcsw_ccin'][i]['scriptPubKey'],decodedTx['vcsw_ccin'][i]['scriptPubKey'])

        return None
Exemple #20
0
    def run_test(self):
        #Give time to explorer to start
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()
        time.sleep(35)

        self.nodes[0].getnewaddress()
        tAddr = self.nodes[0].getnewaddress()
        tAddr2 = self.nodes[0].getnewaddress()
        zAddr = self.nodes[0].z_getnewaddress()
        zAddr2 = self.nodes[1].z_getnewaddress()

#############################################################################################################################

        #### /tx/:txid ####
        print("######## /tx/:txid ########")

        #Test coinbase-transaction
        coinbaseTxId = self.nodes[0].getblock("100")['tx'][0]
        coinbaseTx = self.nodes[0].gettransaction(coinbaseTxId)
        decodedCoinbaseTx = self.nodes[0].decoderawtransaction(coinbaseTx['hex'])
                
        r = requests.get(url = self.BASE_URL+"block/"+self.nodes[0].getblock("400")['hash'], params = {})
        data = r.json()
        r = requests.get(url = self.BASE_URL+"tx/"+coinbaseTxId, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedCoinbaseTx,coinbaseTx)

        #Test t-transaction
        tTxId = self.nodes[0].sendtoaddress(tAddr,10.0001)
        self.sync_all()
        self.nodes[0].generate(2)
        self.sync_all()
        time.sleep(5)

        transparentTx = self.nodes[0].gettransaction(tTxId)
        decodedTransparentTx = self.nodes[0].decoderawtransaction(transparentTx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+tTxId, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedTransparentTx, transparentTx)

        '''
        #This parameter doesn't work on this version of the explorer
        #Test noAsm parameter
        r = requests.get(url = self.BASE_URL+"tx/"+tTxId+"?noAsm=true", params = {})
        data = r.json()
        print(data)
        for output in data['vout']:
            assert_false('asm' in output['scriptPubKey'])
        '''

        #Test z-transaction t->z
        myopid = self.nodes[0].z_sendmany(tAddr,[{"address":zAddr,"amount":4.0},{"address":zAddr2,"amount":6.0}])
        zTxid = wait_and_assert_operationid_status(self.nodes[0],myopid)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].z_getbalance(zAddr),4)
        assert_equal(self.nodes[1].z_getbalance(zAddr2),6)

        shieldTx = self.nodes[0].gettransaction(zTxid)
        decodedShieldTx = self.nodes[0].decoderawtransaction(shieldTx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+zTxid, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedShieldTx,shieldTx)

        #Test z-transaction z->z
        myopid = self.nodes[0].z_sendmany(zAddr,[{"address":zAddr2,"amount":3.0}])
        zTxid2 = wait_and_assert_operationid_status(self.nodes[0],myopid)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        shieldTx = self.nodes[0].gettransaction(zTxid2)
        decodedShieldTx = self.nodes[0].decoderawtransaction(shieldTx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+zTxid2, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedShieldTx,shieldTx,True)

       #Test multiple sidechain creation
        txId = self.nodes[0].sendtoaddress(tAddr2,20.0)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        tx = self.nodes[0].gettransaction(txId)
        rawtx = self.nodes[0].decoderawtransaction(tx['hex'])
        vout = {}
        for outpoint in rawtx['vout']:
            if (outpoint['value'] == Decimal('20.0')):
                vout = outpoint
                break

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_address2 = "0000000000000000000000000000000000000000000000000000000000000acb"
        sc_epoch = 100
        sc_cr_amount = Decimal('5.00000000')

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()
        vk2 = mcTest.generate_params("sc2")

        cswVk = cswMcTest.generate_params("sc1")
        cswVk2 = cswMcTest.generate_params("sc2")

        sc = [{"epoch_length": sc_epoch, "address": sc_address, "amount": sc_cr_amount,"wCertVk": vk, "constant": constant, "mainchainBackwardTransferScFee": MBTR_SC_FEE, "mainchainBackwardTransferRequestDataLength": 1, "wCeasedVk": cswVk, "version":1},
              {"epoch_length": sc_epoch, "address": sc_address2, "amount": sc_cr_amount, "wCertVk": vk2, "constant": constant, "mainchainBackwardTransferScFee": MBTR_SC_FEE, "mainchainBackwardTransferRequestDataLength": 1, "wCeasedVk": cswVk2, "version":1}]

        inputs = [{'txid': txId, 'vout': vout['n']}]
        rawtx = self.nodes[0].createrawtransaction(inputs, {tAddr2: 10.0}, [], sc, [])
        sigRawtx = self.nodes[0].signrawtransaction(rawtx)
        scTxid = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
        self.sync_all()
        time.sleep(2)
        self.nodes[0].generate(1)
        self.sync_all()
        time.sleep(2)
        scTx = self.nodes[0].gettransaction(scTxid)
        scid = scTx['vsc_ccout'][0]['scid']
        scid2 = scTx['vsc_ccout'][1]['scid']

        assert_equal(len(self.nodes[0].getscinfo("*")['items']),2)
        decodedScTx = self.nodes[0].decoderawtransaction(scTx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+scTxid, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedScTx,scTx)

        #Test with multiple forward transfers
        rawtx = self.nodes[0].decoderawtransaction(scTx['hex'])
        vout = {}
        for outpoint in rawtx['vout']:
            if (outpoint['value'] == Decimal('10.0')):
                vout = outpoint
                break
        mcReturnAddress = self.nodes[0].getnewaddress()
        ft = [{"address": sc_address, "amount": sc_cr_amount, "scid": scid, "mcReturnAddress": mcReturnAddress},
              {"address": sc_address2, "amount": sc_cr_amount, "scid": scid2, "mcReturnAddress": mcReturnAddress}]

        inputs = [{'txid': scTxid, 'vout': vout['n']}]
        rawtx = self.nodes[0].createrawtransaction(inputs, {}, [], [], ft)
        sigRawtx = self.nodes[0].signrawtransaction(rawtx)
        ftTxid = self.nodes[0].sendrawtransaction(sigRawtx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        ftTx = self.nodes[0].gettransaction(ftTxid)
        decodedFtTx = self.nodes[0].decoderawtransaction(ftTx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+ftTxid, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedFtTx,ftTx)

        #Test with BackwardTransferRequest
        bwtr_address = self.nodes[0].getnewaddress()

        btwr_txid=self.nodes[0].sc_request_transfer([
            {'mcDestinationAddress': bwtr_address, 'vScRequestData': [generate_random_field_element_hex()], 'scid': scid, 'scFee': Decimal('1.0')},
            {'mcDestinationAddress': bwtr_address, 'vScRequestData': [generate_random_field_element_hex()], 'scid': scid2, 'scFee': Decimal('1.0')}
        ])
        self.sync_all()
        time.sleep(1)
        self.nodes[0].generate(1)
        self.sync_all()
        time.sleep(2)
        bwtrTx = self.nodes[0].gettransaction(btwr_txid)
        decodedBwtrTx = self.nodes[0].decoderawtransaction(bwtrTx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+btwr_txid, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedBwtrTx,bwtrTx)

        #Test with a immature certificate
        self.nodes[0].generate(sc_epoch)
        self.sync_all()
        time.sleep(5)

        #Mine Certificate 1 with quality = 5
        epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], sc_epoch)
        quality = 5
        pkh_node1 = self.nodes[1].getnewaddress()
        bwt_amount = Decimal('3.0')
        proof = mcTest.create_test_proof(
            "sc1", swap_bytes(scid), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [pkh_node1], [bwt_amount])

        amount_cert_1 = [{"address": pkh_node1, "amount": bwt_amount}]
        cert1 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
            epoch_cum_tree_hash, proof, amount_cert_1, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE)
        self.sync_all()
        cert1_block = self.nodes[0].generate(1)[0]
        self.sync_all()
        time.sleep(2)

        r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=1", params = {})
        data = r.json()        
        certTx = self.nodes[0].gettransaction(cert1)
        decodedCertTx = self.nodes[0].decoderawtransaction(certTx['hex'])
        certInfo = self.nodes[0].getcertmaturityinfo(cert1)

        self.validate_full_tx(data, decodedCertTx, certTx)
        self.validate_certificate(data, certInfo, True)

        r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=0", params = {})
        data = r.json()
        self.validate_certificate(data, certInfo, False)       

        r = requests.get(url = self.BASE_URL+"tx/"+cert1, params = {})
        data = r.json()
        self.validate_certificate(data, certInfo, False)

        #Test also the /txs endpoint with blockhash
        r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=1", params = {})
        data = r.json()
        assert_equal(len(data['txs']), 2)
        self.validate_certificate(data['txs'][1], certInfo, True)

        r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=0", params = {})
        data = r.json()
        assert_equal(len(data['txs']), 2)
        self.validate_certificate(data['txs'][1], certInfo, False)

        r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block, params = {})
        data = r.json()
        assert_equal(len(data['txs']), 2)
        self.validate_certificate(data['txs'][1], certInfo, False)

        #Test also the /txs endpoint with address
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=1", params = {})
        data = r.json()
        found = False
        for tx in data['txs']:
            if (tx['version'] == -5):
                assert_false(found)
                found = True
                self.validate_certificate(tx, certInfo, True)
        assert_true(found)

        found = False
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=0", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['version'] == -5):
                assert_false(found)
                found = True
                self.validate_certificate(tx, certInfo, True)
        assert_true(found)
        
        found = False
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1, params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['version'] == -5):
                assert_false(found)
                found = True
                self.validate_certificate(tx, certInfo, True)      
        assert_true(found)

        #Advance of 1 epoch
        self.nodes[0].generate(110)
        self.sync_all()

        #Create a block with 2 certificates (one will be superseded) that let mature the certificate of the previous epoch
        quality = 7
        epoch_number, epoch_cum_tree_hash = get_epoch_data(scid, self.nodes[0], sc_epoch)
        proof = mcTest.create_test_proof(
            "sc1", str(swap_bytes(scid)), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [pkh_node1], [bwt_amount])       
        amount_cert_2 = [{"address": pkh_node1, "amount": bwt_amount}]

        cert2 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
            epoch_cum_tree_hash, proof, amount_cert_2, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE)
        self.sync_all()

        quality = 9
        proof = mcTest.create_test_proof(
            "sc1", str(swap_bytes(scid)), epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash, constant, [pkh_node1], [bwt_amount])       

        cert3 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
            epoch_cum_tree_hash, proof, amount_cert_2, FT_SC_FEE, MBTR_SC_FEE, CERT_FEE)
        cert2_3_block = self.nodes[0].generate(30)[0]
        self.sync_all()
        time.sleep(2)

        #Test that the first certificate became mature

        certInfo = self.nodes[0].getcertmaturityinfo(cert1)
        r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=1", params = {})
        data = r.json()
        self.validate_certificate(data, certInfo, True)

        r = requests.get(url = self.BASE_URL+"tx/"+cert1+"?showImmatureBTs=0", params = {})
        data = r.json()
        self.validate_certificate(data, certInfo, True)       

        r = requests.get(url = self.BASE_URL+"tx/"+cert1, params = {})
        data = r.json()
        self.validate_certificate(data, certInfo, True)


        #Test also the /txs endpoint with blockhash
        r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=1", params = {})
        data = r.json()
        assert_equal(len(data['txs']), 2)
        self.validate_certificate(data['txs'][1], certInfo, True)

        r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block+"&showImmatureBTs=0", params = {})
        data = r.json()
        assert_equal(len(data['txs']), 2)
        self.validate_certificate(data['txs'][1], certInfo, True)

        r = requests.get(url = self.BASE_URL+"txs?block="+cert1_block, params = {})
        data = r.json()
        assert_equal(len(data['txs']), 2)
        self.validate_certificate(data['txs'][1], certInfo, True)

        #Test also the /txs endpoint with address
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=1", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert1):
                self.validate_certificate(tx, certInfo, True)

        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=0", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert1):
                self.validate_certificate(tx, certInfo, True)
        
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1, params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert1):
                self.validate_certificate(tx, certInfo, True)

        #Test that the certificate 2 is superseded
        certTx2 = self.nodes[0].gettransaction(cert2)
        certInfo2 = self.nodes[0].getcertmaturityinfo(cert2)
        
        r = requests.get(url = self.BASE_URL+"tx/"+cert2+"?showImmatureBTs=1", params = {})
        data = r.json()
        self.validate_certificate(data, certInfo2, False)

        r = requests.get(url = self.BASE_URL+"tx/"+cert2+"?showImmatureBTs=0", params = {})
        data = r.json()
        self.validate_certificate(data, certInfo2, False)       

        r = requests.get(url = self.BASE_URL+"tx/"+cert2, params = {})
        data = r.json()
        self.validate_certificate(data, certInfo2, False)     

        #Test also the /txs endpoint with blockhash
        r = requests.get(url = self.BASE_URL+"txs?block="+cert2_3_block+"&showImmatureBTs=1", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert2):
                self.validate_certificate(tx, certInfo2, False)

        r = requests.get(url = self.BASE_URL+"txs?block="+cert2_3_block+"&showImmatureBTs=0", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert2):
                self.validate_certificate(tx, certInfo2, False)

        r = requests.get(url = self.BASE_URL+"txs?block="+cert2_3_block, params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert2):
                self.validate_certificate(tx, certInfo2, False)

        #Test also the /txs endpoint with address
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=1", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert2):
                self.validate_certificate(tx, certInfo2, False)

        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1+"&showImmatureBTs=0", params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert2):
                self.validate_certificate(tx, certInfo2, False)
        
        r = requests.get(url = self.BASE_URL+"txs?address="+pkh_node1, params = {})
        data = r.json()
        for tx in data['txs']:
            if (tx['txid'] == cert2):
                self.validate_certificate(tx, certInfo2, False)


        #Let the sidechains to cease
        self.nodes[0].generate(120)
        self.sync_all()
        assert_equal(self.nodes[0].getscinfo("*",True)['totalItems'], 0)
        time.sleep(20)

        #Test with a CSW

        # CSW sender MC address, in taddress and pub key hash formats
        csw_mc_address = self.nodes[0].getnewaddress()

        sc_csw_amount = Decimal('1.0')
        nullifier = generate_random_field_element_hex()

        # Get the active cert data hash
        actCertData = self.nodes[0].getactivecertdatahash(scid)['certDataHash']
        
        ceasingCumScTxCommTree = self.nodes[0].getceasingcumsccommtreehash(scid)['ceasingCumScTxCommTree']

        scid1_swapped = swap_bytes(scid)
        sc_proof = cswMcTest.create_test_proof(
                "sc1", sc_csw_amount, str(scid1_swapped), nullifier, csw_mc_address, ceasingCumScTxCommTree,
                actCertData, constant)

        sc_csws = [
        {
            "amount": sc_csw_amount,
            "senderAddress": csw_mc_address,
            "scId": scid,
            "epoch": 0,
            "nullifier": nullifier,
            "activeCertData": actCertData,
            "ceasingCumScTxCommTree": ceasingCumScTxCommTree,
            "scProof": sc_proof
        } ]

        # recipient MC address
        taddr_2 = self.nodes[0].getnewaddress()
        sc_csw_tx_outs = {taddr_2: Decimal(sc_csw_amount)}

        rawtx = self.nodes[0].createrawtransaction([], sc_csw_tx_outs, sc_csws)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sigRawtx = self.nodes[0].signrawtransaction(funded_tx['hex'], None, None, "NONE")
        cswTxid = self.nodes[0].sendrawtransaction(sigRawtx['hex'])

        self.sync_all()
        time.sleep(2)
        self.nodes[0].generate(1)
        self.sync_all()
        time.sleep(2)

        r = requests.get(url = self.BASE_URL+"tx/"+cswTxid, params = {})
        data = r.json()

        cswTx = self.nodes[0].gettransaction(cswTxid)
        decodedCswTx = self.nodes[0].decoderawtransaction(cswTx['hex'])
        self.validate_full_tx(data,decodedCswTx,cswTx)

        #Test with an invalid txid
        invalidTxId = "fe86fa1c6d61585e5e24424997d1542d8857758033937fa0812c407d83adfd14"
        r = requests.get(url = self.BASE_URL+"tx/"+invalidTxId, params = {})
        assert_equal(r.text,"Not found")

#############################################################################################################################

        #### /rawtx/:rawId ####
        print("######## /rawtx/:rawId ########")

        #Test coinbase-transaction
        r = requests.get(url = self.BASE_URL+"rawtx/"+coinbaseTxId, params = {})
        data = r.json()
        assert_equal(data['rawtx'],self.nodes[0].gettransaction(coinbaseTxId)['hex'])

        #Test t-transaction
        r = requests.get(url = self.BASE_URL+"rawtx/"+tTxId, params = {})
        data = r.json()
        assert_equal(data['rawtx'],self.nodes[0].gettransaction(tTxId)['hex'])

        #Test z-transaction t->z
        r = requests.get(url = self.BASE_URL+"rawtx/"+zTxid, params = {})
        data = r.json()
        assert_equal(data['rawtx'],self.nodes[0].gettransaction(zTxid)['hex'])

        #Test z-transaction z->z
        r = requests.get(url = self.BASE_URL+"rawtx/"+zTxid2, params = {})
        data = r.json()
        assert_equal(data['rawtx'],self.nodes[0].gettransaction(zTxid2)['hex'])

        #Test multiple sidechain creation and ft
        r = requests.get(url = self.BASE_URL+"rawtx/"+scTxid, params = {})
        data = r.json()
        assert_equal(data['rawtx'],self.nodes[0].gettransaction(scTxid)['hex'])

        #Test with an invalid txid
        invalidTxId = "fe86fa1c6d61585e5e24424997d1542d8857758033937fa0812c407d83adfd14"
        r = requests.get(url = self.BASE_URL+"rawtx/"+invalidTxId, params = {})
        assert_equal(r.text,"Not found")

#############################################################################################################################

        #### /tx/send ####
        print("######## /tx/send ########")
        txId = self.nodes[0].sendtoaddress(tAddr,10.0001)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        tx = self.nodes[0].gettransaction(txId)
        rawtx = self.nodes[0].decoderawtransaction(tx['hex'])
        vout = {}
        for outpoint in rawtx['vout']:
            if (outpoint['value'] == Decimal('10.0001')):
                vout = outpoint
                break

        inputs = [{'txid': txId, 'vout': vout['n']}]
        rawtx = self.nodes[0].createrawtransaction(inputs, {tAddr2:8.0,tAddr:2.0})
        sigRawtx = self.nodes[0].signrawtransaction(rawtx)

        #Test with not signed tx
        r = requests.post(url = self.BASE_URL+"tx/send", json={"rawtx":rawtx})
        assert_equal(r.status_code,400)

        #Test with signed tx
        r = requests.post(url = self.BASE_URL+"tx/send", json={"rawtx":sigRawtx['hex']})
        assert_equal(r.status_code,200)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        txid = r.json()['txid']
        tx = self.nodes[0].gettransaction(txid)
        decodedTx = self.nodes[0].decoderawtransaction(tx['hex'])
        assert_equal(tx['hex'],sigRawtx['hex'])
        r = requests.get(url = self.BASE_URL+"tx/"+txid, params = {})
        data = r.json()
        self.validate_full_tx(data,decodedTx, tx)

#############################################################################################################################

        #### /txs ####

        #Test with blockhash
        txs = []
        for i in range (1,36):
            txs += [self.nodes[0].sendtoaddress(tAddr,Decimal(str(i)))]
        self.sync_all()
        block = self.nodes[0].generate(1)
        self.sync_all()
        #Add the coinbase to the list of transactions
        txs +=[self.nodes[0].getblock(block[0])['tx'][0]]
        time.sleep(5)

        #Test withouth pageNum (1st page)
        r = requests.get(url = self.BASE_URL+"txs?block="+block[0], params = {})
        data = r.json()
        assert_equal(len(data['txs']),10)
        assert_equal(data['pagesTotal'],4)
        for tx in data['txs']:
            assert_true(tx['txid'] in txs)
            transaction = self.nodes[0].gettransaction(tx['txid'])
            decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex'])
            self.validate_full_tx(tx,decodedTransaction,transaction)

        #Test with pageNum
        r = requests.get(url = self.BASE_URL+"txs?pageNum=1&block="+block[0], params = {})
        data = r.json()
        assert_equal(len(data['txs']),10)
        assert_equal(data['pagesTotal'],4)
        for tx in data['txs']:
            assert_true(tx['txid'] in txs)
            transaction = self.nodes[0].gettransaction(tx['txid'])
            decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex'])
            self.validate_full_tx(tx,decodedTransaction,transaction)

        #Test with last pageNum
        r = requests.get(url = self.BASE_URL+"txs?pageNum=3&block="+block[0], params = {})
        data = r.json()
        assert_equal(len(data['txs']),6)
        assert_equal(data['pagesTotal'],4)
        for tx in data['txs']:
            assert_true(tx['txid'] in txs)
            transaction = self.nodes[0].gettransaction(tx['txid'])
            decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex'])
            self.validate_full_tx(tx,decodedTransaction,transaction)

        #Test with invalid blockhash
        invalidBlockHash = "010857e2c8d072c0142aad2faeca8a856e438fe2d1fe963d78dba8d9e5f664b8"
        r = requests.get(url = self.BASE_URL+"txs?block="+invalidBlockHash, params = {})
        assert_equal(r.status_code,404)

        #Test with address and no pageNum (1st page)
        r = requests.get(url = self.BASE_URL+"txs?address="+tAddr, params = {})
        data = r.json()
        assert_equal(len(data['txs']),10)
        assert_equal(data['pagesTotal'],4)
        txs += [txid,txId,tTxId,zTxid]
        for tx in data['txs']:
            assert_true(tx['txid'] in txs)
            transaction = self.nodes[0].gettransaction(tx['txid'])
            decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex'])
            self.validate_full_tx(tx,decodedTransaction,transaction)

        #Test with address and no pageNum (1st page)
        r = requests.get(url = self.BASE_URL+"txs?pageNum=1&address="+tAddr, params = {})
        data = r.json()
        assert_equal(len(data['txs']),10)
        assert_equal(data['pagesTotal'],4)
        for tx in data['txs']:
            assert_true(tx['txid'] in txs)
            transaction = self.nodes[0].gettransaction(tx['txid'])
            decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex'])

            self.validate_full_tx(tx,decodedTransaction,transaction)

        #Test with address and last pageNum
        r = requests.get(url = self.BASE_URL+"txs?pageNum=3&address="+tAddr, params = {})
        data = r.json()
        assert_equal(len(data['txs']),9)
        assert_equal(data['pagesTotal'],4)
        for tx in data['txs']:
            assert_true(tx['txid'] in txs)
            transaction = self.nodes[0].gettransaction(tx['txid'])
            decodedTransaction = self.nodes[0].decoderawtransaction(transaction['hex'])
            self.validate_full_tx(tx,decodedTransaction,transaction)

        #Test with invalid address
        invalidAddress = "ztVfuvhoNcrunLThJvNeRmg7on4NWidvsVk"
        r = requests.get(url = self.BASE_URL+"txs?address="+invalidAddress, params = {})
        data = r.json()
        assert_equal(len(data['txs']),0)
        assert_equal(data['pagesTotal'],0)

        #Test with no parameters
        r = requests.get(url = self.BASE_URL+"txs", params = {})
        assert_equal(r.status_code,503)
    def run_migration_test(self, node, sproutAddr, saplingAddr, target_height):
        # Make sure we are in a good state to run the test
        assert_equal(102,
                     node.getblockcount() % 500,
                     "Should be at block 102 % 500")
        assert_equal(node.z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(node.z_getbalance(saplingAddr), Decimal('0'))
        check_migration_status(node, saplingAddr, DISABLED_BEFORE_MIGRATION)

        # Migrate
        node.z_setmigration(True)
        print("Mining to block 494 % 500...")
        node.generate(392)  # 102 % 500 -> 494 % 500
        self.sync_all()

        # At 494 % 500 we should have no async operations
        assert_equal(0, len(node.z_getoperationstatus()),
                     "num async operations at 494 % 500")
        check_migration_status(node, saplingAddr, ENABLED_BEFORE_MIGRATION)

        node.generate(1)
        self.sync_all()

        # At 495 % 500 we should have an async operation
        operationstatus = node.z_getoperationstatus()
        print("migration operation: {}".format(operationstatus))
        assert_equal(1, len(operationstatus),
                     "num async operations at 495  % 500")
        assert_equal('saplingmigration', operationstatus[0]['method'])
        assert_equal(target_height, operationstatus[0]['target_height'])

        result = wait_and_assert_operationid_status_result(
            node, operationstatus[0]['id'])
        print("result: {}".format(result))
        assert_equal('saplingmigration', result['method'])
        assert_equal(target_height, result['target_height'])
        assert_equal(1, result['result']['num_tx_created'])
        assert_equal(1, len(result['result']['migration_txids']))
        assert_true(
            Decimal(result['result']['amount_migrated']) > Decimal('0'))

        assert_equal(0, len(node.getrawmempool()), "mempool size at 495 % 500")

        node.generate(3)
        self.sync_all()

        # At 498 % 500 the mempool will be empty and no funds will have moved
        assert_equal(0, len(node.getrawmempool()), "mempool size at 498 % 500")
        assert_equal(node.z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(node.z_getbalance(saplingAddr), Decimal('0'))

        node.generate(1)
        self.sync_all()

        # At 499 % 500 there will be a transaction in the mempool and the note will be locked
        mempool = node.getrawmempool()
        print("mempool: {}".format(mempool))
        assert_equal(1, len(mempool), "mempool size at 499 % 500")
        assert_equal(node.z_getbalance(sproutAddr), Decimal('0'))
        assert_equal(node.z_getbalance(saplingAddr), Decimal('0'))
        assert_true(
            node.z_getbalance(saplingAddr, 0) > Decimal('0'),
            "Unconfirmed sapling balance at 499 % 500")
        # Check that unmigrated amount + unfinalized = starting balance - fee
        status = node.z_getmigrationstatus()
        print("status: {}".format(status))
        assert_equal(
            Decimal('9.9999'),
            Decimal(status['unmigrated_amount']) +
            Decimal(status['unfinalized_migrated_amount']))

        # The transaction in the mempool should be the one listed in migration_txids,
        # and it should expire at the next 450 % 500.
        assert_equal(1, len(status['migration_txids']))
        txid = status['migration_txids'][0]
        assert_equal(txid, mempool[0])
        tx = node.getrawtransaction(txid, 1)
        assert_equal(target_height + 450, tx['expiryheight'])

        node.generate(1)
        self.sync_all()

        # At 0 % 500 funds will have moved
        sprout_balance = node.z_getbalance(sproutAddr)
        sapling_balance = node.z_getbalance(saplingAddr)
        print("sprout balance: {}, sapling balance: {}".format(
            sprout_balance, sapling_balance))
        assert_true(sprout_balance < Decimal('10'),
                    "Should have less Sprout funds")
        assert_true(sapling_balance > Decimal('0'),
                    "Should have more Sapling funds")
        assert_true(sprout_balance + sapling_balance, Decimal('9.9999'))

        check_migration_status(node, saplingAddr, DURING_MIGRATION)
        # At 10 % 500 the transactions will be considered 'finalized'
        node.generate(10)
        self.sync_all()
        check_migration_status(node, saplingAddr, AFTER_MIGRATION)
        # Check exact migration status amounts to make sure we account for fee
        status = node.z_getmigrationstatus()
        assert_equal(sprout_balance, Decimal(status['unmigrated_amount']))
        assert_equal(sapling_balance,
                     Decimal(status['finalized_migrated_amount']))
    def run_migration_test(self, node, sproutAddr, saplingAddr, target_height):
        # Make sure we are in a good state to run the test
        assert_equal(102, node.getblockcount() % 500, "Should be at block 102 % 500")
        assert_equal(node.z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(node.z_getbalance(saplingAddr), Decimal('0'))
        check_migration_status(node, False, saplingAddr, True, False, False, 0, 0)

        # Migrate
        node.z_setmigration(True)
        print("Mining to block 494 % 500...")
        node.generate(392)  # 102 % 500 -> 494 % 500
        self.sync_all()

        # At 494 % 500 we should have no async operations
        assert_equal(0, len(node.z_getoperationstatus()), "num async operations at 494 % 500")
        check_migration_status(node, True, saplingAddr, True, False, False, 0, 0)

        node.generate(1)
        self.sync_all()

        # At 495 % 500 we should have an async operation
        operationstatus = node.z_getoperationstatus()
        print("migration operation: {}".format(operationstatus))
        assert_equal(1, len(operationstatus), "num async operations at 495  % 500")
        assert_equal('saplingmigration', operationstatus[0]['method'])
        assert_equal(target_height, operationstatus[0]['target_height'])

        result = wait_and_assert_operationid_status_result(node, operationstatus[0]['id'])
        print("result: {}".format(result))
        assert_equal('saplingmigration', result['method'])
        assert_equal(target_height, result['target_height'])
        assert_equal(1, result['result']['num_tx_created'])

        assert_equal(0, len(node.getrawmempool()), "mempool size at 495 % 500")

        node.generate(3)
        self.sync_all()

        # At 498 % 500 the mempool will be empty and no funds will have moved
        assert_equal(0, len(node.getrawmempool()), "mempool size at 498 % 500")
        assert_equal(node.z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(node.z_getbalance(saplingAddr), Decimal('0'))

        node.generate(1)
        self.sync_all()

        # At 499 % 500 there will be a transaction in the mempool and the note will be locked
        assert_equal(1, len(node.getrawmempool()), "mempool size at 499 % 500")
        assert_equal(node.z_getbalance(sproutAddr), Decimal('0'))
        assert_equal(node.z_getbalance(saplingAddr), Decimal('0'))
        assert_true(node.z_getbalance(saplingAddr, 0) > Decimal('0'), "Unconfirmed sapling balance at 499 % 500")
        # Check that unmigrated amount + unfinalized = starting balance - fee
        status = node.z_getmigrationstatus()
        assert_equal(Decimal('9.9999'), Decimal(status['unmigrated_amount']) + Decimal(status['unfinalized_migrated_amount']))

        node.generate(1)
        self.sync_all()

        # At 0 % 500 funds will have moved
        sprout_balance = node.z_getbalance(sproutAddr)
        sapling_balance = node.z_getbalance(saplingAddr)
        print("sprout balance: {}, sapling balance: {}".format(sprout_balance, sapling_balance))
        assert_true(sprout_balance < Decimal('10'), "Should have less Sprout funds")
        assert_true(sapling_balance > Decimal('0'), "Should have more Sapling funds")
        assert_true(sprout_balance + sapling_balance, Decimal('9.9999'))

        check_migration_status(node, True, saplingAddr, True, True, False, 0, 1)
        # At 10 % 500 the transactions will be considered 'finalized'
        node.generate(10)
        self.sync_all()
        check_migration_status(node, True, saplingAddr, True, False, True, 1, 1)
        # Check exact migration status amounts to make sure we account for fee
        status = node.z_getmigrationstatus()
        assert_equal(sprout_balance, Decimal(status['unmigrated_amount']))
        assert_equal(sapling_balance, Decimal(status['finalized_migrated_amount']))
Exemple #23
0
class SCCreateTest(BitcoinTestFramework):
    alert_filename = None

    def setup_chain(self, split=False):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)
        self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
        with open(self.alert_filename, 'w'):
            pass  # Just open then close to create zero-length file

    def setup_network(self, split=False):

        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[[
                "-sccoinsmaturity=%d" % SC_COINS_MAT, '-logtimemicros=1',
                '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net',
                '-debug=bench'
            ]] * NUMB_OF_NODES)

        connect_nodes_bi(self.nodes, 0, 1)
        self.is_network_split = split
        self.sync_all()

    def run_test(self):
        '''
        This test try to create a SC using the command sc_create using invalid parameters and valid parameters.
        '''
        #{"withdrawalEpochLength", "fromaddress", "toaddress", "amount", "minconf", "fee", "customData"};

        # network topology: (0)--(1)

        mark_logs("Node 1 generates 2 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(2)
        self.sync_all()

        mark_logs("Node 0 generates {} block".format(MINIMAL_SC_HEIGHT),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        tx = []
        errorString = ""
        toaddress = "abcdef"

        #generate wCertVk and constant
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params('sc1')
        constant = generate_random_field_element_hex()

        # create with wrong key in input
        #------------------------------------
        amount = 12.0
        fee = 0.000025

        cmdInput = {
            'version': 0,
            'wrong_key': 123,
            'toaddress': toaddress,
            'amount': amount,
            'fee': fee,
            'wCertVk': vk
        }

        mark_logs("\nNode 1 create SC with wrong key in input", self.nodes,
                  DEBUG_MODE)
        try:
            self.nodes[1].sc_create(cmdInput)
            assert_true(False)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true("wrong_key" in errorString)

        # create with duplicate key in input
        #------------------------------------
        cmdInput = FakeDict([('version', 0), ('fee', fee), ('amount', amount),
                             ('amount', 6.0), ('toaddress', str(toaddress)),
                             ('wCertVk', vk)])

        mark_logs("\nNode 1 create SC with duplicate key in input", self.nodes,
                  DEBUG_MODE)
        try:
            self.nodes[1].sc_create(cmdInput)
            assert_true(False)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true("amount" in errorString)
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(101)
        self.sync_all()

        # Send some ZEC to a Sprout address
        tAddr = get_coinbase_address(self.nodes[0])
        sproutAddr = self.nodes[0].z_getnewaddress('sprout')
        saplingAddr = self.nodes[0].z_getnewaddress('sapling')

        opid = self.nodes[0].z_sendmany(tAddr, [{
            "address": sproutAddr,
            "amount": Decimal('10')
        }], 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], opid)
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))

        # Migrate
        self.nodes[0].z_setmigration(True)
        print "Mining to block 494..."
        self.nodes[0].generate(392)  # 102 -> 494
        self.sync_all()

        # At 494 we should have no async operations
        assert_equal(0, len(self.nodes[0].z_getoperationstatus()),
                     "num async operations at 494")

        self.nodes[0].generate(1)
        self.sync_all()

        # At 495 we should have an async operation
        operationstatus = self.nodes[0].z_getoperationstatus()
        print "migration operation: {}".format(operationstatus)
        assert_equal(1, len(operationstatus), "num async operations at 495")
        assert_equal('saplingmigration', operationstatus[0]['method'])
        assert_equal(500, operationstatus[0]['target_height'])

        result = wait_and_assert_operationid_status_result(
            self.nodes[0], operationstatus[0]['id'])
        print "result: {}".format(result)
        assert_equal('saplingmigration', result['method'])
        assert_equal(500, result['target_height'])
        assert_equal(1, result['result']['num_tx_created'])

        assert_equal(0, len(self.nodes[0].getrawmempool()),
                     "mempool size at 495")

        self.nodes[0].generate(3)
        self.sync_all()

        # At 498 the mempool will be empty and no funds will have moved
        assert_equal(0, len(self.nodes[0].getrawmempool()),
                     "mempool size at 498")
        assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('10'))
        assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))

        self.nodes[0].generate(1)
        self.sync_all()

        # At 499 there will be a transaction in the mempool and the note will be locked
        assert_equal(1, len(self.nodes[0].getrawmempool()),
                     "mempool size at 499")
        assert_equal(self.nodes[0].z_getbalance(sproutAddr), Decimal('0'))
        assert_equal(self.nodes[0].z_getbalance(saplingAddr), Decimal('0'))
        assert_true(self.nodes[0].z_getbalance(saplingAddr, 0) > Decimal('0'),
                    "Unconfirmed sapling")

        self.nodes[0].generate(1)
        self.sync_all()

        # At 500 funds will have moved
        sprout_balance = self.nodes[0].z_getbalance(sproutAddr)
        sapling_balance = self.nodes[0].z_getbalance(saplingAddr)
        print "sprout balance: {}, sapling balance: {}".format(
            sprout_balance, sapling_balance)
        assert_true(sprout_balance < Decimal('10'),
                    "Should have less Sprout funds")
        assert_true(sapling_balance > Decimal('0'),
                    "Should have more Sapling funds")
        assert_true(sprout_balance + sapling_balance, Decimal('9.9999'))
    def run_test(self):
        def get_spendable(nodeIdx, min_amount):
            # get a UTXO for setting fee
            utx = False
            listunspent = self.nodes[nodeIdx].listunspent()
            for aUtx in listunspent:
                if aUtx['amount'] > min_amount:
                    utx = aUtx
                    change = aUtx['amount'] - min_amount
                    break

            if utx == False:
                pprint.pprint(listunspent)

            assert_equal(utx != False, True)
            return utx, change

        '''
        Testing the capabilities of the api for creating raw certificates and handling their decoding.
        Negative tests are also performed by specifying wrong params and incorrect pkey for the signing
        '''

        # forward transfer amount
        cr_amount = Decimal("5.0")
        bt_amount = Decimal("4.0")
        sc_amount = cr_amount

        # node 1 earns some coins, they would be available after 100 blocks
        mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(1)
        self.sync_all()

        mark_logs("Node 0 generates 1 block", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()
        mark_logs("Node 3 generates {} block".format(MINIMAL_SC_HEIGHT - 1),
                  self.nodes, DEBUG_MODE)
        self.nodes[3].generate(MINIMAL_SC_HEIGHT - 1)
        self.sync_all()

        # node 1 has just the coinbase which is now mature
        bal_before = self.nodes[1].getbalance("", 0)

        # create a sc via createraw cmd
        mark_logs(
            "Node 1 creates the SC spending " + str(sc_amount) + " coins ...",
            self.nodes, DEBUG_MODE)
        sc_address = "fade"

        #generate vk and constant for this sidechain
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        sc_cr = [{
            "version": 0,
            "epoch_length": EPOCH_LENGTH,
            "amount": cr_amount,
            "address": sc_address,
            "wCertVk": vk,
            "constant": constant
        }]
        sc_ft = []
        raw_tx = self.nodes[1].createrawtransaction([], {}, [], sc_cr, sc_ft)
        funded_tx = self.nodes[1].fundrawtransaction(raw_tx)
        signed_tx = self.nodes[1].signrawtransaction(funded_tx['hex'])
        creating_tx = self.nodes[1].sendrawtransaction(signed_tx['hex'])
        self.sync_all()

        decoded_tx = self.nodes[1].getrawtransaction(creating_tx, 1)
        scid = decoded_tx['vsc_ccout'][0]['scid']
        scid_swapped = str(swap_bytes(scid))
        mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE)

        #retrieve previous_end_epoch_mc_b_hash
        current_height = self.nodes[3].getblockcount()
        mark_logs("Node3 generating {} blocks".format(EPOCH_LENGTH),
                  self.nodes, DEBUG_MODE)
        self.nodes[3].generate(EPOCH_LENGTH)
        self.sync_all()

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)

        # save them for the last test
        epn_0 = epoch_number
        epoch_cum_tree_hash_0 = epoch_cum_tree_hash

        # -------------------------- end epoch

        sc_funds_pre = self.nodes[3].getscinfo(scid)['items'][0]['balance']

        addr_node2 = self.nodes[2].getnewaddress()

        mark_logs("Node3 generating 2 block, overcoming safeguard", self.nodes,
                  DEBUG_MODE)
        self.nodes[3].generate(2)
        self.sync_all()

        # create wCert proof
        quality = 0
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [addr_node2], [bt_amount])

        utx, change = get_spendable(0, CERT_FEE)
        raw_inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        raw_outs = {self.nodes[0].getnewaddress(): change}

        raw_bwt_outs = [{"address": addr_node2, "amount": bt_amount}]
        raw_params = {
            "scid": scid,
            "quality": quality,
            "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash,
            "scProof": proof,
            "withdrawalEpochNumber": epoch_number
        }
        raw_cert = []
        cert = []

        try:
            raw_cert = self.nodes[0].createrawcertificate(
                raw_inputs, raw_outs, raw_bwt_outs, raw_params)
            signed_cert = self.nodes[0].signrawtransaction(raw_cert)
        except JSONRPCException, e:
            errorString = e.error['message']
            print "\n======> ", errorString
            assert_true(False)
class sc_rawcert(BitcoinTestFramework):

    alert_filename = None

    def setup_chain(self, split=False):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)
        self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
        with open(self.alert_filename, 'w'):
            pass  # Just open then close to create zero-length file

    def setup_network(self, split=False):
        self.nodes = []

        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[[
                '-debug=py', '-debug=sc', '-debug=mempool', '-debug=net',
                '-debug=cert', '-scproofqueuesize=0', '-logtimemicros=1',
                '-txindex=1', '-zapwallettxes=2'
            ]] * NUMB_OF_NODES)

        for idx, _ in enumerate(self.nodes):
            if idx < (NUMB_OF_NODES - 1):
                connect_nodes_bi(self.nodes, idx, idx + 1)

        sync_blocks(self.nodes[1:NUMB_OF_NODES])
        sync_mempools(self.nodes[1:NUMB_OF_NODES])
        self.is_network_split = split
        self.sync_all()

    def run_test(self):
        def get_spendable(nodeIdx, min_amount):
            # get a UTXO for setting fee
            utx = False
            listunspent = self.nodes[nodeIdx].listunspent()
            for aUtx in listunspent:
                if aUtx['amount'] > min_amount:
                    utx = aUtx
                    change = aUtx['amount'] - min_amount
                    break

            if utx == False:
                pprint.pprint(listunspent)

            assert_equal(utx != False, True)
            return utx, change

        '''
        Testing the capabilities of the api for creating raw certificates and handling their decoding.
        Negative tests are also performed by specifying wrong params and incorrect pkey for the signing
        '''

        # forward transfer amount
        cr_amount = Decimal("5.0")
        bt_amount = Decimal("4.0")
        sc_amount = cr_amount

        # node 1 earns some coins, they would be available after 100 blocks
        mark_logs("Node 1 generates 1 block", self.nodes, DEBUG_MODE)
        self.nodes[1].generate(1)
        self.sync_all()

        mark_logs("Node 0 generates 1 block", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()
        mark_logs("Node 3 generates {} block".format(MINIMAL_SC_HEIGHT - 1),
                  self.nodes, DEBUG_MODE)
        self.nodes[3].generate(MINIMAL_SC_HEIGHT - 1)
        self.sync_all()

        # node 1 has just the coinbase which is now mature
        bal_before = self.nodes[1].getbalance("", 0)

        # create a sc via createraw cmd
        mark_logs(
            "Node 1 creates the SC spending " + str(sc_amount) + " coins ...",
            self.nodes, DEBUG_MODE)
        sc_address = "fade"

        #generate vk and constant for this sidechain
        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        sc_cr = [{
            "version": 0,
            "epoch_length": EPOCH_LENGTH,
            "amount": cr_amount,
            "address": sc_address,
            "wCertVk": vk,
            "constant": constant
        }]
        sc_ft = []
        raw_tx = self.nodes[1].createrawtransaction([], {}, [], sc_cr, sc_ft)
        funded_tx = self.nodes[1].fundrawtransaction(raw_tx)
        signed_tx = self.nodes[1].signrawtransaction(funded_tx['hex'])
        creating_tx = self.nodes[1].sendrawtransaction(signed_tx['hex'])
        self.sync_all()

        decoded_tx = self.nodes[1].getrawtransaction(creating_tx, 1)
        scid = decoded_tx['vsc_ccout'][0]['scid']
        scid_swapped = str(swap_bytes(scid))
        mark_logs("created SC id: {}".format(scid), self.nodes, DEBUG_MODE)

        #retrieve previous_end_epoch_mc_b_hash
        current_height = self.nodes[3].getblockcount()
        mark_logs("Node3 generating {} blocks".format(EPOCH_LENGTH),
                  self.nodes, DEBUG_MODE)
        self.nodes[3].generate(EPOCH_LENGTH)
        self.sync_all()

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)

        # save them for the last test
        epn_0 = epoch_number
        epoch_cum_tree_hash_0 = epoch_cum_tree_hash

        # -------------------------- end epoch

        sc_funds_pre = self.nodes[3].getscinfo(scid)['items'][0]['balance']

        addr_node2 = self.nodes[2].getnewaddress()

        mark_logs("Node3 generating 2 block, overcoming safeguard", self.nodes,
                  DEBUG_MODE)
        self.nodes[3].generate(2)
        self.sync_all()

        # create wCert proof
        quality = 0
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [addr_node2], [bt_amount])

        utx, change = get_spendable(0, CERT_FEE)
        raw_inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        raw_outs = {self.nodes[0].getnewaddress(): change}

        raw_bwt_outs = [{"address": addr_node2, "amount": bt_amount}]
        raw_params = {
            "scid": scid,
            "quality": quality,
            "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash,
            "scProof": proof,
            "withdrawalEpochNumber": epoch_number
        }
        raw_cert = []
        cert = []

        try:
            raw_cert = self.nodes[0].createrawcertificate(
                raw_inputs, raw_outs, raw_bwt_outs, raw_params)
            signed_cert = self.nodes[0].signrawtransaction(raw_cert)
        except JSONRPCException, e:
            errorString = e.error['message']
            print "\n======> ", errorString
            assert_true(False)

        decoded_cert_pre = self.nodes[0].decoderawtransaction(raw_cert)
        decoded_cert_pre_list = sorted(decoded_cert_pre.items())

        mark_logs(
            "Node0 sending raw certificate for epoch {}, expecting failure...".
            format(epoch_number), self.nodes, DEBUG_MODE)
        # we expect it to fail because beyond the safeguard
        try:
            cert = self.nodes[0].sendrawtransaction(signed_cert['hex'])
            assert_true(False)
        except JSONRPCException, e:
            errorString = e.error['message']
            print "======> ", errorString, "\n"
        mark_logs(
            "Node0 invalidates last block, thus shortening the chain by one and returning in the safe margin",
            self.nodes, DEBUG_MODE)
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        sync_mempools(self.nodes[1:3])

        mark_logs(
            "Node0 sending raw certificate for epoch {}, expecting success".
            format(epoch_number), self.nodes, DEBUG_MODE)
        try:
            cert = self.nodes[0].sendrawtransaction(signed_cert['hex'])
        except JSONRPCException, e:
            errorString = e.error['message']
            print "\n======> ", errorString
            assert_true(False)

        decoded_cert_pre = self.nodes[0].decoderawtransaction(
            signed_cert['hex'])
        decoded_cert_pre_list = sorted(decoded_cert_pre.items())

        sync_mempools(self.nodes[1:3])

        mark_logs(
            "Node0 generating 4 block, also reverting other nodes' chains",
            self.nodes, DEBUG_MODE)
        mined = self.nodes[0].generate(1)[0]
        minedBlock = self.nodes[0].getblock(mined)
        #epoch_number = 1
        self.nodes[0].generate(3)
        epoch_number, epoch_cum_tree_hash = get_epoch_data(
Exemple #28
0
    def run_test(self):
        # Sanity-check the test harness
        self.nodes[0].generate(200)
        assert_equal(self.nodes[0].getblockcount(), 200)
        self.sync_all()

        # Verify Sapling address is persisted in wallet (even when Sapling is not yet active)
        sapling_addr = self.nodes[0].z_getnewaddress('sapling')

        # Make sure the node has the addresss
        addresses = self.nodes[0].z_listaddresses()
        assert_true(sapling_addr in addresses, "Should contain address before restart")

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Make sure we still have the address after restarting
        addresses = self.nodes[0].z_listaddresses()
        assert_true(sapling_addr in addresses, "Should contain address after restart")

        # Activate Sapling
        self.nodes[0].generate(1)
        self.sync_all()

        # Node 0 shields funds to Sapling address
        taddr0 = self.nodes[0].getnewaddress()
        recipients = []
        recipients.append({"address": sapling_addr, "amount": Decimal('20')})
        myopid = self.nodes[0].z_sendmany(taddr0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Verify shielded balance
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20'))
        
        # Verify size of shielded pools
        pools = self.nodes[0].getblockchaininfo()['valuePools']
        assert_equal(pools[0]['chainValue'], Decimal('0'))  # Sprout
        assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling
        
        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify size of shielded pools
        pools = self.nodes[0].getblockchaininfo()['valuePools']
        assert_equal(pools[0]['chainValue'], Decimal('0'))  # Sprout
        assert_equal(pools[1]['chainValue'], Decimal('20')) # Sapling

        # Node 0 sends some shielded funds to Node 1
        dest_addr = self.nodes[1].z_getnewaddress('sapling')
        recipients = []
        recipients.append({"address": dest_addr, "amount": Decimal('15')})
        myopid = self.nodes[0].z_sendmany(sapling_addr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Verify balances
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15'))

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify balances
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('15'))

        # Verify importing a spending key will update and persist the nullifiers and witnesses correctly
        sk0 = self.nodes[0].z_exportkey(sapling_addr)
        self.nodes[2].z_importkey(sk0, "yes")
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5'))

        # Restart the nodes
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Verify nullifiers persisted correctly by checking balance
        # Prior to PR #3590, there will be an error as spent notes are considered unspent:
        #    Assertion failed: expected: <25.00000000> but was: <5>
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('5'))

        # Verity witnesses persisted correctly by sending shielded funds
        recipients = []
        recipients.append({"address": dest_addr, "amount": Decimal('1')})
        myopid = self.nodes[2].z_sendmany(sapling_addr, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[2], myopid)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Verify balances
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
    def run_test(self):
        sapling_address2 = self.nodes[2].z_getnewaddress('sapling')
        privkey2 = self.nodes[2].z_exportkey(sapling_address2)
        self.nodes[0].z_importkey(privkey2)

        sprout_address0 = self.nodes[0].z_getnewaddress('sprout')
        sapling_address0 = self.nodes[0].z_getnewaddress('sapling')

        # node 0 should have the keys
        dump_path0 = self.nodes[0].z_exportwallet('walletdump')
        (t_keys0, sprout_keys0, sapling_keys0) = parse_wallet_file(dump_path0)

        sapling_line_lengths = [len(sapling_key0.split(' #')[0].split()) for sapling_key0 in sapling_keys0.splitlines()]
        assert_equal(2, len(sapling_line_lengths), "Should have 2 sapling keys")
        assert_true(2 in sapling_line_lengths, "Should have a key with 2 parameters")
        assert_true(4 in sapling_line_lengths, "Should have a key with 4 parameters")

        assert_true(sprout_address0 in sprout_keys0)
        assert_true(sapling_address0 in sapling_keys0)
        assert_true(sapling_address2 in sapling_keys0)

        # node 1 should not have the keys
        dump_path1 = self.nodes[1].z_exportwallet('walletdumpbefore')
        (t_keys1, sprout_keys1, sapling_keys1) = parse_wallet_file(dump_path1)
        
        assert_true(sprout_address0 not in sprout_keys1)
        assert_true(sapling_address0 not in sapling_keys1)

        # import wallet to node 1
        self.nodes[1].z_importwallet(dump_path0)

        # node 1 should now have the keys
        dump_path1 = self.nodes[1].z_exportwallet('walletdumpafter')
        (t_keys1, sprout_keys1, sapling_keys1) = parse_wallet_file(dump_path1)
        
        assert_true(sprout_address0 in sprout_keys1)
        assert_true(sapling_address0 in sapling_keys1)
        assert_true(sapling_address2 in sapling_keys1)

        # make sure we have perserved the metadata
        for sapling_key0 in sapling_keys0.splitlines():
            assert_true(sapling_key0 in sapling_keys1)
    def run_test(self):
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress('sprout')
        zaddr2 = self.nodes[1].z_getnewaddress('sprout')

        self.nodes[0].sendtoaddress(taddr, Decimal('1.0'))
        self.generate_and_sync()

        # Send 1 ANK to a zaddr
        wait_and_assert_operationid_status(
            self.nodes[1], self.nodes[1].z_sendmany(taddr, [{
                'address': zaddr1,
                'amount': 1.0,
                'memo': 'c0ffee01'
            }], 1, 0))
        self.generate_and_sync()

        # Check that we have received 1 note which is not change
        receivedbyaddress = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        listunspent = self.nodes[1].z_listunspent()
        assert_equal(1, len(receivedbyaddress), "Should have received 1 note")
        assert_false(receivedbyaddress[0]['change'],
                     "Note should not be change")
        assert_equal(1, len(listunspent), "Should have 1 unspent note")
        assert_false(listunspent[0]['change'],
                     "Unspent note should not be change")

        # Generate some change
        wait_and_assert_operationid_status(
            self.nodes[1], self.nodes[1].z_sendmany(zaddr1, [{
                'address': zaddr2,
                'amount': 0.6,
                'memo': 'c0ffee02'
            }], 1, 0))
        self.generate_and_sync()

        # Check zaddr1 received
        sortedreceived1 = sorted(self.nodes[1].z_listreceivedbyaddress(
            zaddr1, 0),
                                 key=lambda received: received['amount'])
        assert_equal(2, len(sortedreceived1),
                     "zaddr1 Should have received 2 notes")
        assert_equal(Decimal('0.4'), sortedreceived1[0]['amount'])
        assert_true(sortedreceived1[0]['change'],
                    "Note valued at 0.4 should be change")
        assert_equal(Decimal('1.0'), sortedreceived1[1]['amount'])
        assert_false(sortedreceived1[1]['change'],
                     "Note valued at 1.0 should not be change")
        # Check zaddr2 received
        sortedreceived2 = sorted(self.nodes[1].z_listreceivedbyaddress(
            zaddr2, 0),
                                 key=lambda received: received['amount'])
        assert_equal(1, len(sortedreceived2),
                     "zaddr2 Should have received 1 notes")
        assert_equal(Decimal('0.6'), sortedreceived2[0]['amount'])
        assert_false(sortedreceived2[0]['change'],
                     "Note valued at 0.6 should not be change")
        # Check unspent
        sortedunspent = sorted(self.nodes[1].z_listunspent(),
                               key=lambda received: received['amount'])
        assert_equal(2, len(sortedunspent), "Should have 2 unspent notes")
        assert_equal(Decimal('0.4'), sortedunspent[0]['amount'])
        assert_true(sortedunspent[0]['change'],
                    "Unspent note valued at 0.4 should be change")
        assert_equal(Decimal('0.6'), sortedunspent[1]['amount'])
        assert_false(sortedunspent[1]['change'],
                     "Unspent note valued at 0.6 should not be change")

        # Give node 0 a viewing key
        viewing_key = self.nodes[1].z_exportviewingkey(zaddr1)
        self.nodes[0].z_importviewingkey(viewing_key)
        received_node0 = self.nodes[0].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(received_node0))
        unspent_node0 = self.nodes[0].z_listunspent(1, 9999999, True)
        assert_equal(2, len(unspent_node0))
        # node 0 only has a viewing key so does not see the change field
        assert_false('change' in received_node0[0])
        assert_false('change' in received_node0[1])
        assert_false('change' in unspent_node0[0])
        assert_false('change' in unspent_node0[1])
    def run_test(self):
        self.enable_mocktime()
        self.setup_2_masternodes_network()

        # Prepare the proposal
        self.log.info("preparing budget proposal..")
        firstProposalName = "super-cool"
        firstProposalLink = "https://forum.flitswallet.app/t/test-proposal"
        firstProposalCycles = 2
        firstProposalAddress = self.miner.getnewaddress()
        firstProposalAmountPerCycle = 300
        nextSuperBlockHeight = self.miner.getnextsuperblock()

        proposalFeeTxId = self.miner.preparebudget(
            firstProposalName, firstProposalLink, firstProposalCycles,
            nextSuperBlockHeight, firstProposalAddress,
            firstProposalAmountPerCycle)

        # generate 3 blocks to confirm the tx (and update the mnping)
        self.stake(3, [self.remoteOne, self.remoteTwo])

        # activate sporks
        self.activate_spork(self.minerPos,
                            "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT")
        self.activate_spork(self.minerPos,
                            "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT")
        self.activate_spork(self.minerPos, "SPORK_13_ENABLE_SUPERBLOCKS")

        txinfo = self.miner.gettransaction(proposalFeeTxId)
        assert_equal(txinfo['amount'], -50.00)

        self.log.info("submitting the budget proposal..")

        proposalHash = self.miner.submitbudget(
            firstProposalName, firstProposalLink, firstProposalCycles,
            nextSuperBlockHeight, firstProposalAddress,
            firstProposalAmountPerCycle, proposalFeeTxId)

        # let's wait a little bit and see if all nodes are sync
        time.sleep(1)
        self.check_proposal_existence(firstProposalName, proposalHash)
        self.log.info("proposal broadcast successful!")

        # Proposal is established after 5 minutes. Mine 7 blocks
        # Proposal needs to be on the chain > 5 min.
        self.stake(7, [self.remoteOne, self.remoteTwo])

        # now let's vote for the proposal with the first MN
        self.log.info("broadcasting votes for the proposal now..")
        voteResult = self.ownerOne.mnbudgetvote("alias", proposalHash, "yes",
                                                self.masternodeOneAlias)
        assert_equal(voteResult["detail"][0]["result"], "success")

        # check that the vote was accepted everywhere
        self.stake(1, [self.remoteOne, self.remoteTwo])
        self.check_vote_existence(firstProposalName, self.mnOneTxHash, "YES")
        self.log.info("all good, MN1 vote accepted everywhere!")

        # now let's vote for the proposal with the second MN
        voteResult = self.ownerTwo.mnbudgetvote("alias", proposalHash, "yes",
                                                self.masternodeTwoAlias)
        assert_equal(voteResult["detail"][0]["result"], "success")

        # check that the vote was accepted everywhere
        self.stake(1, [self.remoteOne, self.remoteTwo])
        self.check_vote_existence(firstProposalName, self.mnTwoTxHash, "YES")
        self.log.info("all good, MN2 vote accepted everywhere!")

        # Now check the budget
        blockStart = nextSuperBlockHeight
        blockEnd = blockStart + firstProposalCycles * 145
        TotalPayment = firstProposalAmountPerCycle * firstProposalCycles
        Allotted = firstProposalAmountPerCycle
        RemainingPaymentCount = firstProposalCycles
        expected_budget = [
            self.get_proposal_obj(firstProposalName, firstProposalLink,
                                  proposalHash, proposalFeeTxId, blockStart,
                                  blockEnd, firstProposalCycles,
                                  RemainingPaymentCount, firstProposalAddress,
                                  1, 2, 0, 0, Decimal(str(TotalPayment)),
                                  Decimal(str(firstProposalAmountPerCycle)),
                                  True, True, Decimal(str(Allotted)),
                                  Decimal(str(Allotted)))
        ]
        self.check_budgetprojection(expected_budget)

        # Quick block count check.
        assert_equal(self.ownerOne.getblockcount(), 276)

        self.log.info("starting budget finalization sync test..")
        self.stake(5, [self.remoteOne, self.remoteTwo])

        # assert that there is no budget finalization first.
        assert_true(len(self.ownerOne.mnfinalbudget("show")) == 0)

        # suggest the budget finalization and confirm the tx (+4 blocks).
        budgetFinHash = self.broadcastbudgetfinalization(
            self.miner, with_ping_mns=[self.remoteOne, self.remoteTwo])
        assert (budgetFinHash != "")
        time.sleep(1)

        self.log.info("checking budget finalization sync..")
        self.check_budget_finalization_sync(0, "OK")

        self.log.info(
            "budget finalization synced!, now voting for the budget finalization.."
        )

        self.ownerOne.mnfinalbudget("vote-many", budgetFinHash)
        self.ownerTwo.mnfinalbudget("vote-many", budgetFinHash)
        self.stake(2, [self.remoteOne, self.remoteTwo])

        self.log.info("checking finalization votes..")
        self.check_budget_finalization_sync(2, "OK")

        self.stake(8, [self.remoteOne, self.remoteTwo])
        addrInfo = self.miner.listreceivedbyaddress(0, False, False,
                                                    firstProposalAddress)
        assert_equal(addrInfo[0]["amount"], firstProposalAmountPerCycle)

        self.log.info("budget proposal paid!, all good")

        # Check that the proposal info returns updated payment count
        expected_budget[0]["RemainingPaymentCount"] -= 1
        self.check_budgetprojection(expected_budget)
Exemple #32
0
        assert_equal(
            retrieved_cert['amount'],
            amount_cert_1[0]["amount"])  # Certificate amount has matured
        assert_equal(retrieved_cert['details'][0]['category'], "receive")
        assert_equal(
            retrieved_cert['details'][0]['amount'], amount_cert_1[0]["amount"]
        )  # In cert details you can see the actual amount transferred

        assert_equal(self.nodes[1].getwalletinfo()['immature_balance'],
                     Decimal(0))
        utxos_Node1 = self.nodes[1].listunspent()
        cert_epoch_0_availalble = False
        for utxo in utxos_Node1:
            if ("certified" in utxo.keys()):
                cert_epoch_0_availalble = True
                assert_true(utxo["txid"] == cert_epoch_0)
        assert_true(cert_epoch_0_availalble)

        mark_logs(
            "Checking Node1 balance is duly updated,".format(epoch_number),
            self.nodes, DEBUG_MODE)
        assert_equal(bal_after_cert_2,
                     bal_before_cert_2 + amount_cert_1[0]["amount"])

        Node2_bal_before_cert_expenditure = self.nodes[2].getbalance("", 0)
        mark_logs(
            "Checking that Node1 can spend coins received from bwd transfer in previous epoch",
            self.nodes, DEBUG_MODE)
        mark_logs(
            "Node 1 sends {} coins to node2...".format(
                amount_cert_1[0]["amount"] / 2), self.nodes, DEBUG_MODE)
Exemple #33
0
        # create with a missing mandatory key in input
        #------------------------------------------------
        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': 10,
            'toaddress': toaddress,
            'fee': fee,
            'wCertVk': vk,
            'customData': "bb" * 1024
        }

        mark_logs("\nNode 1 create SC with duplicate key in input", self.nodes,
                  DEBUG_MODE)
        try:
            self.nodes[1].sc_create(cmdInput)
            assert_true(False)
        except JSONRPCException, e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true("amount" in errorString)

        # create with a bad value for amount
        #------------------------------------------------
        cmdInput = {
            'version': 0,
            'withdrawalEpochLength': 10,
            'toaddress': toaddress,
            'amount': -0.1,
            'fee': fee,
            'wCertVk': vk,
            'constant': constant
Exemple #34
0
    def run_test_release(self, release, height):
        self.generate_and_sync(height + 1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress(release)
        zaddrExt = self.nodes[3].z_getnewaddress(release)

        self.nodes[0].sendtoaddress(taddr, 4.0)
        self.generate_and_sync(height + 2)

        # Send 1 ZEC to zaddr1
        opid = self.nodes[1].z_sendmany(taddr, [
            {
                'address': zaddr1,
                'amount': 1,
                'memo': my_memo
            },
            {
                'address': zaddrExt,
                'amount': 2
            },
        ])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()

        # Decrypted transaction details should be correct
        pt = self.nodes[1].z_viewtransaction(txid)
        assert_equal(pt['txid'], txid)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 1 if release == 'sprout' else 2)

        # Output orders can be randomized, so we check the output
        # positions and contents separately
        outputs = []

        assert_equal(pt['outputs'][0]['type'], release)
        if release == 'sprout':
            assert_equal(pt['outputs'][0]['js'], 0)
            jsOutputPrev = pt['outputs'][0]['jsOutput']
        elif pt['outputs'][0]['address'] == zaddr1:
            assert_equal(pt['outputs'][0]['outgoing'], False)
            assert_equal(pt['outputs'][0]['memoStr'], my_memo_str)
        else:
            assert_equal(pt['outputs'][0]['outgoing'], True)
        outputs.append({
            'address': pt['outputs'][0]['address'],
            'value': pt['outputs'][0]['value'],
            'valueZat': pt['outputs'][0]['valueZat'],
            'memo': pt['outputs'][0]['memo'],
        })

        if release != 'sprout':
            assert_equal(pt['outputs'][1]['type'], release)
            if pt['outputs'][1]['address'] == zaddr1:
                assert_equal(pt['outputs'][1]['outgoing'], False)
                assert_equal(pt['outputs'][1]['memoStr'], my_memo_str)
            else:
                assert_equal(pt['outputs'][1]['outgoing'], True)
            outputs.append({
                'address': pt['outputs'][1]['address'],
                'value': pt['outputs'][1]['value'],
                'valueZat': pt['outputs'][1]['valueZat'],
                'memo': pt['outputs'][1]['memo'],
            })

        assert ({
            'address': zaddr1,
            'value': Decimal('1'),
            'valueZat': 100000000,
            'memo': my_memo,
        } in outputs)
        if release != 'sprout':
            assert ({
                'address': zaddrExt,
                'value': Decimal('2'),
                'valueZat': 200000000,
                'memo': no_memo,
            } in outputs)

        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid, r[0]['txid'])
        assert_equal(1, r[0]['amount'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])

        # Confirm transaction (1 ZEC from taddr to zaddr1)
        self.generate_and_sync(height + 3)

        # Require one confirmation, note should be present
        assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1))

        # Generate some change by sending part of zaddr1 to zaddr2
        txidPrev = txid
        zaddr2 = self.nodes[1].z_getnewaddress(release)
        opid = self.nodes[1].z_sendmany(zaddr1, [{
            'address': zaddr2,
            'amount': 0.6
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        self.generate_and_sync(height + 4)

        # Decrypted transaction details should be correct
        pt = self.nodes[1].z_viewtransaction(txid)
        assert_equal(pt['txid'], txid)
        assert_equal(len(pt['spends']), 1)
        assert_equal(len(pt['outputs']), 2)

        assert_equal(pt['spends'][0]['type'], release)
        assert_equal(pt['spends'][0]['txidPrev'], txidPrev)
        if release == 'sprout':
            assert_equal(pt['spends'][0]['js'], 0)
            # jsSpend is randomised during transaction creation
            assert_equal(pt['spends'][0]['jsPrev'], 0)
            assert_equal(pt['spends'][0]['jsOutputPrev'], jsOutputPrev)
        else:
            assert_equal(pt['spends'][0]['spend'], 0)
            assert_equal(pt['spends'][0]['outputPrev'], 0)
        assert_equal(pt['spends'][0]['address'], zaddr1)
        assert_equal(pt['spends'][0]['value'], Decimal('1.0'))
        assert_equal(pt['spends'][0]['valueZat'], 100000000)

        # Output orders can be randomized, so we check the output
        # positions and contents separately
        outputs = []

        assert_equal(pt['outputs'][0]['type'], release)
        if release == 'sapling':
            assert_equal(pt['outputs'][0]['output'], 0)
            assert_equal(pt['outputs'][0]['outgoing'], False)
        outputs.append({
            'address': pt['outputs'][0]['address'],
            'value': pt['outputs'][0]['value'],
            'valueZat': pt['outputs'][0]['valueZat'],
            'memo': pt['outputs'][0]['memo'],
        })

        assert_equal(pt['outputs'][1]['type'], release)
        if release == 'sapling':
            assert_equal(pt['outputs'][1]['output'], 1)
            assert_equal(pt['outputs'][1]['outgoing'], False)
        outputs.append({
            'address': pt['outputs'][1]['address'],
            'value': pt['outputs'][1]['value'],
            'valueZat': pt['outputs'][1]['valueZat'],
            'memo': pt['outputs'][1]['memo'],
        })

        assert ({
            'address': zaddr2,
            'value': Decimal('0.6'),
            'valueZat': 60000000,
            'memo': no_memo,
        } in outputs)
        assert ({
            'address': zaddr1,
            'value': Decimal('0.3999'),
            'valueZat': 39990000,
            'memo': no_memo,
        } in outputs)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")

        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4') - fee, r[0]['amount'])
        assert_true(r[0]['change'],
                    "Note valued at (0.4-fee) should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('1.0'), r[1]['amount'])
        assert_false(r[1]['change'], "Note valued at 1.0 should not be change")
        assert_equal(my_memo, r[1]['memo'])

        # zaddr2 should not have change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(1, len(r), "zaddr2 Should have received 1 notes")
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.6'), r[0]['amount'])
        assert_false(r[0]['change'], "Note valued at 0.6 should not be change")
        assert_equal(no_memo, r[0]['memo'])
Exemple #35
0
    def run_test(self):
        # add zaddr to node 0
        myzaddr0 = self.nodes[0].z_getnewaddress('sprout')

        # send node 0 taddr to zaddr to get out of coinbase
        # Tests using the default cached chain have one address per coinbase output
        mytaddr = get_coinbase_address(self.nodes[0])
        recipients = []
        recipients.append({
            "address": myzaddr0,
            "amount": Decimal('10.0') - Decimal('0.0001')
        })  # utxo amount less fee

        wait_and_assert_operationid_status(self.nodes[0],
                                           self.nodes[0].z_sendmany(
                                               mytaddr, recipients),
                                           timeout=120)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # add zaddr to node 2
        myzaddr = self.nodes[2].z_getnewaddress('sprout')

        # import node 2 zaddr into node 1
        myzkey = self.nodes[2].z_exportkey(myzaddr)
        self.nodes[1].z_importkey(myzkey)

        # encrypt node 1 wallet and wait to terminate
        self.nodes[1].encryptwallet("test")
        bitcoind_processes[1].wait()

        # restart node 1
        self.nodes[1] = start_node(1, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        self.sync_all()

        # send node 0 zaddr to note 2 zaddr
        recipients = []
        recipients.append({"address": myzaddr, "amount": 7.0})

        wait_and_assert_operationid_status(self.nodes[0],
                                           self.nodes[0].z_sendmany(
                                               myzaddr0, recipients),
                                           timeout=120)

        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # check zaddr balance
        zsendmanynotevalue = Decimal('7.0')
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)
        assert_equal(self.nodes[1].z_getbalance(myzaddr), zsendmanynotevalue)

        # add zaddr to node 3
        myzaddr3 = self.nodes[3].z_getnewaddress('sprout')

        # send node 2 zaddr to note 3 zaddr
        recipients = []
        recipients.append({"address": myzaddr3, "amount": 2.0})

        wait_and_assert_operationid_status(self.nodes[2],
                                           self.nodes[2].z_sendmany(
                                               myzaddr, recipients),
                                           timeout=120)

        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()

        # check zaddr balance
        zsendmany2notevalue = Decimal('2.0')
        zsendmanyfee = Decimal('0.0001')
        zaddrremaining = zsendmanynotevalue - zsendmany2notevalue - zsendmanyfee
        assert_equal(self.nodes[3].z_getbalance(myzaddr3), zsendmany2notevalue)
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining)

        # Parallel encrypted wallet can't cache nullifiers for received notes,
        # and therefore can't detect spends. So it sees a balance corresponding
        # to the sum of both notes it received (one as change).
        # TODO: Devise a way to avoid this issue (#1528)
        assert_equal(self.nodes[1].z_getbalance(myzaddr),
                     zsendmanynotevalue + zaddrremaining)

        # send node 2 zaddr on node 1 to taddr
        # This requires that node 1 be unlocked, which triggers caching of
        # uncached nullifiers.
        self.nodes[1].walletpassphrase("test", 600)
        mytaddr1 = self.nodes[1].getnewaddress()
        recipients = []
        recipients.append({"address": mytaddr1, "amount": 1.0})

        wait_and_assert_operationid_status(self.nodes[1],
                                           self.nodes[1].z_sendmany(
                                               myzaddr, recipients),
                                           timeout=120)

        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # check zaddr balance
        # Now that the encrypted wallet has been unlocked, the note nullifiers
        # have been cached and spent notes can be detected. Thus the two wallets
        # are in agreement once more.
        zsendmany3notevalue = Decimal('1.0')
        zaddrremaining2 = zaddrremaining - zsendmany3notevalue - zsendmanyfee
        assert_equal(self.nodes[1].z_getbalance(myzaddr), zaddrremaining2)
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zaddrremaining2)

        # Test viewing keys

        node3mined = Decimal('250.0')
        assert_equal(
            {
                k: Decimal(v)
                for k, v in self.nodes[3].z_gettotalbalance().items()
            }, {
                'transparent': node3mined,
                'private': zsendmany2notevalue,
                'total': node3mined + zsendmany2notevalue,
            })

        # add node 1 address and node 2 viewing key to node 3
        myzvkey = self.nodes[2].z_exportviewingkey(myzaddr)
        self.nodes[3].importaddress(mytaddr1)
        self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1)

        # Check the address has been imported
        assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False)
        assert_equal(myzaddr in self.nodes[3].z_listaddresses(True), True)

        # Node 3 should see the same received notes as node 2; however,
        # some of the notes were change for node 2 but not for node 3.
        # Aside from that the recieved notes should be the same. So,
        # group by txid and then check that all properties aside from
        # change are equal.
        node2Received = dict(
            [r['txid'], r]
            for r in self.nodes[2].z_listreceivedbyaddress(myzaddr))
        node3Received = dict(
            [r['txid'], r]
            for r in self.nodes[3].z_listreceivedbyaddress(myzaddr))
        assert_equal(len(node2Received), len(node2Received))
        for txid in node2Received:
            received2 = node2Received[txid]
            received3 = node3Received[txid]
            # the change field will be omitted for received3, but all other fields should be shared
            assert_true(len(received2) >= len(received3))
            for key in received2:
                # check all the properties except for change
                if key != 'change':
                    assert_equal(received2[key], received3[key])

        # Node 3's balances should be unchanged without explicitly requesting
        # to include watch-only balances
        assert_equal(
            {
                k: Decimal(v)
                for k, v in self.nodes[3].z_gettotalbalance().items()
            }, {
                'transparent': node3mined,
                'private': zsendmany2notevalue,
                'total': node3mined + zsendmany2notevalue,
            })

        # Wallet can't cache nullifiers for notes received by addresses it only has a
        # viewing key for, and therefore can't detect spends. So it sees a balance
        # corresponding to the sum of all notes the address received.
        # TODO: Fix this during the Sapling upgrade (via #2277)
        assert_equal(
            {
                k: Decimal(v)
                for k, v in self.nodes[3].z_gettotalbalance(1, True).items()
            }, {
                'transparent':
                node3mined + Decimal('1.0'),
                'private':
                zsendmany2notevalue + zsendmanynotevalue + zaddrremaining +
                zaddrremaining2,
                'total':
                node3mined + Decimal('1.0') + zsendmany2notevalue +
                zsendmanynotevalue + zaddrremaining + zaddrremaining2,
            })

        # Check individual balances reflect the above
        assert_equal(self.nodes[3].z_getbalance(mytaddr1), Decimal('1.0'))
        assert_equal(self.nodes[3].z_getbalance(myzaddr),
                     zsendmanynotevalue + zaddrremaining + zaddrremaining2)
    def run_test_release(self, release, height):
        self.generate_and_sync(height+1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress(release)

        self.nodes[0].sendtoaddress(taddr, 2.0)
        self.generate_and_sync(height+2)

        # Send 1 ZEC to zaddr1
        opid = self.nodes[1].z_sendmany(taddr,
            [{'address': zaddr1, 'amount': 1, 'memo': my_memo}])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")

        # No confirmation required, one note should be present
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(1, len(r), "Should have received one (unconfirmed) note")
        assert_equal(txid, r[0]['txid'])
        assert_equal(1, r[0]['amount'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])

        # Confirm transaction (1 ZEC from taddr to zaddr1)
        self.generate_and_sync(height+3)

        # Require one confirmation, note should be present
        assert_equal(r, self.nodes[1].z_listreceivedbyaddress(zaddr1))

        # Generate some change by sending part of zaddr1 to zaddr2
        zaddr2 = self.nodes[1].z_getnewaddress(release)
        opid = self.nodes[1].z_sendmany(zaddr1,
            [{'address': zaddr2, 'amount': 0.6}])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)
        self.sync_all()
        self.generate_and_sync(height+4)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        r = sorted(r, key = lambda received: received['amount'])
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")

        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4')-fee, r[0]['amount'])
        assert_true(r[0]['change'], "Note valued at (0.4-fee) should be change")
        assert_equal(no_memo, r[0]['memo'])

        # The old note still exists (it's immutable), even though it is spent
        assert_equal(Decimal('1.0'), r[1]['amount'])
        assert_false(r[1]['change'], "Note valued at 1.0 should not be change")
        assert_equal(my_memo, r[1]['memo'])

        # zaddr2 should not have change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr2, 0)
        r = sorted(r, key = lambda received: received['amount'])
        assert_equal(1, len(r), "zaddr2 Should have received 1 notes")
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.6'), r[0]['amount'])
        assert_false(r[0]['change'], "Note valued at 0.6 should not be change")
        assert_equal(no_memo, r[0]['memo'])