示例#1
0
    def _test_getblockheader(self):
        node = self.nodes[0]

        assert_raises(
            JSONRPCException, lambda: node.getblockheader('nonsense'))

        besthash = node.getbestblockhash()
        secondbesthash = node.getblockhash(199)
        header = node.getblockheader(besthash)

        assert_equal(header['hash'], besthash)
        assert_equal(header['height'], 200)
        assert_equal(header['confirmations'], 1)
        assert_equal(header['previousblockhash'], secondbesthash)
        assert_is_hex_string(header['chainwork'])
        assert_is_hash_string(header['hash'])
        assert_is_hash_string(header['previousblockhash'])
        assert_is_hash_string(header['merkleroot'])
        assert_is_hash_string(header['bits'], length=None)
        assert isinstance(header['time'], int)
        assert isinstance(header['mediantime'], int)
        assert isinstance(header['nonce'], int)
        assert isinstance(header['version'], int)
        assert isinstance(int(header['versionHex'], 16), int)
        assert isinstance(header['difficulty'], Decimal)
示例#2
0
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(105)
        self.sync_all()

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

        node0utxos = self.nodes[0].listunspent(1)
        tx1 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 10})
        txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)["hex"])
        tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 10})
        txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"])
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1])), [txid1])
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist)
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2], blockhash)), txlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): 10})
        self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2

        # We cant find the block from a fully-spent tx
        assert_raises(JSONRPCException, self.nodes[2].gettxoutproof, [txid_spent])
        # ...but we can if we specify the block
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent])
        # ...or if the first tx is not fully-spent
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent])
        try:
            assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist)
        except JSONRPCException:
            assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid2, txid1])), txlist)
        # ...or if we have a -txindex
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent])

        # Quick test of getblock using blockhash and different levels of verbosity
        result = self.nodes[0].getblock(blockhash, 2)
        coinbase_txid = result["tx"][0]["txid"]
        result = self.nodes[0].getblock(blockhash, 1)
        assert_equal(coinbase_txid, result["tx"][0])  # verbosity 1 only lists txids
        result = self.nodes[0].getblock(blockhash, 0)
        assert(c in string.hexdigits for c in result) # verbosity 0 returns raw hex
示例#3
0
    def run_test (self):
        print("Mining blocks...")
        rpc     = self.nodes[0]
        # utxos from block 1 become mature in block 101
        rpc.generate(101)
        self.sync_all()
        rpc.getinfo()
        rpc.getwalletinfo()

        taddr = rpc.getnewaddress()
        print "Sending to " + taddr
        # sending to arbitrary non-notary transparent address is not allowed
        assert_raises(JSONRPCException, rpc.sendtoaddress, taddr,1)
示例#4
0
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(105)
        self.sync_all()

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

        node0utxos = self.nodes[0].listunspent(1)
        tx1 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 10})
        txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)["hex"])
        tx2 = self.nodes[0].createrawtransaction([node0utxos.pop()], {self.nodes[1].getnewaddress(): 10})
        txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"])
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1])), [txid1])
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist)
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2], blockhash)), txlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): 10})
        self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2

        # We cant find the block from a fully-spent tx
        assert_raises(JSONRPCException, self.nodes[2].gettxoutproof, [txid_spent])
        # ...but we can if we specify the block
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent])
        # ...or if the first tx is not fully-spent
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent])
        try:
            assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), txlist)
        except JSONRPCException:
            assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid2, txid1])), txlist)
        # ...or if we have a -txindex
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent])
示例#5
0
 def _test_stopatheight(self):
     assert_equal(self.nodes[0].getblockcount(), 200)
     self.nodes[0].generate(6)
     assert_equal(self.nodes[0].getblockcount(), 206)
     self.log.debug('Node should not stop at this height')
     assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
     try:
         self.nodes[0].generate(1)
     except (ConnectionError, http.client.BadStatusLine):
         pass  # The node already shut down before response
     self.log.debug('Node should stop at this height...')
     self.nodes[0].wait_until_stopped()
     self.start_node(0)
     assert_equal(self.nodes[0].getblockcount(), 207)
示例#6
0
 def _test_stopatheight(self):
     assert_equal(self.nodes[0].getblockcount(), 200)
     self.nodes[0].generate(6)
     assert_equal(self.nodes[0].getblockcount(), 206)
     self.log.debug('Node should not stop at this height')
     assert_raises(subprocess.TimeoutExpired, lambda: self.bitcoind_processes[0].wait(timeout=3))
     try:
         self.nodes[0].generate(1)
     except (ConnectionError, http.client.BadStatusLine):
         pass  # The node already shut down before response
     self.log.debug('Node should stop at this height...')
     self.bitcoind_processes[0].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
     self.nodes[0] = self.start_node(0, self.options.tmpdir)
     assert_equal(self.nodes[0].getblockcount(), 207)
示例#7
0
    def run_test (self):

        # Test the check_node_log utility function
        string_to_find = "Pastel version"
        check_node_log(self, 1, string_to_find)

        # Node 1 was stopped to check the logs, need to be restarted
        self.nodes[1] = self.start_node_with(1, [])
        connect_nodes(self.nodes[1], 0)

        assert_raises(AssertionError, check_node_log, self, 1, "Will not be found")

        # Need to start node 1 before leaving the test
        self.nodes[1] = self.start_node_with(1, [])
        connect_nodes(self.nodes[1], 0)
示例#8
0
 def _test_stopatheight(self):
     assert_equal(self.nodes[0].getblockcount(), 200)
     self.nodes[0].generate(6)
     assert_equal(self.nodes[0].getblockcount(), 206)
     self.log.debug('Node should not stop at this height')
     assert_raises(subprocess.TimeoutExpired,
                   lambda: self.nodes[0].process.wait(timeout=3))
     try:
         self.nodes[0].generate(1)
     except (ConnectionError, http.client.BadStatusLine):
         pass  # The node already shut down before response
     self.log.debug('Node should stop at this height...')
     self.nodes[0].wait_until_stopped()
     self.start_node(0)
     assert_equal(self.nodes[0].getblockcount(), 207)
 def _test_stopatheight(self):
     self.log.info("Test stopping at height")
     assert_equal(self.nodes[0].getblockcount(), HEIGHT)
     self.nodes[0].generatetoaddress(6, ADDRESS_BCRT1_P2WSH_OP_TRUE)
     assert_equal(self.nodes[0].getblockcount(), HEIGHT + 6)
     self.log.debug('Node should not stop at this height')
     assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3))
     try:
         self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_P2WSH_OP_TRUE)
     except (ConnectionError, http.client.BadStatusLine):
         pass  # The node already shut down before response
     self.log.debug('Node should stop at this height...')
     self.nodes[0].wait_until_stopped()
     self.start_node(0)
     assert_equal(self.nodes[0].getblockcount(), HEIGHT + 7)
示例#10
0
 def _test_stopatheight(self):
     assert_equal(self.nodes[0].getblockcount(), 200)
     self.nodes[0].generate(6)
     assert_equal(self.nodes[0].getblockcount(), 206)
     self.log.debug('Node should not stop at this height')
     assert_raises(subprocess.TimeoutExpired,
                   lambda: bitcoind_processes[0].wait(timeout=3))
     try:
         self.nodes[0].generate(1)
     except (ConnectionError, http.client.BadStatusLine):
         pass  # The node already shut down before response
     self.log.debug('Node should stop at this height...')
     bitcoind_processes[0].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT)
     self.nodes[0] = self.start_node(0, self.options.tmpdir)
     assert_equal(self.nodes[0].getblockcount(), 207)
示例#11
0
    def run_test(self):
        # self.nodes[0].generate(200)
        chain_height = self.nodes[0].getblockcount()
        assert_equal(chain_height, 200)
        node0_address = self.nodes[0].getnewaddress()

        # Coinbase at height chain_height-100+1 ok in mempool, should
        # get mined. Coinbase at height chain_height-100+2 is
        # is too immature to spend.
        b = [self.nodes[0].getblockhash(n) for n in range(101, 103)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spends_raw = [
            self.create_tx(txid, node0_address, 50.00)
            for txid in coinbase_txids
        ]

        spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])

        # coinbase at height 102 should be too immature to spend
        assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction,
                      spends_raw[1])

        # mempool should have just spend_101:
        mempoolinfo = self.nodes[0].getmempoolinfo()
        assert_equal(mempoolinfo['size'], 1)
        assert_equal(self.nodes[0].getrawmempool(), [spend_101_id])

        # the size of the memory pool should be greater than 1x ~100 bytes
        assert_greater_than(mempoolinfo['bytes'], 100)
        # the actual memory usage should be strictly greater than the size
        # of the memory pool
        assert_greater_than(mempoolinfo['usage'], mempoolinfo['bytes'])

        # mine a block, spend_101 should get confirmed
        self.nodes[0].generate(1)
        mempoolinfo = self.nodes[0].getmempoolinfo()
        assert_equal(mempoolinfo['size'], 0)
        assert_equal(mempoolinfo['bytes'], 0)
        assert_equal(mempoolinfo['usage'], 0)
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        # ... and now height 102 can be spent:
        spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
        mempoolinfo = self.nodes[0].getmempoolinfo()
        assert_equal(mempoolinfo['size'], 1)
        assert_equal(self.nodes[0].getrawmempool(), [spend_102_id])
        assert_greater_than(mempoolinfo['bytes'], 100)
        assert_greater_than(mempoolinfo['usage'], mempoolinfo['bytes'])
示例#12
0
    def run_test(self):
        chain_height = self.nodes[0].getblockcount()
        assert_equal(chain_height, 200)
        node0_address = self.nodes[0].getnewaddress()

        # Coinbase at height chain_height-100+1 ok in mempool, should
        # get mined. Coinbase at height chain_height-100+2 is
        # is too immature to spend.
        b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ]
        coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
        spends_raw = [ self.create_tx(txid, node0_address, 10) for txid in coinbase_txids ]

        spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0])

        # coinbase at height 102 should be too immature to spend
        assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1])

        # mempool should have just spend_101:
        mempoolinfo = self.nodes[0].getmempoolinfo()
        assert_equal(mempoolinfo['size'], 1)
        assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ])

        # the size of the memory pool should be greater than 1x ~100 bytes
        assert_greater_than(mempoolinfo['bytes'], 100)
        # the actual memory usage should be strictly greater than the size
        # of the memory pool
        assert_greater_than(mempoolinfo['usage'], mempoolinfo['bytes'])

        # mine a block, spend_101 should get confirmed
        self.nodes[0].generate(1)
        mempoolinfo = self.nodes[0].getmempoolinfo()
        assert_equal(mempoolinfo['size'], 0)
        assert_equal(mempoolinfo['bytes'], 0)
        assert_equal(mempoolinfo['usage'], 0)
        assert_equal(set(self.nodes[0].getrawmempool()), set())

        # ... and now height 102 can be spent:
        spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1])
        mempoolinfo = self.nodes[0].getmempoolinfo()
        assert_equal(mempoolinfo['size'], 1)
        assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ])
        assert_greater_than(mempoolinfo['bytes'], 100)
        assert_greater_than(mempoolinfo['usage'], mempoolinfo['bytes'])
示例#13
0
    def _test_getblockheader(self):
        node = self.nodes[0]

        assert_raises(JSONRPCException,
                      lambda: node.getblockheader('nonsense'))

        besthash = node.getbestblockhash()
        secondbesthash = node.getblockhash(199)
        header = node.getblockheader(besthash)

        assert_equal(header['hash'], besthash)
        assert_equal(header['height'], 200)
        assert_equal(header['confirmations'], 1)
        assert_equal(header['previousblockhash'], secondbesthash)
        assert_is_hex_string(header['chainwork'])
        assert_is_hash_string(header['hash'])
        assert_is_hash_string(header['previousblockhash'])
        assert_is_hash_string(header['merkleroot'])
        assert_is_hash_string(header['bits'], length=None)
        assert isinstance(header['time'], int)
        assert isinstance(header['mediantime'], int)
        assert isinstance(header['nonce'], int)
        assert isinstance(header['version'], int)
        assert isinstance(header['difficulty'], Decimal)
示例#14
0
    def run_test(self):
        """Main test logic"""

        self.log.info("Starting test!")
        [n0, n1, n2] = self.nodes  # n2 is the erasing node

        self.log.info("Generate a few blocks upfront to make sure pruning kicks in.")
        # On pruning, we must have a chain longer than PruneAfterHeight and bigger than 550 MiB.
        mine_large_blocks(n0, nblocks=200)
        self.nodes[0].generate(nblocks=200)

        self.log.info("Build a \"bad\" transaction.")
        bad_data = 'n42MaFLwantedToTestThisKYP112MM9jE'
        tx_bad = n1.createrawtransaction([], {bad_data: 0.001})
        (tx_bad, txid_bad) = fund_sign_send(n1, tx_bad)  # also adds inputs and change output
        tx_bad_vouts = n1.decoderawtransaction(tx_bad)['vout']

        self.log.info("Add tx to a block, mine a few big blocks on top.")
        self.sync_all()
        block_hash_bad = n0.generate(nblocks=1)[0]
        # significantly lower nblocks might cause pruning not to work (needs changes to bitcoind pruning logic)
        mine_large_blocks(n0, nblocks=300)
        self.nodes[0].generate(nblocks=300)
        self.sync_all()

        erase_target = {block_hash_bad: {txid_bad: list(range(len(tx_bad_vouts)))}}

        self.log.info("Assert that node 2 serves the tx via RPC.")
        assert_equal(bytes_to_hex_str(hash256(hex_str_to_bytes(n2.getrawtransaction(txid_bad)))), txid_bad)

        self.log.info("Assert that node 2 serves the block with the tx via P2P.")
        n2.add_p2p_connection(P2PInterface())
        n2.p2p.send_message(msg_getdata(inv=[CInv(2, int(block_hash_bad, 16))]))
        n2.p2p.wait_for_block(int(block_hash_bad, 16), timeout=1)

        self.log.info("Stopping node 2.")
        self.stop_node(2)

        self.log.info("Assert that UTXOs not erased according to tool.")
        assert_equal(tool.check(erase_target, n2.datadir, 'regtest'), False)

        def react_to_ui_request(request):
            assert("enable pruning" in request)
            self.log.info("Configuring node 2 to enable pruning.")
            append_config(n2.datadir, ["prune=1"])

            assert("start your node" in request)
            self.log.info("Starting node 2.")
            self.start_node(2)
            connect_nodes_bi(self.nodes, 0, 2)

        self.log.info("Erasing using tool.")
        tool.interactive_erase(erase_target, n2.datadir, 'regtest', self.log.info, react_to_ui_request)

        self.log.info("Assert that the tx's block can't be obtained from node 2 via P2P anymore.")
        n2.add_p2p_connection(P2PInterface())
        n2.p2p.send_message(msg_getdata(inv=[CInv(2, int(block_hash_bad, 16))]))
        assert_raises(AssertionError, n2.p2p.wait_for_block, int(block_hash_bad, 16), timeout=1)

        self.log.info("Assert that tx is different now when obtained from node 2 via RPC.")
        assert_raises_rpc_error(-5, None, n2.getrawtransaction, txid_bad)

        self.log.info("Assert that node 2 accepts new blocks.")
        n0.generate(nblocks=1)
        sync_blocks(self.nodes, timeout=1)

        self.log.info("Spend one output of the bad tx, include that in block.")
        tx_bad_vout = [x for x in n1.listunspent() if x['txid'] == txid_bad][0]
        tx_ok = n1.createrawtransaction([tx_bad_vout], {n0.getnewaddress(): 0.5})
        (tx_ok, txid_ok) = fund_sign_send(n1, tx_ok)
        sync_mempools([n0, n1])
        n0.generate(nblocks=1)

        self.log.info("Assert that node 2 accepts the resulting transaction and block.")
        sync_blocks(self.nodes, timeout=1)
        assert_equal(bytes_to_hex_str(hash256(hex_str_to_bytes(n2.getrawtransaction(txid_ok)))), txid_ok)

        self.log.info("Wait for all nodes to sync again, just in case. Should complete immediately.")
        self.sync_all()

        self.log.info("Stopping node 2 (again).")
        self.stop_node(2)

        self.log.info("Assert that UTXOs are erased according to tool.")
        assert_equal(tool.check(erase_target, n2.datadir, 'regtest'), True)
示例#15
0
    def run_test(self):

        #prepare some coins for multiple *rawtransaction commands
        self.generate_and_sync_inc(1, 2)
        self.generate_and_sync_inc(101)
        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.generate_and_sync_inc(5)

        #########################################
        # sendrawtransaction with missing input #
        #########################################
        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1
        }]  #won't exists
        outputs = {self.nodes[0].getnewaddress(): 4.998}
        rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawtx = self.nodes[2].signrawtransaction(rawtx)

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

        assert_equal("Missing inputs" in errorString, True)

        #####################################
        # getrawtransaction with block hash #
        #####################################

        # make a tx by sending then generate 2 blocks; block1 has the tx in it
        tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
        block1, block2 = self.nodes[2].generate(2)
        self.sync_all()
        # We should be able to get the raw transaction by providing the correct block
        gottx = self.nodes[0].getrawtransaction(tx, 1, block1)
        assert_equal(gottx['txid'], tx)
        assert_equal(gottx['in_active_chain'], True)
        # We should not have the 'in_active_chain' flag when we don't provide a block
        gottx = self.nodes[0].getrawtransaction(tx, 1)
        assert_equal(gottx['txid'], tx)
        assert 'in_active_chain' not in gottx
        # We should have hex for the transaction from the getblock and getrawtransaction calls.
        blk = self.nodes[0].getblock(block1, 2)
        assert_equal(gottx['hex'], blk['tx'][1]['hex'])
        # We should not get the tx if we provide an unrelated block
        assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, tx, 1,
                      block2)
        # An invalid block hash should raise errors
        assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, tx, 1,
                      True)
        assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, tx, 1,
                      "foobar")
        assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, tx, 1,
                      "abcd1234")
        assert_raises(
            JSONRPCException, self.nodes[0].getrawtransaction, tx, 1,
            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")

        #########################
        # RAW TX MULTISIG TESTS #
        #########################
        # 2of2 test
        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']])
        mSigObjValid = self.nodes[2].validateaddress(mSigObj)

        #use balance deltas instead of absolute values
        bal = self.nodes[2].getbalance()

        # send 1.2 BTC to msig adr
        txId = self.nodes[0].sendtoaddress(mSigObj, 1.2)
        self.sync_all()
        self.generate_and_sync_inc(1)
        assert_equal(
            self.nodes[2].getbalance(), bal + Decimal('1.20000')
        )  #node2 has both keys of the 2of2 ms addr., tx should affect the balance

        # 2of3 test from different nodes
        bal = self.nodes[2].getbalance()
        addr1 = self.nodes[1].getnewaddress()
        addr2 = self.nodes[2].getnewaddress()
        addr3 = self.nodes[2].getnewaddress()

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

        mSigObj = self.nodes[2].addmultisigaddress(
            2, [addr1Obj['pubkey'], addr2Obj['pubkey'], addr3Obj['pubkey']])
        mSigObjValid = self.nodes[2].validateaddress(mSigObj)
        assert_equal(mSigObjValid['isvalid'], True)

        txId = self.nodes[0].sendtoaddress(mSigObj, 2.2)
        decTx = self.nodes[0].gettransaction(txId)
        rawTx = self.nodes[0].decoderawtransaction(decTx['hex'])
        sPK = rawTx['vout'][0]['scriptPubKey']['hex']
        [sPK]  # hush pyflakes
        self.sync_all()
        self.generate_and_sync_inc(1)

        # THIS IS A INCOMPLETE FEATURE
        # NODE2 HAS TWO OF THREE KEY AND THE FUNDS SHOULD BE SPENDABLE AND COUNT AT BALANCE CALCULATION
        assert_equal(
            self.nodes[2].getbalance(), bal
        )  # for now, assume the funds of a 2of3 multisig tx are not marked as spendable

        txDetails = self.nodes[0].gettransaction(txId, True)
        rawTx = self.nodes[0].decoderawtransaction(txDetails['hex'])
        vout = False
        for outpoint in rawTx['vout']:
            if outpoint['value'] == Decimal('2.20000'):
                vout = outpoint
                break

        bal = self.nodes[0].getbalance()
        inputs = [{
            "txid": txId,
            "vout": vout['n'],
            "scriptPubKey": vout['scriptPubKey']['hex'],
            "amount": vout['value']
        }]
        outputs = {self.nodes[0].getnewaddress(): 2.199}
        rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
        rawTxPartialSigned = self.nodes[1].signrawtransaction(rawTx, inputs)
        assert_equal(rawTxPartialSigned['complete'],
                     False)  # node1 only has one key, can't comp. sign the tx

        rawTxSigned = self.nodes[2].signrawtransaction(rawTx, inputs)
        assert_equal(
            rawTxSigned['complete'],
            True)  # node2 can sign the tx compl., own two of three keys
        self.nodes[2].sendrawtransaction(rawTxSigned['hex'])
        rawTx = self.nodes[0].decoderawtransaction(rawTxSigned['hex'])
        self.sync_all()
        self.generate_and_sync_inc(1)
        assert_equal(self.nodes[0].getbalance(), bal + self._reward +
                     Decimal('2.19900'))  #block reward + tx

        inputs = [{
            'txid':
            "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000",
            'vout': 1,
            'sequence': 1000
        }]
        outputs = {self.nodes[0].getnewaddress(): 1}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        decrawtx = self.nodes[0].decoderawtransaction(rawtx)
        assert_equal(decrawtx['vin'][0]['sequence'], 1000)
示例#16
0
    def run_test(self):
        print("Mining blocks...")
        self.nodes[0].generate(105)
        self.sync_all()

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

        node0utxos = self.nodes[0].listunspent(1)
        tx1 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[1].getnewaddress(): 10})
        txid1 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx1)["hex"])
        tx2 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[1].getnewaddress(): 10})
        txid2 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx2)["hex"])
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1
                                                                        ])),
            [txid1])
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2])), txlist)
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2], blockhash)), txlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        tx3 = self.nodes[1].createrawtransaction(
            [txin_spent], {self.nodes[0].getnewaddress(): 10})
        self.nodes[0].sendrawtransaction(
            self.nodes[1].signrawtransaction(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2

        # We cant find the block from a fully-spent tx
        assert_raises(JSONRPCException, self.nodes[2].gettxoutproof,
                      [txid_spent])
        # ...but we can if we specify the block
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_spent], blockhash)), [txid_spent])
        # ...or if the first tx is not fully-spent
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_unspent])), [txid_unspent])
        try:
            assert_equal(
                self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                    [txid1, txid2])), txlist)
        except JSONRPCException:
            assert_equal(
                self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                    [txid2, txid1])), txlist)
        # ...or if we have a -txindex
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof(
                [txid_spent])), [txid_spent])

        # Quick test of getblock using blockhash and different levels of verbosity
        result = self.nodes[0].getblock(blockhash, 2)
        coinbase_txid = result["tx"][0]["txid"]
        result = self.nodes[0].getblock(blockhash, 1)
        assert_equal(coinbase_txid,
                     result["tx"][0])  # verbosity 1 only lists txids
        result = self.nodes[0].getblock(blockhash, 0)
        assert (c in string.hexdigits
                for c in result)  # verbosity 0 returns raw hex
示例#17
0
    def run_test(self):
        print("---- Pastel ID tests STARTED ----")
        print(" -pastelid help")
        assert_shows_help(self.nodes[0].pastelid)

        coinbase_addr1 = self.nodes[1].getnewaddress()
        taddr1 = self.nodes[1].getnewaddress()

        print(" -pastelid newkey")
        assert_shows_help(self.nodes[0].pastelid, "newkey")
        self.pastelid1, self.id1_lrkey = self.create_pastelid(0)
        self.pastelid2 = self.create_pastelid()[0]
        self.pastelid3, self.id3_lrkey = self.create_pastelid(1)
        print(f"pastelid1: {self.pastelid1}")
        print(f"pastelid2: {self.pastelid2}")
        print(f"pastelid3: {self.pastelid3}")

        # fail if empty passphrase
        assert_raises_rpc(rpc.RPC_MISC_ERROR, "passphrase for new key cannot be empty", 
            self.nodes[0].pastelid, "newkey", "")

        # List all internally stored PastelID and keys
        print(" -pastelid list")
        # check Pastel IDs on node0
        id_list0 = self.nodes[0].pastelid("list")
        id_list0 = dict((key+str(i), val) for i, k in enumerate(id_list0) for key, val in k.items())
        assert_true(self.pastelid1 in id_list0.values(), f"PastelID {self.pastelid1} not in the list")
        assert_true(self.pastelid2 in id_list0.values(), f"PastelID {self.pastelid2} not in the list")
        # check Pastel IDs on node1
        id_list1 = self.nodes[1].pastelid("list")
        id_list1 = dict((key+str(i), val) for i, k in enumerate(id_list1) for key, val in k.items())
        assert_true(self.pastelid3 in id_list1.values(), f"PastelID {self.pastelid3} not in the list")

        print(" -pastelid sign & verify ed448")
        text_to_sign = "my text to sign"
        # Sign "text" with the internally stored private key associated with the PastelID
        # check that signing with existing passphrase works, default algorithm - EdDSA448
        signature = self.nodes[0].pastelid("sign", text_to_sign, self.pastelid1, self.passphrase)["signature"]
        assert_true(signature, "Cannot sign text using existing passphrase. No ed448 signature was created")
        assert_equal(len(base64.b64decode(signature)), 114)
        # Verify text"'s "signature" (EdDSA448) with the PastelID
        result = self.nodes[0].pastelid("verify", text_to_sign, signature, self.pastelid1)["verification"]
        assert_equal(result, "OK")
        # Fail to verify EdDSA448 signature with the different key (PastelID2)
        result = self.nodes[0].pastelid("verify", text_to_sign, signature, self.pastelid2)["verification"]
        assert_equal(result, "Failed")
        # Fail to verify modified text (ed448 signature)
        text_to_sign_modified = 'X' + text_to_sign[1:]
        result = self.nodes[0].pastelid("verify", text_to_sign_modified, signature, self.pastelid1)["verification"]
        assert_equal(result, "Failed")
        # try to sign using PastelID with invalid passphrase
        assert_raises_rpc(rpc.RPC_MISC_ERROR, self.ERR_READ_PASTELID_FILE,
            self.nodes[1].pastelid, "sign", text_to_sign, self.pastelid1, self.new_passphrase)

        print(" -pastelid sign & verify legroast")
        # Sign with no errors using encoded LegRoast public key
        # returns base64 encoded signature
        lr_signature = self.nodes[0].pastelid("sign", text_to_sign, self.pastelid1, self.passphrase, "legroast")["signature"]
        assert_true(lr_signature, "Cannot sign text using existing passphrase. No LegRoast signature was created")
        assert_equal(len(base64.b64decode(lr_signature)), 14272)
        # Verify text"'s "signature" (LegRoast) with the PastelID
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid1, "legroast")["verification"]
        assert_equal(result, "OK")
        # Fail to verify LegRoast signature with the different key (PastelID2)
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid2, "legroast")["verification"]
        assert_equal(result, "Failed")
        # Fail to verify modified text (LegRoast signature)
        result = self.nodes[0].pastelid("verify", text_to_sign_modified, lr_signature, self.pastelid1, "legroast")["verification"]
        assert_equal(result, "Failed")
        
        # Sign message on node1 with the LegRoast key associated with pastelid3 
        lr_signature = self.nodes[1].pastelid("sign", text_to_sign, self.pastelid3, self.passphrase, "legroast")["signature"]
        assert_true(lr_signature, "Cannot sign text on node1 with LegRoast key associated with pastelid3. No LegRoast signature was created")
        # ... but verify it on node0 that does not have pastelid3 and we don't have any PastelID reg tickets
        assert_raises_rpc(rpc.RPC_MISC_ERROR, "is not stored locally and PastelID registration ticket was not found in the blockchain",
            self.nodes[0].pastelid, "verify", text_to_sign, lr_signature, self.pastelid3, "legroast")
        # now let's register pastelid3
        self.generate_and_sync_inc(10)
        # send all utxos from node #3 to addr[0] to make empty balance
        self.nodes[0].sendtoaddress(taddr1, self.nodes[0].getbalance(), "empty node0", "test", True)
        self.generate_and_sync_inc(1)
        # register pastelid3
        txid = self.nodes[1].tickets("register", "id", self.pastelid3, self.passphrase, taddr1)
        assert_true(txid, "pastelid3 registration failed")
        self.generate_and_sync_inc(1)

        # now we should be able to retrieve lr pubkey for pastelid3 on node0
        # but first make sure pastelid3 is not stored locally on node0
        assert_true(self.pastelid3 not in id_list0.values(), f"PastelID3 {self.pastelid3} should not be stored on node0")
           # Verify text"'s "signature" (LegRoast) with the PastelID3
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid3, "legroast")["verification"]
        assert_equal(result, "OK")
         # Fail to verify LegRoast signature with the different key (PastelID1)
        result = self.nodes[0].pastelid("verify", text_to_sign, lr_signature, self.pastelid1, "legroast")["verification"]
        assert_equal(result, "Failed")
        # Fail to verify modified text (LegRoast signature)
        result = self.nodes[0].pastelid("verify", text_to_sign_modified, lr_signature, self.pastelid3, "legroast")["verification"]
        assert_equal(result, "Failed")
       

        print(" -pastelid passwd")
        assert_shows_help(self.nodes[0].pastelid, "passwd")
        # missing new passphrase
        assert_raises(JSONRPCException, self.nodes[0].pastelid, "passwd", self.pastelid1, self.passphrase)
        # empty new passphrase
        assert_raises_message(JSONRPCException, "cannot be empty", 
            self.nodes[0].pastelid, "passwd", self.pastelid1, self.passphrase, "")
        # empty Pastel ID
        assert_raises_message(JSONRPCException, "cannot be empty", 
            self.nodes[0].pastelid, "passwd", "", self.passphrase, self.new_passphrase)
        # empty passphrase
        assert_raises_message(JSONRPCException, "cannot be empty", 
            self.nodes[0].pastelid, "passwd", self.pastelid1, "", self.new_passphrase)
        # change passphrase
        result = self.nodes[0].pastelid("passwd", self.pastelid1, self.passphrase, self.new_passphrase)["result"]
        assert_equal(result, "successful")
        # try to sign text using old passphrase
        assert_raises_message(JSONRPCException, "Failed to decrypt", self.nodes[0].pastelid, "sign", text_to_sign, self.pastelid1, self.passphrase)
        # signing using new passphrase should work
        signature = self.nodes[0].pastelid("sign", text_to_sign, self.pastelid1, self.new_passphrase)["signature"]
        assert_true(signature, "Cannot sign text using existing passphrase. No ed448 signature was created")
        # verify signature
        result = self.nodes[0].pastelid("verify", text_to_sign, signature, self.pastelid1)["verification"]
        assert_equal(result, "OK")
        print("----- Pastel ID tests FINISHED -----")
示例#18
0
    def run_test(self):
        # create a p2p receiver
        dspReceiver = P2PInterface()
        self.nodes[0].add_p2p_connection(dspReceiver)
        # workaround - nodes think they're in IBD unless one block is mined
        self.nodes[0].generate(1)
        self.sync_all()
        # Disconnect the third node, will be used later for triple-spend
        disconnect_nodes(self.nodes[1], self.nodes[2])
        # Put fourth node (the non-dsproof-enabled node) with the connected group
        # (we will check its log at the end to ensure it ignored dsproof inv's)
        non_dsproof_node = self.nodes[3]
        disconnect_nodes(self.nodes[2], non_dsproof_node)
        connect_nodes(self.nodes[1], non_dsproof_node)

        # Create and mine a regular non-coinbase transaction for spending
        fundingtxid = self.nodes[0].getblock(self.nodes[0].getblockhash(1))['tx'][0]
        fundingtx = FromHex(CTransaction(), self.nodes[0].getrawtransaction(fundingtxid))

        # Create three conflicting transactions. They are only signed, but not yet submitted to the mempool
        firstDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[0].getnewaddress(), 49.95)
        secondDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[0].getnewaddress(), 49.95)
        thirdDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[0].getnewaddress(), 49.95)

        # Send the two conflicting transactions to the network
        # Submit to two different nodes, because a node would simply reject
        # a double spend submitted through RPC
        firstDSTxId = self.nodes[0].sendrawtransaction(firstDSTx)
        self.nodes[1].call_rpc('sendrawtransaction', secondDSTx, ignore_error='txn-mempool-conflict')
        wait_until(
            lambda: dspReceiver.message_count["dsproof-beta"] == 1,
            lock=mininode_lock,
            timeout=25
        )

        # 1. The DSP message is well-formed and contains all fields
        # If the message arrived and was deserialized successfully, then 1. is satisfied
        dsp = dspReceiver.last_message["dsproof-beta"].dsproof
        dsps = set()
        dsps.add(dsp.serialize())

        # Check that it is valid, both spends are signed with the same key
        # NB: pushData is made of the sig + one last byte for hashtype
        pubkey = self.getpubkey()
        sighash1 = getSighashes(dsp.getPrevOutput(), dsp.spender1, fundingtx)
        sighash2 = getSighashes(dsp.getPrevOutput(), dsp.spender2, fundingtx)
        assert(pubkey.verify_ecdsa(dsp.spender1.pushData[0][:-1], sighash1))
        assert(pubkey.verify_ecdsa(dsp.spender2.pushData[0][:-1], sighash2))

        # 2. For p2pkh these is exactly one pushdata per spender
        assert_equal(1, len(dsp.spender1.pushData))
        assert_equal(1, len(dsp.spender2.pushData))

        # 3. The two spenders are different, specifically the signature (push data) has to be different.
        assert(dsp.spender1.pushData != dsp.spender2.pushData)

        # 4. The first & double spenders are sorted with two hashes as keys.
        assert(dsp.spender1.hashOutputs < dsp.spender2.hashOutputs)

        # 5. The double spent output is still available in the UTXO database,
        #    implying no spending transaction has been mined.
        assert_equal(self.nodes[0].gettransaction(firstDSTxId)["confirmations"], 0)

        # The original fundingtx is the same as the transaction being spent reported by the DSP
        assert_equal(hex(dsp.prevTxId)[2:], fundingtxid)
        assert_equal(dsp.prevOutIndex, 0)

        # 6. No other valid proof is known.
        #    IE if a valid proof is known, no new proofs will be constructed
        #    We submit a _triple_ spend transaction to the third node
        connect_nodes(self.nodes[0], self.nodes[2])
        self.nodes[2].call_rpc('sendrawtransaction', thirdDSTx, ignore_error='txn-mempool-conflict')
        #    Await for a new dsp to be relayed to the node
        #    if such a dsp (or the double or triple spending tx) arrives, the test fails
        assert_raises(
            AssertionError,
            wait_until,
            lambda: dspReceiver.message_count["dsproof-beta"] == 2 or dspReceiver.message_count["tx"] == 2,
            lock=mininode_lock,
            timeout=5
        )

        # Only P2PKH inputs are protected
        # Check that a non-P2PKH output is not protected
        self.nodes[0].generate(1)
        fundingtxid = self.nodes[0].getblock(self.nodes[0].getblockhash(2))['tx'][0]
        fundingtx = FromHex(CTransaction(), self.nodes[0].getrawtransaction(fundingtxid))
        fundingtx.rehash()
        nonP2PKHTx = create_tx_with_script(fundingtx, 0, b'', int(49.95 * COIN), CScript([OP_TRUE]))
        signedNonP2PKHTx = self.nodes[0].signrawtransactionwithwallet(ToHex(nonP2PKHTx))
        self.nodes[0].sendrawtransaction(signedNonP2PKHTx['hex'])
        self.sync_all()

        tx = FromHex(CTransaction(), signedNonP2PKHTx['hex'])
        tx.rehash()

        firstDSTx = create_tx_with_script(tx, 0, b'', int(49.90 * COIN), CScript([OP_TRUE]))
        secondDSTx = create_tx_with_script(tx, 0, b'', int(49.90 * COIN), CScript([OP_FALSE]))

        self.nodes[0].sendrawtransaction(ToHex(firstDSTx))
        self.nodes[1].call_rpc('sendrawtransaction', ToHex(secondDSTx), ignore_error='txn-mempool-conflict')

        assert_raises(
            AssertionError,
            wait_until,
            lambda: dspReceiver.message_count["dsproof-beta"] == 2,
            lock=mininode_lock,
            timeout=5
        )

        # Check that unconfirmed outputs are also protected
        self.nodes[0].generate(1)
        unconfirmedtx = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 25)
        self.sync_all()

        firstDSTx = create_raw_transaction(self.nodes[0], unconfirmedtx, self.nodes[0].getnewaddress(), 24.9)
        secondDSTx = create_raw_transaction(self.nodes[0], unconfirmedtx, self.nodes[0].getnewaddress(), 24.9)

        self.nodes[0].sendrawtransaction(firstDSTx)
        self.nodes[1].call_rpc('sendrawtransaction', secondDSTx, ignore_error='txn-mempool-conflict')

        wait_until(
            lambda: dspReceiver.message_count["dsproof-beta"] == 2,
            lock=mininode_lock,
            timeout=5
        )
        dsp2 = dspReceiver.last_message["dsproof-beta"].dsproof
        dsps.add(dsp2.serialize())
        assert(len(dsps) == 2)

        # Check that a double spent tx, which has some non-P2PKH inputs
        # in its ancestor, still results in a dsproof being emitted.
        self.nodes[0].generate(1)
        # Create a 1-of-2 multisig address which will be an in-mempool
        # ancestor to a double-spent tx
        pubkey0 = self.nodes[0].getaddressinfo(
            self.nodes[0].getnewaddress())['pubkey']
        pubkey1 = self.nodes[1].getaddressinfo(
            self.nodes[1].getnewaddress())['pubkey']
        p2sh = self.nodes[0].addmultisigaddress(1, [pubkey0, pubkey1], "")['address']
        # Fund the p2sh address
        fundingtxid = self.nodes[0].sendtoaddress(p2sh, 49)
        vout = find_output(self.nodes[0], fundingtxid, Decimal('49'))
        self.sync_all()

        # Spend from the P2SH to a P2PKH, which we will double spend from
        # in the next step.
        p2pkh1 = self.nodes[0].getnewaddress()
        rawtx1 = create_raw_transaction(self.nodes[0], fundingtxid, p2pkh1, 48.999, vout)
        signed_tx1 = self.nodes[0].signrawtransactionwithwallet(rawtx1)
        txid1 = self.nodes[0].sendrawtransaction(signed_tx1['hex'])
        vout1 = find_output(self.nodes[0], txid1, Decimal('48.999'))
        self.sync_all()

        # Now double spend the P2PKH which has a P2SH ancestor.
        firstDSTx = create_raw_transaction(self.nodes[0], txid1, self.nodes[0].getnewaddress(), 48.9, vout1)
        secondDSTx = create_raw_transaction(self.nodes[0], txid1, self.nodes[1].getnewaddress(), 48.9, vout1)
        self.nodes[0].sendrawtransaction(firstDSTx)
        self.nodes[1].call_rpc('sendrawtransaction', secondDSTx, ignore_error='txn-mempool-conflict')

        # We still get a dsproof, showing that not all ancestors have
        # to be P2PKH.
        wait_until(
            lambda: dspReceiver.message_count["dsproof-beta"] == 3,
            lock=mininode_lock,
            timeout=5
        )
        dsp3 = dspReceiver.last_message["dsproof-beta"].dsproof
        dsps.add(dsp3.serialize())
        assert(len(dsps) == 3)

        # Check that a double spent tx, which has some unconfirmed ANYONECANPAY
        # transactions in its ancestry, still results in a dsproof being emitted.
        self.nodes[0].generate(1)
        fundingtxid = self.nodes[0].getblock(self.nodes[0].getblockhash(5))['tx'][0]
        vout1 = find_output(self.nodes[0], fundingtxid, Decimal('50'))
        addr = self.nodes[1].getnewaddress()
        pubkey = self.nodes[1].getaddressinfo(addr)['pubkey']
        inputs = [
            {'txid': fundingtxid,
             'vout': vout1, 'amount': 49.99,
             'scriptPubKey': pubkey}
        ]
        outputs = {addr: 49.99}
        rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
        signed = self.nodes[0].signrawtransactionwithwallet(rawtx,
                                                            None,
                                                            "NONE|FORKID|ANYONECANPAY")
        assert 'complete' in signed
        assert_equal(signed['complete'], True)
        assert 'errors' not in signed
        txid = self.nodes[0].sendrawtransaction(signed['hex'])
        self.sync_all()
        # The ANYONECANPAY is still unconfirmed, but let's create some
        # double spends from it.
        vout2 = find_output(self.nodes[0], txid, Decimal('49.99'))
        firstDSTx = create_raw_transaction(self.nodes[1], txid, self.nodes[0].getnewaddress(), 49.98, vout2)
        secondDSTx = create_raw_transaction(self.nodes[1], txid, self.nodes[1].getnewaddress(), 49.98, vout2)
        self.nodes[0].sendrawtransaction(firstDSTx)
        self.nodes[1].call_rpc('sendrawtransaction', secondDSTx, ignore_error='txn-mempool-conflict')
        # We get a dsproof.
        wait_until(
            lambda: dspReceiver.message_count["dsproof-beta"] == 4,
            lock=mininode_lock,
            timeout=5
        )
        dsp4 = dspReceiver.last_message["dsproof-beta"].dsproof
        dsps.add(dsp4.serialize())
        assert(len(dsps) == 4)

        # Create a P2SH to double-spend directly (1-of-1 multisig)
        self.nodes[0].generate(1)
        self.sync_all()
        pubkey2 = self.nodes[0].getaddressinfo(
            self.nodes[0].getnewaddress())['pubkey']
        p2sh = self.nodes[0].addmultisigaddress(1, [pubkey2,], "")['address']
        fundingtxid = self.nodes[0].sendtoaddress(p2sh, 49)
        vout = find_output(self.nodes[0], fundingtxid, Decimal('49'))
        self.sync_all()
        # Now double spend it
        firstDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[0].getnewaddress(), 48.9, vout)
        secondDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[1].getnewaddress(), 48.9, vout)
        self.nodes[0].sendrawtransaction(firstDSTx)
        self.nodes[1].call_rpc('sendrawtransaction', secondDSTx, ignore_error='txn-mempool-conflict')
        # No dsproof is generated.
        assert_raises(
            AssertionError,
            wait_until,
            lambda: dspReceiver.message_count["dsproof-beta"] == 5,
            lock=mininode_lock,
            timeout=5
        )

        # Check end conditions - still only 4 DSPs
        last_dsp = dspReceiver.last_message["dsproof-beta"].dsproof
        dsps.add(last_dsp.serialize())
        assert(len(dsps) == 4)

        # Next, test that submitting a double-spend via the RPC interface also results in a broadcasted
        # dsproof
        self.nodes[0].generate(1)
        self.sync_all()
        fundingtxid = self.nodes[0].getblock(self.nodes[0].getblockhash(6))['tx'][0]
        # Create 2 new double-spends
        firstDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[0].getnewaddress(), 49.95)
        secondDSTx = create_raw_transaction(self.nodes[0], fundingtxid, self.nodes[0].getnewaddress(), 49.95)

        # Send the two conflicting transactions to the same node via RPC
        assert_equal(dspReceiver.message_count["dsproof-beta"], 4)
        self.nodes[0].sendrawtransaction(firstDSTx)
        # send second tx to same node via RPC
        # -- it's normal for it to reject the tx, but it should still generate a dsproof broadcast
        assert_raises_rpc_error(
            -26,
            "txn-mempool-conflict (code 18)",
            self.nodes[0].sendrawtransaction,
            secondDSTx
        )
        wait_until(
            lambda: dspReceiver.message_count["dsproof-beta"] == 5,
            lock=mininode_lock,
            timeout=5
        )

        # Finally, ensure that the non-dsproof node has the messages we expect in its log
        # (this checks that dsproof was disabled for this node)
        debug_log = os.path.join(non_dsproof_node.datadir, 'regtest', 'debug.log')
        dsp_inv_ctr = 0
        with open(debug_log, encoding='utf-8') as dl:
            for line in dl.readlines():
                if "Got DSProof INV" in line:
                    # Ensure that if this node did see a dsproof inv, it explicitly ignored it
                    assert "(ignored, -doublespendproof=0)" in line
                    dsp_inv_ctr += 1
                else:
                    # Ensure this node is not processing dsproof messages and not requesting them via getdata
                    assert ("received: dsproof-beta" not in line and "Good DSP" not in line
                            and "DSP broadcasting" not in line and "bad-dsproof" not in line)
        # We expect it to have received at least some DSP inv broadcasts
        assert_greater_than(dsp_inv_ctr, 0)
示例#19
0
    def run_test(self):
        # Mine three blocks. After this, nodes[0] blocks
        # 101, 102, and 103 are spend-able.
        new_blocks = self.nodes[1].generate(4)
        self.sync_all()

        node0_address = self.nodes[0].getnewaddress()
        node1_address = self.nodes[1].getnewaddress()

        # Three scenarios for re-orging coinbase spends in the memory pool:
        # 1. Direct coinbase spend  :  spend_101
        # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
        # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
        # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
        # and make sure the mempool code behaves correctly.
        b = [self.nodes[0].getblockhash(n) for n in range(101, 105)]
        coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
        spend_101_raw = self.create_tx(coinbase_txids[1], node1_address,
                                       self._reward)
        spend_102_raw = self.create_tx(coinbase_txids[2], node0_address,
                                       self._reward)
        spend_103_raw = self.create_tx(coinbase_txids[3], node0_address,
                                       self._reward)

        # Create a block-height-locked transaction which will be invalid after reorg
        timelock_tx = self.nodes[0].createrawtransaction(
            [{
                "txid": coinbase_txids[0],
                "vout": 0
            }], {node0_address: self._reward})
        # Set the time lock, ensuring we don't clobber the rest of the Sapling v4 tx format
        timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1)
        timelock_tx = timelock_tx[:-38] + hex(
            self.nodes[0].getblockcount() +
            2)[2:] + "000000" + timelock_tx[-30:]
        timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"]
        assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction,
                      timelock_tx)

        # Broadcast and mine spend_102 and 103:
        spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
        spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
        self.nodes[0].generate(1)
        assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction,
                      timelock_tx)

        # Create 102_1 and 103_1:
        spend_102_1_raw = self.create_tx(spend_102_id, node1_address,
                                         self._reward)
        spend_103_1_raw = self.create_tx(spend_103_id, node1_address,
                                         self._reward)

        # Broadcast and mine 103_1:
        spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
        last_block = self.nodes[0].generate(1)
        timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)

        # ... now put spend_101 and spend_102_1 in memory pools:
        spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
        spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)

        self.sync_all()

        assert_equal(set(self.nodes[0].getrawmempool()),
                     set([spend_101_id, spend_102_1_id, timelock_tx_id]))

        for node in self.nodes:
            node.invalidateblock(last_block[0])
        assert_equal(set(self.nodes[0].getrawmempool()),
                     set([spend_101_id, spend_102_1_id, spend_103_1_id]))

        # Use invalidateblock to re-org back and make all those coinbase spends
        # immature/invalid:
        for node in self.nodes:
            node.invalidateblock(new_blocks[0])

        self.sync_all()

        # mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())
示例#20
0
    def run_test(self):
        # Generate a Sapling address for node 1
        node1_zaddr = self.nodes[1].z_getnewaddress('sapling')

        self.nodes[1].stop()
        bitcoind_processes[1].wait()
        self.nodes[1] = self.start_node_with(1, [
            "-mineraddress=%s" % node1_zaddr,
        ])
        connect_nodes(self.nodes[1], 0)

        # Node 0 can mine blocks, because it is targeting a transparent address
        print("Mining block with node 0")
        self.nodes[0].generate(1)
        self.sync_all()
        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 3802400)
        assert_equal(walletinfo['balance'], 0)

        # Node 1 cannot mine blocks, because it is targeting a Sapling address
        # but Heartwood is not yet active
        print("Attempting to mine block with node 1")
        assert_raises(JSONRPCException, self.nodes[1].generate, 1)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 0)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 0)

        # Stop node 1 and check logs to verify the block was rejected correctly
        string_to_find = "CheckTransaction(): coinbase has output descriptions"
        check_node_log(self, 1, string_to_find)

        # Restart node 1
        self.nodes[1] = self.start_node_with(
            1, ["-mineraddress=%s" % node1_zaddr])
        connect_nodes(self.nodes[1], 0)

        # Activate Heartwood
        print("Activating Heartwood")
        self.nodes[0].generate(8)
        self.sync_all()

        # Node 1 can now mine blocks!
        print("Mining block with node 1")
        self.nodes[1].generate(1)
        self.sync_all()

        # Transparent coinbase outputs are subject to coinbase maturity
        assert_equal(self.nodes[0].getbalance(), Decimal('0'))
        assert_equal(self.nodes[0].z_gettotalbalance()['transparent'], '0.00')
        assert_equal(self.nodes[0].z_gettotalbalance()['private'], '0.00')
        assert_equal(self.nodes[0].z_gettotalbalance()['total'], '0.00')

        # Shielded coinbase outputs are not subject to coinbase maturity
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 97)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 97)
        assert_equal(self.nodes[1].z_gettotalbalance()['private'], '97.00')
        assert_equal(self.nodes[1].z_gettotalbalance()['total'], '97.00')

        # Send from Sapling coinbase to Sapling address and transparent address
        # (to check that a non-empty vout is allowed when spending shielded
        # coinbase)
        print("Sending Sapling coinbase to Sapling address")
        node0_zaddr = self.nodes[0].z_getnewaddress('sapling')
        node0_taddr = self.nodes[0].getnewaddress()
        recipients = []
        recipients.append({"address": node0_zaddr, "amount": Decimal('2')})
        recipients.append({"address": node0_taddr, "amount": Decimal('2')})
        myopid = self.nodes[1].z_sendmany(node1_zaddr, 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(self.nodes[0].z_getbalance(node0_zaddr), 2)
        assert_equal(self.nodes[0].z_getbalance(node0_taddr), 2)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 93)
示例#21
0
    def run_test(self):
        # Generate a Sapling address for node 1
        node1_zaddr = self.nodes[1].z_getnewaddress('sapling')

        self.nodes[1].stop()
        bitcoind_processes[1].wait()
        self.nodes[1] = self.start_node_with(1, [
            "-mineraddress=%s" % node1_zaddr,
        ])
        connect_nodes(self.nodes[1], 0)

        # Node 0 can mine blocks, because it is targeting a transparent address
        print("Mining block with node 0")
        self.nodes[0].generate(1)
        self.sync_all()
        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 5)
        assert_equal(walletinfo['balance'], 0)

        # Node 1 cannot mine blocks, because it is targeting a Sapling address
        # but Heartwood is not yet active
        print("Attempting to mine block with node 1")
        assert_raises(JSONRPCException, self.nodes[1].generate, 1)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 0)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 0)

        # Stop node 1 and check logs to verify the block was rejected correctly
        print("Checking node 1 logs")
        self.nodes[1].stop()
        bitcoind_processes[1].wait()
        logpath = self.options.tmpdir + "/node1/regtest/debug.log"
        foundErrorMsg = False
        with open(logpath, "r") as myfile:
            logdata = myfile.readlines()
        for logline in logdata:
            if "CheckTransaction(): coinbase has output descriptions" in logline:
                foundErrorMsg = True
                break
        assert (foundErrorMsg)

        # Restart node 1
        self.nodes[1] = self.start_node_with(1, [
            "-mineraddress=%s" % node1_zaddr,
        ])
        connect_nodes(self.nodes[1], 0)

        # Activate Heartwood
        print("Activating Heartwood")
        self.nodes[0].generate(8)
        self.sync_all()

        # Node 1 can now mine blocks!
        print("Mining block with node 1")
        self.nodes[1].generate(1)
        self.sync_all()

        # Transparent coinbase outputs are subject to coinbase maturity
        assert_equal(self.nodes[0].getbalance(), Decimal('0'))
        assert_equal(self.nodes[0].z_gettotalbalance()['transparent'], '0.00')
        assert_equal(self.nodes[0].z_gettotalbalance()['private'], '0.00')
        assert_equal(self.nodes[0].z_gettotalbalance()['total'], '0.00')

        # Shielded coinbase outputs are not subject to coinbase maturity
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 5)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 5)
        assert_equal(self.nodes[1].z_gettotalbalance()['private'], '5.00')
        assert_equal(self.nodes[1].z_gettotalbalance()['total'], '5.00')

        # Send from Sapling coinbase to Sapling address and transparent address
        # (to check that a non-empty vout is allowed when spending shielded
        # coinbase)
        print("Sending Sapling coinbase to Sapling address")
        node0_zaddr = self.nodes[0].z_getnewaddress('sapling')
        node0_taddr = self.nodes[0].getnewaddress()
        recipients = []
        recipients.append({"address": node0_zaddr, "amount": Decimal('2')})
        recipients.append({"address": node0_taddr, "amount": Decimal('2')})
        myopid = self.nodes[1].z_sendmany(node1_zaddr, 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(self.nodes[0].z_getbalance(node0_zaddr), 2)
        assert_equal(self.nodes[0].z_getbalance(node0_taddr), 2)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 1)
示例#22
0
    def run_test(self):
        print("Mining blocks...")
        self.nodes[0].generate(105)
        self.sync_all()

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

        node0utxos = self.nodes[0].listunspent(1)
        utxo1 = node0utxos.pop()
        tx1 = self.nodes[0].createrawtransaction([utxo1], {self.nodes[1].getnewaddress(): utxo1['amount']})
        txid1 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx1)["hex"])
        utxo2 = node0utxos.pop()
        tx2 = self.nodes[0].createrawtransaction([utxo2], {self.nodes[1].getnewaddress(): utxo2['amount']})
        txid2 = self.nodes[0].sendrawtransaction(self.nodes[0].signrawtransaction(tx2)["hex"])
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        hashlist = []
        resp = self.nodes[0].getrawtransaction(txid1, 1)
        txhash1 = resp['hash']
        resp = self.nodes[0].getrawtransaction(txid2, 1)
        txhash2 = resp['hash']
        hashlist.append(txhash1)
        hashlist.append(txhash2)
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1])), [txhash1])
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), hashlist)
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2], blockhash)), hashlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        tx3 = self.nodes[1].createrawtransaction([txin_spent], {self.nodes[0].getnewaddress(): txin_spent['amount']})
        self.nodes[0].sendrawtransaction(self.nodes[1].signrawtransaction(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_spent_hash = txhash1 if txin_spent["txid"] == txid1 else txhash2
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2
        txid_unspent_hash = txhash1 if txin_spent["txid"] != txid1 else txhash2

        # We cant find the block from a fully-spent tx
        assert_raises(JSONRPCException, self.nodes[2].gettxoutproof, [txid_spent])
        # ...but we can if we specify the block
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_spent], blockhash)), [txid_spent_hash])
        # ...or if the first tx is not fully-spent
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid_unspent])), [txid_unspent_hash])
        try:
            assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1, txid2])), hashlist)
        except JSONRPCException:
            assert_equal(self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid2, txid1])), hashlist)
        # ...or if we have a -txindex
        assert_equal(self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof([txid_spent])), [txid_spent_hash])

        # Quick test of getblock using blockhash and different levels of verbosity
        result = self.nodes[0].getblock(blockhash, 2)
        coinbase_txid = result["tx"][0]["txid"]
        result = self.nodes[0].getblock(blockhash, 1)
        assert_equal(coinbase_txid, result["tx"][0])  # verbosity 1 only lists txids
        result = self.nodes[0].getblock(blockhash, 0)
        assert(c in string.hexdigits for c in result) # verbosity 0 returns raw hex

        # Test getblock heights including negatives relative to the head
        assert_equal(self.nodes[0].getblock("0")["height"], 0)
        assert_raises(JSONRPCException, self.nodes[0].getblock, ["108"])
        assert_equal(self.nodes[0].getblock("107")["height"], 107)
        assert_equal(self.nodes[0].getblock("-1")["height"], 107)
        assert_equal(self.nodes[0].getblock("-2")["height"], 106)
        assert_equal(self.nodes[0].getblock("-20")["height"], 88)
        assert_equal(self.nodes[0].getblock("-107")["height"], 1)
        assert_equal(self.nodes[0].getblock("-108")["height"], 0)
        assert_raises(JSONRPCException, self.nodes[0].getblock, ["-109"])
        assert_raises(JSONRPCException, self.nodes[0].getblock, ["-0"])

        # Test getblockhash negative heights
        assert_equal(self.nodes[0].getblockhash(-1), self.nodes[0].getblockhash(107))
        assert_equal(self.nodes[0].getblockhash(-2), self.nodes[0].getblockhash(106))
示例#23
0
    def run_faucet_tests(self):
        rpc = self.rpc

        # basic sanity tests
        result = rpc.getwalletinfo()
        assert_greater_than(result['txcount'], 100)
        assert_greater_than(result['balance'], 0.0)
        balance = result['balance']

        faucet = rpc.faucetaddress()
        assert_equal(faucet['result'], 'success')
        # verify all keys look like valid AC addrs, could be better
        for x in [
                'myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress'
        ]:
            assert_equal(faucet[x][0], 'R')

        result = rpc.faucetaddress(self.pubkey)
        assert_success(result)
        # test that additional CCaddress key is returned
        for x in [
                'myCCaddress', 'FaucetCCaddress', 'Faucetmarker', 'myaddress',
                'CCaddress'
        ]:
            assert_equal(result[x][0], 'R')

        # no funds in the faucet yet
        result = rpc.faucetget()
        assert_error(result)

        result = rpc.faucetinfo()
        assert_success(result)

        result = rpc.faucetfund("0")
        assert_error(result)

        result = rpc.faucetfund("-1")
        assert_error(result)

        # we need at least 1 + txfee to get
        result = rpc.faucetfund("2")
        assert_success(result)
        assert result['hex'], "hex key found"

        # broadcast the xtn
        result = rpc.sendrawtransaction(result['hex'])
        txid = result[0]
        assert txid, "found txid"

        # we need the tx above to be confirmed in the next block
        rpc.generate(1)

        result = rpc.getwalletinfo()
        balance2 = result['balance']
        # make sure our balance is less now
        assert_greater_than(balance, balance2)

        result = rpc.faucetinfo()
        assert_success(result)
        assert_greater_than(result['funding'], 0)

        result = rpc.faucetget()
        assert_success(result)
        assert result['hex'], "hex key found"

        # try to broadcast the xtn, but we will get 'faucet is only for brand new addresses'
        assert_raises(JSONRPCException, rpc.sendrawtransaction,
                      [result['hex']])

        newaddr = rpc.getnewaddress()
        assert newaddr, "got a new address"
        result = rpc.validateaddress(newaddr)
        newpubkey = result['pubkey']
        assert newpubkey, "got a pubkey for new address"
示例#24
0
    def run_test(self):
        # Mine three blocks. After this, nodes[0] blocks
        # 101, 102, and 103 are spend-able.
        new_blocks = self.nodes[1].generate(4)
        self.sync_all()

        node0_address = self.nodes[0].getnewaddress()
        node1_address = self.nodes[1].getnewaddress()

        # Three scenarios for re-orging coinbase spends in the memory pool:
        # 1. Direct coinbase spend  :  spend_101
        # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1
        # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1
        # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase),
        # and make sure the mempool code behaves correctly.
        b = [ self.nodes[0].getblockhash(n) for n in range(101, 105) ]
        coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ]
        spend_101_raw = self.create_tx(coinbase_txids[1], node1_address, 10)
        spend_102_raw = self.create_tx(coinbase_txids[2], node0_address, 10)
        spend_103_raw = self.create_tx(coinbase_txids[3], node0_address, 10)

        # Create a block-height-locked transaction which will be invalid after reorg
        timelock_tx = self.nodes[0].createrawtransaction([{"txid": coinbase_txids[0], "vout": 0}], {node0_address: 10})
        # Set the time lock
        timelock_tx = timelock_tx.replace("ffffffff", "11111111", 1)
        timelock_tx = timelock_tx[:-8] + hex(self.nodes[0].getblockcount() + 2)[2:] + "000000"
        timelock_tx = self.nodes[0].signrawtransaction(timelock_tx)["hex"]
        assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)

        # Broadcast and mine spend_102 and 103:
        spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw)
        spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw)
        self.nodes[0].generate(1)
        assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, timelock_tx)

        # Create 102_1 and 103_1:
        spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 10)
        spend_103_1_raw = self.create_tx(spend_103_id, node1_address, 10)

        # Broadcast and mine 103_1:
        spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw)
        last_block = self.nodes[0].generate(1)
        timelock_tx_id = self.nodes[0].sendrawtransaction(timelock_tx)

        # ... now put spend_101 and spend_102_1 in memory pools:
        spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw)
        spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw)

        self.sync_all()

        assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id, timelock_tx_id ]))

        for node in self.nodes:
            node.invalidateblock(last_block[0])
        assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id, spend_103_1_id ]))

        # Use invalidateblock to re-org back and make all those coinbase spends
        # immature/invalid:
        for node in self.nodes:
            node.invalidateblock(new_blocks[0])

        self.sync_all()

        # mempool should be empty.
        assert_equal(set(self.nodes[0].getrawmempool()), set())
示例#25
0
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(105)
        self.sync_all()

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

        node0utxos = self.nodes[0].listunspent(1)
        tx1 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[1].getnewaddress(): 11.4375})
        txid1 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx1)["hex"])
        tx2 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[1].getnewaddress(): 11.4375})
        txid2 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx2)["hex"])
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1
                                                                        ])),
            [txid1])
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2])), txlist)
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2], blockhash)), txlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        tx3 = self.nodes[1].createrawtransaction(
            [txin_spent], {self.nodes[0].getnewaddress(): 11.4375})
        self.nodes[0].sendrawtransaction(
            self.nodes[1].signrawtransaction(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2

        # We cant find the block from a fully-spent tx
        assert_raises(JSONRPCException, self.nodes[2].gettxoutproof,
                      [txid_spent])
        # ...but we can if we specify the block
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_spent], blockhash)), [txid_spent])
        # ...or if the first tx is not fully-spent
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_unspent])), [txid_unspent])
        try:
            assert_equal(
                self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                    [txid1, txid2])), txlist)
        except JSONRPCException:
            assert_equal(
                self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                    [txid2, txid1])), txlist)
        # ...or if we have a -txindex
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof(
                [txid_spent])), [txid_spent])

        # send funds to node 2, it will use them for sending a certificate
        tx0 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[2].getnewaddress(): 11.4375})
        self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx0)["hex"])

        # reach sc fork and create a SC
        self.nodes[0].generate(MINIMAL_SC_HEIGHT - 105)
        self.sync_all()
        prev_epoch_hash = self.nodes[0].getbestblockhash()

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

        certMcTest = CertTestUtils(self.options.tmpdir, self.options.srcdir)
        cswMcTest = CSWTestUtils(self.options.tmpdir, self.options.srcdir)

        # generate wCertVk and constant
        certVk = certMcTest.generate_params("sc")
        cswVk = cswMcTest.generate_params("sc")
        constant1 = generate_random_field_element_hex()

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

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

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

        # advance 1 epoch
        mark_logs("\nLet 1 epochs pass by...", self.nodes, DEBUG_MODE)
        q = 1
        cert_fee = Decimal("0.0")

        cert, epoch_number = advance_epoch(certMcTest, self.nodes[2],
                                           self.sync_all, scid, "sc",
                                           constant1, sc_epoch_len, q,
                                           cert_fee)

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

        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [cert])

        # send some coin for having a tx in the next block as well
        t_addr1 = self.nodes[1].getnewaddress()
        tx = self.nodes[0].sendtoaddress(t_addr1, 0.1)
        self.sync_all()

        # mine one block for having last cert and tx in chain
        mark_logs("\nNode0 generates 1 block confirming last cert and tx",
                  self.nodes, DEBUG_MODE)
        bl_hash = self.nodes[0].generate(1)[-1]
        self.sync_all()

        proof1 = self.nodes[1].gettxoutproof([cert])
        proof2 = self.nodes[2].gettxoutproof([tx, cert])

        assert_equal(self.nodes[2].verifytxoutproof(proof1), [cert])
        assert_equal(self.nodes[2].verifytxoutproof(proof2), [tx, cert])

        # spend cert change: since there are no bwts in the cert, it will be fully spent
        tx = self.nodes[2].sendtoaddress(t_addr1, 0.1)
        self.sync_all()

        mark_logs("\nNode0 generates 1 block confirming last tx", self.nodes,
                  DEBUG_MODE)
        self.nodes[0].generate(1)
        self.sync_all()

        # We cant find the block from a fully-spent cert
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [cert])
        # ...but we can if we specify the block
        proof = self.nodes[0].gettxoutproof([cert], bl_hash)
        # ...or if we have a -txindex
        proof = self.nodes[3].gettxoutproof([cert])

        assert_equal(self.nodes[0].verifytxoutproof(proof), [cert])
示例#26
0
    def run_test(self):
        print "Mining blocks..."
        self.nodes[0].generate(105)
        self.sync_all()

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

        node0utxos = self.nodes[0].listunspent(1)
        # ZEN_MOD_START
        tx1 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[1].getnewaddress(): 11.4375})
        # ZEN_MOD_END
        txid1 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx1)["hex"])
        # ZEN_MOD_START
        tx2 = self.nodes[0].createrawtransaction(
            [node0utxos.pop()], {self.nodes[1].getnewaddress(): 11.4375})
        # ZEN_MOD_END
        txid2 = self.nodes[0].sendrawtransaction(
            self.nodes[0].signrawtransaction(tx2)["hex"])
        assert_raises(JSONRPCException, self.nodes[0].gettxoutproof, [txid1])

        self.nodes[0].generate(1)
        blockhash = self.nodes[0].getblockhash(chain_height + 1)
        self.sync_all()

        txlist = []
        blocktxn = self.nodes[0].getblock(blockhash, True)["tx"]
        txlist.append(blocktxn[1])
        txlist.append(blocktxn[2])

        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof([txid1
                                                                        ])),
            [txid1])
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2])), txlist)
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid1, txid2], blockhash)), txlist)

        txin_spent = self.nodes[1].listunspent(1).pop()
        # ZEN_MOD_START
        tx3 = self.nodes[1].createrawtransaction(
            [txin_spent], {self.nodes[0].getnewaddress(): 11.4375})
        # ZEN_MOD_END
        self.nodes[0].sendrawtransaction(
            self.nodes[1].signrawtransaction(tx3)["hex"])
        self.nodes[0].generate(1)
        self.sync_all()

        txid_spent = txin_spent["txid"]
        txid_unspent = txid1 if txin_spent["txid"] != txid1 else txid2

        # We cant find the block from a fully-spent tx
        assert_raises(JSONRPCException, self.nodes[2].gettxoutproof,
                      [txid_spent])
        # ...but we can if we specify the block
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_spent], blockhash)), [txid_spent])
        # ...or if the first tx is not fully-spent
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                [txid_unspent])), [txid_unspent])
        try:
            assert_equal(
                self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                    [txid1, txid2])), txlist)
        except JSONRPCException:
            assert_equal(
                self.nodes[2].verifytxoutproof(self.nodes[2].gettxoutproof(
                    [txid2, txid1])), txlist)
        # ...or if we have a -txindex
        assert_equal(
            self.nodes[2].verifytxoutproof(self.nodes[3].gettxoutproof(
                [txid_spent])), [txid_spent])
    def run_test(self):
        # Generate a Sapling address for node 1
        node1_zaddr = self.nodes[1].z_getnewaddress('sapling')

        self.nodes[1].stop()
        bitcoind_processes[1].wait()
        self.nodes[1] = self.start_node_with(1, [
            "-mineraddress=%s" % node1_zaddr,
        ])
        connect_nodes(self.nodes[1], 0)

        # Node 0 can mine blocks, because it is targeting a transparent address
        print("Mining block with node 0")
        self.nodes[0].generate(1)
        self.sync_all()
        walletinfo = self.nodes[0].getwalletinfo()
        assert_equal(walletinfo['immature_balance'], 5)
        assert_equal(walletinfo['balance'], 0)

        # Node 1 cannot mine blocks, because it is targeting a Sapling address
        # but Heartwood is not yet active
        print("Attempting to mine block with node 1")
        assert_raises(JSONRPCException, self.nodes[1].generate, 1)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 0)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 0)

        # Stop node 1 and check logs to verify the block was rejected correctly
        string_to_find = "CheckTransaction(): coinbase has output descriptions"
        check_node_log(self, 1, string_to_find)

        # Restart node 1
        self.nodes[1] = self.start_node_with(
            1, ["-mineraddress=%s" % node1_zaddr])
        connect_nodes(self.nodes[1], 0)

        # Activate Heartwood
        print("Activating Heartwood")
        self.nodes[0].generate(8)
        self.sync_all()

        # Node 1 can now mine blocks!
        print("Mining block with node 1")
        self.nodes[1].generate(1)
        self.sync_all()

        # Transparent coinbase outputs are subject to coinbase maturity
        assert_equal(self.nodes[0].getbalance(), Decimal('0'))
        assert_equal(self.nodes[0].z_gettotalbalance()['transparent'], '0.00')
        assert_equal(self.nodes[0].z_gettotalbalance()['private'], '0.00')
        assert_equal(self.nodes[0].z_gettotalbalance()['total'], '0.00')

        # Shielded coinbase outputs are not subject to coinbase maturity
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr, 0), 5)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 5)
        assert_equal(self.nodes[1].z_gettotalbalance()['private'], '5.00')
        assert_equal(self.nodes[1].z_gettotalbalance()['total'], '5.00')

        # Send from Sapling coinbase to Sapling address and transparent address
        # (to check that a non-empty vout is allowed when spending shielded
        # coinbase)
        print("Sending Sapling coinbase to Sapling address")
        node0_zaddr = self.nodes[0].z_getnewaddress('sapling')
        node0_taddr = self.nodes[0].getnewaddress()
        recipients = []
        recipients.append({"address": node0_zaddr, "amount": Decimal('2')})
        recipients.append({"address": node0_taddr, "amount": Decimal('2')})
        myopid = self.nodes[1].z_sendmany(node1_zaddr, 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(self.nodes[0].z_getbalance(node0_zaddr), 2)
        assert_equal(self.nodes[0].z_getbalance(node0_taddr), 2)
        assert_equal(self.nodes[1].z_getbalance(node1_zaddr), 1)

        # Generate a Unified Address for node 1
        self.nodes[1].z_getnewaccount()
        node1_addr0 = self.nodes[1].z_getaddressforaccount(0)
        assert_equal(node1_addr0['account'], 0)
        assert_equal(set(node1_addr0['receiver_types']),
                     set(['p2pkh', 'sapling', 'orchard']))
        node1_ua = node1_addr0['address']

        # Set node 1's miner address to the UA
        self.nodes[1].stop()
        bitcoind_processes[1].wait()
        self.nodes[1] = self.start_node_with(1, [
            "-mineraddress=%s" % node1_ua,
        ])
        connect_nodes(self.nodes[1], 0)

        # The UA starts with zero balance.
        assert_equal(self.nodes[1].z_getbalanceforaccount(0)['pools'], {})

        # Node 1 can mine blocks because the miner selects the Sapling receiver
        # of its UA.
        print("Mining block with node 1")
        self.nodes[1].generate(1)
        self.sync_all()

        # The UA balance should show that Sapling funds were received.
        assert_equal(self.nodes[1].z_getbalanceforaccount(0)['pools'], {
            'sapling': {
                'valueZat': 5 * COIN
            },
        })

        # Activate NU5
        print("Activating NU5")
        self.nodes[0].generate(7)
        self.sync_all()

        # Now any block mined by node 1 should use the Orchard receiver of its UA.
        print("Mining block with node 1")
        self.nodes[1].generate(1)
        self.sync_all()
        assert_equal(
            self.nodes[1].z_getbalanceforaccount(0)['pools'],
            {
                'sapling': {
                    'valueZat': 5 * COIN
                },
                # 6.25 ZEC because the FR always ends when Canopy activates, and
                # regtest has no defined funding streams.
                'orchard': {
                    'valueZat': 6.25 * COIN
                },
            })