示例#1
0
    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])
示例#2
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)

        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': zaddr2,
            'amount': 0.6
        }])
        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,
            'memo': my_memo
        }])
        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[0]['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'])
示例#3
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)

        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'])
    def test_received_sapling(self, height):
        self.generate_and_sync(height + 1)
        taddr = self.nodes[1].getnewaddress()
        zaddr1 = self.nodes[1].z_getnewaddress('sapling')
        zaddrExt = self.nodes[2].z_getnewaddress('sapling')

        txid_taddr = 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']), 2)

        # Outputs are not returned in a defined order but the amounts are deterministic
        outputs = sorted(pt['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'sapling')
        assert_equal(outputs[0]['address'], zaddr1)
        assert_equal(outputs[0]['value'], Decimal('1'))
        assert_equal(outputs[0]['valueZat'], 100000000)
        assert_equal(outputs[0]['output'], 0)
        assert_equal(outputs[0]['outgoing'], False)
        assert_equal(outputs[0]['memo'], my_memo)
        assert_equal(outputs[0]['memoStr'], my_memo_str)

        assert_equal(outputs[1]['type'], 'sapling')
        assert_equal(outputs[1]['address'], zaddrExt)
        assert_equal(outputs[1]['value'], Decimal('2'))
        assert_equal(outputs[1]['valueZat'], 200000000)
        assert_equal(outputs[1]['output'], 1)
        assert_equal(outputs[1]['outgoing'], True)
        assert_equal(outputs[1]['memo'], no_memo)
        assert 'memoStr' not in outputs[1]

        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")
        c = self.nodes[1].z_getnotescount()
        assert_equal(0, c['sapling'], "Count of confirmed notes should be 0")

        # 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_equal(100000000, r[0]['amountZat'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(my_memo, r[0]['memo'])
        assert_equal(0, r[0]['confirmations'])
        assert_equal(-1, r[0]['blockindex'])
        assert_equal(0, r[0]['blockheight'])

        c = self.nodes[1].z_getnotescount(0)
        assert_equal(1, c['sapling'], "Count of unconfirmed notes should be 1")

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

        # adjust confirmations
        r[0]['confirmations'] = 1
        # adjust blockindex
        r[0]['blockindex'] = 1
        # adjust height
        r[0]['blockheight'] = 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('sapling')
        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'], 'sapling')
        assert_equal(pt['spends'][0]['txidPrev'], txidPrev)
        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)

        # Outputs are not returned in a defined order but the amounts are deterministic
        outputs = sorted(pt['outputs'], key=lambda x: x['valueZat'])
        assert_equal(outputs[0]['type'], 'sapling')
        assert_equal(outputs[0]['address'], zaddr1)
        assert_equal(outputs[0]['value'], Decimal('0.4') - DEFAULT_FEE)
        assert_equal(outputs[0]['valueZat'], 40000000 - DEFAULT_FEE_ZATS)
        assert_equal(outputs[0]['output'], 1)
        assert_equal(outputs[0]['outgoing'], False)
        assert_equal(outputs[0]['memo'], no_memo)
        assert 'memoStr' not in outputs[0]

        assert_equal(outputs[1]['type'], 'sapling')
        assert_equal(outputs[1]['address'], zaddr2)
        assert_equal(outputs[1]['value'], Decimal('0.6'))
        assert_equal(outputs[1]['valueZat'], 60000000)
        assert_equal(outputs[1]['output'], 0)
        assert_equal(outputs[1]['outgoing'], False)
        assert_equal(outputs[1]['memo'], no_memo)
        assert 'memoStr' not in outputs[1]

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('0.4') - DEFAULT_FEE, r[0]['amount'])
        assert_equal(40000000 - DEFAULT_FEE_ZATS, r[0]['amountZat'])
        assert_equal(
            r[0]['change'], True,
            "Note valued at (0.4-" + str(DEFAULT_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_equal(100000000, r[1]['amountZat'])
        assert_equal(r[1]['change'], False,
                     "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)
        assert_equal(len(r), 1, "zaddr2 Should have received 1 notes")
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(r[0]['txid'], txid)
        assert_equal(r[0]['amount'], Decimal('0.6'))
        assert_equal(r[0]['amountZat'], 60000000)
        assert_equal(r[0]['change'], False,
                     "Note valued at 0.6 should not be change")
        assert_equal(r[0]['memo'], no_memo)
        assert 0 <= r[0]['outindex'] < 2

        c = self.nodes[1].z_getnotescount(0)
        assert_equal(
            c['sapling'], 3,
            "Count of unconfirmed notes should be 3(2 in zaddr1 + 1 in zaddr2)"
        )

        # As part of UA support, a transparent address is now accepted
        r = self.nodes[1].z_listreceivedbyaddress(taddr, 0)
        assert_equal(len(r), 1)
        assert_equal(r[0]['pool'], 'transparent')
        assert_equal(r[0]['txid'], txid_taddr)
        assert_equal(r[0]['amount'], Decimal('4'))
        assert_equal(r[0]['amountZat'], 400000000)
        assert_equal(r[0]['confirmations'], 3)
        assert 0 <= r[0]['outindex'] < 2

        # Test unified address
        node = self.nodes[1]

        # Create a unified address on one node, try z_listreceivedbyaddress on another node
        account = self.nodes[0].z_getnewaccount()['account']
        r = self.nodes[0].z_getaddressforaccount(account)
        unified_addr = r['address']
        # this address isn't in node1's wallet
        assert_raises_message(JSONRPCException,
                              "From address does not belong to this node",
                              node.z_listreceivedbyaddress, unified_addr, 0)

        # create a UA on node1
        r = node.z_getnewaccount()
        account = r['account']
        r = node.z_getaddressforaccount(account)
        unified_addr = r['address']
        receivers = node.z_listunifiedreceivers(unified_addr)
        assert_equal(len(receivers), 3)
        assert 'p2pkh' in receivers
        assert 'sapling' in receivers
        assert 'orchard' in receivers
        assert_raises_message(
            JSONRPCException,
            "The provided address is a bare receiver from a Unified Address in this wallet.",
            node.z_listreceivedbyaddress, receivers['p2pkh'], 0)
        assert_raises_message(
            JSONRPCException,
            "The provided address is a bare receiver from a Unified Address in this wallet.",
            node.z_listreceivedbyaddress, receivers['sapling'], 0)

        # Wallet contains no notes
        r = node.z_listreceivedbyaddress(unified_addr, 0)
        assert_equal(len(r), 0, "unified_addr should have received zero notes")

        # Create a note in this UA on node1
        opid = node.z_sendmany(zaddr1, [{
            'address': unified_addr,
            'amount': 0.1
        }])
        txid_sapling = wait_and_assert_operationid_status(node, opid)
        self.generate_and_sync(height + 5)

        # Create a UTXO that unified_address's transparent component references, on node1
        outputs = {receivers['p2pkh']: 0.2}
        txid_taddr = node.sendmany("", outputs)

        r = node.z_listreceivedbyaddress(unified_addr, 0)
        assert_equal(len(r), 2, "unified_addr should have received 2 payments")
        # The return list order isn't defined, so sort by pool name
        r = sorted(r, key=lambda x: x['pool'])
        assert_equal(r[0]['pool'], 'sapling')
        assert_equal(r[0]['txid'], txid_sapling)
        assert_equal(r[0]['amount'], Decimal('0.1'))
        assert_equal(r[0]['amountZat'], 10000000)
        assert_equal(r[0]['memo'], no_memo)
        assert 0 <= r[0]['outindex'] < 2
        assert_equal(r[0]['confirmations'], 1)
        assert_equal(r[0]['change'], False)
        assert_equal(r[0]['blockheight'], height + 5)
        assert_equal(r[0]['blockindex'], 1)
        assert 'blocktime' in r[0]

        assert_equal(r[1]['pool'], 'transparent')
        assert_equal(r[1]['txid'], txid_taddr)
        assert_equal(r[1]['amount'], Decimal('0.2'))
        assert_equal(r[1]['amountZat'], 20000000)
        assert 0 <= r[1]['outindex'] < 2
        assert_equal(r[1]['confirmations'], 0)
        assert_equal(r[1]['change'], False)
        assert 'memo' not in r[1]
        assert_equal(r[1]['blockheight'], 0)  # not yet mined
        assert_equal(r[1]['blockindex'], -1)  # not yet mined
        assert 'blocktime' in r[1]
    def test_received_sprout(self, height):
        self.generate_and_sync(height + 2)

        zaddr1 = self.nodes[1].z_getnewaddress('sprout')

        # Send 10 ZEC each zaddr1 and zaddrExt via z_shieldcoinbase
        result = self.nodes[0].z_shieldcoinbase(
            get_coinbase_address(self.nodes[0]), zaddr1, 0, 1)
        txid_shielding1 = wait_and_assert_operationid_status(
            self.nodes[0], result['opid'])

        zaddrExt = self.nodes[2].z_getnewaddress('sprout')
        result = self.nodes[0].z_shieldcoinbase(
            get_coinbase_address(self.nodes[0]), zaddrExt, 0, 1)
        txid_shieldingExt = wait_and_assert_operationid_status(
            self.nodes[0], result['opid'])

        self.sync_all()

        # Decrypted transaction details should not be visible on node 0
        pt = self.nodes[0].z_viewtransaction(txid_shielding1)
        assert_equal(pt['txid'], txid_shielding1)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 0)

        # Decrypted transaction details should be correct on node 1
        pt = self.nodes[1].z_viewtransaction(txid_shielding1)
        assert_equal(pt['txid'], txid_shielding1)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 1)
        assert_equal(pt['outputs'][0]['type'], 'sprout')
        assert_equal(pt['outputs'][0]['js'], 0)
        assert_equal(pt['outputs'][0]['address'], zaddr1)
        assert_equal(pt['outputs'][0]['value'], Decimal('10'))
        assert_equal(pt['outputs'][0]['valueZat'], 1000000000)
        assert_equal(pt['outputs'][0]['memo'], no_memo)
        jsOutputPrev = pt['outputs'][0]['jsOutput']

        # Second transaction should not be known to node 1
        assert_raises_message(JSONRPCException,
                              "Invalid or non-wallet transaction id",
                              self.nodes[1].z_viewtransaction,
                              txid_shieldingExt)

        # Second transaction should be visible on node0
        pt = self.nodes[2].z_viewtransaction(txid_shieldingExt)
        assert_equal(pt['txid'], txid_shieldingExt)
        assert_equal(len(pt['spends']), 0)
        assert_equal(len(pt['outputs']), 1)
        assert_equal(pt['outputs'][0]['type'], 'sprout')
        assert_equal(pt['outputs'][0]['js'], 0)
        assert_equal(pt['outputs'][0]['address'], zaddrExt)
        assert_equal(pt['outputs'][0]['value'], Decimal('10'))
        assert_equal(pt['outputs'][0]['valueZat'], 1000000000)
        assert_equal(pt['outputs'][0]['memo'], no_memo)

        r = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(0, len(r), "Should have received no confirmed note")
        c = self.nodes[1].z_getnotescount()
        assert_equal(0, c['sprout'], "Count of confirmed notes should be 0")

        # 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_shielding1, r[0]['txid'])
        assert_equal(10, r[0]['amount'])
        assert_equal(1000000000, r[0]['amountZat'])
        assert_false(r[0]['change'], "Note should not be change")
        assert_equal(no_memo, r[0]['memo'])
        assert_equal(0, r[0]['confirmations'])
        assert_equal(-1, r[0]['blockindex'])
        assert_equal(0, r[0]['blockheight'])

        c = self.nodes[1].z_getnotescount(0)
        assert_equal(1, c['sprout'], "Count of unconfirmed notes should be 1")

        # Confirm transaction (10 ZEC shielded)
        self.generate_and_sync(height + 3)

        # Require one confirmation, note should be present
        r0 = self.nodes[1].z_listreceivedbyaddress(zaddr1)
        assert_equal(1, len(r0), "Should have received one (unconfirmed) note")
        assert_equal(txid_shielding1, r0[0]['txid'])
        assert_equal(10, r0[0]['amount'])
        assert_equal(1000000000, r0[0]['amountZat'])
        assert_false(r0[0]['change'], "Note should not be change")
        assert_equal(no_memo, r0[0]['memo'])
        assert_equal(1, r0[0]['confirmations'])
        assert_equal(height + 3, r0[0]['blockheight'])

        taddr = self.nodes[1].getnewaddress()
        # Generate some change by sending part of zaddr1 back to taddr
        opid = self.nodes[1].z_sendmany(zaddr1, [{
            'address': taddr,
            'amount': 0.6
        }])
        txid = wait_and_assert_operationid_status(self.nodes[1], opid)

        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)
        # TODO: enable once z_viewtransaction displays transparent elements
        # assert_equal(len(pt['outputs']), 2)
        assert_equal(len(pt['outputs']), 1)

        assert_equal(pt['spends'][0]['type'], 'sprout')
        assert_equal(pt['spends'][0]['txidPrev'], txid_shielding1)
        assert_equal(pt['spends'][0]['js'], 0)
        assert_equal(pt['spends'][0]['jsPrev'], 0)
        assert_equal(pt['spends'][0]['jsOutputPrev'], jsOutputPrev)
        assert_equal(pt['spends'][0]['address'], zaddr1)
        assert_equal(pt['spends'][0]['value'], Decimal('10.0'))
        assert_equal(pt['spends'][0]['valueZat'], 1000000000)

        # We expect a transparent output and a Sprout output, but the RPC does
        # not define any particular ordering of these within the returned JSON.
        outputs = [{
            'type': output['type'],
            'address': output['address'],
            'value': output['value'],
            'valueZat': output['valueZat'],
        } for output in pt['outputs']]
        for (i, output) in enumerate(pt['outputs']):
            if 'memo' in output:
                outputs[i]['memo'] = output['memo']

        # TODO: enable once z_viewtransaction displays transparent elements
        # assert({
        #     'type': 'transparent',
        #     'address': taddr,
        #     'value': Decimal('0.6'),
        #     'valueZat': 60000000,
        # } in outputs)
        assert ({
            'type': 'sprout',
            'address': zaddr1,
            'value': Decimal('9.4') - DEFAULT_FEE,
            'valueZat': 940000000 - DEFAULT_FEE_ZATS,
            'memo': no_memo,
        } in outputs)

        # zaddr1 should have a note with change
        r = self.nodes[1].z_listreceivedbyaddress(zaddr1, 0)
        assert_equal(2, len(r), "zaddr1 Should have received 2 notes")
        r = sorted(r, key=lambda received: received['amount'])
        assert_equal(txid, r[0]['txid'])
        assert_equal(Decimal('9.4') - DEFAULT_FEE, r[0]['amount'])
        assert_equal(940000000 - DEFAULT_FEE_ZATS, r[0]['amountZat'])
        assert_true(
            r[0]['change'],
            "Note valued at (9.4-" + str(DEFAULT_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('10.0'), r[1]['amount'])
        assert_equal(1000000000, r[1]['amountZat'])
        assert_false(r[1]['change'],
                     "Note valued at 10.0 should not be change")
        assert_equal(no_memo, r[1]['memo'])
示例#6
0
    def run_test(self):

        #amounts
        creation_amount = Decimal("50")
        bwt_amount = Decimal("5")
        tAddr1 = self.nodes[1].getnewaddress()
        node1Addr = self.nodes[1].validateaddress(tAddr1)['address']
        self.nodes[0].generate(MINIMAL_SC_HEIGHT)
        self.sync_all()

        ########### Create the sidechain ##################
        print("########### Create the sidechain ##################")

        mcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        cmdInput = {
            "version": 0,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'toaddress': "dada",
            'amount': creation_amount,
            'wCertVk': vk,
            'constant': constant
        }

        ret = self.nodes[0].sc_create(cmdInput)
        creating_tx = ret['txid']
        scid = ret['scid']
        scid_swapped = str(swap_bytes(scid))
        self.sync_all()

        decoded_tx = self.nodes[0].getrawtransaction(creating_tx, 1)
        assert_equal(scid, decoded_tx['vsc_ccout'][0]['scid'])

        sc_creation_block_hash = self.nodes[0].generate(1)[0]
        sc_creation_block = self.nodes[0].getblock(sc_creation_block_hash)
        self.sync_all()

        #Advance for 1 Epoch
        self.nodes[0].generate(EPOCH_LENGTH)
        self.sync_all()

        ########### Mine Certificate 1 with quality = 5 ##################
        print(
            "########### Mine Certificate 1 with quality = 5 ##################"
        )

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 5
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount])

        amount_cert_1 = [{"address": node1Addr, "amount": bwt_amount}]

        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()
        maturityHeight = sc_creation_block["height"] + (
            EPOCH_LENGTH * 2) + EPOCH_LENGTH * 0.2 - 1

        #Add to mempool Certificate 2 with quality = 7
        print(
            "########### Add to mempool Certificate 2 with quality = 7 ##################"
        )
        quality = 7
        bwt_amount2 = Decimal("7")
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount2])

        amount_cert_2 = [{"address": node1Addr, "amount": bwt_amount2}]

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

        #Mine a block
        self.nodes[0].generate(1)
        self.sync_all()

        #Mine a block with a new Certificate 3 with quality = 8
        print(
            "########### Mine a block with a new Certificate 3 with quality = 8 ##################"
        )
        quality = 8
        bwt_amount3 = Decimal("7")
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount3])

        amount_cert_3 = [{"address": node1Addr, "amount": bwt_amount3}]

        cert3 = self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                                  epoch_cum_tree_hash, proof,
                                                  amount_cert_3, FT_SC_FEE,
                                                  MBTR_SC_FEE, CERT_FEE)
        self.sync_all()
        cert3_block = self.nodes[0].generate(1)[0]
        self.sync_all()

        #Advance of 1 epoch
        print("########### Advance of 1 epoch ##################")
        self.nodes[0].generate(116)
        self.sync_all()

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], EPOCH_LENGTH)
        quality = 9
        bwt_amount4 = Decimal("9")
        proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                         quality, MBTR_SC_FEE, FT_SC_FEE,
                                         epoch_cum_tree_hash, constant,
                                         [node1Addr], [bwt_amount4])

        amount_cert_4 = [{"address": node1Addr, "amount": bwt_amount4}]

        self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                          epoch_cum_tree_hash, proof,
                                          amount_cert_4, FT_SC_FEE,
                                          MBTR_SC_FEE, CERT_FEE)

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

        #Enter in the next epoch
        new_epoch_block = self.nodes[0].generate(1)[0]
        self.sync_all()

        rpcCertBlock = self.nodes[0].getblock(cert3_block, 2)
        cert_3_json = {}
        for cert in rpcCertBlock['cert']:
            if (cert['txid'] == cert3):
                cert_3_json = cert
        assert_true(cert_3_json != {})
        tipHeight = self.nodes[0].getblockcount()

        #Test that we require -maturityheightindex=1 to run the getblockexpanded
        try:
            self.nodes[1].getblockexpanded("640")
            assert (False)
        except JSONRPCException as e:
            errorString = e.error['message']
            print(errorString)
            assert ("maturityHeightIndex option not set: can not retrieve info"
                    in errorString)

        #Test that we see the certificate 3 but non the certificate 2 and 1
        for i in range(1, tipHeight + 1):
            rpcDataByHeight = self.nodes[0].getblockexpanded(str(i))
            rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded(
                str(i), 2)
            rpcDataByHash = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'])
            rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'], 2)

            if (rpcDataByHash['height'] >= MINIMAL_SC_HEIGHT):
                assert_true('matureCertificate' in rpcDataByHash)
                assert_true('matureCertificate' in rpcDataByHeight)
                assert_true('matureCertificate' in rpcDataByHashVerbosity)
                assert_true('matureCertificate' in rpcDataByHeightVerbosity)
                if (rpcDataByHash['height'] == int(maturityHeight)):
                    assert_equal(len(rpcDataByHash['matureCertificate']), 1)
                    assert_equal(len(rpcDataByHeight['matureCertificate']), 1)
                    assert_equal(rpcDataByHash['matureCertificate'][0], cert3)
                    assert_equal(rpcDataByHeight['matureCertificate'][0],
                                 cert3)
                    assert_equal(
                        len(rpcDataByHashVerbosity['matureCertificate']), 1)
                    assert_equal(
                        len(rpcDataByHeightVerbosity['matureCertificate']), 1)
                    assert_equal(
                        rpcDataByHashVerbosity['matureCertificate'][0],
                        cert_3_json)
                    assert_equal(
                        rpcDataByHeightVerbosity['matureCertificate'][0],
                        cert_3_json)
                else:
                    assert_equal(len(rpcDataByHash['matureCertificate']), 0)
                    assert_equal(len(rpcDataByHeight['matureCertificate']), 0)
                    assert_equal(
                        len(rpcDataByHashVerbosity['matureCertificate']), 0)
                    assert_equal(
                        len(rpcDataByHeightVerbosity['matureCertificate']), 0)
            else:
                assert_false('matureCertificate' in rpcDataByHash)
                assert_false('matureCertificate' in rpcDataByHeight)
                assert_false('matureCertificate' in rpcDataByHashVerbosity)
                assert_false('matureCertificate' in rpcDataByHeightVerbosity)

        self.nodes[0].invalidateblock(new_epoch_block)
        self.nodes[0].invalidateblock(cert4_block)
        self.nodes[1].invalidateblock(new_epoch_block)
        self.nodes[1].invalidateblock(cert4_block)
        assert_equal(self.nodes[0].getblockcount(), 639)
        assert_equal(self.nodes[1].getblockcount(), 639)

        self.nodes[0].clearmempool()
        self.nodes[1].clearmempool()
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        assert_equal(len(self.nodes[1].getrawmempool()), 0)
        self.sync_all()

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

        rpcDataByHeight = self.nodes[0].getblockexpanded("640")
        rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded("640", 2)
        rpcDataByHash = self.nodes[0].getblockexpanded(rpcDataByHeight['hash'])
        rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
            rpcDataByHeight['hash'], 2)
        assert_equal(len(rpcDataByHash['matureCertificate']), 0)
        assert_equal(len(rpcDataByHeight['matureCertificate']), 0)
        assert_equal(len(rpcDataByHashVerbosity['matureCertificate']), 0)
        assert_equal(len(rpcDataByHeightVerbosity['matureCertificate']), 0)

        self.nodes[0].invalidateblock(fake_block)
        self.nodes[1].invalidateblock(fake_block)

        self.nodes[0].sc_send_certificate(scid, epoch_number, quality,
                                          epoch_cum_tree_hash, proof,
                                          amount_cert_4, FT_SC_FEE,
                                          MBTR_SC_FEE, CERT_FEE)
        self.nodes[0].generate(2)
        self.sync_all()

        rpcDataByHeight = self.nodes[0].getblockexpanded("640")
        rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded("640", 2)
        rpcDataByHash = self.nodes[0].getblockexpanded(rpcDataByHeight['hash'])
        rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
            rpcDataByHeight['hash'], 2)
        assert_equal(len(rpcDataByHash['matureCertificate']), 1)
        assert_equal(len(rpcDataByHeight['matureCertificate']), 1)
        assert_equal(len(rpcDataByHashVerbosity['matureCertificate']), 1)
        assert_equal(len(rpcDataByHeightVerbosity['matureCertificate']), 1)
        assert_equal(rpcDataByHashVerbosity['matureCertificate'][0],
                     cert_3_json)
        assert_equal(rpcDataByHeightVerbosity['matureCertificate'][0],
                     cert_3_json)
        assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['state'],
                     "ALIVE")

        #Let the sidechain cease
        self.nodes[0].generate(130)
        self.sync_all()

        assert_equal(self.nodes[0].getscinfo(scid)['items'][0]['state'],
                     "CEASED")
        tipHeightCeased = self.nodes[0].getblockcount()

        for i in range(tipHeight, tipHeightCeased + 1):
            rpcDataByHeight = self.nodes[0].getblockexpanded(str(i))
            rpcDataByHeightVerbosity = self.nodes[0].getblockexpanded(
                str(i), 2)
            rpcDataByHash = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'])
            rpcDataByHashVerbosity = self.nodes[0].getblockexpanded(
                rpcDataByHeight['hash'], 2)

            assert_equal(len(rpcDataByHash['matureCertificate']), 0)
            assert_equal(len(rpcDataByHeight['matureCertificate']), 0)
            assert_equal(len(rpcDataByHashVerbosity['matureCertificate']), 0)
            assert_equal(len(rpcDataByHeightVerbosity['matureCertificate']), 0)
    def run_test(self):
        '''
        Test that the JSON result of the rpc command listsinceblock includes a matured certificate backward transfer even when:
        1) the input block range specified does not contain the block where such certificate has been mined.
        2) The certificate matures in one of the blocks of the specified range
        '''

        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 - 2),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 2)
        self.sync_all()

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

        # create SC
        #------------------------------------------------------------------------------------------------------------
        cmdInput = {
            'version': 0,
            'toaddress': "abcd",
            'amount': 20.0,
            'wCertVk': vk,
            'withdrawalEpochLength': EPOCH_LENGTH,
            'constant': constant
        }

        mark_logs("\nNode 1 create SC", self.nodes, DEBUG_MODE)
        try:
            res = self.nodes[1].sc_create(cmdInput)
            tx = res['txid']
            scid = res['scid']
            pprint.pprint(res)
            self.sync_all()
        except JSONRPCException as e:
            errorString = e.error['message']
            mark_logs(errorString, self.nodes, DEBUG_MODE)
            assert_true(False)

        mark_logs("\nNode 0 generates 1 block", self.nodes, DEBUG_MODE)
        bl = self.nodes[0].generate(1)[-1]
        self.sync_all()

        item = self.nodes[0].getscinfo(scid)['items'][0]
        elen = item['withdrawalEpochLength']
        wlen = item['certSubmissionWindowLength']
        ch = item['createdAtBlockHeight']

        scid_swapped = str(swap_bytes(scid))

        q = 10
        blocks_d = {}
        block_heights_d = {}
        certs_d = {}
        mat_height_d = {}

        taddr1 = self.nodes[1].getnewaddress()
        taddr2 = self.nodes[2].getnewaddress()

        # advance some epochs and send a certificate for any of them
        for i in range(3):

            am_bwt1 = Decimal(i + 1) + Decimal('0.01')
            am_bwt2 = Decimal(i + 1) + Decimal('0.02')
            am_out = Decimal('0.001') * (i + 1)

            mark_logs("Advance epoch...", self.nodes, DEBUG_MODE)
            self.nodes[0].generate(EPOCH_LENGTH - 1)
            self.sync_all()
            epoch_number, epoch_cum_tree_hash = get_epoch_data(
                scid, self.nodes[0], EPOCH_LENGTH)

            mark_logs("Node 1 sends a cert", self.nodes, DEBUG_MODE)
            #==============================================================
            pkh_arr = []
            am_bwt_arr = []
            raw_bwt_outs = [{
                "address": taddr1,
                "amount": am_bwt1
            }, {
                "address": taddr2,
                "amount": am_bwt2
            }]
            for entry in raw_bwt_outs:
                pkh_arr.append(entry["address"])
                am_bwt_arr.append(entry["amount"])

            proof = mcTest.create_test_proof("sc1", scid_swapped, epoch_number,
                                             q, MBTR_SC_FEE, FT_SC_FEE,
                                             epoch_cum_tree_hash, constant,
                                             pkh_arr, am_bwt_arr)

            utx, change = get_spendable(self.nodes[1], CERT_FEE + am_out)
            raw_inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
            raw_outs = {taddr1: change, taddr2: am_out}

            raw_params = {
                "scid": scid,
                "quality": q,
                "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash,
                "scProof": proof,
                "withdrawalEpochNumber": epoch_number
            }

            # use the raw version of the command for having more than one standard output
            # -------------------------------------
            # vout 1: standard output (taddr1) - change
            # vout 2: standard output (taddr2)
            # vout 3: bwt (taddr1)
            # vout 3: bwt (taddr2)
            try:
                raw_cert = self.nodes[1].createrawcertificate(
                    raw_inputs, raw_outs, raw_bwt_outs, raw_params)
                signed_cert = self.nodes[1].signrawtransaction(raw_cert)
                certs_d[i] = self.nodes[1].sendrawtransaction(
                    signed_cert['hex'])
            except JSONRPCException as e:
                errorString = e.error['message']
                print("\n======> ", errorString)
                assert_true(False)

            self.sync_all()

            mark_logs("cert = {}".format(certs_d[i]), self.nodes, DEBUG_MODE)
            mat_height_d[i] = ch - 1 + (i + 2) * elen + wlen
            print("mat height = {}".format(mat_height_d[i]))

            mark_logs("Node 0 generates 1 block", self.nodes, DEBUG_MODE)
            bl = self.nodes[0].generate(1)[-1]
            self.sync_all()
            c = self.nodes[0].getblockcount()
            blocks_d[i] = bl
            block_heights_d[i] = c

        # the first of the 3 certificates has reached maturity and Node2 has a consistent balance
        bal = self.nodes[2].getbalance()
        print("Node2 balance = {}".format(bal))
        assert_equal(
            bal,
            Decimal('1.02') + Decimal('0.001') + Decimal('0.002') +
            Decimal('0.003'))

        mark_logs("Calling listsinceblock on Node2 for all transactions",
                  self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock("", 1, False, True)
        # pprint.pprint(ret)

        mat_block_hash = self.nodes[2].getblockhash(mat_height_d[0])
        # first cert is there and its backward transfer to Node2 is mature
        # we also have one ordinary output from this cert, and we should have no maturity info
        cert = certs_d[0]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['category'], 'receive')
                assert_equal(x['blockhash'], blocks_d[0])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['amount'], Decimal('1.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    assert_equal(x['maturityblockhash'], mat_block_hash)
                    found_bwt = True
                else:
                    assert_false('maturityblockhash' in x)
                    assert_equal(x['amount'], Decimal('0.001'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # cert 2 is there and is immature
        # we also have one ordinary output from this cert
        cert = certs_d[1]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[1])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('2.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.002'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # last cert is there and is immature
        # we also have one ordinary output from this cert
        cert = certs_d[2]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[2])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('3.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.003'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # calling the cmd targeting the block where the second certificate has been mined
        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(
                block_heights_d[1], blocks_d[1]), self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(blocks_d[1], 1, False, True)
        pprint.pprint(ret)

        cert = certs_d[0]
        # first cert is there, it is mature and it refers to the block where it matured
        # we should not see the standard output anymore
        mat_block_hash = self.nodes[2].getblockhash(mat_height_d[0])
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
                assert_equal(x['amount'], Decimal('1.02'))
                assert_equal(x['category'], 'receive')
                assert_equal(x['blockhash'], blocks_d[0])
                assert_equal(x['maturityblockhash'], mat_block_hash)
                assert_equal(x['isBackwardTransfer'], True)
        assert_true(found)

        # cert 2 is not there (since-block is not part of the range)
        cert = certs_d[1]
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
        assert_false(found)

        # last cert is there and is immature, we have also standard output
        cert = certs_d[2]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[2])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('3.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.003'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # calling the cmd targeting the block where the last certificate has been mined
        # There must be no certificates at all, since none of them is contained or matures in this block range
        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(
                block_heights_d[2], blocks_d[2]), self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(blocks_d[2], 1, False, True)
        assert_true(len(ret['transactions']) == 0)

        # reach the height of the second certificate and re-issue the command
        c = self.nodes[0].getblockcount()
        mark_logs("Node 0 generates {} block".format(mat_height_d[1] - c),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(mat_height_d[1] - c)
        self.sync_all()
        print("chain height = {}".format(self.nodes[0].getblockcount()))

        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(
                block_heights_d[2], blocks_d[2]), self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(blocks_d[2], 1, False, True)

        cert = certs_d[0]
        # first cert is not there
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
        assert_false(found)

        cert = certs_d[1]
        # second cert is there, it is mature and it refers to the block where it matured
        found = False
        mat_block_hash = self.nodes[2].getblockhash(mat_height_d[1])
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
                assert_equal(x['amount'], Decimal('2.02'))
                assert_equal(x['category'], 'receive')
                assert_equal(x['blockhash'], blocks_d[1])
                assert_equal(x['maturityblockhash'], mat_block_hash)
                assert_equal(x['isBackwardTransfer'], True)
        assert_true(found)

        cert = certs_d[2]
        # last cert is not there
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
        assert_false(found)

        # get the block before the one containing the last certificate
        h = block_heights_d[2] - 1
        bl = self.nodes[0].getblockhash(h)

        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(h, bl),
            self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(bl, 1, False, True)

        # last cert is there and is immature
        # we also have one ordinary output from this cert
        cert = certs_d[2]
        found_bwt = False
        found_out = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                assert_equal(x['blockhash'], blocks_d[2])
                if 'isBackwardTransfer' in x:
                    assert_equal(x['category'], 'immature')
                    assert_equal(x['amount'], Decimal('3.02'))
                    assert_equal(x['isBackwardTransfer'], True)
                    found_bwt = True
                else:
                    assert_equal(x['category'], 'receive')
                    assert_equal(x['amount'], Decimal('0.003'))
                    found_out = True
        assert_true(found_bwt)
        assert_true(found_out)

        # reach the height of the third certificate, that will make the SC cease, and re-issue the command
        c = self.nodes[0].getblockcount()
        mark_logs("Node 0 generates {} block".format(mat_height_d[2] - c),
                  self.nodes, DEBUG_MODE)
        self.nodes[0].generate(mat_height_d[2] - c)
        self.sync_all()
        print("chain height = {}".format(self.nodes[0].getblockcount()))

        ret = self.nodes[0].getscinfo(scid, False, False)['items'][0]
        assert_equal(ret['ceasingHeight'], mat_height_d[2])
        assert_equal(ret['state'], "CEASED")

        mark_logs(
            "Calling listsinceblock on Node2 for h={}, hash={}".format(h, bl),
            self.nodes, DEBUG_MODE)
        ret = self.nodes[2].listsinceblock(bl, 1, False, True)

        # last cert bwt is not there anymore as expected
        # but we still have one ordinary output from this cert
        cert = certs_d[2]
        found = False
        for x in ret['transactions']:
            if x['txid'] == cert:
                found = True
                assert_false('isBackwardTransfer' in x)
                assert_equal(x['blockhash'], blocks_d[2])
                assert_equal(x['category'], 'receive')
                assert_equal(x['amount'], Decimal('0.003'))
        assert_true(found)
示例#8
0
    def run_test(self):
        # Give time to explorer to start
        self.nodes[0].generate(150)
        self.sync_all()
        time.sleep(30)
        info = self.nodes[0].getinfo()

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

        # #### /status ####
        print("#### /status ####")

        # Test the endpoint without parameter (= getInfo)
        r = requests.get(url=self.BASE_URL + "status", params={})
        data = r.json()['info']
        assert_equal(data['version'], info['version'])
        assert_equal(data['protocolversion'], info['protocolversion'])
        assert_equal(data['blocks'], info['blocks'])
        assert_equal(data['timeoffset'], info['timeoffset'])
        assert_equal(data['connections'], info['connections'])
        assert_equal(data['proxy'], info['proxy'])
        assert_equal(self.truncate(float(data['difficulty']), 8),
                     self.truncate(float(info['difficulty']), 8))
        assert_equal(data['testnet'], info['testnet'])
        # assert_equal(float(data['relayfee']),float(info['relayfee']))
        assert_equal(data['errors'], info['errors'])
        assert_equal(data['network'], 'regtest')

        # Test the endpoint with parameter getDifficulty
        r = requests.get(url=self.BASE_URL + "status?q=getDifficulty",
                         params={})
        data = r.json()
        assert_equal(self.truncate(float(data['difficulty']), 8),
                     self.truncate(float(info['difficulty']), 8))

        # Test the endpoint with parameter getTotalSupply
        r = requests.get(url=self.BASE_URL + "status?q=getTotalSupply",
                         params={})
        data = r.json()
        assert_equal(self.truncate(float(data['supply']), 8),
                     self.truncate(float(info['blocks'] * 12.5), 8))

        # Test the endpoint with parameter getLastBlockHash
        r = requests.get(url=self.BASE_URL + "status?q=getLastBlockHash",
                         params={})
        data = r.json()
        lastBlockHash = self.nodes[0].getblock("150")
        assert_equal({}, data,
                     'data is empty because the method is trying to return '
                     'this.node.services.bitcoind.tiphash that is undefined')
        # assert_equal(data['syncTipHash'], lastBlockHash['hash'])

        # Test the endpoint with parameter getBestBlockHash
        r = requests.get(url=self.BASE_URL + "status?q=getBestBlockHash",
                         params={})
        data = r.json()
        blockchainInfo = self.nodes[0].getblockchaininfo()
        assert_equal(data['bestblockhash'], blockchainInfo['bestblockhash'])

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

        #### /sync ####
        print("#### /sync ####")

        # Test the endpoint
        r = requests.get(url=self.BASE_URL + "sync", params={})
        data = r.json()
        assert_equal(data['status'], 'finished')
        assert_equal(data['blockChainHeight'], blockchainInfo['blocks'])
        assert_equal(data['syncPercentage'], 100)
        assert_equal(data['error'], None)
        assert_equal(data['type'], 'bitcore node')
        assert_equal(data['height'], blockchainInfo['blocks'])

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

        #### /peer ####
        print("#### /peer ####")

        # Test the endpoint
        r = requests.get(url=self.BASE_URL + "peer", params={})
        data = r.json()
        assert_true(data['connected'])
        assert_equal(data['host'], '127.0.0.1')
        assert_equal(data['port'], None)

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

        #### /version ####
        print("#### /version ####")

        # Test the endpoint
        r = requests.get(url=self.BASE_URL + "version", params={})
        data = r.json()
        assert_equal('1.0.1', data['version'])

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

        #### /estimatefee ####
        print("#### /estimatefee ####")

        estimateFee = self.nodes[0].estimatefee(10)

        # Test the endpoint
        r = requests.get(url=self.BASE_URL + "utils/estimatefee?nbBlocks=10",
                         params={})
        data = r.json()

        # Estimate fee method is broken in zendoo #
        assert_equal({}, data, 'Estimate fee method is broken in zendoo')
        assert_equal(-1, estimateFee,
                     'Estimate fee method is broken in zendoo')

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

        #### /currency ####
        print("#### /currency ####")

        r = requests.get(url="https://blockchain.info/ticker", params={})
        bitstampRate = r.json()

        r = requests.get(
            url="https://bittrex.com/api/v1.1/public/getticker?market=btc-zen",
            params={})
        bittrexRate = r.json()['result']['Last']

        bitstamp = bitstampRate['USD']['last'] * bittrexRate

        # Test the endpoint
        r = requests.get(url=self.BASE_URL + "currency", params={})
        data = r.json()
        assert_equal(self.truncate(float(data['data']['bitstamp']), 8),
                     self.truncate(float(bitstamp), 8))

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

        #### /message/verify ####
        print("#### /message/verify ####")

        address = self.nodes[0].getnewaddress()
        message = "Hello World!"
        invalidMessage = "Bye World!"
        signature = self.nodes[0].signmessage(address, message)
        signatureReplaced = signature.replace("+", "%2b")

        # Test the endpoint in GET
        r = requests.get(url=self.BASE_URL + "messages/verify?address=" +
                         address + "&signature=" + signatureReplaced +
                         "&message=" + message,
                         params={})
        data = r.json()
        assert_true(data['result'])

        # Test the endpoint in GET with invalid message
        r = requests.get(url=self.BASE_URL + "messages/verify?address=" +
                         address + "&signature=" + signatureReplaced +
                         "&message=" + invalidMessage,
                         params={})
        data = r.json()
        assert_false(data['result'])

        # Test the endpoint in POST
        r = requests.post(url=self.BASE_URL + "messages/verify",
                          json={
                              "address": address,
                              "signature": signature,
                              "message": message
                          })
        data = r.json()
        print(data)
        assert_true(data['result'])

        # Test the endpoint in POST with invalid message
        r = requests.post(url=self.BASE_URL + "messages/verify",
                          json={
                              "address": address,
                              "signature": signature,
                              "message": invalidMessage
                          })
        data = r.json()
        assert_false(data['result'])

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

        #### /charts ####
        print("#### /charts ####")

        # Test the endpoint
        r = requests.get(url=self.BASE_URL + "charts", params={})
        data = r.json()['charts']
        assert_equal(len(data), 4)
        assert_equal(data['block-size']['name'], 'Block Size')
        assert_equal(data['block-interval']['name'], 'Block Interval')
        assert_equal(data['difficulty']['name'], 'Difficulty')
        assert_equal(data['mining-revenue']['name'], 'Mining revenue')

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

        #### /chart/:chartType ####
        print("#### /chart/:chartType ####")

        # Test the endpoint with mining-revenue parameter
        txs = []
        for i in range(1, 11):
            txs += [self.nodes[0].sendtoaddress(address, Decimal(str(i)))]
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        time.sleep(10)

        miningRevenue = Decimal(12.5)
        for tx in txs:
            transaction = self.nodes[0].gettransaction(tx)
            miningRevenue += abs(transaction['fee'])

        r = requests.get(url=self.BASE_URL + "chart/mining-revenue", params={})
        data = r.json()['data']
        assert_equal(len(data['json']['revenue']), 151)
        assert_equal(len(data['json']['height']), 151)
        for i in range(0, 151):
            assert_equal(i + 1, data['json']['height'][i])
            if (i == 150):
                assert_equal(
                    "{:.8f}".format(float(abs(miningRevenue))),
                    "{:.8f}".format(float(data['json']['revenue'][i])))
            else:
                assert_equal(
                    "{:.8f}".format(float(data['json']['revenue'][i])),
                    "{:.8f}".format(float(Decimal(12.5))))

        # Test the endpoint with block-size and difficulty parameter
        r = requests.get(url=self.BASE_URL + "chart/block-size", params={})
        data = r.json()['data']
        assert_equal(len(data['json']['size']), 151)
        assert_equal(len(data['json']['height']), 151)

        r = requests.get(url=self.BASE_URL + "chart/difficulty", params={})
        data2 = r.json()['data']
        assert_equal(len(data2['json']['difficulty']), 151)
        assert_equal(len(data2['json']['height']), 151)
        for i in range(0, 151):
            block = self.nodes[0].getblock(str(i + 1))
            assert_equal(data['json']['height'][i], i + 1)
            assert_equal(data['json']['size'][i], block['size'])
            assert_equal(
                self.truncate(float(data2['json']['difficulty'][i]), 8),
                self.truncate(float(block['difficulty']), 8))

        # Test the endpoint with block-interval parameter
        block0 = self.nodes[0].generate(1)
        self.sync_all()
        time.sleep(2)
        t0 = self.nodes[0].getblock(block0[0])['time']
        block1 = self.nodes[0].generate(1)
        self.sync_all()
        time.sleep(2)
        t1 = self.nodes[0].getblock(block1[0])['time']

        r = requests.get(url=self.BASE_URL + "chart/block-interval", params={})
        data = r.json()['data']

        assert_equal(len(data['json']['blockinterval']), 152)
        assert_equal(data['json']['blockinterval'][151], (t1 - t0))
示例#9
0
        ia = self.nodes[2].getscinfo(scid_1)['items'][0]["immatureAmounts"]
        for entry in ia:
            if entry["maturityHeight"] == curh + 2:
                assert_equal(entry["amount"], creation_amount)
            print "...OK"
            print

        creating_tx = self.nodes[2].getscinfo(
            scid_1)['items'][0]['creatingTxHash']

        mark_logs("\nNode 2 invalidates best block", self.nodes, DEBUG_MODE)
        try:
            self.nodes[2].invalidateblock(self.nodes[2].getbestblockhash())
        except JSONRPCException, e:
            errorString = e.error['message']
            print errorString
        time.sleep(1)
        print "Current height: ", self.nodes[2].getblockcount()
        print "Checking that sc info on Node2 is not available in blockchain (just in mempool)..."
        scinfo = self.nodes[2].getscinfo(scid_1)['items'][0]
        assert_false('creatingTxHash' in scinfo)
        assert_true(scinfo['unconfCreatingTxHash'], creating_tx)

        print "...OK"
        print
        time.sleep(1)


if __name__ == '__main__':
    sc_fwd_maturity().main()
    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 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])
    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'])
class AsyncProofVerifierTest(BitcoinTestFramework):
    def setup_chain(self):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, NUMB_OF_NODES)

    def setup_network(self, split=False):
        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[
                [
                    "-forcelocalban", "-sccoinsmaturity=0", '-logtimemicros=1',
                    '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net',
                    '-debug=bench', '-debug=cert'
                ],
                [
                    "-forcelocalban", "-sccoinsmaturity=0", '-logtimemicros=1',
                    '-debug=sc', '-debug=py', '-debug=mempool', '-debug=net',
                    '-debug=bench', '-debug=cert'
                ],
                # Skip proof verification for the last node
                [
                    "-forcelocalban", "-skipscproof", "-sccoinsmaturity=0",
                    '-logtimemicros=1', '-debug=sc', '-debug=py',
                    '-debug=mempool', '-debug=net', '-debug=bench',
                    '-debug=cert'
                ]
            ])

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

    # Retrieves the first unspent UTXO from a node excluding the ones spent as input
    # of another transaction.
    #
    # This is particularly useful if we can't rely on zzz because we can't call the
    # sync_all() function.
    def get_first_unspent_utxo_excluding(self, node_index,
                                         excluding_transaction_ids):

        recently_spent = []

        # Save all the inputs spent by the last transaction
        for txid in excluding_transaction_ids:
            last_tx_vin = self.nodes[node_index].getrawtransaction(txid,
                                                                   1)['vin']

            for input_entry in last_tx_vin:
                recently_spent.append(
                    (input_entry['txid'], input_entry['vout']))

        # Take the first unspent UTXO
        list_unspent = self.nodes[0].listunspent()
        counter = 0
        utxo = list_unspent[counter]

        # Loop until we find an unspent UTXO not included in the input list of the excluding transaction
        while (utxo['txid'], utxo['vout']) in recently_spent:
            counter = counter + 1
            utxo = list_unspent[counter]

        return utxo

    def run_test(self):
        '''
        Verify that the async proof verifier for sidechain proofs works as expected.
        '''

        # Prepare some coins
        self.nodes[0].generate(MINIMAL_SC_HEIGHT / 2 + 1)
        self.sync_all()

        # Generate some coins on node 2
        self.nodes[2].generate(MINIMAL_SC_HEIGHT / 2 + 1)
        self.sync_all()

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_epoch_len = EPOCH_LENGTH
        sc_cr_amount = Decimal('12.00000000')

        cert_mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        csw_mc_test = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        vk = cert_mc_test.generate_params("sc")
        csw_vk = csw_mc_test.generate_params("sc")
        constant = generate_random_field_element_hex()

        sc_cr = []
        sc_cr.append({
            "version": 0,
            "epoch_length": sc_epoch_len,
            "amount": sc_cr_amount,
            "address": sc_address,
            "wCertVk": vk,
            "wCeasedVk": csw_vk,
            "constant": constant
        })

        rawtx = self.nodes[0].createrawtransaction([], {}, [], sc_cr)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sig_raw_tx = self.nodes[0].signrawtransaction(funded_tx['hex'])
        final_raw_tx = self.nodes[0].sendrawtransaction(sig_raw_tx['hex'])
        self.sync_all()

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

        # Advance one epoch
        mark_logs("\nLet 1 epoch pass by...", self.nodes, DEBUG_MODE)

        cert1, epoch_number = advance_epoch(cert_mc_test, self.nodes[0],
                                            self.sync_all, scid, "sc",
                                            constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for SC epoch {} {}".format(epoch_number, cert1),
            self.nodes, DEBUG_MODE)

        # Check that the certificate is in the mempool
        mark_logs("Check certificate is in mempool...", self.nodes, DEBUG_MODE)
        assert_true(cert1 in self.nodes[0].getrawmempool())
        assert_true(cert1 in self.nodes[1].getrawmempool())

        # Generate blocks to reach the next epoch
        mark_logs("\nLet another epoch pass by...", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(sc_epoch_len)
        self.sync_all()

        # Check that the certificate is not in the mempool anymore
        mark_logs("Check certificate is not in mempool anymore...", self.nodes,
                  DEBUG_MODE)
        assert_false(cert1 in self.nodes[0].getrawmempool())
        assert_false(cert1 in self.nodes[1].getrawmempool())

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], sc_epoch_len)
        cert_quality = 1
        cert_fee = Decimal("0.00001")
        ft_fee = 0
        mbtr_fee = 0

        # Manually create a certificate with invalid proof to test the ban mechanism
        # mark_logs("\nTest the node ban mechanism by sending a certificate with invalid proof", self.nodes, DEBUG_MODE)

        # Create an invalid proof by providing the wrong epoch_number
        proof = cert_mc_test.create_test_proof("sc", scid_swapped,
                                               epoch_number + 1, cert_quality,
                                               mbtr_fee, ft_fee,
                                               epoch_cum_tree_hash, constant,
                                               [], [])

        try:
            # The send_certificate call must be ok since the proof verification is disabled on node 2
            invalid_cert = self.nodes[2].sc_send_certificate(
                scid, epoch_number, cert_quality, epoch_cum_tree_hash, proof,
                [], ft_fee, mbtr_fee, cert_fee)
        except JSONRPCException, e:
            error_string = e.error['message']
            print "Send certificate failed with reason {}".format(error_string)
            assert (False)

        mark_logs(
            "\n==> certificate for SC epoch {} {}".format(
                epoch_number, invalid_cert), self.nodes, DEBUG_MODE)

        # Check that the certificate is in node 2 mempool
        assert_true(invalid_cert in self.nodes[2].getrawmempool())

        # Wait until the other nodes process the certificate relayed by node 2
        mark_logs(
            "\nWait for the certificate to be relayed by node 2 and processd by node 1",
            self.nodes, DEBUG_MODE)
        time.sleep(MEMPOOL_LONG_WAIT_TIME)

        # Check that the other nodes didn't accept the certificate containing the wrong proof
        mark_logs(
            "\nCheck that node 1 and node 2 didn't receive/accept the invalid certificate",
            self.nodes, DEBUG_MODE)
        assert_false(invalid_cert in self.nodes[0].getrawmempool())
        assert_false(invalid_cert in self.nodes[1].getrawmempool())

        # Check that the node 1 (the only one connected to node 2) has banned node 2
        mark_logs("\nCheck that node 1 has banned node 2", self.nodes,
                  DEBUG_MODE)
        assert_equal(len(self.nodes[1].listbanned()), 1)

        # Remove node 2 from banned list
        self.nodes[0].clearbanned()
        self.nodes[1].clearbanned()

        mark_logs("\nStop node 2", self.nodes, DEBUG_MODE)
        stop_node(self.nodes[2], 2)
        self.nodes.pop()

        self.sync_all()

        # Create the valid proof
        proof = cert_mc_test.create_test_proof("sc", scid_swapped,
                                               epoch_number, cert_quality,
                                               mbtr_fee, ft_fee,
                                               epoch_cum_tree_hash, constant,
                                               [], [])

        try:
            cert2 = self.nodes[0].sc_send_certificate(scid, epoch_number,
                                                      cert_quality,
                                                      epoch_cum_tree_hash,
                                                      proof, [], ft_fee,
                                                      mbtr_fee, cert_fee)
        except JSONRPCException, e:
            error_string = e.error['message']
            print "Send certificate failed with reason {}".format(error_string)
            assert (False)
    def run_test(self):
        '''
        Verify that the async proof verifier for sidechain proofs works as expected.
        '''

        # Prepare some coins
        self.nodes[0].generate(MINIMAL_SC_HEIGHT / 2 + 1)
        self.sync_all()

        # Generate some coins on node 2
        self.nodes[2].generate(MINIMAL_SC_HEIGHT / 2 + 1)
        self.sync_all()

        sc_address = "0000000000000000000000000000000000000000000000000000000000000abc"
        sc_epoch_len = EPOCH_LENGTH
        sc_cr_amount = Decimal('12.00000000')

        cert_mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        csw_mc_test = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        vk = cert_mc_test.generate_params("sc")
        csw_vk = csw_mc_test.generate_params("sc")
        constant = generate_random_field_element_hex()

        sc_cr = []
        sc_cr.append({
            "version": 0,
            "epoch_length": sc_epoch_len,
            "amount": sc_cr_amount,
            "address": sc_address,
            "wCertVk": vk,
            "wCeasedVk": csw_vk,
            "constant": constant
        })

        rawtx = self.nodes[0].createrawtransaction([], {}, [], sc_cr)
        funded_tx = self.nodes[0].fundrawtransaction(rawtx)
        sig_raw_tx = self.nodes[0].signrawtransaction(funded_tx['hex'])
        final_raw_tx = self.nodes[0].sendrawtransaction(sig_raw_tx['hex'])
        self.sync_all()

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

        # Advance one epoch
        mark_logs("\nLet 1 epoch pass by...", self.nodes, DEBUG_MODE)

        cert1, epoch_number = advance_epoch(cert_mc_test, self.nodes[0],
                                            self.sync_all, scid, "sc",
                                            constant, sc_epoch_len)

        mark_logs(
            "\n==> certificate for SC epoch {} {}".format(epoch_number, cert1),
            self.nodes, DEBUG_MODE)

        # Check that the certificate is in the mempool
        mark_logs("Check certificate is in mempool...", self.nodes, DEBUG_MODE)
        assert_true(cert1 in self.nodes[0].getrawmempool())
        assert_true(cert1 in self.nodes[1].getrawmempool())

        # Generate blocks to reach the next epoch
        mark_logs("\nLet another epoch pass by...", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(sc_epoch_len)
        self.sync_all()

        # Check that the certificate is not in the mempool anymore
        mark_logs("Check certificate is not in mempool anymore...", self.nodes,
                  DEBUG_MODE)
        assert_false(cert1 in self.nodes[0].getrawmempool())
        assert_false(cert1 in self.nodes[1].getrawmempool())

        epoch_number, epoch_cum_tree_hash = get_epoch_data(
            scid, self.nodes[0], sc_epoch_len)
        cert_quality = 1
        cert_fee = Decimal("0.00001")
        ft_fee = 0
        mbtr_fee = 0

        # Manually create a certificate with invalid proof to test the ban mechanism
        # mark_logs("\nTest the node ban mechanism by sending a certificate with invalid proof", self.nodes, DEBUG_MODE)

        # Create an invalid proof by providing the wrong epoch_number
        proof = cert_mc_test.create_test_proof("sc", scid_swapped,
                                               epoch_number + 1, cert_quality,
                                               mbtr_fee, ft_fee,
                                               epoch_cum_tree_hash, constant,
                                               [], [])

        try:
            # The send_certificate call must be ok since the proof verification is disabled on node 2
            invalid_cert = self.nodes[2].sc_send_certificate(
                scid, epoch_number, cert_quality, epoch_cum_tree_hash, proof,
                [], ft_fee, mbtr_fee, cert_fee)
        except JSONRPCException, e:
            error_string = e.error['message']
            print "Send certificate failed with reason {}".format(error_string)
            assert (False)
        mark_logs("sent csw tx {}".format(normal_final_raw_tx), self.nodes,
                  DEBUG_MODE)

        # Wait for the transaction to be sent to node 1
        mark_logs("\nWait for the transaction to be sent to node 1",
                  self.nodes, DEBUG_MODE)
        time.sleep(MEMPOOL_SHORT_WAIT_TIME)

        # Check that the normal transaction is in the mempool
        mark_logs("Check normal tx is in mempool...", self.nodes, DEBUG_MODE)
        assert_true(normal_final_raw_tx in self.nodes[1].getrawmempool())

        # Check that the certificate is not in the mempool yet
        mark_logs("Check certificate is not in mempool...", self.nodes,
                  DEBUG_MODE)
        assert_false(cert2 in self.nodes[1].getrawmempool())

        # Wait for the certificate proof verification to complete
        mark_logs("Wait for the certificate proof verification to complete...",
                  self.nodes, DEBUG_MODE)
        self.sync_all()

        # Check that the certificate is in the mempool
        mark_logs("Check certificate tx is in mempool...", self.nodes,
                  DEBUG_MODE)
        assert_true(cert2 in self.nodes[1].getrawmempool())

        # Mine one block to have last cert in chain
        mark_logs("\nNode0 generates 1 block confirming last cert", self.nodes,
                  DEBUG_MODE)
        self.nodes[0].generate(1)