def test_no_blockhash(self):
        txid = self.nodes[2].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        blockhash, = self.nodes[2].generate(1)
        self.sync_all()

        txs = self.nodes[0].listtransactions()
        assert_array_result(txs, {"txid": txid}, {
            "category": "receive",
            "amount": 1,
            "blockhash": blockhash,
            "confirmations": 1,
        })
        assert_equal(self.nodes[0].listsinceblock(), {
            "lastblock": blockhash,
            "removed": [],
            "transactions": txs
        })
        assert_equal(self.nodes[0].listsinceblock(""), {
            "lastblock": blockhash,
            "removed": [],
            "transactions": txs
        })

        # contract test
        co = Contract(self.nodes[2])
        co.call_payable()
        txid = co.call_sendCoinTest(self.nodes[0].getnewaddress(), 1)['txid']
        self.sync_all()
        assert txid in self.nodes[0].getrawmempool()
        blockhash, = self.nodes[2].generate(1)
        blockhash, = self.nodes[2].generate(1)
        assert txid not in self.nodes[2].getrawmempool()
        assert txid not in self.nodes[0].getrawmempool()
        self.sync_all()
        txs = self.nodes[0].listtransactions()
Exemplo n.º 2
0
    def test_publish_fork_with_utxo(self, is_contract_output=False):
        '''
             ab0[utxo1]
          /         \
        aa1 [ca1]   bb1 [cb1]
         |           |
        aa2         bb2
         |           |
        aa3         bb3
                     |
                    bb4
                     |
                    ...
        :param contract_output:
        :return:
        '''
        hex_content = get_contract_hex(self.contract_file)
        coster = self.node0.getnewaddress()
        if is_contract_output:
            ct = Contract(self.node0, self.options.tmpdir, debug=False)
            tmp_tx1 = ct.call_payable(amount=2000)['txid']
            tmp_tx2 = ct.call_sendCoinTest(coster, 1000)['txid']
            # print(ct.publish_txid, tmp_tx1, tmp_tx2)
        else:
            self.node0.sendtoaddress(coster, 1000)
        self.node0.generate(2)
        self.sync_all()
        blocks_num = self.node1.getblockcount()
        '''
        分割成2个网络,然后各自用同一个utxo发布合约
        '''
        self.split_network()
        sender_pub = self.node0.validateaddress(coster)['pubkey']
        sender_pri = self.node0.dumpprivkey(coster)
        amount = 0
        changeaddress = self.node0.getnewaddress()
        result = self.publish_contract(self.node0, hex_content, coster,
                                       sender_pub, sender_pri, amount,
                                       changeaddress)
        # print(result)
        txid_a1 = result['txid']
        contract_a1 = result['contractaddress']
        # 第一组节点同步,这是该组链高度应该为12
        block_a1, block_a2 = self.node0.generate(2)
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        assert_equal(self.node1.getblockcount(), blocks_num + 2)
        assert_equal(self.node1.getbestblockhash(), block_a2)
        last_block_hash = block_a2

        # 第二组开始发布合约
        amount = 1
        changeaddress = self.node2.getnewaddress()
        result = self.publish_contract(self.node2, hex_content, coster,
                                       sender_pub, sender_pri, amount,
                                       changeaddress)
        # print(result)
        txid_b1 = result['txid']
        contract_b1 = result['contractaddress']
        # 第二组节点同步,这是该组链高度应该为22
        block_b13 = self.node2.generate(12)[11]
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        assert_equal(self.node2.getblockcount(), blocks_num + 12)
        assert_equal(self.node2.getbestblockhash(), block_b13)

        blocks = self.make_more_work_than(2, 0)

        # 合并网络
        for i in range(4):
            print("before join:", i, self.nodes[i].getblockcount(),
                  int(self.nodes[i].getchaintipwork(), 16))
        self.join_network()
        for i in range(4):
            print(i, self.nodes[i].getblockcount(),
                  int(self.nodes[i].getchaintipwork(), 16))
        # 确认存在分叉存在,并且主链为22个区块的
        tips = self.nodes[0].getchaintips()
        # print(tips)
        assert_equal(len(tips), self.tips_num + 1)
        self.tips_num += 1
        assert_equal(self.node2.getblockcount(), blocks_num + 12 + len(blocks))
        assert_equal(self.node2.getbestblockhash(),
                     block_b13 if not blocks else blocks[-1])
        self.node0.gettransaction(txid_a1)
        # 确认分叉上的合约在主链上不能被调用
        assert_raises_rpc_error(
            -1, "CallContractReal => GetContractInfo fail, contractid is " +
            contract_a1, self.node0.callcontract, True, 1, contract_a1,
            self.node0.getnewaddress(), "payable")
        # 主链合约是可以调用的
        self.node0.callcontract(True, 1, contract_b1,
                                self.node0.getnewaddress(), "payable")
        # 未完成的用例,下面的有问题,先屏蔽
        # '''
        # listsinceblock(lastblockhash) should now include txid_a1, as seen from nodes[0]
        # 这里只有node0节点才成功,换成其他节点时失败的,这不应该
        # '''
        lsbres = self.nodes[0].listsinceblock(last_block_hash)
        assert any(
            tx['txid'] == txid_a1
            for tx in lsbres['removed'])  # 这里只有node0节点才成功,换成其他节点时失败的,这不应该

        # but it should not include 'removed' if include_removed=false
        lsbres2 = self.nodes[0].listsinceblock(blockhash=last_block_hash,
                                               include_removed=False)
        assert 'removed' not in lsbres2
    def run_test(self):
        self.nodes[1].generate(2)
        sync_blocks(self.nodes)
        balance = self.nodes[0].getbalance()
        contract_obj = Contract(self.nodes[0], self.options.tmpdir)  #构造合约
        txA = contract_obj.publish_txid  #发布合约的交易ID
        txB = contract_obj.call_payable(amount=1)['txid']
        txC = contract_obj.call_payable(amount=1)['txid']
        sync_mempools(self.nodes)
        self.nodes[1].generate(1)

        sync_blocks(self.nodes)
        newbalance = self.nodes[0].getbalance()
        print(balance - newbalance)
        assert (balance - newbalance < Decimal("19.67900001")
                )  # no more than fees lost
        balance = newbalance

        # Disconnect nodes so node0's transactions don't get into node1's mempool
        disconnect_nodes(self.nodes[0], 1)

        # Identify the contract outputs
        # 分别获取发布合约与调用合约的交易输出
        nA, vA = next((i, vout["value"])
                      for i, vout in enumerate(self.nodes[0].getrawtransaction(
                          txA, 1)["vout"]) if vout["value"] != Decimal("1"))
        nB, vB = next((i, vout["value"])
                      for i, vout in enumerate(self.nodes[0].getrawtransaction(
                          txB, 1)["vout"]) if vout["value"] != Decimal("1"))
        nC, vC = next((i, vout["value"])
                      for i, vout in enumerate(self.nodes[0].getrawtransaction(
                          txC, 1)["vout"]) if vout["value"] != Decimal("1"))

        # self.stop_node(0)
        # self.start_node(0, extra_args=["-minrelaytxfee=0.001"])
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        assert_equal(self.nodes[0].getbalance(), balance)
        inputs = []
        # spend 9985.026 + 9997.646 mgc outputs from txD and txE
        # 花费掉vA和vB
        inputs.append({"txid": txA, "vout": nA})
        inputs.append({"txid": txB, "vout": nB})
        outputs = {}
        outputs[self.nodes[0].getnewaddress()] = Decimal(int(vA))
        outputs[self.nodes[1].getnewaddress()] = Decimal(int(vB))
        signed = self.nodes[0].signrawtransaction(
            self.nodes[0].createrawtransaction(inputs, outputs))
        txAB1 = self.nodes[0].sendrawtransaction(signed["hex"])

        # Identify the 9985mgc output
        # 找到va的输出
        nAB, vAB = next((i, vout["value"]) for i, vout in enumerate(
            self.nodes[0].getrawtransaction(txAB1, 1)["vout"])
                        if vout["value"] == Decimal(int(vA)))

        # Create a child tx spending AB1 and C
        inputs = []
        inputs.append({"txid": txAB1, "vout": nAB})
        inputs.append({"txid": txC, "vout": nC})
        outputs = {}
        addrABC2 = self.nodes[0].getnewaddress()
        outputs[addrABC2] = Decimal("19977")
        signed2 = self.nodes[0].signrawtransaction(
            self.nodes[0].createrawtransaction(inputs, outputs))
        txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"])

        # In mempool txs from self should increase balance from change
        newbalance = self.nodes[0].getbalance()
        print(
            newbalance, balance, balance - newbalance, newbalance -
            (balance - Decimal(str(vA + vB + vC)) + Decimal("19977")))
        assert_equal(newbalance,
                     balance - Decimal(str(vA + vB + vC)) + Decimal("19977"))
        balance = newbalance

        # Restart the node with a higher min relay fee so the parent tx is no longer in mempool
        # TODO: redo with eviction
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=10.00000"])

        # Verify txs no longer in either node's mempool
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        assert_equal(len(self.nodes[1].getrawmempool()), 0)

        # Not in mempool txs from self should only reduce balance
        # inputs are still spent, but change not received
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance - Decimal("19977"))
        # Unconfirmed received funds that are not in mempool, also shouldn't show
        # up in unconfirmed balance
        unconfbalance = self.nodes[0].getunconfirmedbalance(
        ) + self.nodes[0].getbalance()
        assert_equal(unconfbalance, newbalance)
        # Also shouldn't show up in listunspent
        x = self.nodes[0].listunspent(1, 9999999, [addrABC2])
        assert (not txABC2 in [utxo["txid"] for utxo in x])
        balance = newbalance

        # Abandon original transaction and verify inputs are available again
        # including that the child tx was also abandoned
        self.nodes[0].abandontransaction(txAB1)
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance + Decimal(str(vA + vB + vC)))
        balance = newbalance

        # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=0.00001"])
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        assert_equal(self.nodes[0].getbalance(), balance)

        # But if its received again then it is unabandoned
        # And since now in mempool, the change is available
        # But its child tx remains abandoned
        # There is currently a bug around this and so this test doesn't work.  See Issue #0060 in testin
        self.nodes[0].sendrawtransaction(signed["hex"])
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance,
                     balance - Decimal(str(vA + vB)) + Decimal(int(vA)))
        balance = newbalance

        # Send child tx again so its unabandoned
        self.nodes[0].sendrawtransaction(signed2["hex"])
        newbalance = self.nodes[0].getbalance()
        assert_equal(
            newbalance,
            balance - Decimal(int(vAB)) - Decimal(vC) + Decimal("19977"))
        balance = newbalance

        # Remove using high relay fee again
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=10.00000"])
        assert_equal(len(self.nodes[0].getrawmempool()), 0)
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance - Decimal("19977"))
        balance = newbalance

        # Create a double spend of AB1 by spending again from only A's 10 output
        # Mine double spend from node 1
        inputs = []
        inputs.append({"txid": txA, "vout": nA})
        inputs.append({"txid": txC, "vout": nC})
        outputs = {}
        outputs[self.nodes[1].getnewaddress()] = Decimal("19950")
        tx = self.nodes[0].createrawtransaction(inputs, outputs)
        signed = self.nodes[0].signrawtransaction(tx)
        self.nodes[1].sendrawtransaction(signed["hex"])
        self.nodes[1].generate(1)

        connect_nodes(self.nodes[0], 1)
        sync_blocks(self.nodes)

        # Verify that B and C's 10 MGC outputs are available for spending again because AB1 is now conflicted
        newbalance = self.nodes[0].getbalance()
        assert_equal(newbalance, balance + Decimal(vC))
        balance = newbalance

        # There is currently a minor bug around this and so this test doesn't work.  See Issue #7315
        # Invalidate the block with the double spend and B's 10 MGC output should no longer be available
        # Don't think C's should either
        self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
        newbalance = self.nodes[0].getbalance()
        # assert_equal(newbalance, balance - Decimal("10"))
        self.log.info(
            "If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer"
        )
        self.log.info(
            "conflicted has not resumed causing its inputs to be seen as spent.  See Issue #7315"
        )
        self.log.info(str(balance) + " -> " + str(newbalance) + " ?")

        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=0.00001"])
        disconnect_nodes(self.nodes[0], 1)
        node = self.nodes[0]
        node.generate(2)
        assert_equal([], node.getrawmempool())  # make sure mempool is empty
        new_address = node.getnewaddress()
        balance = node.getbalance()
        contract_balance = node.getbalanceof(contract_obj.contract_id)
        amount = 1
        txD = contract_obj.call_sendCoinTest(new_address, amount,
                                             amount=0)['txid']
        txE = contract_obj.call_sendCoinTest(new_address, amount,
                                             amount=0)['txid']
        txD_fee = self.get_txfee(txD)
        txE_fee = self.get_txfee(txE)
        newbalance = node.getbalance()
        assert_equal(contract_balance,
                     node.getbalanceof(contract_obj.contract_id))

        # 放弃合约的sendcoin交易
        self.stop_node(0)
        self.start_node(0, extra_args=["-minrelaytxfee=10.0000"])
        assert_equal([], node.getrawmempool())  # make sure mempool is empty
        assert_equal(newbalance, balance + txD_fee + txE_fee)
        node.abandontransaction(txD)
        node.abandontransaction(txE)
        assert_equal(node.getbalance(), balance)
        node.generate(2)
        assert_equal(contract_balance,
                     node.getbalanceof(contract_obj.contract_id))
    def run_test(self):
        self.nodes[0].generate(2)
        # Simple send, 0 to 1:
        txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10)
        self.sync_all()
        assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, {
            "category": "send",
            "account": "",
            "amount": Decimal("-10"),
            "confirmations": 0
        })
        assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, {
            "category": "receive",
            "account": "",
            "amount": Decimal("10"),
            "confirmations": 0
        })
        # mine a block, confirmations should change:
        self.nodes[0].generate(1)
        self.sync_all()
        array0 = [
            o
            for i, o in enumerate(self.nodes[0].listtransactions("*", 1000, 0))
            if o["txid"] == txid
        ]
        array1 = [
            o
            for i, o in enumerate(self.nodes[1].listtransactions("*", 1000, 0))
            if o["txid"] == txid
        ]
        assert_array_result(array0, {"txid": txid}, {
            "category": "send",
            "account": "",
            "amount": Decimal("-10"),
            "confirmations": 1
        })
        assert_array_result(array1, {"txid": txid}, {
            "category": "receive",
            "account": "",
            "amount": Decimal("10"),
            "confirmations": 1
        })

        # send-to-self:
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2)
        assert_array_result(self.nodes[0].listtransactions(), {
            "txid": txid,
            "category": "send"
        }, {"amount": Decimal("-0.2")})
        assert_array_result(self.nodes[0].listtransactions(), {
            "txid": txid,
            "category": "receive"
        }, {"amount": Decimal("0.2")})

        # sendmany from node1: twice to self, twice to node2:
        send_to = {
            self.nodes[0].getnewaddress(): 0.11,
            self.nodes[1].getnewaddress(): 0.22,
            self.nodes[0].getaccountaddress("from1"): 0.33,
            self.nodes[1].getaccountaddress("toself"): 0.44
        }

        sender = self.nodes[1].getnewaddress("1")
        for i in range(4):
            self.nodes[1].sendtoaddress(sender, 0.5)
        self.nodes[1].generate(1)
        txid = self.nodes[1].sendmany("1", send_to)
        self.sync_all()
        assert_array_result(self.nodes[1].listtransactions(), {
            "category": "send",
            "amount": Decimal("-0.11")
        }, {"txid": txid})
        assert_array_result(self.nodes[0].listtransactions(), {
            "category": "receive",
            "amount": Decimal("0.11")
        }, {"txid": txid})
        assert_array_result(self.nodes[1].listtransactions(), {
            "category": "send",
            "amount": Decimal("-0.22")
        }, {"txid": txid})
        assert_array_result(self.nodes[1].listtransactions(), {
            "category": "receive",
            "amount": Decimal("0.22")
        }, {"txid": txid})
        assert_array_result(self.nodes[1].listtransactions(), {
            "category": "send",
            "amount": Decimal("-0.33")
        }, {"txid": txid})
        assert_array_result(self.nodes[0].listtransactions(), {
            "category": "receive",
            "amount": Decimal("0.33")
        }, {
            "txid": txid,
            "account": "from1"
        })
        assert_array_result(self.nodes[1].listtransactions(), {
            "category": "send",
            "amount": Decimal("-0.44")
        }, {
            "txid": txid,
            "account": "1"
        })
        assert_array_result(self.nodes[1].listtransactions(), {
            "category": "receive",
            "amount": Decimal("0.44")
        }, {
            "txid": txid,
            "account": "toself"
        })

        multisig = self.nodes[1].createmultisig(
            1, [self.nodes[1].getnewaddress()])
        self.nodes[0].importaddress(multisig["redeemScript"], "watchonly",
                                    False, True)
        txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
        self.nodes[1].generate(1)
        self.sync_all()
        assert (len(self.nodes[0].listtransactions("watchonly", 100, 0,
                                                   False)) == 0)
        assert_array_result(
            self.nodes[0].listtransactions("watchonly", 100, 0, True), {
                "category": "receive",
                "amount": Decimal("0.1")
            }, {
                "txid": txid,
                "account": "watchonly"
            })

        self.run_rbf_opt_in_test()

        # add contract test
        print(self.nodes[0].getbalance())
        co = Contract(self.nodes[0], self.options.tmpdir)
        txid, contract_id = co.publish_txid, co.contract_id
        co.call_payable()
        self.sync_all()
        array0 = [
            o for i, o in enumerate(self.nodes[0].listtransactions())
            if o["txid"] == txid
        ]
        assert array0 != []
        txid = co.call_sendCoinTest(self.nodes[1].getnewaddress(), 1)['txid']
        self.sync_all()
        assert [
            o for i, o in enumerate(self.nodes[1].listtransactions())
            if o["txid"] == txid
        ] != []
    def test_double_sendcoins(self):
        '''
        测试同一个合约,分别在主链与分叉链上转走全部金额到不同的地址
        理论短链的交易不应该打回到内存池,因为合约没钱
        ab0[contract_ab]
          /         \
        aa1 [cca1]   bb1 [ccb1]
         |           |
        aa2         bb2
         |           |
        aa3         bb3
                     |
                    bb4
                     |
                    ...
        :return:
        '''
        self.sync_all()
        self.node0.generate(2)
        assert_equal(self.node0.getrawmempool(), [])  # make sure mempool empty
        assert_equal(self.node1.getrawmempool(), [])  # make sure mempool empty
        ct = Contract(self.node1, self.options.tmpdir, debug=False)
        ct.call_payable(amount=100)
        print(ct.publish_txid)
        self.sync_all()
        self.node0.generate(2)
        self.sync_all()
        blocks_num = self.node1.getblockcount()
        contract_balance = 100

        # split mgc network
        self.split_network()
        self.node1.generate(2)  # fork
        self.node3.generate(8)  # fork

        # in group 1
        addr_N1 = self.node1.getnewaddress()
        txid1 = ct.call_sendCoinTest(addr_N1, contract_balance, amount=0).txid
        self.node1.generate(2)
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        assert_equal(self.node1.getbalanceof(addr_N1), 100)
        assert_equal(ct.get_balance(), 0)

        # in group 2
        addr_N3 = self.node3.getnewaddress()
        txid2 = ct.call_sendCoinTest(addr_N3,
                                     contract_balance,
                                     amount=0,
                                     exec_node=self.node3).txid
        self.node3.generate(3)
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        assert_equal(self.node3.getbalanceof(addr_N3), 100)
        assert_equal(ct.get_balance(exec_node=self.node3), 0)

        # join network
        print("join network")
        connect_nodes_bi(self.nodes, 1, 2)
        sync_blocks(self.nodes)

        for i in range(4):
            print("mempool:", self.nodes[i].getrawmempool())
        # 确认存在分叉存在
        tips = self.nodes[1].getchaintips()
        print(tips)
        assert_equal(len(tips), self.tips_num + 1)
        self.tips_num += 1

        # assert
        assert_equal(self.node1.getbalanceof(addr_N1), 0)
        assert_equal(self.node3.getbalanceof(addr_N3), contract_balance)
        assert_equal(ct.get_balance(), 0)
        assert_equal(ct.get_balance(exec_node=self.node3), 0)
        assert txid1 not in self.node1.getrawmempool()