Esempio n. 1
0
 def run_test(self):
     self.nodes[0].generate(3)
     stop_node(self.nodes[0], 0)
     wait_bitcoinds()
     self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex", "-checkblockindex=1"])
     assert_equal(self.nodes[0].getblockcount(), 3)
     print "Success"
Esempio n. 2
0
    def run_test(self):
        blockhashes = []
        print("Mining blocks...")
        for _ in range(8):
            blockhashes.extend(self.nodes[0].generate(1))
            time.sleep(1)
        self.sync_all()
        times = [self.nodes[1].getblock(b)['time'] for b in blockhashes]
        assert_equal(blockhashes,
                     self.nodes[1].getblockhashes(times[0] + 100, 0))
        # test various ranges; the api returns blocks have times LESS THAN
        # 'high' (first argument), not less than or equal, hence the +1
        assert_equal(blockhashes[0:8],
                     self.nodes[1].getblockhashes(times[8 - 1] + 1, times[0]))
        assert_equal(blockhashes[2:6],
                     self.nodes[1].getblockhashes(times[6 - 1] + 1, times[2]))
        assert_equal(blockhashes[5:8],
                     self.nodes[1].getblockhashes(times[8 - 1] + 1, times[5]))
        assert_equal(blockhashes[6:7],
                     self.nodes[1].getblockhashes(times[7 - 1] + 1, times[6]))
        assert_equal(blockhashes[4:6],
                     self.nodes[1].getblockhashes(times[6 - 1] + 1, times[4]))
        assert_equal(blockhashes[1:1],
                     self.nodes[1].getblockhashes(times[1 - 1] + 1, times[1]))

        # Restart all nodes to ensure indices are saved to disk and recovered
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # generating multiple blocks within the same second should
        # result in timestamp index entries with unique times
        # (not realistic but there is logic to ensure this)
        blockhashes = self.nodes[0].generate(10)
        self.sync_all()
        firsttime = self.nodes[1].getblock(blockhashes[0])['time']
        assert_equal(
            blockhashes, self.nodes[1].getblockhashes(firsttime + 10 + 1,
                                                      firsttime))

        # the api can also return 'logical' times, which is the key of the
        # timestamp index (the content being blockhash). Logical times are
        # block times when possible, but since keys must be unique, and the
        # previous 10 block were generated in much less than 10 seconds,
        # each logical time should be one greater than the previous.
        results = self.nodes[1].getblockhashes(firsttime + 10 + 1, firsttime,
                                               {'logicalTimes': True})
        ltimes = [r['logicalts'] for r in results]
        assert_equal(ltimes, list(range(firsttime, firsttime + 10)))

        # there's also a flag to exclude orphaned blocks; results should
        # be the same in this test
        assert_equal(
            results, self.nodes[1].getblockhashes(firsttime + 10 + 1,
                                                  firsttime, {
                                                      'logicalTimes': True,
                                                      'noOrphans': True
                                                  }))
Esempio n. 3
0
 def run_test(self):
     self.nodes[0].generate(3)
     stop_node(self.nodes[0], 0)
     wait_bitcoinds()
     self.nodes[0] = start_node(
         0, self.options.tmpdir,
         ["-debug", "-reindex", "-checkblockindex=1"])
     assert_equal(self.nodes[0].getblockcount(), 3)
     print("Success")
Esempio n. 4
0
    def run_test(self):
        #do some -walletbroadcast tests
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(
            3, self.options.tmpdir,
            [["-walletbroadcast=0"], ["-walletbroadcast=0"],
             ["-walletbroadcast=0"]])
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        self.sync_all()

        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        self.sync_all()
        self.nodes[1].generate(1)  #mine a block, tx should not be in there
        self.sync_all()
        assert_equal(
            self.nodes[2].getbalance(), Decimal('2425.00000000')
        )  #default should not be changed because tx was not broadcasted
        assert_equal(
            self.nodes[2].getbalance("*"), Decimal('2425.00000000')
        )  #default should not be changed because tx was not broadcasted

        #now broadcast from another node, mine a block, sync, and check the balance
        self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        assert_equal(self.nodes[2].getbalance(),
                     Decimal('2427.00000000'))  #should not be
        assert_equal(self.nodes[2].getbalance("*"),
                     Decimal('2427.00000000'))  #should not be

        #create another tx
        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)

        #restart the nodes with -walletbroadcast=1
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(3, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        sync_blocks(self.nodes)

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

        # tx should be added to balance because after restarting the nodes tx should be broadcast
        assert_equal(self.nodes[2].getbalance(), Decimal('2429.00000000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('2429.00000000'))
Esempio n. 5
0
 def reindex(self, justchainstate=False):
     self.nodes[0].generate(3)
     blockcount = self.nodes[0].getblockcount()
     stop_node(self.nodes[0], 0)
     wait_bitcoinds()
     self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug", "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"])
     while self.nodes[0].getblockcount() < blockcount:
         time.sleep(0.1)
     assert_equal(self.nodes[0].getblockcount(), blockcount)
     print("Success")
Esempio n. 6
0
def main():
    import optparse

    parser = optparse.OptionParser(usage="%prog [options]")
    parser.add_option(
        "--nocleanup",
        dest="nocleanup",
        default=False,
        action="store_true",
        help="Leave bitcoinds and test.* datadir on exit or error")
    parser.add_option(
        "--srcdir",
        dest="srcdir",
        default="../../src",
        help=
        "Source directory containing bitcoind/bitcoin-cli (default: %default%)"
    )
    parser.add_option("--tmpdir",
                      dest="tmpdir",
                      default=tempfile.mkdtemp(prefix="test"),
                      help="Root directory for datadirs")
    (options, args) = parser.parse_args()

    os.environ['PATH'] = options.srcdir + ":" + os.environ['PATH']

    check_json_precision()

    success = False
    try:
        print("Initializing test directory " + options.tmpdir)
        if not os.path.isdir(options.tmpdir):
            os.makedirs(options.tmpdir)
        initialize_chain(options.tmpdir)

        run_test(options.tmpdir)

        success = True

    except AssertionError as e:
        print("Assertion failed: " + e.message)
    except Exception as e:
        print("Unexpected exception caught during testing: " + str(e))
        traceback.print_tb(sys.exc_info()[2])

    if not options.nocleanup:
        print("Cleaning up")
        wait_bitcoinds()
        shutil.rmtree(options.tmpdir)

    if success:
        print("Tests successful")
        sys.exit(0)
    else:
        print("Failed")
        sys.exit(1)
Esempio n. 7
0
def main():
    import optparse

    parser = optparse.OptionParser(usage="%prog [options]")
    parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
                      help="Leave bitcoinds and test.* datadir on exit or error")
# ZEN_MOD_START
    parser.add_option("--srcdir", dest="srcdir", default="../../src",
                      help="Source directory containing zend/zen-cli (default: %default%)")
# ZEN_MOD_END
    parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
                      help="Root directory for datadirs")
    (options, args) = parser.parse_args()

    os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']

    check_json_precision()

    success = False
    nodes = []
    try:
        print("Initializing test directory "+options.tmpdir)
        if not os.path.isdir(options.tmpdir):
            os.makedirs(options.tmpdir)
        initialize_chain(options.tmpdir)

        nodes = start_nodes(1, options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']])

        run_test(nodes, options.tmpdir)

        success = True

    except AssertionError as e:
        print("Assertion failed: "+e.message)
    except JSONRPCException as e:
        print("JSONRPC error: "+e.error['message'])
        traceback.print_tb(sys.exc_info()[2])
    except Exception as e:
        print("Unexpected exception caught during testing: "+str(sys.exc_info()[0]))
        traceback.print_tb(sys.exc_info()[2])

    if not options.nocleanup:
        print("Cleaning up")
        stop_nodes(nodes)
        wait_bitcoinds()
        shutil.rmtree(options.tmpdir)

    if success:
        print("Tests successful")
        sys.exit(0)
    else:
        print("Failed")
        sys.exit(1)
Esempio n. 8
0
def main():
    import optparse

    parser = optparse.OptionParser(usage="%prog [options]")
    parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
                      help="Leave bitcoinds and test.* datadir on exit or error")
    parser.add_option("--srcdir", dest="srcdir", default="../../src",
                      help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
    parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
                      help="Root directory for datadirs")
    (options, args) = parser.parse_args()

    os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']

    check_json_precision()

    success = False
    nodes = []
    try:
        print("Initializing test directory "+options.tmpdir)
        if not os.path.isdir(options.tmpdir):
            os.makedirs(options.tmpdir)
        initialize_chain(options.tmpdir)

        nodes = start_nodes(1, options.tmpdir, extra_args=[['-experimentalfeatures', '-developerencryptwallet']])

        run_test(nodes, options.tmpdir)

        success = True

    except AssertionError as e:
        print("Assertion failed: "+e.message)
    except JSONRPCException as e:
        print("JSONRPC error: "+e.error['message'])
        traceback.print_tb(sys.exc_info()[2])
    except Exception as e:
        print("Unexpected exception caught during testing: "+str(sys.exc_info()[0]))
        traceback.print_tb(sys.exc_info()[2])

    if not options.nocleanup:
        print("Cleaning up")
        stop_nodes(nodes)
        wait_bitcoinds()
        shutil.rmtree(options.tmpdir)

    if success:
        print("Tests successful")
        sys.exit(0)
    else:
        print("Failed")
        sys.exit(1)
Esempio n. 9
0
 def run_allowip_test(self, allow_ips, rpchost, rpcport):
     '''
     Start a node with rpcwallow IP, and request getinfo
     at a non-localhost IP.
     '''
     base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
     self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
     try:
         # connect to node through non-loopback interface
         node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0)
         node.getinfo()
     finally:
         node = None # make sure connection will be garbage collected and closed
         stop_nodes(self.nodes)
         wait_bitcoinds()
Esempio n. 10
0
def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
    '''
    Start a node with rpcwallow IP, and request getinfo
    at a non-localhost IP.
    '''
    base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
    nodes = start_nodes(1, tmpdir, [base_args])
    try:
        # connect to node through non-loopback interface
        url = "http://*****:*****@%s:%d" % (rpchost, rpcport,)
        node = get_rpc_proxy(url, 1)
        node.getinfo()
    finally:
        node = None # make sure connection will be garbage collected and closed
        stop_nodes(nodes)
        wait_bitcoinds()
Esempio n. 11
0
def run_allowip_test(tmpdir, allow_ips, rpchost, rpcport):
    '''
    Start a node with rpcwallow IP, and request getinfo
    at a non-localhost IP.
    '''
    base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
    nodes = start_nodes(1, tmpdir, [base_args])
    try:
        # connect to node through non-loopback interface
        url = "http://*****:*****@%s:%d" % (rpchost, rpcport,)
        node = AuthServiceProxy(url)
        node.getinfo()
    finally:
        node = None # make sure connection will be garbage collected and closed
        stop_nodes(nodes)
        wait_bitcoinds()
Esempio n. 12
0
def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
    '''
    Start a node with requested rpcallowip and rpcbind parameters,
    then try to connect, and check if the set of bound addresses
    matches the expected set.
    '''
    expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
    base_args = ['-disablewallet', '-nolisten']
    if allow_ips:
        base_args += ['-rpcallowip=' + x for x in allow_ips]
    binds = ['-rpcbind=' + addr for addr in addresses]
    nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to)
    try:
        pid = bitcoind_processes[0].pid
        assert_equal(set(get_bind_addrs(pid)), set(expected))
    finally:
        stop_nodes(nodes)
        wait_bitcoinds()
Esempio n. 13
0
def run_bind_test(tmpdir, allow_ips, connect_to, addresses, expected):
    '''
    Start a node with requested rpcallowip and rpcbind parameters,
    then try to connect, and check if the set of bound addresses
    matches the expected set.
    '''
    expected = [(addr_to_hex(addr), port) for (addr, port) in expected]
    base_args = ['-disablewallet', '-nolisten']
    if allow_ips:
        base_args += ['-rpcallowip=' + x for x in allow_ips]
    binds = ['-rpcbind='+addr for addr in addresses]
    nodes = start_nodes(1, tmpdir, [base_args + binds], connect_to)
    try:
        pid = bitcoind_processes[0].pid
        assert_equal(set(get_bind_addrs(pid)), set(expected))
    finally:
        stop_nodes(nodes)
        wait_bitcoinds()
Esempio n. 14
0
    def run_test(self):
        # z_getnewaddress is deprecated, but enabled by default so it should succeed
        self.nodes[0].z_getnewaddress()

        # zcrawkeygen is deprecated, and not enabled by default so it should fail
        errorString = ''
        try:
            self.nodes[0].zcrawkeygen()
        except JSONRPCException as e:
            errorString = e.error['message']
        assert "DEPRECATED" in errorString

        # restart with a specific selection of deprecated methods enabled
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network_internal(["getnewaddress", "zcrawkeygen"])

        # z_getnewaddress is enabled by default, so it should succeed
        self.nodes[0].z_getnewaddress()

        # getnewaddress and zcrawkeygen are enabled so they should succeed.
        self.nodes[0].getnewaddress()
        self.nodes[0].zcrawkeygen()

        # restart with no deprecated methods enabled
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network_internal(["none"])

        errorString = ''
        try:
            self.nodes[0].z_getnewaddress()
        except JSONRPCException as e:
            errorString = e.error['message']
        assert "DEPRECATED" in errorString

        errorString = ''
        try:
            self.nodes[0].zcrawkeygen()
        except JSONRPCException as e:
            errorString = e.error['message']
        assert "DEPRECATED" in errorString
Esempio n. 15
0
 def stop_nodes(self):
     stop_nodes(self.nodes)
     wait_bitcoinds()
Esempio n. 16
0
    def run_test(self):
        print("Mining blocks...")

        min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
        # if the fee's positive delta is higher than this value tests will fail,
        # neg. delta always fail the tests.
        # The size of the signature of every input may be at most 2 bytes larger
        # than a minimum sized signature.

        #            = 2 bytes * minRelayTxFeePerByte
        feeTolerance = max(2 * min_relay_tx_fee / 1000, Decimal("0.00000001"))

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

        watchonly_address = self.nodes[0].getnewaddress()
        watchonly_pubkey = self.nodes[0].validateaddress(
            watchonly_address)["pubkey"]
        watchonly_amount = Decimal(200)
        self.nodes[3].importpubkey(watchonly_pubkey, "", True)
        watchonly_txid = self.nodes[0].sendtoaddress(watchonly_address,
                                                     watchonly_amount)
        self.nodes[0].sendtoaddress(self.nodes[3].getnewaddress(),
                                    watchonly_amount / 10)

        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.5)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 5.0)

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

        ###############
        # simple test #
        ###############
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0,
                     True)  #test if we have enough inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 2.2}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0,
                     True)  #test if we have enough inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 2.6}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0, True)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')

        ################################
        # simple test with two outputs #
        ################################
        inputs = []
        outputs = {
            self.nodes[0].getnewaddress(): 2.6,
            self.nodes[1].getnewaddress(): 2.5
        }
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(len(dec_tx['vin']) > 0, True)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')

        #########################################################################
        # test a fundrawtransaction with a VIN greater than the required amount #
        #########################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 5.0:
                utx = aUtx
                break

        assert_equal(utx != False, True)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): Decimal('1.0')}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(fee + totalOut,
                     utx['amount'])  #compare vin total and totalout+fee

        #####################################################################
        # test a fundrawtransaction with which will not get a change output #
        #####################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 5.0:
                utx = aUtx
                break

        assert_equal(utx != False, True)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {
            self.nodes[0].getnewaddress(): Decimal('5.0') - fee - feeTolerance
        }
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(rawtxfund['changepos'], -1)
        assert_equal(fee + totalOut,
                     utx['amount'])  #compare vin total and totalout+fee

        #########################################################################
        # test a fundrawtransaction with a VIN smaller than the required amount #
        #########################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 1.0:
                utx = aUtx
                break

        assert_equal(utx != False, True)

        inputs = [{'txid': utx['txid'], 'vout': utx['vout']}]
        outputs = {self.nodes[0].getnewaddress(): Decimal('1.0')}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)

        # 4-byte version + 4-byte versionGroupId + 1-byte vin count + 36-byte prevout then script_len
        rawtx = rawtx[:90] + "0100" + rawtx[92:]

        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for i, out in enumerate(dec_tx['vout']):
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts += 1
            else:
                assert_equal(i, rawtxfund['changepos'])

        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        ###########################################
        # test a fundrawtransaction with two VINs #
        ###########################################
        utx = False
        utx2 = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 1.0:
                utx = aUtx
            if aUtx['amount'] == 5.0:
                utx2 = aUtx

        assert_equal(utx != False, True)

        inputs = [{
            'txid': utx['txid'],
            'vout': utx['vout']
        }, {
            'txid': utx2['txid'],
            'vout': utx2['vout']
        }]
        outputs = {self.nodes[0].getnewaddress(): 6.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts += 1

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        matchingIns = 0
        for vinOut in dec_tx['vin']:
            for vinIn in inputs:
                if vinIn['txid'] == vinOut['txid']:
                    matchingIns += 1

        assert_equal(
            matchingIns,
            2)  #we now must see two vins identical to vins given as params

        #########################################################
        # test a fundrawtransaction with two VINs and two vOUTs #
        #########################################################
        utx = False
        utx2 = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 1.0:
                utx = aUtx
            if aUtx['amount'] == 5.0:
                utx2 = aUtx

        assert_equal(utx != False, True)

        inputs = [{
            'txid': utx['txid'],
            'vout': utx['vout']
        }, {
            'txid': utx2['txid'],
            'vout': utx2['vout']
        }]
        outputs = {
            self.nodes[0].getnewaddress(): 6.0,
            self.nodes[0].getnewaddress(): 1.0
        }
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if out['scriptPubKey']['addresses'][0] in outputs:
                matchingOuts += 1

        assert_equal(matchingOuts, 2)
        assert_equal(len(dec_tx['vout']), 3)

        ##############################################
        # test a fundrawtransaction with invalid vin #
        ##############################################
        listunspent = self.nodes[2].listunspent()
        inputs = [{
            'txid':
            "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1",
            'vout': 0
        }]  #invalid vin!
        outputs = {self.nodes[0].getnewaddress(): 1.0}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        errorString = ""
        try:
            rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        except JSONRPCException as e:
            errorString = e.error['message']

        assert_equal("Insufficient" in errorString, True)

        ############################################################
        #compare fee of a standard pubkeyhash transaction
        inputs = []
        outputs = {self.nodes[1].getnewaddress(): 1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction with multiple outputs
        inputs = []
        outputs = {
            self.nodes[1].getnewaddress(): 1.1,
            self.nodes[1].getnewaddress(): 1.2,
            self.nodes[1].getnewaddress(): 0.1,
            self.nodes[1].getnewaddress(): 1.3,
            self.nodes[1].getnewaddress(): 0.2,
            self.nodes[1].getnewaddress(): 0.3
        }
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)
        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendmany("", outputs)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a 2of2 multisig p2sh transaction

        # create 2of2 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)

        mSigObj = self.nodes[1].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])

        inputs = []
        outputs = {mSigObj: 1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction

        # create 4of5 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()
        addr3 = self.nodes[1].getnewaddress()
        addr4 = self.nodes[1].getnewaddress()
        addr5 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)
        addr3Obj = self.nodes[1].validateaddress(addr3)
        addr4Obj = self.nodes[1].validateaddress(addr4)
        addr5Obj = self.nodes[1].validateaddress(addr5)

        mSigObj = self.nodes[1].addmultisigaddress(4, [
            addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'],
            addr4Obj['pubkey'], addr5Obj['pubkey']
        ])

        inputs = []
        outputs = {mSigObj: 1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1)
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        # spend a 2of2 multisig transaction over fundraw

        # create 2of2 addr
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey']])

        # send 1.2 BTC to msig addr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        oldBalance = self.nodes[1].getbalance()
        inputs = []
        outputs = {self.nodes[1].getnewaddress(): 1.1}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[2].fundrawtransaction(rawTx)

        signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance + Decimal('1.10000000'),
                     self.nodes[1].getbalance())

        ############################################################
        # locked wallet test
        self.nodes[1].encryptwallet("test")
        self.nodes.pop(1)
        stop_nodes(self.nodes)
        wait_bitcoinds()

        self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)

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

        error = False
        try:
            self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2)
        except:
            error = True
        assert (error)

        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {self.nodes[0].getnewaddress(): 1.1}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #now we need to unlock
        self.nodes[1].walletpassphrase("test", 100)
        signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance + Decimal('11.10000000'),
                     self.nodes[0].getbalance())

        ###############################################
        # multiple (~19) inputs tx test | Compare fee #
        ###############################################

        #empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(),
                                    self.nodes[1].getbalance(), "", "", True)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0, 20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        inputs = []
        outputs = {
            self.nodes[0].getnewaddress(): 0.15,
            self.nodes[0].getnewaddress(): 0.04
        }
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[1].sendmany("", outputs)
        signedFee = self.nodes[1].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee)
        assert (feeDelta >= 0 and feeDelta <= feeTolerance * 19)  #~19 inputs

        #############################################
        # multiple (~19) inputs tx test | sign/send #
        #############################################

        #again, empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(),
                                    self.nodes[1].getbalance(), "", "", True)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0, 20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {
            self.nodes[0].getnewaddress(): 0.15,
            self.nodes[0].getnewaddress(): 0.04
        }
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)
        fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(oldBalance + Decimal('10.19000000'),
                     self.nodes[0].getbalance())  #0.19+block reward

        #####################################################
        # test fundrawtransaction with OP_RETURN and no vin #
        #####################################################

        rawtx = "0100000000010000000000000000066a047465737400000000"
        dec_tx = self.nodes[2].decoderawtransaction(rawtx)

        assert_equal(len(dec_tx['vin']), 0)
        assert_equal(len(dec_tx['vout']), 1)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])

        assert_greater_than(len(dec_tx['vin']), 0)  # at least one vin
        assert_equal(len(dec_tx['vout']), 2)  # one change output added

        ##################################################
        # test a fundrawtransaction using only watchonly #
        ##################################################

        inputs = []
        outputs = {self.nodes[2].getnewaddress(): watchonly_amount / 2}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)

        result = self.nodes[3].fundrawtransaction(rawtx, True)
        res_dec = self.nodes[0].decoderawtransaction(result["hex"])
        assert_equal(len(res_dec["vin"]), 1)
        assert_equal(res_dec["vin"][0]["txid"], watchonly_txid)

        assert_equal("fee" in result.keys(), True)
        assert_greater_than(result["changepos"], -1)

        ###############################################################
        # test fundrawtransaction using the entirety of watched funds #
        ###############################################################

        inputs = []
        outputs = {self.nodes[2].getnewaddress(): watchonly_amount}
        rawtx = self.nodes[3].createrawtransaction(inputs, outputs)

        result = self.nodes[3].fundrawtransaction(rawtx, True)
        res_dec = self.nodes[0].decoderawtransaction(result["hex"])
        assert_equal(len(res_dec["vin"]), 2)
        assert (res_dec["vin"][0]["txid"] == watchonly_txid
                or res_dec["vin"][1]["txid"] == watchonly_txid)

        assert_greater_than(result["fee"], 0)
        assert_greater_than(result["changepos"], -1)
        assert_equal(
            result["fee"] + res_dec["vout"][result["changepos"]]["value"],
            watchonly_amount / 10)

        signedtx = self.nodes[3].signrawtransaction(result["hex"])
        assert (not signedtx["complete"])
        signedtx = self.nodes[0].signrawtransaction(signedtx["hex"])
        assert (signedtx["complete"])
        self.nodes[0].sendrawtransaction(signedtx["hex"])
Esempio n. 17
0
    def run_test(self):
        # Sanity-check the test harness
        self.nodes[0].generate(200)
        assert_equal(self.nodes[0].getblockcount(), 200)
        self.sync_all()

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

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

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

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

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

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

        # Verify shielded balance
        assert_equal(self.nodes[0].z_getbalance(sapling_addr), Decimal('20'))

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

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

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

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

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

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

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

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

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

        # Verify importing a viewing key will update and persist the nullifiers and witnesses correctly
        extfvk0 = self.nodes[0].z_exportviewingkey(sapling_addr)
        self.nodes[3].z_importviewingkey(extfvk0, "yes")
        assert_equal(self.nodes[3].z_getbalance(sapling_addr), Decimal('5'))
        assert_equal(self.nodes[3].z_gettotalbalance()['private'], '0.00')
        assert_equal(self.nodes[3].z_gettotalbalance(1, True)['private'], '5.00')

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

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

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

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

        # Verify balances
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
Esempio n. 18
0
    def run_test(self):
        '''
               (3)
               /
        (0)--(1)
               \
               (2)
        Simulate multiple split for having more forks on different blocks
        '''
        blocks = []

        blocks.append(self.nodes[0].getblockhash(0))
        print("\n\nGenesis block is:\n" + blocks[0])

        s = "Node 1 generates a block"
        print("\n" + s)
        self.mark_logs(s)

        blocks.extend(self.nodes[1].generate(1))  # block height 1
        print blocks[len(blocks) - 1]
        self.sync_all()

        #    Node(0): [0]->[1]
        #      |
        #      |
        #    Node(1): [0]->[1]
        #      /\
        #     /  \
        #    +   Node(2): [0]->[1]
        #    |
        # Node(3): [0]->[1]

        print("\n\nSplit nodes (1)----x   x---(3)")
        #        self.split_network_2()
        #-------------------------------------------------
        disconnect_nodes(self.nodes[1], 3)
        disconnect_nodes(self.nodes[3], 1)
        #        connect_nodes_bi(self.nodes, 1, 2)
        #        connect_nodes_bi(self.nodes, 0, 1)
        #-------------------------------------------------
        time.sleep(2)
        print("The network is split")
        self.mark_logs("The network is split 2")

        s = "Node 1 generates a block"
        print("\n" + s)
        self.mark_logs(s)

        blocks.extend(self.nodes[1].generate(1))  # block height 2
        bl2 = blocks[2]
        print bl2
        time.sleep(2)

        #    Node(0): [0]->[1]->[2h]
        #      |
        #      |
        #    Node(1): [0]->[1]->[2h]
        #       \
        #        \
        #        Node(2): [0]->[1]->[2h]
        #
        # Node(3): [0]->[1]

        print("\n\nSplit nodes (1)----x   x---(2)")
        #        self.split_network()
        #-------------------------------------------------
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = self.setup_nodes()
        connect_nodes_bi(self.nodes, 0, 1)
        #-------------------------------------------------
        self.is_network_split = True
        time.sleep(2)

        print("The network is split")
        self.mark_logs("The network is split")

        print("\nNode1 generating 7 honest block")
        blocks.extend(self.nodes[1].generate(7))  # block height 3
        bl3 = blocks[3]
        print bl3
        time.sleep(2)

        print("\nNode3 generating 8 mal block")
        blocks.extend(self.nodes[3].generate(8))  # block height 2M
        for i in range(10, 18):
            print blocks[i]
        time.sleep(2)

        #        raw_input("press enter to go on..")

        print("\nNode2 generating 8 mal block")
        blocks.extend(self.nodes[2].generate(8))  # block height 2m
        for i in range(18, 26):
            print blocks[i]
        time.sleep(2)

        #      Node(0): [0]->[1]->[2h]->[3h]
        #        |
        #        |
        #      Node(1): [0]->[1]->[2h]->[3h]
        #
        #
        #          Node(2): [0]->[1]->[2h]->[3m]
        #
        # Node(3): [0]->[1]->[2M]

        #        raw_input("press enter to go on..")

        for i in range(0, 4):
            self.dump_ordered_tips(self.nodes[i].getchaintips())
            print "---"

        print("\n\nJoin nodes (1)--(2)")
        # raw_input("press enter to join the netorks..")
        self.mark_logs("Joining network")
        #        self.join_network()
        #-------------------------------------------------
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = self.setup_nodes()
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        #-------------------------------------------------
        time.sleep(10)

        print("\nNetwork joined")
        self.mark_logs("Network joined")

        for i in range(0, 4):
            self.dump_ordered_tips(self.nodes[i].getchaintips())
            print "---"

#      Node(0): [0]->[1]->[2h]->[3h]      **Active**
#        |
#        |
#        |
#      Node(1): [0]->[1]->[2h]->[3h]      **Active**
#         \                 \
#          \                 +->[3m]
#           \
#          Node(2): [0]->[1]->[2h]->[3m]  **Active**
#                               \
#                                +->[3h]
#
# Node(3): [0]->[1]->[2M]

#        raw_input("press enter to go on..")

        try:
            print "\nChecking finality of block[", bl2, "]"
            print "  Node0 has: %d" % self.nodes[0].getblockfinalityindex(bl2)
            print "  Node1 has: %d" % self.nodes[1].getblockfinalityindex(bl2)
            print "\nChecking finality of block[", bl3, "]"
            print "  Node0 has: %d" % self.nodes[0].getblockfinalityindex(bl3)
            print "  Node1 has: %d" % self.nodes[1].getblockfinalityindex(bl3)
        except JSONRPCException, e:
            errorString = e.error['message']
            print errorString
Esempio n. 19
0
    def run_test (self):
        print "Mining blocks..."
        self.nodes[0].generate(4)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 20)
        assert_equal(self.nodes[2].getbalance(), 0)

        # At this point in time, commitment tree is the empty root

        # Node 0 creates a joinsplit transaction
        mytaddr0 = get_coinbase_address(self.nodes[0])
        myzaddr0 = self.nodes[0].z_getnewaddress('sprout')
        recipients = []
        recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')})
        myopid = self.nodes[0].z_sendmany(mytaddr0, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Sync up mempools and mine the transaction.  All nodes have the same anchor.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Stop nodes.
        stop_nodes(self.nodes)
        wait_bitcoinds()

        # Relaunch nodes and partition network into two:
        # A: node 0
        # B: node 1, 2
        self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3 )
        connect_nodes_bi(self.nodes,1,2)

        # Partition B, node 1 mines an empty block
        self.nodes[1].generate(1)

        # Partition A, node 0 creates a joinsplit transaction
        recipients = []
        recipients.append({"address":myzaddr0, "amount": Decimal('10.0') - Decimal('0.0001')})
        myopid = self.nodes[0].z_sendmany(mytaddr0, recipients)
        txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        rawhex = self.nodes[0].getrawtransaction(txid)

        # Partition A, node 0 mines a block with the transaction
        self.nodes[0].generate(1)

        # Partition B, node 1 mines the same joinsplit transaction
        txid2 = self.nodes[1].sendrawtransaction(rawhex)
        assert_equal(txid, txid2)
        self.nodes[1].generate(1)

        # Check that Partition B is one block ahead and that they have different tips
        assert_equal(self.nodes[0].getblockcount() + 1, self.nodes[1].getblockcount())
        assert( self.nodes[0].getbestblockhash() != self.nodes[1].getbestblockhash())

        # Shut down all nodes so any in-memory state is saved to disk
        stop_nodes(self.nodes)
        wait_bitcoinds()

        # Relaunch nodes and reconnect the entire network
        self.nodes = start_nodes(3, self.options.tmpdir, extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3 )
        connect_nodes_bi(self.nodes,0, 1)
        connect_nodes_bi(self.nodes,1, 2)
        connect_nodes_bi(self.nodes,0, 2)

        # Mine a new block and let it propagate
        self.nodes[1].generate(1)
        
        # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception.
        self.sync_all()
      
        # v1.0.4 will reach here safely
        assert_equal( self.nodes[0].getbestblockhash(), self.nodes[1].getbestblockhash())
        assert_equal( self.nodes[1].getbestblockhash(), self.nodes[2].getbestblockhash())
Esempio n. 20
0
class headers(BitcoinTestFramework):

    alert_filename = None

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

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

        self.nodes = start_nodes(
            NUMB_OF_NODES,
            self.options.tmpdir,
            extra_args=[[
                "-debug=cbh", "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH),
                "-cbhminage=" + str(minAge)
            ],
                        [
                            "-debug=cbh",
                            "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH),
                            "-cbhminage=" + str(minAge)
                        ],
                        [
                            "-debug=cbh",
                            "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH),
                            "-cbhminage=" + str(minAge)
                        ],
                        [
                            "-debug=cbh",
                            "-cbhsafedepth=" + str(FINALITY_SAFE_DEPTH),
                            "-cbhminage=" + str(minAge)
                        ]])

        if not split:
            # 2 and 3 are joint only if split==false
            connect_nodes_bi(self.nodes, 2, 3)
            connect_nodes_bi(self.nodes, 3, 2)
            sync_blocks(self.nodes[2:NUMB_OF_NODES])
            sync_mempools(self.nodes[2:NUMB_OF_NODES])

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

    def disconnect_nodes(self, from_connection, node_num):
        ip_port = "127.0.0.1:" + str(p2p_port(node_num))
        from_connection.disconnectnode(ip_port)
        # poll until version handshake complete to avoid race conditions
        # with transaction relaying
        while any(peer['version'] == 0
                  for peer in from_connection.getpeerinfo()):
            time.sleep(0.1)

    def split_network(self):
        # Split the network of 4 nodes into nodes 0-1-2 and 3.
        assert not self.is_network_split
        self.disconnect_nodes(self.nodes[2], 3)
        self.disconnect_nodes(self.nodes[3], 2)
        self.is_network_split = True

    def join_network(self):
        #Join the (previously split) network pieces together: 0-1-2-3
        assert self.is_network_split
        connect_nodes_bi(self.nodes, 2, 3)
        connect_nodes_bi(self.nodes, 3, 2)
        #        self.sync_all()
        sync_blocks(self.nodes, 1, False, 5)
        self.is_network_split = False

    def mark_logs(self, msg):
        self.nodes[0].dbg_log(msg)
        self.nodes[1].dbg_log(msg)
        self.nodes[2].dbg_log(msg)
        self.nodes[3].dbg_log(msg)

    def swap_bytes(self, input_buf):
        return codecs.encode(codecs.decode(input_buf, 'hex')[::-1],
                             'hex').decode()

    def is_in_block(self, tx, bhash, node_idx=0):
        blk_txs = self.nodes[node_idx].getblock(bhash, True)['tx']
        for i in blk_txs:
            if (i == tx):
                return True
        return False

    def is_in_mempool(self, tx, node_idx=0):
        mempool = self.nodes[node_idx].getrawmempool()
        for i in mempool:
            if (i == tx):
                return True
        return False

    def run_test(self):
        blocks = []
        self.bl_count = 0

        blocks.append(self.nodes[1].getblockhash(0))

        small_target_h = 3

        s = "  Node1 generates %d blocks" % (CBH_DELTA + small_target_h)
        print(s)
        print
        self.mark_logs(s)
        blocks.extend(self.nodes[1].generate(CBH_DELTA + small_target_h))
        self.sync_all()

        #-------------------------------------------------------------------------------------------------------
        print "Trying to send a tx with a scriptPubKey referencing a block too recent..."
        #-------------------------------------------------------------------------------------------------------
        # Create a tx having in its scriptPubKey a custom referenced block in the CHECKBLOCKATHEIGHT part

        # select necessary utxos for doing the PAYMENT
        usp = self.nodes[1].listunspent()

        PAYMENT = Decimal('1.0')
        FEE = Decimal('0.00005')
        amount = Decimal('0')
        inputs = []

        print "  Node1 sends %f coins to Node2" % PAYMENT

        for x in usp:
            amount += Decimal(x['amount'])
            inputs.append({"txid": x['txid'], "vout": x['vout']})
            if amount >= PAYMENT + FEE:
                break

        outputs = {
            self.nodes[1].getnewaddress(): (Decimal(amount) - PAYMENT - FEE),
            self.nodes[2].getnewaddress(): PAYMENT
        }
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)

        # build an object from the raw tx in order to be able to modify it
        tx_01 = CTransaction()
        f = cStringIO.StringIO(unhexlify(rawTx))
        tx_01.deserialize(f)

        decodedScriptOrig = self.nodes[1].decodescript(
            binascii.hexlify(tx_01.vout[1].scriptPubKey))

        scriptOrigAsm = decodedScriptOrig['asm']

        #        print "Original scriptPubKey asm 1:   ", scriptOrigAsm
        #        print

        # store the hashed script, it is reused
        params = scriptOrigAsm.split()
        hash_script = hex_str_to_bytes(params[2])

        # new referenced block height
        modTargetHeigth = CBH_DELTA + small_target_h - FINALITY_MIN_AGE + 5

        # new referenced block hash
        modTargetHash = hex_str_to_bytes(
            self.swap_bytes(blocks[modTargetHeigth]))

        # build modified script
        modScriptPubKey = CScript([
            OP_DUP, OP_HASH160, hash_script, OP_EQUALVERIFY, OP_CHECKSIG,
            modTargetHash, modTargetHeigth, OP_CHECKBLOCKATHEIGHT
        ])

        tx_01.vout[1].scriptPubKey = modScriptPubKey
        tx_01.rehash()

        decodedScriptMod = self.nodes[1].decodescript(
            binascii.hexlify(tx_01.vout[1].scriptPubKey))
        print "  Modified scriptPubKey in tx 1: ", decodedScriptMod['asm']

        signedRawTx = self.nodes[1].signrawtransaction(ToHex(tx_01))

        h = self.nodes[1].getblockcount()
        assert_greater_than(FINALITY_MIN_AGE, h - modTargetHeigth)

        #raw_input("\npress enter to go on ..")
        try:
            txid = self.nodes[1].sendrawtransaction(signedRawTx['hex'])
            print "  Tx sent: ", txid
            # should fail, therefore force test failure
            assert_equal(True, False)

        except JSONRPCException, e:
            print "  ==> tx has been rejected as expected:"
            print "      referenced block height=%d, chainActive.height=%d, minimumAge=%d" % (
                modTargetHeigth, h, FINALITY_MIN_AGE)
            print

        #-------------------------------------------------------------------------------------------------------
        print "Check that small digit height for referenced blocks works in scriptPubKey"
        #-------------------------------------------------------------------------------------------------------
        # check that small height works for 'check block at height' in script
        #--------------------------------------------------------------------
        node1_pay = Decimal('0.5')
        s = "  Node1 sends %f coins to Node3 for checking script in tx" % node1_pay
        print s
        self.mark_logs(s)

        tx1 = self.nodes[1].sendtoaddress(self.nodes[3].getnewaddress(),
                                          node1_pay)
        print "  ==> tx sent: ", tx1

        sync_mempools(self.nodes[0:4])

        assert_equal(self.is_in_mempool(tx1), True)

        script = self.nodes[1].getrawtransaction(
            tx1, 1)['vout'][0]['scriptPubKey']['asm']
        tokens = script.split()
        small_h = int(tokens[6])
        small_h_hash = self.swap_bytes(tokens[5])

        print "  ScriptPubKey: ", script

        assert_equal(small_h, small_target_h)
        assert_equal(small_h_hash, blocks[int(small_h)])

        print("  Node1 generating 1 honest block")
        blocks.extend(self.nodes[1].generate(1))
        self.sync_all()

        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        # check tx is no more in mempool
        assert_equal(self.is_in_mempool(tx1), False)

        # check tx is in the block just mined
        assert_equal(self.is_in_block(tx1, blocks[-1], 3), True)

        # check the balance is the one expected
        assert_equal(self.nodes[3].getbalance(), node1_pay)

        s = "  Node3 sends 0.25 coins to Node2 for checking script in tx"
        print s
        self.mark_logs(s)

        tx2 = self.nodes[3].sendtoaddress(self.nodes[2].getnewaddress(), 0.25)
        print "  ==> tx sent: ", tx2

        sync_mempools(self.nodes[0:4])

        assert_equal(self.is_in_mempool(tx2), True)

        print("  Node1 generating 1 honest block")
        blocks.extend(self.nodes[1].generate(1))
        self.sync_all()

        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        # check tx is no more in mempool
        assert_equal(self.is_in_mempool(tx2), False)

        # check tx is in the block just mined
        assert_equal(self.is_in_block(tx2, blocks[-1], 1), True)

        print "  ==> OK, small digit height works in scripts:"
        print
        #--------------------------------------------------------------------

        print "Verify that a legal tx, when the referenced block is reverted, becomes invalid until the necessary depth of the referenced block height has been reached..."
        print "  Restarting network with -cbhminage=0"
        # restart Nodes and check their balance: node1 does not have 1000 coins but node2 does not have either
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False, 0)

        chunks = 305
        s = "  Node0 generates %d blocks" % chunks
        print(s)
        self.mark_logs(s)
        blocks.extend(self.nodes[0].generate(chunks))
        self.sync_all()

        print "  Split network: (0)---(1)---(2)   (3)"
        self.split_network()

        print "  Node0 generating 1 honest block"
        blocks.extend(self.nodes[0].generate(1))
        sync_blocks(self.nodes, 1, False, 5)
        #        self.sync_all()
        #        time.sleep(5)

        # we will perform on attack aimed at reverting from this block (latest generated) upward
        hash_attacked = blocks[-1]
        h_attacked = self.nodes[1].getblockcount()
        assert hash_attacked == blocks[h_attacked]
        hash_attacked_swapped = self.swap_bytes(hash_attacked)
        hex_s = "%04x" % h_attacked
        h_attacked_swapped = self.swap_bytes(hex_s)
        h_safe_estimated = h_attacked + FINALITY_SAFE_DEPTH + 1

        print "  Honest network has current h[%d]" % h_attacked

        # we will create a transaction whose output will have a CHECKBLOCKATHEIGHT on this block
        h_checked = h_attacked - CBH_DELTA
        hex_s = "%04x" % h_checked
        h_checked_swapped = self.swap_bytes(hex_s)
        hash_checked = blocks[h_checked]
        hash_checked_swapped = self.swap_bytes(hash_checked)

        # select necessary utxos for doing the PAYMENT, there might be a lot of them
        usp = self.nodes[1].listunspent()

        PAYMENT = Decimal('1000.0')
        FEE = Decimal('0.00005')
        amount = Decimal('0')
        inputs = []

        for x in usp:
            amount += Decimal(x['amount'])
            inputs.append({"txid": x['txid'], "vout": x['vout']})
            if amount >= PAYMENT + FEE:
                break

        print "  Creating raw tx referencing the current block %d where Node1 sends %f coins to Node2..." % (
            h_attacked, PAYMENT)

        outputs = {
            self.nodes[1].getnewaddress(): (Decimal(amount) - PAYMENT - FEE),
            self.nodes[2].getnewaddress(): PAYMENT
        }
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)

        # replace hash and h referenced in tx's script with the ones of target block
        from_buf = str(hash_checked_swapped) + '02' + str(h_checked_swapped)
        to_buf = str(hash_attacked_swapped) + '02' + str(h_attacked_swapped)
        rawTxReplaced = rawTx.replace(from_buf, to_buf)

        # modifying just one vout is enough for tampering the whole tx
        script = self.nodes[1].decoderawtransaction(
            rawTx)['vout'][0]['scriptPubKey']['asm']

        decodedRep = self.nodes[1].decoderawtransaction(rawTxReplaced)

        scriptRep = decodedRep['vout'][0]['scriptPubKey']['asm']
        print "  Changed script in tx"
        print "    from: ", script
        print "    to:   ", scriptRep

        signedRawTx = self.nodes[1].signrawtransaction(rawTx)
        signedRawTxReplaced = self.nodes[1].signrawtransaction(rawTxReplaced)

        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        amountRep = Decimal('0')
        changeRep = Decimal('0')
        nAm = -1
        nCh = -1

        # get the amount and the change of the tx, they might not be ordered as vout entries
        for x in decodedRep['vout']:
            if x['value'] == PAYMENT:
                amountRep = x['value']
                nAm = x['n']
            else:
                changeRep = x['value']
                nCh = x['n']

        # the tx modified has a script that does not pass the check at referenced block, tx 1000 coins (and also related change)
        # will be unspendable once the chain is reverted
        tx_1000 = self.nodes[1].sendrawtransaction(signedRawTxReplaced['hex'])
        print "  ==> tx sent: ", tx_1000
        print "       amount (vout[%d]): %f" % (nAm, amountRep)
        print "       change (vout[%d]): %f" % (nCh, changeRep)

        sync_mempools(self.nodes[0:3])
        assert_equal(self.is_in_mempool(tx_1000, 1), True)
        print "  OK, tx is in mempool..."

        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        print("  Node0 generating 1 honest block")
        blocks.extend(self.nodes[0].generate(1))
        time.sleep(5)

        # check tx is no more in mempool
        assert_equal(self.is_in_mempool(tx_1000, 1), False)

        # check tx is in the block just mined
        assert_equal(self.is_in_block(tx_1000, blocks[-1], 1), True)
        print "  OK, tx is not in mempool anymore (it is contained in the block just mined)"
        print "  Block: (%d) %s" % (int(
            self.nodes[2].getblockcount()), blocks[-1])

        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        print "  Node3 generating 3 malicious blocks thus reverting the honest chain once the ntw is joined!"
        blocks.extend(self.nodes[3].generate(3))
        time.sleep(2)

        self.join_network()

        time.sleep(2)
        print "  Network joined: (0)---(1)---(2)---(3)"
        self.mark_logs("Network joined")

        # check attacked transaction is back in the mempool of nodes belonging to the honest portion of the joined network
        assert_equal(self.is_in_mempool(tx_1000, 0), True)
        assert_equal(self.is_in_mempool(tx_1000, 1), True)
        assert_equal(self.is_in_mempool(tx_1000, 2), True)
        assert_equal(self.is_in_mempool(tx_1000, 3), False)

        print "  ==> the block has been reverted, the tx is back in the mempool of the reverted nodes!"

        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        print("  Node0 generating 1 honest block")
        blocks.extend(self.nodes[0].generate(1))
        time.sleep(2)

        # check tx_1000 is in the block just mined
        assert_equal(self.is_in_block(tx_1000, blocks[-1], 2), True)

        print "  ==> TX referencing reverted block has been mined in a new block!!"
        print "       Block: (%d) %s" % (int(
            self.nodes[3].getblockcount()), blocks[-1])

        # restart Nodes and check their balance: node1 does not have 1000 coins but node2 does not have either
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False, 0)

        print "  Balances after node restart:"
        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node3 balance: ", self.nodes[3].getbalance()

        print "  Node3 generating %d honest blocks more" % (
            FINALITY_SAFE_DEPTH - 2)

        blocks.extend(self.nodes[3].generate(FINALITY_SAFE_DEPTH - 2))
        self.sync_all()

        # if safe depth is set to FINALITY_SAFE_DEPTH, from the previos block on the tx will become valid

        h_safe = self.nodes[1].getblockcount()

        assert_equal(h_safe, h_safe_estimated)

        print "  OK, at h[%d] the attacked tx should have been restored, node will have it after a restart" % h_safe

        node1_bal_before = Decimal(self.nodes[1].getbalance())
        node2_bal_before = Decimal(self.nodes[2].getbalance())

        print "  Balances before node restart:"
        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node2 balance: ", self.nodes[3].getbalance()

        # restart Nodes and check their balance, at this point the 1000 coins should be in the wallet of node2
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False, 0)

        node1_bal_after = Decimal(self.nodes[1].getbalance())
        node2_bal_after = Decimal(self.nodes[2].getbalance())

        print "  Balances after node restart:"
        print "  | Node0 balance: ", self.nodes[0].getbalance()
        print "  | Node1 balance: ", self.nodes[1].getbalance()
        print "  | Node2 balance: ", self.nodes[2].getbalance()
        print "  | Node2 balance: ", self.nodes[3].getbalance()

        # ensure both the amount (to the recipient) and the change (to the sender) have been restored
        assert_equal(node1_bal_before + changeRep, node1_bal_after)
        assert_equal(node2_bal_before + amountRep, node2_bal_after)
Esempio n. 21
0
    def run_test(self):

        # helper functions
        def getaddresstxids(node_index, addresses, start, end):
            return self.nodes[node_index].getaddresstxids({
                'addresses': addresses,
                'start': start,
                'end': end
            })

        def getaddressdeltas(node_index,
                             addresses,
                             start,
                             end,
                             chainInfo=None):
            params = {
                'addresses': addresses,
                'start': start,
                'end': end,
            }
            if chainInfo is not None:
                params.update({'chainInfo': chainInfo})
            return self.nodes[node_index].getaddressdeltas(params)

        # default received value is the balance value
        def check_balance(node_index,
                          address,
                          expected_balance,
                          expected_received=None):
            if isinstance(address, list):
                bal = self.nodes[node_index].getaddressbalance(
                    {'addresses': address})
            else:
                bal = self.nodes[node_index].getaddressbalance(address)
            assert_equal(bal['balance'], expected_balance)
            if expected_received is None:
                expected_received = expected_balance
            assert_equal(bal['received'], expected_received)

        # begin test

        self.nodes[0].generate(105)
        self.sync_all()
        assert_equal(self.nodes[0].getbalance(), 5 * 10)
        assert_equal(self.nodes[1].getblockcount(), 105)
        assert_equal(self.nodes[1].getbalance(), 0)

        # only the oldest 5; subsequent are not yet mature
        unspent_txids = [u['txid'] for u in self.nodes[0].listunspent()]

        # Currently our only unspents are coinbase transactions, choose any one
        tx = self.nodes[0].getrawtransaction(unspent_txids[0], 1)

        # It just so happens that the first output is the mining reward,
        # which has type pay-to-public-key-hash, and the second output
        # is the founders' reward, which has type pay-to-script-hash.
        addr_p2pkh = tx['vout'][0]['scriptPubKey']['addresses'][0]
        addr_p2sh = tx['vout'][1]['scriptPubKey']['addresses'][0]

        # Check that balances from mining are correct (105 blocks mined); in
        # regtest, all mining rewards from a single call to generate() are sent
        # to the same pair of addresses.
        check_balance(1, addr_p2pkh, 105 * 10 * COIN)
        check_balance(1, addr_p2sh, 105 * 2.5 * COIN)

        # Multiple address arguments, results are the sum
        check_balance(1, [addr_p2sh, addr_p2pkh], 105 * 12.5 * COIN)

        assert_equal(len(self.nodes[1].getaddresstxids(addr_p2pkh)), 105)
        assert_equal(len(self.nodes[1].getaddresstxids(addr_p2sh)), 105)
        # test getaddresstxids for lightwalletd
        assert_equal(len(self.nodes[3].getaddresstxids(addr_p2pkh)), 105)
        assert_equal(len(self.nodes[3].getaddresstxids(addr_p2sh)), 105)

        # only the oldest 5 transactions are in the unspent list,
        # dup addresses are ignored
        height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2pkh], 1, 5)
        assert_equal(sorted(height_txids), sorted(unspent_txids))

        height_txids = getaddresstxids(1, [addr_p2sh], 1, 5)
        assert_equal(sorted(height_txids), sorted(unspent_txids))

        # each txid should appear only once
        height_txids = getaddresstxids(1, [addr_p2pkh, addr_p2sh], 1, 5)
        assert_equal(sorted(height_txids), sorted(unspent_txids))

        # do some transfers, make sure balances are good
        txids_a1 = []
        addr1 = self.nodes[1].getnewaddress()
        expected = 0
        expected_deltas = []  # for checking getaddressdeltas (below)
        for i in range(5):
            # first transaction happens at height 105, mined in block 106
            txid = self.nodes[0].sendtoaddress(addr1, i + 1)
            txids_a1.append(txid)
            self.nodes[0].generate(1)
            self.sync_all()
            expected += i + 1
            expected_deltas.append({
                'height': 106 + i,
                'satoshis': (i + 1) * COIN,
                'txid': txid,
            })
        check_balance(1, addr1, expected * COIN)
        assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)),
                     sorted(txids_a1))
        assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)),
                     sorted(txids_a1))

        # Restart all nodes to ensure indices are saved to disk and recovered
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        bal = self.nodes[1].getaddressbalance(addr1)
        assert_equal(bal['balance'], expected * COIN)
        assert_equal(bal['received'], expected * COIN)
        assert_equal(sorted(self.nodes[0].getaddresstxids(addr1)),
                     sorted(txids_a1))
        assert_equal(sorted(self.nodes[1].getaddresstxids(addr1)),
                     sorted(txids_a1))

        # Send 3 from addr1, but -- subtlety alert! -- addr1 at this
        # time has 4 UTXOs, with values 1, 2, 3, 4. Sending value 3 requires
        # using up the value 4 UTXO, because of the tx fee
        # (the 3 UTXO isn't quite large enough).
        #
        # The txid from sending *from* addr1 is also added to the list of
        # txids associated with that address (test will verify below).

        addr2 = self.nodes[2].getnewaddress()
        txid = self.nodes[1].sendtoaddress(addr2, 3)
        self.sync_all()

        # the one tx in the mempool refers to addresses addr1 and addr2,
        # check that duplicate addresses are processed correctly
        mempool = self.nodes[0].getaddressmempool(
            {'addresses': [addr2, addr1, addr2]})
        assert_equal(len(mempool), 3)
        # test getaddressmempool for lightwalletd node
        mempool = self.nodes[3].getaddressmempool(
            {'addresses': [addr2, addr1, addr2]})
        assert_equal(len(mempool), 3)

        # addr2 (first arg)
        assert_equal(mempool[0]['address'], addr2)
        assert_equal(mempool[0]['satoshis'], 3 * COIN)
        assert_equal(mempool[0]['txid'], txid)

        # addr1 (second arg)
        assert_equal(mempool[1]['address'], addr1)
        assert_equal(mempool[1]['satoshis'], (-4) * COIN)
        assert_equal(mempool[1]['txid'], txid)

        # addr2 (third arg)
        assert_equal(mempool[2]['address'], addr2)
        assert_equal(mempool[2]['satoshis'], 3 * COIN)
        assert_equal(mempool[2]['txid'], txid)

        # a single address can be specified as a string (not json object)
        addr1_mempool = self.nodes[0].getaddressmempool(addr1)
        assert_equal(len(addr1_mempool), 1)
        # Don't check the timestamp; it's local to the node, and can mismatch
        # due to propagation delay.
        del addr1_mempool[0]['timestamp']
        for key in addr1_mempool[0].keys():
            assert_equal(mempool[1][key], addr1_mempool[0][key])

        tx = self.nodes[0].getrawtransaction(txid, 1)
        assert_equal(tx['vin'][0]['address'], addr1)
        assert_equal(tx['vin'][0]['value'], 4)
        assert_equal(tx['vin'][0]['valueSat'], 4 * COIN)

        txids_a1.append(txid)
        expected_deltas.append({
            'height': 111,
            'satoshis': (-4) * COIN,
            'txid': txid,
        })
        self.sync_all()  # ensure transaction is included in the next block
        self.nodes[0].generate(1)
        self.sync_all()

        # the send to addr2 tx is now in a mined block, no longer in the mempool
        mempool = self.nodes[0].getaddressmempool(
            {'addresses': [addr2, addr1]})
        assert_equal(len(mempool), 0)

        # Test DisconnectBlock() by invalidating the most recent mined block
        tip = self.nodes[1].getchaintips()[0]
        for i in range(self.num_nodes):
            node = self.nodes[i]
            # the value 4 UTXO is no longer in our balance
            check_balance(i, addr1, (expected - 4) * COIN, expected * COIN)
            check_balance(i, addr2, 3 * COIN)

            assert_equal(node.getblockcount(), 111)
            node.invalidateblock(tip['hash'])
            assert_equal(node.getblockcount(), 110)

            mempool = node.getaddressmempool({'addresses': [addr2, addr1]})
            assert_equal(len(mempool), 2)

            check_balance(i, addr1, expected * COIN)
            check_balance(i, addr2, 0)

        # now re-mine the addr1 to addr2 send
        self.nodes[0].generate(1)
        self.sync_all()
        for node in self.nodes:
            assert_equal(node.getblockcount(), 111)

        mempool = self.nodes[0].getaddressmempool(
            {'addresses': [addr2, addr1]})
        assert_equal(len(mempool), 0)

        # the value 4 UTXO is no longer in our balance
        check_balance(2, addr1, (expected - 4) * COIN, expected * COIN)

        # Ensure the change from that transaction appears
        tx = self.nodes[0].getrawtransaction(txid, 1)
        change_vout = list(
            filter(lambda v: v['valueZat'] != 3 * COIN, tx['vout']))
        change = change_vout[0]['scriptPubKey']['addresses'][0]

        # test getaddressbalance
        for node in (2, 3):
            bal = self.nodes[node].getaddressbalance(change)
            assert (bal['received'] > 0)

        # the inequality is due to randomness in the tx fee
        assert (bal['received'] < (4 - 3) * COIN)
        assert_equal(bal['received'], bal['balance'])
        assert_equal(self.nodes[2].getaddresstxids(change), [txid])

        # Further checks that limiting by height works

        # various ranges
        for i in range(5):
            height_txids = getaddresstxids(1, [addr1], 106, 106 + i)
            assert_equal(height_txids, txids_a1[0:i + 1])

        height_txids = getaddresstxids(1, [addr1], 1, 108)
        assert_equal(height_txids, txids_a1[0:3])

        # Further check specifying multiple addresses
        txids_all = list(txids_a1)
        txids_all += self.nodes[1].getaddresstxids(addr_p2pkh)
        txids_all += self.nodes[1].getaddresstxids(addr_p2sh)
        multitxids = self.nodes[1].getaddresstxids(
            {'addresses': [addr1, addr_p2sh, addr_p2pkh]})
        # No dups in return list from getaddresstxids
        assert_equal(len(multitxids), len(set(multitxids)))

        # set(txids_all) removes its (expected) duplicates
        assert_equal(set(multitxids), set(txids_all))

        # test getaddressdeltas
        for node in (1, 3):
            deltas = self.nodes[node].getaddressdeltas({'addresses': [addr1]})
            assert_equal(len(deltas), len(expected_deltas))
            for i in range(len(deltas)):
                assert_equal(deltas[i]['address'], addr1)
                assert_equal(deltas[i]['height'], expected_deltas[i]['height'])
                assert_equal(deltas[i]['satoshis'],
                             expected_deltas[i]['satoshis'])
                assert_equal(deltas[i]['txid'], expected_deltas[i]['txid'])

        # 106-111 is the full range (also the default)
        deltas_limited = getaddressdeltas(1, [addr1], 106, 111)
        assert_equal(deltas_limited, deltas)

        # only the first element missing
        deltas_limited = getaddressdeltas(1, [addr1], 107, 111)
        assert_equal(deltas_limited, deltas[1:])

        deltas_limited = getaddressdeltas(1, [addr1], 109, 109)
        assert_equal(deltas_limited, deltas[3:4])

        # the full range (also the default)
        deltas_info = getaddressdeltas(1, [addr1], 106, 111, chainInfo=True)
        assert_equal(deltas_info['deltas'], deltas)

        # check the additional items returned by chainInfo
        assert_equal(deltas_info['start']['height'], 106)
        block_hash = self.nodes[1].getblockhash(106)
        assert_equal(deltas_info['start']['hash'], block_hash)

        assert_equal(deltas_info['end']['height'], 111)
        block_hash = self.nodes[1].getblockhash(111)
        assert_equal(deltas_info['end']['hash'], block_hash)

        # Test getaddressutxos by comparing results with deltas
        utxos = self.nodes[3].getaddressutxos(addr1)

        # The value 4 note was spent, so won't show up in the utxo list,
        # so for comparison, remove the 4 (and -4 for output) from the
        # deltas list
        deltas = self.nodes[1].getaddressdeltas({'addresses': [addr1]})
        deltas = list(filter(lambda d: abs(d['satoshis']) != 4 * COIN, deltas))
        assert_equal(len(utxos), len(deltas))
        for i in range(len(utxos)):
            assert_equal(utxos[i]['address'], addr1)
            assert_equal(utxos[i]['height'], deltas[i]['height'])
            assert_equal(utxos[i]['satoshis'], deltas[i]['satoshis'])
            assert_equal(utxos[i]['txid'], deltas[i]['txid'])

        # Check that outputs with the same address in the same tx return one txid
        # (can't use createrawtransaction() as it combines duplicate addresses)
        addr = "t2LMJ6Arw9UWBMWvfUr2QLHM4Xd9w53FftS"
        addressHash = unhexlify("97643ce74b188f4fb6bbbb285e067a969041caf2")
        scriptPubKey = CScript([OP_HASH160, addressHash, OP_EQUAL])
        # Add an unrecognized script type to vout[], a legal script that pays,
        # but won't modify the addressindex (since the address can't be extracted).
        # (This extra output has no effect on the rest of the test.)
        scriptUnknown = CScript(
            [OP_HASH160, OP_DUP, OP_DROP, addressHash, OP_EQUAL])
        unspent = list(
            filter(lambda u: u['amount'] >= 4, self.nodes[0].listunspent()))
        tx = CTransaction()
        tx.vin = [
            CTxIn(COutPoint(int(unspent[0]['txid'], 16), unspent[0]['vout']))
        ]
        tx.vout = [
            CTxOut(1 * COIN, scriptPubKey),
            CTxOut(2 * COIN, scriptPubKey),
            CTxOut(7 * COIN, scriptUnknown),
        ]
        tx = self.nodes[0].signrawtransaction(
            hexlify(tx.serialize()).decode('utf-8'))
        txid = self.nodes[0].sendrawtransaction(tx['hex'], True)
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(self.nodes[1].getaddresstxids(addr), [txid])
        check_balance(2, addr, 3 * COIN)
Esempio n. 22
0
    def run_test(self):
        '''
        Test that a backward transfer amount under its dust threshold is not accepted in the mempool.
        Since this dust threshold depends on minrelaytxfee and this is an optional zend flag, test that 
        a node with a different value set behaves correctly and the network is not affected (no forks happen)
        '''

        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
        mc_test = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mc_test.generate_params('sc1')
        constant = generate_random_field_element_hex()

        # create SC
        #------------------------------------------------------------------------------------------------------------
        cmd_input = {
            'version': 0,
            'toaddress': "abcd",
            'amount': 1.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(cmd_input)
            scid = res['scid']
            pprint.pprint(res)
            self.sync_all()
        except JSONRPCException as e:
            error_string = e.error['message']
            mark_logs(error_string,self.nodes,DEBUG_MODE)
            assert_true(False)

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

        scid_swapped = str(swap_bytes(scid))
        addr_node2   = self.nodes[2].getnewaddress()

        # this amount is next to the border of the dust (54 zat, according to mintxrelayfee default value) but it is sufficiently big not to be refused
        bwt_amount = Decimal('0.00000060')
        bwt_cert = [{"address": addr_node2, "amount": bwt_amount}, {"address": addr_node2, "amount": bwt_amount}]
        bwt_amount_array = [bwt_amount, bwt_amount]
        addr_array = [addr_node2, addr_node2]
        q = 10

        bl_list = []
        # advance some epoch and send a small backward transfer via a certificate for any epoch
        for i in range(3):

            if i == 1:
                # On the second loop, connect a fourth node from scratch with a greater mintxrelayfee, which would make the
                # node mempool reject the cert, and check this option does not prevent the chain update anyway
                mark_logs("Connecting a new Node3 with a greater -mintxrelayfee", self.nodes, DEBUG_MODE)
                self.nodes.append(start_node(
                    3, self.options.tmpdir , extra_args=[
                        '-logtimemicros=1', '-debug=cert', '-debug=sc', '-debug=py', '-debug=mempool',
                        '-allowdustoutput=0', '-minrelaytxfee='+str(CUSTOM_FEE_RATE_ZEN_PER_KBYTE)]))

                connect_nodes_bi(self.nodes, 2, 3)
                self.sync_all()

            mark_logs("\nAdvance 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 with a bwd transfers of {} coins to Node2".format(bwt_amount), self.nodes, DEBUG_MODE)
            #==============================================================
            proof = mc_test.create_test_proof(
                "sc1", scid_swapped, epoch_number, q, MBTR_SC_FEE, FT_SC_FEE, epoch_cum_tree_hash,
                constant, addr_array, bwt_amount_array)

            try:
                cert = self.nodes[1].sc_send_certificate(scid, epoch_number, q,
                    epoch_cum_tree_hash, proof, bwt_cert, FT_SC_FEE, MBTR_SC_FEE)
            except JSONRPCException as e:
                error_string = e.error['message']
                print ("Send certificate failed with reason {}".format(error_string))
                assert_true(False)

            sync_blocks(self.nodes[0:2])
            sync_mempools(self.nodes[0:2])

            mark_logs("cert = {}".format(cert), self.nodes, DEBUG_MODE)

            if i == 1:
                # check that the certificate has ben accepted by Node0 but not by Node3 wich has a greater mintxrelayfee
                mp0 = self.nodes[0].getrawmempool()
                mp3 = self.nodes[3].getrawmempool()
                assert_true(cert in mp0)
                assert_false(cert in mp3)

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

        # dust amont for a cert backward transfer is 54 Zat using the 100 Zat/Kbyte default mintxrelayfee rate
        # check that no certificates with dust amount can be sent via any command type
        dust_amount = Decimal("0.00000053")
        bwt_cert = [{"address": addr_node2, "amount": dust_amount}]
        bwt_amount_array = [dust_amount]
        addr_array = [addr_node2]
        quality = 0
        proof = mc_test.create_test_proof(
            "sc1", scid_swapped, epoch_number, quality, MBTR_SC_FEE, FT_SC_FEE,
            epoch_cum_tree_hash, constant, addr_array, bwt_amount_array)

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

        raw_params = {
            "scid": scid,
            "quality": quality,
            "endEpochCumScTxCommTreeRoot": epoch_cum_tree_hash,
            "scProof": proof,
            "withdrawalEpochNumber": epoch_number
        }
        raw_cert = []
        cert = []

        try:
            raw_cert    = self.nodes[0].createrawcertificate(raw_inputs, raw_outs, raw_bwt_outs, raw_params)
            signed_cert = self.nodes[0].signrawtransaction(raw_cert)
            mark_logs("Node 0 sends a raw cert with a bwd transfers of {} coins to Node2 ... expecting failure".format(dust_amount), self.nodes, DEBUG_MODE)
            cert = self.nodes[0].sendrawtransaction(signed_cert['hex'])
            assert False
        except JSONRPCException as e:
            error_string = e.error['message']
            print ("======> " + error_string)

        try:
            mark_logs("Node 0 sends a cert with a bwd transfers of {} coins to Node2 ... expecting failure".format(dust_amount), self.nodes, DEBUG_MODE)
            cert = self.nodes[0].sc_send_certificate(scid, epoch_number, q,
                epoch_cum_tree_hash, proof, bwt_cert, FT_SC_FEE, MBTR_SC_FEE)
            assert False
        except JSONRPCException as e:
            error_string = e.error['message']
            print ("======> " + error_string)

        bal = self.nodes[2].getbalance()
        utx = self.nodes[2].listunspent()
        print ("Node2 balance = {}".format(bal))
        assert_equal(bal, 2*bwt_amount)

        # the dust threshold for a bwt (54 Zat) is lower than the one for a standard output due to the replay protection
        # extension in the pub script (63 Zat). As a result we can not spend exactly one UTXOs coming from backward transfer
        # otherwise we would create a dust output.
        mark_logs("Node2 tries to spent one utxo from bwt sending {} coins to Node0 ... expecting failure".format(utx[0]['amount']), self.nodes, DEBUG_MODE)
        # try spending one utxo
        inputs  = [ {'txid' : utx[0]['txid'], 'vout' : utx[0]['vout']}]
        outputs = { self.nodes[0].getnewaddress() : utx[0]['amount'] }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx   = self.nodes[2].signrawtransaction(rawtx)

        error_string = ""
        try:
            rawtx   = self.nodes[2].sendrawtransaction(rawtx['hex'])
            assert False
        except JSONRPCException as e:
            error_string = e.error['message']
            print (error_string)

        # we can spend a pair of them instead
        mark_logs("Node2 tries to spent both utxo from bwt sending {} coins to Node0".format(bal), self.nodes, DEBUG_MODE)
        # try spending two utxos
        inputs  = [ {'txid' : utx[0]['txid'], 'vout' : utx[0]['vout']}, {'txid' : utx[1]['txid'], 'vout' : utx[1]['vout']}]
        outputs = { self.nodes[0].getnewaddress() : bal }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx   = self.nodes[2].signrawtransaction(rawtx)

        error_string = ""
        try:
            rawtx   = self.nodes[2].sendrawtransaction(rawtx['hex'])
        except JSONRPCException as e:
            error_string = e.error['message']
            print (error_string)
            assert False

        print ("tx = {}".format(rawtx))

        sync_blocks(self.nodes[0:2])
        sync_mempools(self.nodes[0:2])
        # just to be sure tx is propagated
        time.sleep(2)

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

        mark_logs("\nChecking persistance stopping and restarting nodes", self.nodes, DEBUG_MODE)
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False)
Esempio n. 23
0
    def run_test(self):
        '''
        Test the situation when bot a fw transfer and a certificate for the same scid are in the mempool and a block is mined"
        '''

        def get_epoch_data(node, sc_creating_height, epoch_length):
            current_height = node.getblockcount()
            epoch_number = (current_height - sc_creating_height + 1) // epoch_length - 1
            epoch_block_hash = node.getblockhash(sc_creating_height - 1 + ((epoch_number + 1) * epoch_length))
            return epoch_number, epoch_block_hash

        # forward transfer amounts
        creation_amount = Decimal("1000")
        fwt_amount = Decimal("3.0")

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

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

        # generate a tx in mempool whose coins will be used by the tx creating the sc as input. This will make the creation tx orphan
        # and with null prio (that is because its inputs have 0 conf). As a consequence it would be processed after the forward transfer, making the block invalid.
        # Handling sc dependancies will prevent this scenario.
        tx = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), creation_amount);
        mark_logs("Node 0 sent {} coins to itself via {}".format(creation_amount, tx), self.nodes, DEBUG_MODE)
        self.sync_all()

        totScAmount = 0
        # sidechain creation
        #-------------------
        # generate wCertVk and constant
        mcTest = MCTestUtils(self.options.tmpdir, self.options.srcdir)
        vk = mcTest.generate_params("sc1")
        constant = generate_random_field_element_hex()

        creating_tx = self.nodes[0].sc_create(EPOCH_LENGTH, "dada", creation_amount, vk, "", constant)
        mark_logs("Node 0 created a sidechain via {}".format(creating_tx), self.nodes, DEBUG_MODE)
        self.sync_all()

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

        totScAmount += creation_amount

        mark_logs("Node 0 sends to sidechain ", self.nodes, DEBUG_MODE)
        txes = []
        for i in range(1, BUNCH_SIZE+1):
            amounts = []
            interm_amount = 0
            for j in range(1, BUNCH_SIZE+1):
                scaddr = str(hex(j*i)) 
                amount = j*i*Decimal('0.01')
                interm_amount += amount
                amounts.append({"address": scaddr, "amount": amount, "scid": scid})
            txes.append(self.nodes[0].sc_sendmany(amounts))
            mark_logs("Node 0 send many amounts (tot={}) to sidechain via {}".format(interm_amount, txes[-1]), self.nodes, DEBUG_MODE)
            self.sync_all()
            totScAmount += interm_amount


        mark_logs("Check creation tx is in mempools", self.nodes, DEBUG_MODE)
        assert_equal(True, creating_tx in self.nodes[1].getrawmempool())

        #pprint.pprint(self.nodes[1].getrawmempool(True))

        mp = self.nodes[1].getrawmempool(True)
        prio_cr_tx = mp[creating_tx]['currentpriority']
        dep_cr_tx  = mp[creating_tx]['depends'][0]

        mark_logs("creation tx prio {}".format(prio_cr_tx), self.nodes, DEBUG_MODE)
        assert_equal(0, prio_cr_tx)
        mark_logs("creation tx depends on {}".format(dep_cr_tx), self.nodes, DEBUG_MODE)
        assert_equal(tx, dep_cr_tx)

        mark_logs("Check fw txes are in mempools and their prio is greater than sc creation prio", self.nodes, DEBUG_MODE)
        for fwt in txes:
            assert_equal(True, fwt in self.nodes[1].getrawmempool())
            prio_fwt = mp[fwt]['currentpriority']
            dep_fwt  = mp[fwt]['depends'][-1]
            assert_true(prio_fwt > prio_cr_tx)
            assert_equal(dep_fwt, creating_tx)


        mark_logs("Node1 generates 1 block", self.nodes, DEBUG_MODE)
        bl_hash = self.nodes[1].generate(1)[0]
        self.sync_all()

        mark_logs("Check mempools are empty", self.nodes, DEBUG_MODE)
        assert_equal(0, len(self.nodes[0].getrawmempool()))

        mark_logs("Check that all fw txes are in block", self.nodes, DEBUG_MODE)
        block = self.nodes[0].getblock(bl_hash, True)
        vtx   = block['tx']
        for fwt in txes:
            assert_equal(True, fwt in vtx)

        mark_logs("Check that creating tx is the third in list (after coinbase)", self.nodes, DEBUG_MODE)
        assert_equal(creating_tx, vtx[2])


        #-------------------------------------------------------
        mark_logs("stopping and restarting nodes with '-deprecatedgetblocktemplate=1'", self.nodes, DEBUG_MODE)
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False, True)

        mark_logs("Node 0 invalidates last block", self.nodes, DEBUG_MODE)
        self.nodes[0].invalidateblock(bl_hash)

        mark_logs("Check creation tx is in mempool", self.nodes, DEBUG_MODE)
        assert_equal(True, creating_tx in self.nodes[0].getrawmempool())

        mark_logs("Check fw txes are in mempool", self.nodes, DEBUG_MODE)
        for fwt in txes:
            assert_equal(True, fwt in self.nodes[0].getrawmempool())

        mp = self.nodes[0].getrawmempool(True)
        prio_cr_tx = mp[creating_tx]['currentpriority']
        dep_cr_tx  = mp[creating_tx]['depends'][0]

        mark_logs("creation tx prio {}".format(prio_cr_tx), self.nodes, DEBUG_MODE)
        #assert_equal(0, prio_cr_tx) TODO lower prio via rpc
        mark_logs("creation tx depends on {}".format(dep_cr_tx), self.nodes, DEBUG_MODE)
        assert_equal(tx, dep_cr_tx)

        mark_logs("Check fw txes are in mempools and their prio is greater than sc creation prio", self.nodes, DEBUG_MODE)
        for fwt in txes:
            assert_equal(True, fwt in self.nodes[0].getrawmempool())
            prio_fwt = mp[fwt]['currentpriority']
            dep_fwt  = mp[fwt]['depends'][-1]
            #assert_true(prio_fwt > prio_cr_tx) TODO see above
            assert_equal(dep_fwt, creating_tx)

        mark_logs("Node0 generates 1 block", self.nodes, DEBUG_MODE)
        bl_hash = self.nodes[0].generate(1)[0]
        self.sync_all()

        mark_logs("Check mempool is empty", self.nodes, DEBUG_MODE)
        assert_equal(0, len(self.nodes[0].getrawmempool()))

        mark_logs("Check that all fw txes are in block", self.nodes, DEBUG_MODE)
        block = self.nodes[0].getblock(bl_hash, True)
        vtx   = block['tx']
        for fwt in txes:
            assert_equal(True, fwt in vtx)

        mark_logs("Check that creating tx is the third in list (after coinbase)", self.nodes, DEBUG_MODE)
        assert_equal(creating_tx, vtx[2])

        mark_logs("Node0 generates 5 more blocks", self.nodes, DEBUG_MODE)
        self.nodes[0].generate(5)
        self.sync_all()

        mark_logs("Check that sc balance is as expected", self.nodes, DEBUG_MODE)
        pprint.pprint(self.nodes[1].getscinfo(scid))
        assert_equal(totScAmount, self.nodes[1].getscinfo(scid)['balance'])
        mark_logs("Check that both nodes share the same view of sc info", self.nodes, DEBUG_MODE)
        assert_equal(self.nodes[0].getscinfo(scid), self.nodes[1].getscinfo(scid))
Esempio n. 24
0
    def run_test(self):
        self.nodes[0].generate(105)
        self.sync_all()

        chain_height = self.nodes[1].getblockcount()
        assert_equal(chain_height, 105)

        # Test getrawtransaction changes and the getspentinfo RPC

        # send coinbase to address addr1
        addr1 = self.nodes[1].getnewaddress()
        txid1 = self.nodes[0].sendtoaddress(addr1, 2)
        self.sync_all()
        block_hash1 = self.nodes[0].generate(1)
        self.sync_all()

        # send from addr1 to addr2
        # (the only utxo on node 1 is from address addr1)
        addr2 = self.nodes[2].getnewaddress()
        txid2 = self.nodes[1].sendtoaddress(addr2, 1)
        self.sync_all()

        # addr1 to addr2 transaction is not confirmed, so it has no height
        tx2 = self.nodes[2].getrawtransaction(txid2, 1)
        assert ('height' not in tx2)

        # confirm addr1 to addr2 transaction
        block_hash2 = self.nodes[0].generate(1)
        self.sync_all()

        # Restart all nodes to ensure index files are saved to disk and recovered
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Check new fields added to getrawtransaction
        tx1 = self.nodes[2].getrawtransaction(txid1, 1)
        assert_equal(tx1['vin'][0]['value'], 10)  # coinbase
        assert_equal(tx1['vin'][0]['valueSat'], 10 * COIN)
        # we want the non-change (payment) output
        vout = filter(lambda o: o['value'] == 2, tx1['vout'])
        n = vout[0]['n']
        assert_equal(vout[0]['spentTxId'], txid2)
        assert_equal(vout[0]['spentIndex'], 0)
        assert_equal(vout[0]['spentHeight'], 107)
        assert_equal(tx1['height'], 106)

        tx2 = self.nodes[2].getrawtransaction(txid2, 1)
        assert_equal(tx2['vin'][0]['address'], addr1)
        assert_equal(tx2['vin'][0]['value'], 2)
        assert_equal(tx2['vin'][0]['valueSat'], 2 * COIN)
        # since this transaction's outputs haven't yet been
        # spent, these fields should not be present
        assert ('spentTxId' not in tx2['vout'][0])
        assert ('spentIndex' not in tx2['vout'][0])
        assert ('spentHeight' not in tx2['vout'][0])
        assert_equal(tx2['height'], 107)

        # Given a transaction output, getspentinfo() returns a reference
        # to the (later, confirmed) transaction that spent that output,
        # that is, the transaction that used this output as an input.
        spentinfo = self.nodes[2].getspentinfo({'txid': txid1, 'index': n})
        assert_equal(spentinfo['height'], 107)
        assert_equal(spentinfo['index'], 0)
        assert_equal(spentinfo['txid'], txid2)

        # specifying an output that hasn't been spent should fail
        try:
            self.nodes[1].getspentinfo({'txid': txid2, 'index': 0})
            fail('getspentinfo should have thrown an exception')
        except JSONRPCException, e:
            assert_equal(e.error['message'], "Unable to get spent info")
Esempio n. 25
0
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(4)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 20)
        assert_equal(self.nodes[2].getbalance(), 0)

        # At this point in time, commitment tree is the empty root

        # Node 0 creates a joinsplit transaction
        mytaddr0 = get_coinbase_address(self.nodes[0])
        myzaddr0 = self.nodes[0].z_getnewaddress('sprout')
        recipients = []
        recipients.append({
            "address": myzaddr0,
            "amount": Decimal('10.0') - Decimal('0.0001')
        })
        myopid = self.nodes[0].z_sendmany(mytaddr0, recipients)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Sync up mempools and mine the transaction.  All nodes have the same anchor.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Stop nodes.
        stop_nodes(self.nodes)
        wait_bitcoinds()

        # Relaunch nodes and partition network into two:
        # A: node 0
        # B: node 1, 2
        self.nodes = start_nodes(
            3,
            self.options.tmpdir,
            extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3)
        connect_nodes_bi(self.nodes, 1, 2)

        # Partition B, node 1 mines an empty block
        self.nodes[1].generate(1)

        # Partition A, node 0 creates a joinsplit transaction
        recipients = []
        recipients.append({
            "address": myzaddr0,
            "amount": Decimal('10.0') - Decimal('0.0001')
        })
        myopid = self.nodes[0].z_sendmany(mytaddr0, recipients)
        txid = wait_and_assert_operationid_status(self.nodes[0], myopid)
        rawhex = self.nodes[0].getrawtransaction(txid)

        # Partition A, node 0 mines a block with the transaction
        self.nodes[0].generate(1)

        # Partition B, node 1 mines the same joinsplit transaction
        txid2 = self.nodes[1].sendrawtransaction(rawhex)
        assert_equal(txid, txid2)
        self.nodes[1].generate(1)

        # Check that Partition B is one block ahead and that they have different tips
        assert_equal(self.nodes[0].getblockcount() + 1,
                     self.nodes[1].getblockcount())
        assert (self.nodes[0].getbestblockhash() !=
                self.nodes[1].getbestblockhash())

        # Shut down all nodes so any in-memory state is saved to disk
        stop_nodes(self.nodes)
        wait_bitcoinds()

        # Relaunch nodes and reconnect the entire network
        self.nodes = start_nodes(
            3,
            self.options.tmpdir,
            extra_args=[['-regtestprotectcoinbase', '-debug=zrpc']] * 3)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)

        # Mine a new block and let it propagate
        self.nodes[1].generate(1)

        # Due to a bug in v1.0.0-1.0.3, node 0 will die with a tree root assertion, so sync_all() will throw an exception.
        self.sync_all()

        # v1.0.4 will reach here safely
        assert_equal(self.nodes[0].getbestblockhash(),
                     self.nodes[1].getbestblockhash())
        assert_equal(self.nodes[1].getbestblockhash(),
                     self.nodes[2].getbestblockhash())
Esempio n. 26
0
class WalletTest(BitcoinTestFramework):
    def setup_chain(self):
        print("Initializing test directory " + self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, 4)

    def setup_network(self, split=False):
        self.nodes = start_nodes(3, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        self.is_network_split = False
        self.sync_all()

    def run_test(self):
        print "Mining blocks..."

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

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 10)
        assert_equal(self.nodes[2].getbalance(), 0)
        assert_equal(self.nodes[0].getbalance("*"), 40)
        assert_equal(self.nodes[1].getbalance("*"), 10)
        assert_equal(self.nodes[2].getbalance("*"), 0)

        # Send 21 BTC from 0 to 2 using sendtoaddress call.
        # Second transaction will be child of first, and will require a fee
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 0)

        # Have node0 mine a block, thus it will collect its own fee.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Have node1 generate 100 blocks (so node0 can recover the fee)
        self.nodes[1].generate(100)
        self.sync_all()

        # node0 should end up with 50 btc in block rewards plus fees, but
        # minus the 21 plus fees sent to node2
        assert_equal(self.nodes[0].getbalance(), 50 - 21)
        assert_equal(self.nodes[2].getbalance(), 21)
        assert_equal(self.nodes[0].getbalance("*"), 50 - 21)
        assert_equal(self.nodes[2].getbalance("*"), 21)

        # Node0 should have three unspent outputs.
        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        node0utxos = self.nodes[0].listunspent(1)
        assert_equal(len(node0utxos), 3)

        # Check 'generated' field of listunspent
        # Node 0: has one coinbase utxo and two regular utxos
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node0utxos), 1)
        # Node 1: has 101 coinbase utxos and no regular utxos
        node1utxos = self.nodes[1].listunspent(1)
        assert_equal(len(node1utxos), 101)
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node1utxos), 101)
        # Node 2: has no coinbase utxos and two regular utxos
        node2utxos = self.nodes[2].listunspent(1)
        assert_equal(len(node2utxos), 2)
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node2utxos), 0)

        # Catch an attempt to send a transaction with an absurdly high fee.
        # Send 1.0 from an utxo of value 10.0 but don't specify a change output, so then
        # the change of 9.0 becomes the fee, which is greater than estimated fee of 0.0019.
        inputs = []
        outputs = {}
        for utxo in node2utxos:
            if utxo["amount"] == Decimal("10.0"):
                break
        assert_equal(utxo["amount"], Decimal("10.0"))
        inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
        outputs[self.nodes[2].getnewaddress("")] = Decimal("1.0")
        raw_tx = self.nodes[2].createrawtransaction(inputs, outputs)
        signed_tx = self.nodes[2].signrawtransaction(raw_tx)
        try:
            self.nodes[2].sendrawtransaction(signed_tx["hex"])
        except JSONRPCException, e:
            errorString = e.error['message']
        assert ("absurdly high fees" in errorString)
        assert ("900000000 > 190000" in errorString)

        # create both transactions
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
            outputs[self.nodes[2].getnewaddress("")] = utxo["amount"]
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].getbalance(), 0)
        assert_equal(self.nodes[2].getbalance(), 50)
        assert_equal(self.nodes[0].getbalance("*"), 0)
        assert_equal(self.nodes[2].getbalance("*"), 50)

        # Send 10 BTC normal
        address = self.nodes[0].getnewaddress("")
        self.nodes[2].settxfee(Decimal('0.001'))
        self.nodes[2].sendtoaddress(address, 10, "", "", False)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('39.99900000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('39.99900000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('10.00000000'))

        # Send 10 BTC with subtract fee from amount
        self.nodes[2].sendtoaddress(address, 10, "", "", True)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('29.99900000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('29.99900000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('19.99900000'))

        # Sendmany 10 BTC
        self.nodes[2].sendmany("", {address: 10}, 0, "", [])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('19.99800000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('19.99800000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('29.99900000'))

        # Sendmany 10 BTC with subtract fee from amount
        self.nodes[2].sendmany("", {address: 10}, 0, "", [address])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('39.99800000'))

        # Test ResendWalletTransactions:
        # Create a couple of transactions, then start up a fourth
        # node (nodes[3]) and ask nodes[0] to rebroadcast.
        # EXPECT: nodes[3] should have those transactions in its mempool.
        txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        sync_mempools(self.nodes)

        self.nodes.append(start_node(3, self.options.tmpdir))
        connect_nodes_bi(self.nodes, 0, 3)
        sync_blocks(self.nodes)

        relayed = self.nodes[0].resendwallettransactions()
        assert_equal(set(relayed), set([txid1, txid2]))
        sync_mempools(self.nodes)

        assert (txid1 in self.nodes[3].getrawmempool())

        #check if we can list zero value tx as available coins
        #1. create rawtx
        #2. hex-changed one output to 0.0
        #3. sign and send
        #4. check if recipient (node0) can list the zero value tx
        usp = self.nodes[1].listunspent()
        inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}]
        outputs = {
            self.nodes[1].getnewaddress(): 9.998,
            self.nodes[0].getnewaddress(): 11.11
        }

        rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace(
            "c0833842", "00000000")  #replace 11.11 with 0.0 (int32)
        decRawTx = self.nodes[1].decoderawtransaction(rawTx)
        signedRawTx = self.nodes[1].signrawtransaction(rawTx)
        decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
        zeroValueTxid = decRawTx['txid']
        self.nodes[1].sendrawtransaction(signedRawTx['hex'])

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

        unspentTxs = self.nodes[0].listunspent(
        )  #zero value tx must be in listunspents output
        found = False
        for uTx in unspentTxs:
            if uTx['txid'] == zeroValueTxid:
                found = True
                assert_equal(uTx['amount'], Decimal('0.00000000'))
        assert (found)

        #do some -walletbroadcast tests
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(
            3, self.options.tmpdir,
            [["-walletbroadcast=0"], ["-walletbroadcast=0"],
             ["-walletbroadcast=0"]])
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        self.sync_all()

        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        self.sync_all()
        self.nodes[1].generate(1)  #mine a block, tx should not be in there
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')
                     )  #should not be changed because tx was not broadcasted
        assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')
                     )  #should not be changed because tx was not broadcasted

        #now broadcast from another node, mine a block, sync, and check the balance
        self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        assert_equal(self.nodes[2].getbalance(),
                     Decimal('11.99800000'))  #should not be
        assert_equal(self.nodes[2].getbalance("*"),
                     Decimal('11.99800000'))  #should not be

        #create another tx
        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)

        #restart the nodes with -walletbroadcast=1
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(3, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        sync_blocks(self.nodes)

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

        #tx should be added to balance because after restarting the nodes tx should be broadcastet
        assert_equal(self.nodes[2].getbalance(),
                     Decimal('13.99800000'))  #should not be
        assert_equal(self.nodes[2].getbalance("*"),
                     Decimal('13.99800000'))  #should not be

        # send from node 0 to node 2 taddr
        mytaddr = self.nodes[2].getnewaddress()
        mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        mybalance = self.nodes[2].z_getbalance(mytaddr)
        assert_equal(mybalance, Decimal('10.0'))

        mytxdetails = self.nodes[2].gettransaction(mytxid)
        myvjoinsplits = mytxdetails["vjoinsplit"]
        assert_equal(0, len(myvjoinsplits))

        # z_sendmany is expected to fail if tx size breaks limit
        myzaddr = self.nodes[0].z_getnewaddress()

        recipients = []
        num_t_recipients = 3000
        amount_per_recipient = Decimal('0.00000001')
        errorString = ''
        for i in xrange(0, num_t_recipients):
            newtaddr = self.nodes[2].getnewaddress()
            recipients.append({
                "address": newtaddr,
                "amount": amount_per_recipient
            })

        # Issue #2759 Workaround START
        # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process
        # loop above to create new addresses, that when z_sendmany is called with a large amount of
        # rpc data in recipients, the connection fails with a 'broken pipe' error.  Making a RPC call
        # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP
        # connection into a good state to handle a large amount of data in recipients.
        self.nodes[0].getinfo()
        # Issue #2759 Workaround END

        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException, e:
            errorString = e.error['message']
Esempio n. 27
0
class RawTransactionsTest(BitcoinTestFramework):

    def setup_chain(self):
        print("Initializing test directory "+self.options.tmpdir)
        initialize_chain_clean(self.options.tmpdir, 3)

    def setup_network(self, split=False):
        self.nodes = start_nodes(3, self.options.tmpdir,
                           extra_args=[['-experimentalfeatures', '-developerencryptwallet']] * 4)

        connect_nodes_bi(self.nodes,0,1)
        connect_nodes_bi(self.nodes,1,2)
        connect_nodes_bi(self.nodes,0,2)

        self.is_network_split=False
        self.sync_all()

    def run_test(self):
        print "Mining blocks..."
        feeTolerance = Decimal(0.00000002) #if the fee's positive delta is higher than this value tests will fail, neg. delta always fail the tests

        self.nodes[2].generate(1)
        self.sync_all()
        self.nodes[0].generate(101)
        self.sync_all()
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5);
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0);
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0);
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        ###############
        # simple test #
        ###############
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 1.0 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enought inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 2.2 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0, True) #test if we have enough inputs

        ##############################
        # simple test with two coins #
        ##############################
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 2.6 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        assert_equal(len(dec_tx['vin']) > 0, True)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')


        ################################
        # simple test with two outputs #
        ################################
        inputs  = [ ]
        outputs = { self.nodes[0].getnewaddress() : 2.6, self.nodes[1].getnewaddress() : 2.5 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(len(dec_tx['vin']) > 0, True)
        assert_equal(dec_tx['vin'][0]['scriptSig']['hex'], '')


        #########################################################################
        # test a fundrawtransaction with a VIN greater than the required amount #
        #########################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 5.0:
                utx = aUtx
                break;

        assert_equal(utx!=False, True)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        outputs = { self.nodes[0].getnewaddress() : 1.0 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee



        #####################################################################
        # test a fundrawtransaction with which will not get a change output #
        #####################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 5.0:
                utx = aUtx
                break;

        assert_equal(utx!=False, True)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        outputs = { self.nodes[0].getnewaddress() : Decimal(5.0) - fee - feeTolerance }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        for out in dec_tx['vout']:
            totalOut += out['value']

        assert_equal(rawtxfund['changepos'], -1)
        assert_equal(fee + totalOut, utx['amount']) #compare vin total and totalout+fee



        #########################################################################
        # test a fundrawtransaction with a VIN smaller than the required amount #
        #########################################################################
        utx = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 1.0:
                utx = aUtx
                break;

        assert_equal(utx!=False, True)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']}]
        outputs = { self.nodes[0].getnewaddress() : 1.0 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)

        # 4-byte version + 1-byte vin count + 36-byte prevout then script_len
        rawtx = rawtx[:82] + "0100" + rawtx[84:]

        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for i, out in enumerate(dec_tx['vout']):
            totalOut += out['value']
            if outputs.has_key(out['scriptPubKey']['addresses'][0]):
                matchingOuts+=1
            else:
                assert_equal(i, rawtxfund['changepos'])

        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
        assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)


        ###########################################
        # test a fundrawtransaction with two VINs #
        ###########################################
        utx  = False
        utx2 = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 1.0:
                utx = aUtx
            if aUtx['amount'] == 5.0:
                utx2 = aUtx


        assert_equal(utx!=False, True)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]
        outputs = { self.nodes[0].getnewaddress() : 6.0 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if outputs.has_key(out['scriptPubKey']['addresses'][0]):
                matchingOuts+=1

        assert_equal(matchingOuts, 1)
        assert_equal(len(dec_tx['vout']), 2)

        matchingIns = 0
        for vinOut in dec_tx['vin']:
            for vinIn in inputs:
                if vinIn['txid'] == vinOut['txid']:
                    matchingIns+=1

        assert_equal(matchingIns, 2) #we now must see two vins identical to vins given as params

        #########################################################
        # test a fundrawtransaction with two VINs and two vOUTs #
        #########################################################
        utx  = False
        utx2 = False
        listunspent = self.nodes[2].listunspent()
        for aUtx in listunspent:
            if aUtx['amount'] == 1.0:
                utx = aUtx
            if aUtx['amount'] == 5.0:
                utx2 = aUtx


        assert_equal(utx!=False, True)

        inputs  = [ {'txid' : utx['txid'], 'vout' : utx['vout']},{'txid' : utx2['txid'], 'vout' : utx2['vout']} ]
        outputs = { self.nodes[0].getnewaddress() : 6.0, self.nodes[0].getnewaddress() : 1.0 }
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)
        assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        fee = rawtxfund['fee']
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
        totalOut = 0
        matchingOuts = 0
        for out in dec_tx['vout']:
            totalOut += out['value']
            if outputs.has_key(out['scriptPubKey']['addresses'][0]):
                matchingOuts+=1

        assert_equal(matchingOuts, 2)
        assert_equal(len(dec_tx['vout']), 3)

        ##############################################
        # test a fundrawtransaction with invalid vin #
        ##############################################
        listunspent = self.nodes[2].listunspent()
        inputs  = [ {'txid' : "1c7f966dab21119bac53213a2bc7532bff1fa844c124fd750a7d0b1332440bd1", 'vout' : 0} ] #invalid vin!
        outputs = { self.nodes[0].getnewaddress() : 1.0}
        rawtx   = self.nodes[2].createrawtransaction(inputs, outputs)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        errorString = ""
        try:
            rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        except JSONRPCException,e:
            errorString = e.error['message']

        assert_equal("Insufficient" in errorString, True);



        ############################################################
        #compare fee of a standard pubkeyhash transaction
        inputs = []
        outputs = {self.nodes[1].getnewaddress():1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1.1);
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee);
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################

        ############################################################
        #compare fee of a standard pubkeyhash transaction with multiple outputs
        inputs = []
        outputs = {self.nodes[1].getnewaddress():1.1,self.nodes[1].getnewaddress():1.2,self.nodes[1].getnewaddress():0.1,self.nodes[1].getnewaddress():1.3,self.nodes[1].getnewaddress():0.2,self.nodes[1].getnewaddress():0.3}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)
        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendmany("", outputs);
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee);
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################


        ############################################################
        #compare fee of a 2of2 multisig p2sh transaction

        # create 2of2 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)

        mSigObj = self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])

        inputs = []
        outputs = {mSigObj:1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1);
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee);
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################


        ############################################################
        #compare fee of a standard pubkeyhash transaction

        # create 4of5 addr
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[1].getnewaddress()
        addr3 = self.nodes[1].getnewaddress()
        addr4 = self.nodes[1].getnewaddress()
        addr5 = self.nodes[1].getnewaddress()

        addr1Obj = self.nodes[1].validateaddress(addr1)
        addr2Obj = self.nodes[1].validateaddress(addr2)
        addr3Obj = self.nodes[1].validateaddress(addr3)
        addr4Obj = self.nodes[1].validateaddress(addr4)
        addr5Obj = self.nodes[1].validateaddress(addr5)

        mSigObj = self.nodes[1].addmultisigaddress(4, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey'], addr4Obj['pubkey'], addr5Obj['pubkey']])

        inputs = []
        outputs = {mSigObj:1.1}
        rawTx = self.nodes[0].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[0].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.1);
        signedFee = self.nodes[0].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee);
        assert(feeDelta >= 0 and feeDelta <= feeTolerance)
        ############################################################


        ############################################################
        # spend a 2of2 multisig transaction over fundraw

        # create 2of2 addr
        addr1 = self.nodes[2].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()

        addr1Obj = self.nodes[2].validateaddress(addr1)
        addr2Obj = self.nodes[2].validateaddress(addr2)

        mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']])


        # send 1.2 BTC to msig addr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2);
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        oldBalance = self.nodes[1].getbalance()
        inputs = []
        outputs = {self.nodes[1].getnewaddress():1.1}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[2].fundrawtransaction(rawTx)

        signedTx = self.nodes[2].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[2].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance+Decimal('1.10000000'), self.nodes[1].getbalance())

        ############################################################
        # locked wallet test
        self.nodes[1].encryptwallet("test")
        self.nodes.pop(1)
        stop_nodes(self.nodes)
        wait_bitcoinds()

        self.nodes = start_nodes(3, self.options.tmpdir)

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

        error = False
        try:
            self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.2);
        except:
            error = True
        assert(error)

        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {self.nodes[0].getnewaddress():1.1}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #now we need to unlock
        self.nodes[1].walletpassphrase("test", 100)
        signedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(signedTx['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        # make sure funds are received at node1
        assert_equal(oldBalance+Decimal('11.10000000'), self.nodes[0].getbalance())



        ###############################################
        # multiple (~19) inputs tx test | Compare fee #
        ###############################################

        #empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True);
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0,20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01);
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        inputs = []
        outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)

        #create same transaction over sendtoaddress
        txId = self.nodes[1].sendmany("", outputs);
        signedFee = self.nodes[1].getrawmempool(True)[txId]['fee']

        #compare fee
        feeDelta = Decimal(fundedTx['fee']) - Decimal(signedFee);
        assert(feeDelta >= 0 and feeDelta <= feeTolerance*19) #~19 inputs


        #############################################
        # multiple (~19) inputs tx test | sign/send #
        #############################################

        #again, empty node1, send some small coins from node0 to node1
        self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), self.nodes[1].getbalance(), "", "", True);
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        for i in range(0,20):
            self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.01);
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        #fund a tx with ~20 small inputs
        oldBalance = self.nodes[0].getbalance()

        inputs = []
        outputs = {self.nodes[0].getnewaddress():0.15,self.nodes[0].getnewaddress():0.04}
        rawTx = self.nodes[1].createrawtransaction(inputs, outputs)
        fundedTx = self.nodes[1].fundrawtransaction(rawTx)
        fundedAndSignedTx = self.nodes[1].signrawtransaction(fundedTx['hex'])
        txId = self.nodes[1].sendrawtransaction(fundedAndSignedTx['hex'])
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(oldBalance+Decimal('10.19000000'), self.nodes[0].getbalance()) #0.19+block reward

        #####################################################
        # test fundrawtransaction with OP_RETURN and no vin #
        #####################################################

        rawtx   = "0100000000010000000000000000066a047465737400000000"
        dec_tx  = self.nodes[2].decoderawtransaction(rawtx)

        assert_equal(len(dec_tx['vin']), 0)
        assert_equal(len(dec_tx['vout']), 1)

        rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
        dec_tx  = self.nodes[2].decoderawtransaction(rawtxfund['hex'])

        assert_greater_than(len(dec_tx['vin']), 0) # at least one vin
        assert_equal(len(dec_tx['vout']), 2) # one change output added
Esempio n. 28
0
    def run_test(self):
        # Sanity-check the test harness
        assert_equal(self.nodes[0].getblockcount(), 200)

        # Get a new Orchard account on node 0
        acct0 = self.nodes[0].z_getnewaccount()['account']
        ua0 = self.nodes[0].z_getaddressforaccount(acct0,
                                                   ['orchard'])['address']

        # Activate NU5
        self.nodes[0].generate(5)
        self.sync_all()

        # Get a recipient address
        acct1 = self.nodes[1].z_getnewaccount()['account']
        ua1 = self.nodes[1].z_getaddressforaccount(acct1,
                                                   ['orchard'])['address']

        # Send a transaction to node 1 so that it has an Orchard note to spend.
        recipients = [{"address": ua1, "amount": 10}]
        myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]),
                                          recipients, 1, 0,
                                          'AllowRevealedSenders')
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Check the value sent to ua1 was received
        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 10_0000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[1].z_getbalanceforaccount(acct1))

        # Create an Orchard spend, so that the note commitment tree root gets altered.
        recipients = [{"address": ua0, "amount": 1}]
        myopid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[1], myopid)

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

        # Verify the balance on both nodes
        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 9_0000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[1].z_getbalanceforaccount(acct1))

        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 1_0000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[0].z_getbalanceforaccount(acct0))

        # Split the network. We'll advance the state of nodes 0/1 so that after
        # we re-join the network, we need to roll back more than one block after
        # the wallet is restored, into a chain state that the wallet never observed.
        self.split_network()

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

        # Shut down the network and delete node 0's wallet
        stop_nodes(self.nodes)
        wait_bitcoinds()

        tmpdir = self.options.tmpdir
        os.remove(os.path.join(tmpdir, "node0", "regtest", "wallet.dat"))

        # Restart the network, still split; the split here is note necessary to reproduce
        # the error but it is sufficient, and we will later use the split to check the
        # corresponding rewind.
        self.setup_network(True)

        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 9_0000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[1].z_getbalanceforaccount(acct1))

        # Get a new account with an Orchard UA on node 0
        acct0new = self.nodes[0].z_getnewaccount()['account']
        ua0new = self.nodes[0].z_getaddressforaccount(acct0,
                                                      ['orchard'])['address']

        # Send a transaction to the Orchard account. When we mine this transaction,
        # the bug causes the state of note commitment tree in the wallet to not match
        # the state of the global note commitment tree.
        recipients = [{"address": ua0new, "amount": 1}]
        myopid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0)
        rollback_tx = wait_and_assert_operationid_status(self.nodes[1], myopid)

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

        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 1_0000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[0].z_getbalanceforaccount(acct0new))

        # Node 2 has no progress since the network was first split, so this should roll
        # everything back to the original fork point.
        self.nodes[2].generate(10)

        # Re-join the network
        self.join_network()

        assert_equal(set([rollback_tx]), set(self.nodes[1].getrawmempool()))

        # Resend un-mined transactions and sync the network
        self.nodes[1].resendwallettransactions()
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 1_0000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[0].z_getbalanceforaccount(acct0new))

        # Spend from the note that was just received
        recipients = [{"address": ua1, "amount": Decimal('0.3')}]
        myopid = self.nodes[0].z_sendmany(ua0new, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        assert_equal(
            {
                'pools': {
                    'orchard': {
                        'valueZat': 8_3000_0000
                    }
                },
                'minimum_confirmations': 1
            }, self.nodes[1].z_getbalanceforaccount(acct1))
Esempio n. 29
0
    def run_test(self):
        print("Mining blocks...")

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

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

        blockchaininfo = self.nodes[0].getblockchaininfo()
        assert_equal(blockchaininfo['estimatedheight'], 4)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 10)
        assert_equal(self.nodes[2].getbalance(), 0)
        assert_equal(self.nodes[0].getbalance("*"), 40)
        assert_equal(self.nodes[1].getbalance("*"), 10)
        assert_equal(self.nodes[2].getbalance("*"), 0)

        # Send 21 BTC from 0 to 2 using sendtoaddress call.
        # Second transaction will be child of first, and will require a fee
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 0)

        blockchaininfo = self.nodes[0].getblockchaininfo()
        assert_equal(blockchaininfo['estimatedheight'], 105)

        # Have node0 mine a block, thus it will collect its own fee.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Have node1 generate 100 blocks (so node0 can recover the fee)
        self.nodes[1].generate(100)
        self.sync_all()

        # node0 should end up with 50 btc in block rewards plus fees, but
        # minus the 21 plus fees sent to node2
        assert_equal(self.nodes[0].getbalance(), 50 - 21)
        assert_equal(self.nodes[2].getbalance(), 21)
        assert_equal(self.nodes[0].getbalance("*"), 50 - 21)
        assert_equal(self.nodes[2].getbalance("*"), 21)

        # Node0 should have three unspent outputs.
        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        node0utxos = self.nodes[0].listunspent(1)
        assert_equal(len(node0utxos), 3)

        # Check 'generated' field of listunspent
        # Node 0: has one coinbase utxo and two regular utxos
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node0utxos), 1)
        # Node 1: has 101 coinbase utxos and no regular utxos
        node1utxos = self.nodes[1].listunspent(1)
        assert_equal(len(node1utxos), 101)
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node1utxos), 101)
        # Node 2: has no coinbase utxos and two regular utxos
        node2utxos = self.nodes[2].listunspent(1)
        assert_equal(len(node2utxos), 2)
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node2utxos), 0)

        # Catch an attempt to send a transaction with an absurdly high fee.
        # Send 1.0 from an utxo of value 10.0 but don't specify a change output, so then
        # the change of 9.0 becomes the fee, which is greater than estimated fee of 0.0021.
        inputs = []
        outputs = {}
        for utxo in node2utxos:
            if utxo["amount"] == Decimal("10.0"):
                break
        assert_equal(utxo["amount"], Decimal("10.0"))
        inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
        outputs[self.nodes[2].getnewaddress("")] = Decimal("1.0")
        raw_tx = self.nodes[2].createrawtransaction(inputs, outputs)
        signed_tx = self.nodes[2].signrawtransaction(raw_tx)
        try:
            self.nodes[2].sendrawtransaction(signed_tx["hex"])
        except JSONRPCException as e:
            errorString = e.error['message']
        assert ("absurdly high fees" in errorString)
        assert ("900000000 > 10000000" in errorString)

        # create both transactions
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
            outputs[self.nodes[2].getnewaddress("")] = utxo["amount"]
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].getbalance(), 0)
        assert_equal(self.nodes[2].getbalance(), 50)
        assert_equal(self.nodes[0].getbalance("*"), 0)
        assert_equal(self.nodes[2].getbalance("*"), 50)

        # Send 10 BTC normal
        address = self.nodes[0].getnewaddress("")
        self.nodes[2].settxfee(Decimal('0.001'))
        self.nodes[2].sendtoaddress(address, 10, "", "", False)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('39.99900000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('39.99900000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('10.00000000'))

        # Send 10 BTC with subtract fee from amount
        self.nodes[2].sendtoaddress(address, 10, "", "", True)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('29.99900000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('29.99900000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('19.99900000'))

        # Sendmany 10 BTC
        self.nodes[2].sendmany("", {address: 10}, 0, "", [])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('19.99800000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('19.99800000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('29.99900000'))

        # Sendmany 10 BTC with subtract fee from amount
        self.nodes[2].sendmany("", {address: 10}, 0, "", [address])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('39.99800000'))

        # Test ResendWalletTransactions:
        # Create a couple of transactions, then start up a fourth
        # node (nodes[3]) and ask nodes[0] to rebroadcast.
        # EXPECT: nodes[3] should have those transactions in its mempool.
        txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        sync_mempools(self.nodes)

        self.nodes.append(start_node(3, self.options.tmpdir))
        connect_nodes_bi(self.nodes, 0, 3)
        sync_blocks(self.nodes)

        relayed = self.nodes[0].resendwallettransactions()
        assert_equal(set(relayed), set([txid1, txid2]))
        sync_mempools(self.nodes)

        assert (txid1 in self.nodes[3].getrawmempool())

        #check if we can list zero value tx as available coins
        #1. create rawtx
        #2. hex-changed one output to 0.0
        #3. sign and send
        #4. check if recipient (node0) can list the zero value tx
        usp = self.nodes[1].listunspent()
        inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}]
        outputs = {
            self.nodes[1].getnewaddress(): 9.998,
            self.nodes[0].getnewaddress(): 11.11
        }

        rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace(
            "c0833842", "00000000")  #replace 11.11 with 0.0 (int32)
        decRawTx = self.nodes[1].decoderawtransaction(rawTx)
        signedRawTx = self.nodes[1].signrawtransaction(rawTx)
        decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
        zeroValueTxid = decRawTx['txid']
        self.nodes[1].sendrawtransaction(signedRawTx['hex'])

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

        unspentTxs = self.nodes[0].listunspent(
        )  #zero value tx must be in listunspents output
        found = False
        for uTx in unspentTxs:
            if uTx['txid'] == zeroValueTxid:
                found = True
                assert_equal(uTx['amount'], Decimal('0.00000000'))
                assert_equal(uTx['amountZat'], 0)
        assert (found)

        #do some -walletbroadcast tests
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(
            3, self.options.tmpdir,
            [["-walletbroadcast=0"], ["-walletbroadcast=0"],
             ["-walletbroadcast=0"]])
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        self.sync_all()

        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        self.sync_all()
        self.nodes[1].generate(1)  #mine a block, tx should not be in there
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')
                     )  #should not be changed because tx was not broadcasted
        assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')
                     )  #should not be changed because tx was not broadcasted

        #now broadcast from another node, mine a block, sync, and check the balance
        self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        assert_equal(self.nodes[2].getbalance(),
                     Decimal('11.99800000'))  #should not be
        assert_equal(self.nodes[2].getbalance("*"),
                     Decimal('11.99800000'))  #should not be

        #create another tx
        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)

        #restart the nodes with -walletbroadcast=1
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(3, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        sync_blocks(self.nodes)

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

        # tx should be added to balance because after restarting the nodes tx should be broadcast
        assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000'))

        # check integer balances from getbalance
        assert_equal(self.nodes[2].getbalance("*", 1, False, True), 1399800000)

        # send from node 0 to node 2 taddr
        mytaddr = self.nodes[2].getnewaddress()
        mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        mybalance = self.nodes[2].z_getbalance(mytaddr)
        assert_equal(mybalance, Decimal('10.0'))

        # check integer balances from z_getbalance
        assert_equal(self.nodes[2].z_getbalance(mytaddr, 1, True), 1000000000)

        mytxdetails = self.nodes[2].gettransaction(mytxid)
        myvjoinsplits = mytxdetails["vjoinsplit"]
        assert_equal(0, len(myvjoinsplits))
        assert ("joinSplitPubKey" not in mytxdetails)
        assert ("joinSplitSig" not in mytxdetails)

        # z_sendmany is expected to fail if tx size breaks limit
        myzaddr = self.nodes[0].z_getnewaddress()

        recipients = []
        num_t_recipients = 1000
        num_z_recipients = 2100
        amount_per_recipient = Decimal('0.00000001')
        errorString = ''
        for i in range(0, num_t_recipients):
            newtaddr = self.nodes[2].getnewaddress()
            recipients.append({
                "address": newtaddr,
                "amount": amount_per_recipient
            })
        for i in range(0, num_z_recipients):
            newzaddr = self.nodes[2].z_getnewaddress()
            recipients.append({
                "address": newzaddr,
                "amount": amount_per_recipient
            })

        # Issue #2759 Workaround START
        # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process
        # loop above to create new addresses, that when z_sendmany is called with a large amount of
        # rpc data in recipients, the connection fails with a 'broken pipe' error.  Making a RPC call
        # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP
        # connection into a good state to handle a large amount of data in recipients.
        self.nodes[0].getinfo()
        # Issue #2759 Workaround END

        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert ("size of raw transaction would be larger than limit"
                in errorString)

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

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

        mytxid = wait_and_assert_operationid_status(
            self.nodes[2], self.nodes[2].z_sendmany(mytaddr, recipients))

        self.sync_all()

        # check balances
        zsendmanynotevalue = Decimal('7.0')
        zsendmanyfee = Decimal('0.0001')
        node2utxobalance = Decimal(
            '23.998') - zsendmanynotevalue - zsendmanyfee

        # check shielded balance status with getwalletinfo
        wallet_info = self.nodes[2].getwalletinfo()
        assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]),
                     zsendmanynotevalue)
        assert_equal(Decimal(wallet_info["shielded_balance"]), Decimal('0.0'))

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

        assert_equal(self.nodes[2].getbalance(), node2utxobalance)
        assert_equal(self.nodes[2].getbalance("*"), node2utxobalance)

        # check zaddr balance with z_getbalance
        assert_equal(self.nodes[2].z_getbalance(myzaddr), zsendmanynotevalue)

        # check via z_gettotalbalance
        resp = self.nodes[2].z_gettotalbalance()
        assert_equal(Decimal(resp["transparent"]), node2utxobalance)
        assert_equal(Decimal(resp["private"]), zsendmanynotevalue)
        assert_equal(Decimal(resp["total"]),
                     node2utxobalance + zsendmanynotevalue)

        # check confirmed shielded balance with getwalletinfo
        wallet_info = self.nodes[2].getwalletinfo()
        assert_equal(Decimal(wallet_info["shielded_unconfirmed_balance"]),
                     Decimal('0.0'))
        assert_equal(Decimal(wallet_info["shielded_balance"]),
                     zsendmanynotevalue)

        # there should be at least one Sapling output
        mytxdetails = self.nodes[2].getrawtransaction(mytxid, 1)
        assert_greater_than(len(mytxdetails["vShieldedOutput"]), 0)
        # the Sapling output should take in all the public value
        assert_equal(mytxdetails["valueBalance"], -zsendmanynotevalue)

        # send from private note to node 0 and node 2
        node0balance = self.nodes[0].getbalance()  # 25.99794745
        node2balance = self.nodes[2].getbalance()  # 16.99790000

        recipients = []
        recipients.append({
            "address": self.nodes[0].getnewaddress(),
            "amount": 1
        })
        recipients.append({
            "address": self.nodes[2].getnewaddress(),
            "amount": 1.0
        })

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

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

        node0balance += Decimal('1.0')
        node2balance += Decimal('1.0')
        assert_equal(Decimal(self.nodes[0].getbalance()), node0balance)
        assert_equal(Decimal(self.nodes[0].getbalance("*")), node0balance)
        assert_equal(Decimal(self.nodes[2].getbalance()), node2balance)
        assert_equal(Decimal(self.nodes[2].getbalance("*")), node2balance)

        #send a tx with value in a string (PR#6380 +)
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2")
        txObj = self.nodes[0].gettransaction(txId)
        assert_equal(txObj['amount'], Decimal('-2.00000000'))
        assert_equal(txObj['amountZat'], -200000000)

        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),
                                           "0.0001")
        txObj = self.nodes[0].gettransaction(txId)
        assert_equal(txObj['amount'], Decimal('-0.00010000'))
        assert_equal(txObj['amountZat'], -10000)

        #check if JSON parser can handle scientific notation in strings
        txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),
                                           "1e-4")
        txObj = self.nodes[0].gettransaction(txId)
        assert_equal(txObj['amount'], Decimal('-0.00010000'))
        assert_equal(txObj['amountZat'], -10000)

        #this should fail
        errorString = ""
        try:
            txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),
                                               "1f-4")
        except JSONRPCException as e:
            errorString = e.error['message']

        assert_equal("Invalid amount" in errorString, True)

        errorString = ""
        try:
            self.nodes[0].generate(
                "2"
            )  #use a string to as block amount parameter must fail because it's not interpreted as amount
        except JSONRPCException as e:
            errorString = e.error['message']

        assert_equal("not an integer" in errorString, True)

        myzaddr = self.nodes[0].z_getnewaddress()
        recipients = [{"address": myzaddr, "amount": Decimal('0.0')}]
        errorString = ''

        # Make sure that amount=0 transactions can use the default fee
        # without triggering "absurd fee" errors
        try:
            myopid = self.nodes[0].z_sendmany(myzaddr, recipients)
            assert (myopid)
        except JSONRPCException as e:
            errorString = e.error['message']
            print(errorString)
            assert (False)

        # This fee is larger than the default fee and since amount=0
        # it should trigger error
        fee = Decimal('0.1')
        recipients = [{"address": myzaddr, "amount": Decimal('0.0')}]
        minconf = 1
        errorString = ''

        try:
            myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf,
                                              fee)
        except JSONRPCException as e:
            errorString = e.error['message']
        assert ('Small transaction amount' in errorString)

        # This fee is less than default and greater than amount, but still valid
        fee = Decimal('0.0000001')
        recipients = [{"address": myzaddr, "amount": Decimal('0.00000001')}]
        minconf = 1
        errorString = ''

        try:
            myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf,
                                              fee)
            assert (myopid)
        except JSONRPCException as e:
            errorString = e.error['message']
            print(errorString)
            assert (False)

        # Make sure amount=0, fee=0 transaction are valid to add to mempool
        # though miners decide whether to add to a block
        fee = Decimal('0.0')
        minconf = 1
        recipients = [{"address": myzaddr, "amount": Decimal('0.0')}]
        errorString = ''

        try:
            myopid = self.nodes[0].z_sendmany(myzaddr, recipients, minconf,
                                              fee)
            assert (myopid)
        except JSONRPCException as e:
            errorString = e.error['message']
            print(errorString)
            assert (False)
Esempio n. 30
0
    def run_test (self):
        print "Mining blocks..."

        self.nodes[0].generate(4)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 40)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 40)
        assert_equal(self.nodes[1].getbalance(), 10)
        assert_equal(self.nodes[2].getbalance(), 0)
        assert_equal(self.nodes[0].getbalance("*"), 40)
        assert_equal(self.nodes[1].getbalance("*"), 10)
        assert_equal(self.nodes[2].getbalance("*"), 0)

        # Send 21 BTC from 0 to 2 using sendtoaddress call.
        # Second transaction will be child of first, and will require a fee
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 0)

        # Have node0 mine a block, thus it will collect its own fee.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Have node1 generate 100 blocks (so node0 can recover the fee)
        self.nodes[1].generate(100)
        self.sync_all()

        # node0 should end up with 50 btc in block rewards plus fees, but
        # minus the 21 plus fees sent to node2
        assert_equal(self.nodes[0].getbalance(), 50-21)
        assert_equal(self.nodes[2].getbalance(), 21)
        assert_equal(self.nodes[0].getbalance("*"), 50-21)
        assert_equal(self.nodes[2].getbalance("*"), 21)

        # Node0 should have three unspent outputs.
        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        node0utxos = self.nodes[0].listunspent(1)
        assert_equal(len(node0utxos), 3)

        # Check 'generated' field of listunspent
        # Node 0: has one coinbase utxo and two regular utxos
        assert_equal(sum(int(uxto["generated"] is True) for uxto in node0utxos), 1)
        # Node 1: has 101 coinbase utxos and no regular utxos
        node1utxos = self.nodes[1].listunspent(1)
        assert_equal(len(node1utxos), 101)
        assert_equal(sum(int(uxto["generated"] is True) for uxto in node1utxos), 101)
        # Node 2: has no coinbase utxos and two regular utxos
        node2utxos = self.nodes[2].listunspent(1)
        assert_equal(len(node2utxos), 2)
        assert_equal(sum(int(uxto["generated"] is True) for uxto in node2utxos), 0)

        # create both transactions
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]})
            outputs[self.nodes[2].getnewaddress("")] = utxo["amount"]
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].getbalance(), 0)
        assert_equal(self.nodes[2].getbalance(), 50)
        assert_equal(self.nodes[0].getbalance("*"), 0)
        assert_equal(self.nodes[2].getbalance("*"), 50)

        # Send 10 BTC normal
        address = self.nodes[0].getnewaddress("")
        self.nodes[2].settxfee(Decimal('0.001'))
        self.nodes[2].sendtoaddress(address, 10, "", "", False)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('39.99900000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('39.99900000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('10.00000000'))

        # Send 10 BTC with subtract fee from amount
        self.nodes[2].sendtoaddress(address, 10, "", "", True)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('29.99900000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('29.99900000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('19.99900000'))

        # Sendmany 10 BTC
        self.nodes[2].sendmany("", {address: 10}, 0, "", [])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('19.99800000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('19.99800000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('29.99900000'))

        # Sendmany 10 BTC with subtract fee from amount
        self.nodes[2].sendmany("", {address: 10}, 0, "", [address])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000'))
        assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('39.99800000'))

        # Test ResendWalletTransactions:
        # Create a couple of transactions, then start up a fourth
        # node (nodes[3]) and ask nodes[0] to rebroadcast.
        # EXPECT: nodes[3] should have those transactions in its mempool.
        txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        sync_mempools(self.nodes)

        self.nodes.append(start_node(3, self.options.tmpdir))
        connect_nodes_bi(self.nodes, 0, 3)
        sync_blocks(self.nodes)

        relayed = self.nodes[0].resendwallettransactions()
        assert_equal(set(relayed), set([txid1, txid2]))
        sync_mempools(self.nodes)

        assert(txid1 in self.nodes[3].getrawmempool())

        #check if we can list zero value tx as available coins
        #1. create rawtx
        #2. hex-changed one output to 0.0
        #3. sign and send
        #4. check if recipient (node0) can list the zero value tx
        usp = self.nodes[1].listunspent()
        inputs = [{"txid":usp[0]['txid'], "vout":usp[0]['vout']}]
        outputs = {self.nodes[1].getnewaddress(): 9.998, self.nodes[0].getnewaddress(): 11.11}

        rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") #replace 11.11 with 0.0 (int32)
        decRawTx = self.nodes[1].decoderawtransaction(rawTx)
        signedRawTx = self.nodes[1].signrawtransaction(rawTx)
        decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
        zeroValueTxid= decRawTx['txid']
        self.nodes[1].sendrawtransaction(signedRawTx['hex'])

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

        unspentTxs = self.nodes[0].listunspent() #zero value tx must be in listunspents output
        found = False
        for uTx in unspentTxs:
            if uTx['txid'] == zeroValueTxid:
                found = True
                assert_equal(uTx['amount'], Decimal('0.00000000'));
        assert(found)

        #do some -walletbroadcast tests
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]])
        connect_nodes_bi(self.nodes,0,1)
        connect_nodes_bi(self.nodes,1,2)
        connect_nodes_bi(self.nodes,0,2)
        self.sync_all()

        txIdNotBroadcasted  = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2);
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        self.sync_all()
        self.nodes[1].generate(1) #mine a block, tx should not be in there
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('9.99800000')); #should not be changed because tx was not broadcasted
        assert_equal(self.nodes[2].getbalance("*"), Decimal('9.99800000')); #should not be changed because tx was not broadcasted

        #now broadcast from another node, mine a block, sync, and check the balance
        self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        assert_equal(self.nodes[2].getbalance(), Decimal('11.99800000')); #should not be
        assert_equal(self.nodes[2].getbalance("*"), Decimal('11.99800000')); #should not be

        #create another tx
        txIdNotBroadcasted  = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2);

        #restart the nodes with -walletbroadcast=1
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(3, self.options.tmpdir)
        connect_nodes_bi(self.nodes,0,1)
        connect_nodes_bi(self.nodes,1,2)
        connect_nodes_bi(self.nodes,0,2)
        sync_blocks(self.nodes)

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

        #tx should be added to balance because after restarting the nodes tx should be broadcastet
        assert_equal(self.nodes[2].getbalance(), Decimal('13.99800000')); #should not be
        assert_equal(self.nodes[2].getbalance("*"), Decimal('13.99800000')); #should not be

        # send from node 0 to node 2 taddr
        mytaddr = self.nodes[2].getnewaddress();
        mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0);
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        mybalance = self.nodes[2].z_getbalance(mytaddr)
        assert_equal(mybalance, Decimal('10.0'));

        mytxdetails = self.nodes[2].gettransaction(mytxid)
        myvjoinsplits = mytxdetails["vjoinsplit"]
        assert_equal(0, len(myvjoinsplits))

        # z_sendmany is expected to fail if tx size breaks limit
        myzaddr = self.nodes[0].z_getnewaddress()

        recipients = []
        num_t_recipients = 3000
        amount_per_recipient = Decimal('0.00000001')
        errorString = ''
        for i in xrange(0,num_t_recipients):
            newtaddr = self.nodes[2].getnewaddress()
            recipients.append({"address":newtaddr, "amount":amount_per_recipient})
        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException,e:
            errorString = e.error['message']
Esempio n. 31
0
    def run_test(self):
        print "Mining blocks..."

        self.nodes[0].generate(4)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 11.4375 * 4)
        assert_equal(walletinfo['balance'], 0)

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

        assert_equal(self.nodes[0].getbalance(), 11.4375 * 4)
        assert_equal(self.nodes[1].getbalance(), 11.4375)
        assert_equal(self.nodes[2].getbalance(), 0)
        assert_equal(self.nodes[0].getbalance("*"), 11.4375 * 4)
        assert_equal(self.nodes[1].getbalance("*"), 11.4375)
        assert_equal(self.nodes[2].getbalance("*"), 0)

        # Send 21 BTC from 0 to 2 using sendtoaddress call.
        # Second transaction will be child of first, and will require a fee
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 12)
        self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11.4375)

        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 0)

        # Have node0 mine a block, thus it will collect its own fee.
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # Have node1 generate 100 blocks (so node0 can recover the fee)
        self.nodes[1].generate(100)
        self.sync_all()

        # node0 should end up with (11.4375*4 + 8.75) btc in block rewards plus fees, but
        # minus the 23.4375 plus fees sent to node2
        assert_equal(self.nodes[0].getbalance(),
                     (11.4375 * 4 + 8.75) - 23.4375)
        assert_equal(self.nodes[2].getbalance(), 23.4375)
        assert_equal(self.nodes[0].getbalance("*"),
                     (11.4375 * 4 + 8.75) - 23.4375)
        assert_equal(self.nodes[2].getbalance("*"), 23.4375)

        # Node0 should have three unspent outputs.
        # Create a couple of transactions to send them to node2, submit them through
        # node1, and make sure both node0 and node2 pick them up properly:
        node0utxos = self.nodes[0].listunspent(1)
        assert_equal(len(node0utxos), 3)

        # Check 'generated' field of listunspent
        # Node 0: has one coinbase utxo and two regular utxos
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node0utxos), 1)
        # Node 1: has 101 coinbase utxos and no regular utxos
        node1utxos = self.nodes[1].listunspent(1)
        assert_equal(len(node1utxos), 101)
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node1utxos), 101)
        # Node 2: has no coinbase utxos and two regular utxos
        node2utxos = self.nodes[2].listunspent(1)
        assert_equal(len(node2utxos), 2)
        assert_equal(
            sum(int(uxto["generated"] is True) for uxto in node2utxos), 0)

        # create both transactions
        txns_to_send = []
        for utxo in node0utxos:
            inputs = []
            outputs = {}
            inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]})
            outputs[self.nodes[2].getnewaddress("")] = utxo["amount"]
            raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
            txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx))

        # Have node 1 (miner) send the transactions
        self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True)
        self.nodes[1].sendrawtransaction(txns_to_send[2]["hex"], True)

        # Have node1 mine a block to confirm transactions:
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()

        assert_equal(self.nodes[0].getbalance(), 0)
        assert_equal(self.nodes[2].getbalance(), 11.4375 * 4 + 8.75)
        assert_equal(self.nodes[0].getbalance("*"), 0)
        assert_equal(self.nodes[2].getbalance("*"), 11.4375 * 4 + 8.75)

        # Send 11.4375 BTC normal
        address = self.nodes[0].getnewaddress("")
        self.nodes[2].settxfee(Decimal('0.001'))
        txid = self.nodes[2].sendtoaddress(address, 11.4375, "", "", False)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        # 43.0615 = (11.4375*3 + 8.75) - 0.001
        assert_equal(self.nodes[2].getbalance(), Decimal('43.0615'))
        assert_equal(self.nodes[0].getbalance(), Decimal('11.4375'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('43.0615'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('11.4375'))

        # Send 11.4375 BTC with subtract fee from amount
        txid = self.nodes[2].sendtoaddress(address, 11.4375, "", "", True)
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        # 31.624 = (11.4375*2 + 8.75) - 0.001
        assert_equal(self.nodes[2].getbalance(), Decimal('31.624'))
        assert_equal(self.nodes[0].getbalance(), Decimal('22.874'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('31.624'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('22.874'))

        # Sendmany 10 BTC
        self.nodes[2].sendmany("", {address: 10}, 0, "", [])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        # 21.623 = 31.624 -10 - 0.001
        assert_equal(self.nodes[2].getbalance(), Decimal('21.623'))
        assert_equal(self.nodes[0].getbalance(), Decimal('32.874'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('21.623'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('32.874'))

        # Sendmany 10 BTC with subtract fee from amount
        self.nodes[2].sendmany("", {address: 10}, 0, "", [address])
        self.sync_all()
        self.nodes[2].generate(1)
        self.sync_all()
        # 11.623 = 21.623 - 10
        assert_equal(self.nodes[2].getbalance(), Decimal('11.623'))
        assert_equal(self.nodes[0].getbalance(), Decimal('42.873'))
        assert_equal(self.nodes[2].getbalance("*"), Decimal('11.623'))
        assert_equal(self.nodes[0].getbalance("*"), Decimal('42.873'))

        # Test ResendWalletTransactions:
        # Create a couple of transactions, then start up a fourth
        # node (nodes[3]) and ask nodes[0] to rebroadcast.
        # EXPECT: nodes[3] should have those transactions in its mempool.
        txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        sync_mempools(self.nodes)

        self.nodes.append(start_node(3, self.options.tmpdir))
        connect_nodes_bi(self.nodes, 0, 3)
        sync_blocks(self.nodes)

        relayed = self.nodes[0].resendwallettransactions()
        assert_equal(set(relayed), set([txid1, txid2]))
        sync_mempools(self.nodes)

        assert (txid1 in self.nodes[3].getrawmempool())

        #check if we can list zero value tx as available coins
        #1. create rawtx
        #2. hex-changed one output to 0.0
        #3. sign and send
        #4. check if recipient (node0) can list the zero value tx
        usp = self.nodes[1].listunspent()

        # position 0 might randomly contain an amount different than the wanted one, this is
        # because coinbase has changed across forks (also in regtest)
        # That would lead to failure in checks when calling sendrawtransaction
        newbal = usp[0]['amount']
        #        print newbal, "\n"

        inputs = [{"txid": usp[0]['txid'], "vout": usp[0]['vout']}]
        #        outputs = {self.nodes[1].getnewaddress(): 11.4365, self.nodes[0].getnewaddress(): 11.11}
        outputs = {
            self.nodes[1].getnewaddress(): newbal,
            self.nodes[0].getnewaddress(): 11.11
        }

        rawTx = self.nodes[1].createrawtransaction(inputs, outputs).replace(
            "c0833842", "00000000")  #replace 11.11 with 0.0 (int32)
        decRawTx = self.nodes[1].decoderawtransaction(rawTx)
        signedRawTx = self.nodes[1].signrawtransaction(rawTx)
        decRawTx = self.nodes[1].decoderawtransaction(signedRawTx['hex'])
        zeroValueTxid = decRawTx['txid']
        self.nodes[1].sendrawtransaction(signedRawTx['hex'])

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

        unspentTxs = self.nodes[0].listunspent(
        )  #zero value tx must be in listunspents output
        found = False
        for uTx in unspentTxs:
            if uTx['txid'] == zeroValueTxid:
                found = True
                assert_equal(uTx['amount'], Decimal('0.00000000'))
        assert (found)

        #do some -walletbroadcast tests
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(
            3, self.options.tmpdir,
            [["-walletbroadcast=0"], ["-walletbroadcast=0"],
             ["-walletbroadcast=0"]])
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        self.sync_all()

        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        self.sync_all()
        self.nodes[1].generate(1)  #mine a block, tx should not be in there
        self.sync_all()
        assert_equal(self.nodes[2].getbalance(), Decimal('11.623'))
        #should not be changed because tx was not broadcasted
        assert_equal(self.nodes[2].getbalance("*"), Decimal('11.623'))
        #should not be changed because tx was not broadcasted

        #now broadcast from another node, mine a block, sync, and check the balance
        self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
        self.sync_all()
        self.nodes[1].generate(1)
        self.sync_all()
        txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
        assert_equal(self.nodes[2].getbalance(), Decimal('13.623'))
        #should not be
        assert_equal(self.nodes[2].getbalance("*"), Decimal('13.623'))
        #should not be

        #create another tx
        txIdNotBroadcasted = self.nodes[0].sendtoaddress(
            self.nodes[2].getnewaddress(), 2)

        #restart the nodes with -walletbroadcast=1
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.nodes = start_nodes(3, self.options.tmpdir)
        connect_nodes_bi(self.nodes, 0, 1)
        connect_nodes_bi(self.nodes, 1, 2)
        connect_nodes_bi(self.nodes, 0, 2)
        sync_blocks(self.nodes)

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

        #tx should be added to balance because after restarting the nodes tx should be broadcastet
        assert_equal(self.nodes[2].getbalance(), Decimal('15.623'))
        #should not be
        assert_equal(self.nodes[2].getbalance("*"), Decimal('15.623'))
        #should not be

        # send from node 0 to node 2 taddr
        mytaddr = self.nodes[2].getnewaddress()
        mytxid = self.nodes[0].sendtoaddress(mytaddr, 10.0)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        mybalance = self.nodes[2].z_getbalance(mytaddr)
        assert_equal(mybalance, Decimal('10.0'))

        mytxdetails = self.nodes[2].gettransaction(mytxid)
        myvjoinsplits = mytxdetails["vjoinsplit"]
        assert_equal(0, len(myvjoinsplits))

        # z_sendmany is expected to fail if tx size breaks limit
        myzaddr = self.nodes[0].z_getnewaddress()

        recipients = []
        num_t_recipients = 3000
        amount_per_recipient = Decimal('0.00000001')
        errorString = ''
        for i in xrange(0, num_t_recipients):
            newtaddr = self.nodes[2].getnewaddress()
            recipients.append({
                "address": newtaddr,
                "amount": amount_per_recipient
            })

        # Issue #2759 Workaround START
        # HTTP connection to node 0 may fall into a state, during the few minutes it takes to process
        # loop above to create new addresses, that when z_sendmany is called with a large amount of
        # rpc data in recipients, the connection fails with a 'broken pipe' error.  Making a RPC call
        # to node 0 before calling z_sendmany appears to fix this issue, perhaps putting the HTTP
        # connection into a good state to handle a large amount of data in recipients.
        self.nodes[0].getinfo()
        # Issue #2759 Workaround END

        try:
            self.nodes[0].z_sendmany(myzaddr, recipients)
        except JSONRPCException, e:
            errorString = e.error['message']
    def run_test(self):
        # Sanity-check the test harness
        assert_equal(self.nodes[0].getblockcount(), 200)

        # Send some Orchard funds to node 2 for later spending after we split the network
        acct0 = self.nodes[0].z_getnewaccount()['account']
        ua0 = self.nodes[0].z_getaddressforaccount(acct0, ['sapling', 'orchard'])['address']

        recipients = [{"address": ua0, "amount": 10}]
        myopid = self.nodes[0].z_sendmany(get_coinbase_address(self.nodes[0]), recipients, 1, 0, 'AllowRevealedSenders')
        wait_and_assert_operationid_status(self.nodes[0], myopid)

        # Mine the tx & activate NU5
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        assert_equal(
                {'pools': {'orchard': {'valueZat': 10_0000_0000}}, 'minimum_confirmations': 1},
                self.nodes[0].z_getbalanceforaccount(acct0))

        # Send to a new orchard-only unified address
        acct1 = self.nodes[1].z_getnewaccount()['account']
        ua1 = self.nodes[1].z_getaddressforaccount(acct1, ['orchard'])['address']

        recipients = [{"address": ua1, "amount": 1}]
        myopid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        assert_equal(
                {'pools': {'orchard': {'valueZat': 9_0000_0000}}, 'minimum_confirmations': 1},
                self.nodes[0].z_getbalanceforaccount(acct0))
        assert_equal(
                {'pools': {'orchard': {'valueZat': 1_0000_0000}}, 'minimum_confirmations': 1},
                self.nodes[1].z_getbalanceforaccount(acct1))

        # Send another Orchard transaction from node 0 back to itself, so that the
        # note commitment tree gets advanced.
        recipients = [{"address": ua0, "amount": 1}]
        myopid = self.nodes[0].z_sendmany(ua0, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[0], myopid)

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

        # Shut down the nodes, and restart so that we can check wallet load
        stop_nodes(self.nodes);
        wait_bitcoinds()
        self.setup_network()

        assert_equal(
                {'pools': {'orchard': {'valueZat': 9_0000_0000}}, 'minimum_confirmations': 1},
                self.nodes[0].z_getbalanceforaccount(acct0))

        recipients = [{"address": ua0, "amount": Decimal('0.5')}]
        myopid = self.nodes[1].z_sendmany(ua1, recipients, 1, 0)
        wait_and_assert_operationid_status(self.nodes[1], myopid)

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

        assert_equal(
                {'pools': {'orchard': {'valueZat': 9_5000_0000}}, 'minimum_confirmations': 1},
                self.nodes[0].z_getbalanceforaccount(acct0))
Esempio n. 33
0
    def run_test(self):
        # Sanity-check the test harness
        self.nodes[0].generate(200)
        assert_equal(self.nodes[0].getblockcount(), 200)
        self.sync_all()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # Verify balances
        assert_equal(self.nodes[2].z_getbalance(sapling_addr), Decimal('4'))
        assert_equal(self.nodes[1].z_getbalance(dest_addr), Decimal('16'))
Esempio n. 34
0
    def run_test(self):
        self.nodes[0].generate(105)
        self.sync_all()

        chain_height = self.nodes[1].getblockcount()
        assert_equal(chain_height, 105)

        # Test getrawtransaction changes and the getspentinfo RPC

        # send coinbase to address a
        a = self.nodes[1].getnewaddress()
        txid_a = self.nodes[0].sendtoaddress(a, 2)
        self.sync_all()
        self.nodes[0].generate(1)
        self.sync_all()

        # send from a to b
        # (the only utxo on node 1 is from address a)
        b = self.nodes[2].getnewaddress()
        txid_b = self.nodes[1].sendtoaddress(b, 1)
        self.sync_all()

        # a to b transaction is not confirmed, so it has no height
        tx_b = self.nodes[2].getrawtransaction(txid_b, 1)
        assert ('height' not in tx_b)

        self.sync_all()
        tx_a = self.nodes[2].getrawtransaction(txid_a, 1)

        # txid_b is not yet confirmed, so height is invalid (-1)
        vout = list(filter(lambda o: o['value'] == 2, tx_a['vout']))
        assert_equal(vout[0]['spentTxId'], txid_b)
        assert_equal(vout[0]['spentIndex'], 0)
        assert_equal(vout[0]['spentHeight'], -1)

        # confirm txid_b (a to b transaction)
        self.nodes[0].generate(1)
        self.sync_all()

        # Restart all nodes to ensure index files are saved to disk and recovered
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        # Check new fields added to getrawtransaction
        tx_a = self.nodes[2].getrawtransaction(txid_a, 1)
        assert_equal(tx_a['vin'][0]['value'], 10)  # coinbase
        assert_equal(tx_a['vin'][0]['valueSat'], 10 * COIN)
        # we want the non-change (payment) output
        vout = list(filter(lambda o: o['value'] == 2, tx_a['vout']))
        assert_equal(vout[0]['spentTxId'], txid_b)
        assert_equal(vout[0]['spentIndex'], 0)
        assert_equal(vout[0]['spentHeight'], 107)
        assert_equal(tx_a['height'], 106)

        tx_b = self.nodes[2].getrawtransaction(txid_b, 1)
        assert_equal(tx_b['vin'][0]['address'], a)
        assert_equal(tx_b['vin'][0]['value'], 2)
        assert_equal(tx_b['vin'][0]['valueSat'], 2 * COIN)
        # since this transaction's outputs haven't yet been
        # spent, these fields should not be present
        assert ('spentTxId' not in tx_b['vout'][0])
        assert ('spentIndex' not in tx_b['vout'][0])
        assert ('spentHeight' not in tx_b['vout'][0])
        assert_equal(tx_b['height'], 107)
Esempio n. 35
0
            assert_equal(sc_post_regeneration["last certificate epoch"],
                         Decimal(0))
            assert_equal(
                sc_post_regeneration["balance"], creation_amount + fwt_amount +
                fwt_amount_immature_at_epoch - bwt_amount)
            assert (cert_epoch_1 not in self.nodes[0].getrawmempool())
            assert (speding_bwd_tx not in self.nodes[0].getrawmempool())

        assert_equal(node2_balance_ante_cert, self.nodes[2].getbalance())
        assert_equal(node3_balance_ante_cert, self.nodes[3].getbalance())

        mark_logs(
            "Checking certificates persistance stopping and restarting nodes",
            self.nodes, DEBUG_MODE)
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network(False)

        for idx, node in enumerate(self.nodes):
            mark_logs("Checking Node{} after restart".format(idx), self.nodes,
                      DEBUG_MODE)
            sc_post_regeneration = node.getscinfo(scid)
            assert_equal(sc_post_regeneration["last certificate epoch"],
                         Decimal(0))
            assert_equal(
                sc_post_regeneration["balance"], creation_amount + fwt_amount +
                fwt_amount_immature_at_epoch - bwt_amount)
            assert (cert_epoch_1 not in self.nodes[0].getrawmempool())
            assert (speding_bwd_tx not in self.nodes[0].getrawmempool())

Esempio n. 36
0
    def main(self):
        import optparse

        parser = optparse.OptionParser(usage="%prog [options]")
        parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
                          help="Leave bitcoinds and test.* datadir on exit or error")
        parser.add_option("--noshutdown", dest="noshutdown", default=False, action="store_true",
                          help="Don't stop bitcoinds after the test execution")
        parser.add_option("--zendir", dest="zendir", default="ZenCore/src",
                          help="Source directory containing zend/zen-cli (default: %default)")
        parser.add_option("--scjarpath", dest="scjarpath", default="../examples/simpleapp/target/Sidechains-SDK-simpleapp-0.2.0.jar;../examples/simpleapp/target/lib/* com.horizen.examples.SimpleApp", #New option. Main class path won't be needed in future
                          help="Directory containing .jar file for SC (default: %default)")
        parser.add_option("--tmpdir", dest="tmpdir", default="../examples/simpleapp/target/tmp",
                          help="Root directory for datadirs")
        parser.add_option("--tracerpc", dest="trace_rpc", default=False, action="store_true",
                          help="Print out all RPC calls as they are made")

        self.add_options(parser)
        self.sc_add_options(parser)
        (self.options, self.args) = parser.parse_args()

        if self.options.trace_rpc:
            import logging
            logging.basicConfig(level=logging.DEBUG)

        os.environ['PATH'] = self.options.zendir+":"+os.environ['PATH']

        check_json_precision()

        success = False
        try:
            if not os.path.isdir(self.options.tmpdir):
                os.makedirs(self.options.tmpdir)

            print("Initializing test directory "+self.options.tmpdir)

            self.setup_chain()

            self.setup_network()

            self.sc_setup_chain()

            self.sc_setup_network()

            self.run_test()

            success = True

        except JSONRPCException as e:
            print("JSONRPC error: "+e.error['message'])
            traceback.print_tb(sys.exc_info()[2])
        except SCAPIException as e: #New exception for SC API
            print("SCAPI error: "+e.error)
            traceback.print_tb(sys.exc_info()[2])
        except TimeoutException as e:
            print("Timeout while: " + e.operation) #Timeout for SC Operations
            traceback.print_tb(sys.exc_info()[2])
        except AssertionError as e:
            print("Assertion failed: "+e.message)
            traceback.print_tb(sys.exc_info()[2])
        except Exception as e:
            print("Unexpected exception caught during testing: "+str(e))
            traceback.print_tb(sys.exc_info()[2])

        if not self.options.noshutdown: #Support for tests with MC only, SC only, MC/SC
            if hasattr(self,"sc_nodes"):
                print("Stopping SC nodes")
                stop_sc_nodes(self.sc_nodes)
            if hasattr(self, "nodes"):
                print("Stopping MC nodes")
                stop_nodes(self.nodes)
                wait_bitcoinds()
        else:
            print("Note: client processes were not stopped and may still be running")

        if not self.options.nocleanup and not self.options.noshutdown:
            print("Cleaning up")
            shutil.rmtree(self.options.tmpdir)

        if success:
            print("Test successful")
            sys.exit(0)
        else:
            print("Failed")
            sys.exit(1)
Esempio n. 37
0
    def run_test(self):
        def get_source(listed_addresses, source):
            return next(src for src in listed_addresses if src['source'] == source)

        print("Testing height 1 (Sapling)")
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getblockcount(), 1)
        listed_addresses = self.list_addresses(0, ['mnemonic_seed'])
        # There should be a single address from the coinbase, which was derived
        # from the mnemonic seed.
        assert 'transparent' in get_source(listed_addresses, 'mnemonic_seed')

        # If we import a t-address, we should see imported_watchonly as a source.
        taddr_import = self.nodes[1].getnewaddress()
        self.nodes[0].importaddress(taddr_import)
        listed_addresses = self.list_addresses(0, ['imported_watchonly', 'mnemonic_seed'])
        imported_watchonly_src = get_source(listed_addresses, 'imported_watchonly')
        assert_equal(imported_watchonly_src['transparent']['addresses'][0], taddr_import)

        account = self.nodes[0].z_getnewaccount()['account']
        sprout_1 = self.nodes[0].z_getnewaddress('sprout')
        sapling_1 = self.nodes[0].z_getnewaddress('sapling')
        unified_1 = self.nodes[0].z_getaddressforaccount(account)['address']
        types_and_addresses = [
            ('sprout', sprout_1),
            ('sapling', sapling_1),
            ('unified', unified_1),
        ]

        for addr_type, addr in types_and_addresses:
            res = self.nodes[0].z_validateaddress(addr)
            assert res['isvalid']
            # assert res['ismine'] # this isn't present for unified addresses
            assert_equal(res['type'], addr_type)

        # We should see the following sources:
        # - imported_watchonly (for the previously-imported t-addr)
        # - legacy_random (for the new Sprout address)
        # - mnemonic_seed (for the previous t-addrs and the new Sapling and Unified addrs)
        listed_addresses = self.list_addresses(0, ['imported_watchonly', 'legacy_random', 'mnemonic_seed'])
        legacy_random_src = get_source(listed_addresses, 'legacy_random')
        mnemonic_seed_src = get_source(listed_addresses, 'mnemonic_seed')

        # Check Sprout addrs
        assert_equal(legacy_random_src['sprout']['addresses'], [sprout_1])

        # Check Sapling addrs
        assert_equal(
            set([(obj['zip32KeyPath'], x) for obj in mnemonic_seed_src['sapling'] for x in obj['addresses']]),
            set([("m/32'/1'/2147483647'/0'", sapling_1)]),
        )

        # Check Unified addrs
        unified_obj = mnemonic_seed_src['unified']
        assert_equal(unified_obj[0]['account'], 0)
        assert_equal(unified_obj[0]['addresses'][0]['address'], unified_1)
        assert 'diversifier_index' in unified_obj[0]['addresses'][0]
        assert_equal(unified_obj[0]['addresses'][0]['receiver_types'], ['p2pkh', 'sapling', 'orchard'])

        # import the key for sapling_1 into node 1
        sapling_1_key = self.nodes[0].z_exportkey(sapling_1)
        self.nodes[1].z_importkey(sapling_1_key)

        # verify that we see the imported source
        listed_addresses = self.list_addresses(1, ['imported', 'mnemonic_seed'])
        imported_src = get_source(listed_addresses, 'imported')
        assert_equal(imported_src['sapling'][0]['addresses'], [sapling_1])

        # stop the nodes & restart to ensure that the imported address
        # still shows up in listaddresses output
        stop_nodes(self.nodes)
        wait_bitcoinds()
        self.setup_network()

        listed_addresses = self.list_addresses(1, ['imported', 'mnemonic_seed'])
        imported_src = get_source(listed_addresses, 'imported')
        assert_equal(imported_src['sapling'][0]['addresses'], [sapling_1])

        print("Testing height 2 (NU5)")
        self.nodes[0].generate(1)
        self.sync_all()
        assert_equal(self.nodes[0].getblockcount(), 2)
        # Sprout address generation is no longer allowed
        sapling_2 = self.nodes[0].z_getnewaddress('sapling')
        unified_2 = self.nodes[0].z_getaddressforaccount(account)['address']
        types_and_addresses = [
            ('sapling', sapling_2),
            ('unified', unified_2),
        ]

        for addr_type, addr in types_and_addresses:
            res = self.nodes[0].z_validateaddress(addr)
            assert res['isvalid']
            # assert res['ismine'] # this isn't present for unified addresses
            assert_equal(res['type'], addr_type)

        # We should see the same sources (address generation does not change across the NU5 boundary).
        listed_addresses = self.list_addresses(0, ['imported_watchonly', 'legacy_random', 'mnemonic_seed'])
        legacy_random_src = get_source(listed_addresses, 'legacy_random')
        mnemonic_seed_src = get_source(listed_addresses, 'mnemonic_seed')

        # Check Sprout addrs
        assert_equal(legacy_random_src['sprout']['addresses'], [sprout_1])

        # Check Sapling addrs
        assert_equal(
            set([(obj['zip32KeyPath'], x) for obj in mnemonic_seed_src['sapling'] for x in obj['addresses']]),
            set([
                ("m/32'/1'/2147483647'/0'", sapling_1),
                ("m/32'/1'/2147483647'/1'", sapling_2),
            ]),
        )

        # Check Unified addrs
        unified_obj = mnemonic_seed_src['unified']
        assert_equal(unified_obj[0]['account'], 0)
        assert_equal(
            set([addr['address'] for addr in unified_obj[0]['addresses']]),
            set([unified_1, unified_2]),
        )
        assert 'diversifier_index' in unified_obj[0]['addresses'][0]
        assert 'diversifier_index' in unified_obj[0]['addresses'][1]
        assert_equal(unified_obj[0]['addresses'][0]['receiver_types'], ['p2pkh', 'sapling', 'orchard'])
        assert_equal(unified_obj[0]['addresses'][1]['receiver_types'], ['p2pkh', 'sapling', 'orchard'])

        print("Generate mature coinbase, spend to create and detect change")
        self.nodes[0].generate(100)
        self.sync_all()
        self.nodes[0].sendmany('', {taddr_import: 1})
        listed_addresses = self.list_addresses(0, ['imported_watchonly', 'legacy_random', 'mnemonic_seed'])
        mnemonic_seed_src = get_source(listed_addresses, 'mnemonic_seed')
        assert len(mnemonic_seed_src['transparent']['changeAddresses']) > 0