Beispiel #1
0
    def test_callcontract_fork(self, with_send=False, crash_point=1):
        '''
        调用同一合约,不含send操作与含send操作
        ab0[contract_ab]
          /         \
        aa1 [cca1]   bb1 [ccb1]
         |           |
        aa2         bb2
         |           |
        aa3         bb3
                     |
                    bb4
                     |
                    ...
        :param with_send:
        :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)
        ct2 = Contract(self.node1, self.options.tmpdir, debug=False)
        ct2.call_payable(amount=1000)
        print(ct.publish_txid)
        self.sync_all()
        self.node0.generate(2)
        self.sync_all()
        blocks_num = self.node1.getblockcount()

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

        # in group 1
        balance = self.node1.getbalance()

        # tx_ai,tx_a11,tx_a12这3个交易,在合并网络后,应该都会被重新打回内存池中,毕竟是短链
        tx_a1 = ct.call_payable(amount=2000)['txid']
        tx_a11 = ct.call_contractDataTest(amount=0)['txid']
        tx_a12 = ct.call_contractDataTest(amount=0)['txid']
        if with_send:
            tmp_ct = Contract(self.node1, debug=False)
            print(tmp_ct.publish_txid)
            # why after this call ,ct balance at node1 is 1980,it should 1990
            tx_a13 = ct.call_callOtherContractTest(ct2.contract_id,
                                                   'callOtherContractTest',
                                                   tmp_ct.contract_id,
                                                   "contractDataTest",
                                                   amount=0)
            print("ct balance:", ct.get_balance())
            print(tx_a13.txid)
        print(tx_a1, tx_a11, tx_a12)
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        last_block_hash = self.node1.generate(2)[-1]
        assert self.node1.getrawmempool() == []
        self.sync_all([self.nodes[:2], self.nodes[2:]])

        # in group 2
        tx_b1 = ct.call_payable(amount=2000,
                                exec_node=self.node3,
                                sender=self.node3.getnewaddress())['txid']
        print(tx_b1)
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        self.node3.generate(2)
        self.sync_all([self.nodes[:2], self.nodes[2:]])
        assert tx_b1 not in self.node3.getrawmempool()
        tx_b11 = ct.call_contractDataTest(amount=0,
                                          exec_node=self.node3)['txid']
        print("ct balance:", ct.get_balance(exec_node=self.node3))
        if with_send:
            # 这里有两个crash point,下面代码分别对应不同的CP
            if crash_point == 1:
                tx_b12 = ct.call_callOtherContractTest(ct2.contract_id,
                                                       'callOtherContractTest',
                                                       ct.contract_id,
                                                       "contractDataTest",
                                                       exec_node=self.node3,
                                                       amount=0)
                print("ct balance at node3:",
                      ct.get_balance(exec_node=self.node3))

            else:
                # 这里也在node1中的内存池?
                tx_b12 = ct.call_callOtherContractTest(ct2.contract_id,
                                                       'callOtherContractTest',
                                                       ct.contract_id,
                                                       "contractDataTest",
                                                       amount=0)
                tx_b13 = ct.call_reentrancyTest(amount=0).txid
                print("tx_b13:", tx_b13)
                print("ct balance:", ct.get_balance(exec_node=self.node1))
            print("ct balance at node3:", ct.get_balance(exec_node=self.node3))
            print("ct balance at node1:", ct.get_balance(exec_node=self.node1))
            print("tx_b12:", tx_b12.txid)
        print(tx_b11)
        block_b16 = self.node3.generate(6)[-1]
        assert_equal(self.node3.getrawmempool(), [])
        if with_send and crash_point == 1:
            assert_equal(self.node1.getrawmempool(), [])
        elif with_send and crash_point == 2:
            assert_equal(sorted(self.node1.getrawmempool()),
                         sorted([tx_b12.txid, tx_b13]))
        self.sync_all([self.nodes[:2], self.nodes[2:]])

        # join network
        more_work_blocks = self.make_more_work_than(3, 1)
        for i in range(4):
            print("before join:", i, self.nodes[i].getblockcount(),
                  int(self.nodes[i].getchaintipwork(), 16))
            print("mempool:", self.nodes[i].getrawmempool())

        print("ct balance at node3:", ct.get_balance(exec_node=self.node3))
        print("ct balance at node1:", ct.get_balance(exec_node=self.node1))
        print("join network")
        connect_nodes_bi(self.nodes, 1, 2)
        sync_blocks(self.nodes)

        print("ct balance at node1:", ct.get_balance(exec_node=self.node1))
        print("ct balance at node3:", ct.get_balance(exec_node=self.node3))

        for i in range(4):
            print("mempool:", self.nodes[i].getrawmempool())
        if with_send:
            print(
                "assert_equal(len(self.node1.getrawmempool()), 5),should {} == 5"
                .format(len(self.node1.getrawmempool())))
            with_send_crash_point2 = len(self.node1.getrawmempool())
            for tx in self.node1.getrawmempool():
                # tx_ai,tx_a11,tx_a12
                if tx == tx_a1:
                    self.log.info("tx_a1 in mempool")
                elif tx == tx_a11:
                    self.log.info("tx_a11 in mempool")
                elif tx == tx_a12:
                    self.log.info("tx_a12 in mempool")
                elif tx == tmp_ct.publish_txid:
                    self.log.info("node1 tmp_ct in mempool")
                elif tx == tx_a13.txid:
                    self.log.info("tx_a13 in mempool")
                if crash_point == 2:
                    if tx == tx_b12.txid:
                        self.log.info("tx_b12 in mempool")
                    elif tx == tx_b13:
                        self.log.info("tx_b13 in mempool")
            # 短链的块内交易必须是打回内存池的,否则可能有bug了
            # 这里不能确定具体数量,不好判断
            assert len(self.node1.getrawmempool()) >= 5 and len(
                self.node1.getrawmempool()) < 8
        else:
            print(
                " assert_equal(len(self.node1.getrawmempool()), 3),should {} == 3"
                .format(len(self.node1.getrawmempool())))
            for tx in self.node1.getrawmempool():
                # tx_ai,tx_a11,tx_a12
                if tx == tx_a1:
                    self.log.info("tx_a1 in mempool")
                elif tx == tx_a11:
                    self.log.info("tx_a11 in mempool")
                elif tx == tx_a12:
                    self.log.info("tx_a12 in mempool")
            assert_equal(len(self.node1.getrawmempool()),
                         3)  # 短链的块内交易必须是打回内存池的,否则可能有bug了
        assert (balance - MINER_REWARD * 2 -
                2000) - self.node1.getbalance() < 100
        print("node2 ct get_balance:", ct.get_balance(exec_node=self.node2))
        bal = 2000
        if with_send and crash_point == 1:
            bal = 2000 - 10  #这里20是因为send都从第一个合约里边去扣了
        assert_equal(self.node1.getbalanceof(ct.contract_id),
                     bal)  # 减去合约的send调用
        assert_equal(self.node0.getbalanceof(ct.contract_id),
                     bal)  # 减去合约的send调用
        assert_equal(
            ct.call_get('counter', broadcasting=False, amount=0)['return'][0],
            4)  # 因为本节点mempool有合约交易,所以应该为4
        assert_equal(
            ct.call_get('counter',
                        broadcasting=False,
                        exec_node=self.node2,
                        amount=0)['return'][0], 2)  # 该节点内存池中没有交易哦,所以应该为2
        for i in range(4):
            print("node{} ct2 get_balance:{}".format(
                i, ct2.get_balance(exec_node=self.nodes[i])))
        if with_send:
            assert_equal(self.node0.getbalanceof(ct2.contract_id), 1000 -
                         10 if crash_point == 1 else 1000)  # 减去合约的send调用
            assert_equal(self.node1.getbalanceof(ct2.contract_id), 1000 -
                         10 if crash_point == 1 else 1000)  # 减去合约的send调用
            assert_equal(self.node2.getbalanceof(ct2.contract_id), 1000 -
                         10 if crash_point == 1 else 1000)  # 减去合约的send调用
            assert_equal(self.node3.getbalanceof(ct2.contract_id), 1000 -
                         10 if crash_point == 1 else 1000)  # 减去合约的send调用
        else:
            assert_equal(self.node0.getbalanceof(ct2.contract_id),
                         1000)  # 减去合约的send调用
            assert_equal(self.node1.getbalanceof(ct2.contract_id),
                         1000)  # 减去合约的send调用
            assert_equal(self.node2.getbalanceof(ct2.contract_id),
                         1000)  # 减去合约的send调用
            assert_equal(self.node3.getbalanceof(ct2.contract_id),
                         1000)  # 减去合约的send调用

        for i in range(4):
            print(i, self.nodes[i].getblockcount(),
                  int(self.nodes[i].getchaintipwork(), 16))
        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 + 16 + len(more_work_blocks))
        assert_equal(
            self.node2.getbestblockhash(),
            block_b16 if not more_work_blocks else more_work_blocks[-1])
        # print(self.node1.gettransaction(tx_a1))
        # print(self.node1.gettransaction(tx_a11))

        # clear node0's and node1's mempool and check balance
        self.node1.generate(4)
        sync_blocks(self.nodes)
        assert_equal(self.node0.getrawmempool(), [])
        assert_equal(self.node1.getrawmempool(), [])
        if with_send and crash_point == 1:
            assert_equal(self.node1.getbalanceof(ct.contract_id), 4000 - 20)
        elif with_send and crash_point == 2:
            # what the he?
            assert_equal(
                self.node1.getbalanceof(ct.contract_id),
                4000 - 20 if with_send_crash_point2 == 7 else 4000 - 10)
        else:
            assert_equal(self.node1.getbalanceof(ct.contract_id), 4000)
        bal = 4000
        if with_send and crash_point == 1:
            bal = 4000 - 20  #应该是4000- 20 的,但是现在的send都是从第一个合约里扣
        elif with_send and crash_point == 2:
            bal = 4000 - 10
        assert_equal(self.node1.getbalanceof(ct.contract_id), bal)
        assert (balance - MINER_REWARD * 2 -
                2000) - self.node1.getbalance() < 100

        # In bestchain,ensure contract data is correct
        for i in range(4):
            assert_equal(
                ct.call_get('counter',
                            exec_node=self.nodes[i],
                            sender=self.nodes[i].getnewaddress(),
                            amount=0)['return'][0], 4)

        # 未完成的用例,下面的有问题,先屏蔽
        # '''
        # listsinceblock(lastblockhash) should now include txid_a1, as seen from nodes[0]
        # 这里只有node1节点才成功,换成其他节点时失败的,这不应该
        lsbres = self.nodes[1].listsinceblock(last_block_hash)
        assert any(
            tx['txid'] == tx_a1
            for tx in lsbres['transactions'])  # 这里只有node1节点才成功,换成其他节点时失败的,这不应该

        # but it should not include 'removed' if include_removed=false
        lsbres2 = self.nodes[1].listsinceblock(blockhash=last_block_hash,
                                               include_removed=False)
        assert 'removed' not in lsbres2
Beispiel #2
0
    def test_mix_contract_transaction_fork(self, gen_blocks=False):
        '''
        在2条分叉链中,混合执行各种交易,然后:
        1.不产生块,合并网络
        2.产生块,合并网络

        :return:
        '''
        self.sync_all()
        self.node1.generate(2)
        assert_equal(self.node1.getrawmempool(), [])  # make sure mempool empty
        assert_equal(self.node0.getrawmempool(), [])  # make sure mempool empty
        ct = Contract(self.node0, self.options.tmpdir, debug=False)
        ct2 = Contract(self.node0, self.options.tmpdir, debug=False)
        ct2.call_payable(amount=1000)
        print(ct.publish_txid)
        self.sync_all()
        self.node0.generate(2)
        self.sync_all()
        blocks_num = self.node0.getblockcount()

        # split mgc network
        self.split_network()
        self.node0.generate(2)  # fork
        self.node2.generate(8)  # fork
        balances = [n.getbalance() for n in self.nodes]

        # in group 1
        # normal transaction
        sendtxs_a = [
            self.node0.sendtoaddress(self.node3.getnewaddress(), 1000)
            for i in range(5)
        ]

        # publish contract transaction
        ccontracts_a = [
            Contract(self.node0, self.options.tmpdir, debug=False)
            for i in range(5)
        ]

        # call contract transaction
        call_contract_txs_a = [
            ct.call_payable(amount=1000).txid for ct in ccontracts_a
        ]
        call_contract_txs_a1 = [
            ct.call_callOtherContractTest(ccontracts_a[0].contract_id,
                                          'callOtherContractTest',
                                          ccontracts_a[-1].contract_id,
                                          "contractDataTest").txid
            for ct in ccontracts_a
        ]

        # long mempool chain transaction
        for i in range(8):
            result = ccontracts_a[1].call_reentrancyTest(throw_exception=False)

        ccontracts_a[2].call_maxContractCallTest(2).txid
        self.sync_all([self.nodes[:2], self.nodes[2:]])

        # in group 2
        sendtxs_b = [
            self.node2.sendtoaddress(self.node1.getnewaddress(), 1000)
            for i in range(5)
        ]

        # publish contract transaction
        ccontracts_b = [
            Contract(self.node2, self.options.tmpdir, debug=False)
            for i in range(5)
        ]

        # call contract transaction
        call_contract_txs_b = [
            ct.call_payable(amount=1000).txid for ct in ccontracts_b
        ]
        call_contract_txs_b1 = [
            ct.call_callOtherContractTest(ccontracts_b[0].contract_id,
                                          'callOtherContractTest',
                                          ccontracts_b[-1].contract_id,
                                          "contractDataTest").txid
            for ct in ccontracts_b
        ]

        # long mempool chain transaction

        for i in range(8):
            result = ccontracts_b[1].call_reentrancyTest(throw_exception=False)

        ccontracts_b[2].call_maxContractCallTest(2).txid
        self.sync_all([self.nodes[:2], self.nodes[2:]])

        # join network
        if gen_blocks:
            for i in range(4):
                print("before make_more_work_than:", i,
                      self.nodes[i].getblockcount(),
                      int(self.nodes[i].getchaintipwork(), 16))
                print("mempool:", self.nodes[i].getrawmempool())
            blocks_a = self.node0.generate(2)
            blocks_b = self.node2.generate(8)
            more_work_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))
                print("mempool:", self.nodes[i].getrawmempool())

        print("join network")
        connect_nodes_bi(self.nodes, 0, 2)
        try:
            print("sync_mempools.......")
            sync_mempools(self.nodes, timeout=30)
            print("sync_mempools done")
        except Exception as e:
            print("sync mempool failed,ignore!")

        sync_blocks(self.nodes)

        if gen_blocks:
            for i in range(4):
                print("mempool:", self.nodes[i].getrawmempool())
        for i in range(4):
            print(i, self.nodes[i].getblockcount(),
                  int(self.nodes[i].getchaintipwork(), 16))
        tips = self.nodes[0].getchaintips()
        print("tips:", tips)
        assert_equal(len(tips), self.tips_num + 1)
        self.tips_num += 1

        # 合并后,节点再次调用合约,该交易应该回被不同组的节点抛弃,因为合约不存在
        self.log.info(
            "when joined,contractCall will throw EXCEPTION because of the contractPublish transaction be droped by different group"
        )
        tx1, tx2 = None, None
        # make sure contract publish transaction in mempool
        for i, c in enumerate(ccontracts_a):
            # sometimes assert failed here
            if c.publish_txid not in self.node0.getrawmempool():
                print("OOPS!!!!!!!OMG!!!!That's IMPOSSABLE")
                print(
                    "contractPublish transaction {} not in mempool,index is {}.When call will throw exception"
                    .format(c.publish_txid, i))
        result = ccontracts_a[2].call_reentrancyTest()
        if not result.reason():
            tx1 = result.txid
        result = ccontracts_b[2].call_reentrancyTest()
        if not result.reason():
            tx2 = result.txid
        try:
            sync_mempools(self.nodes, timeout=30)
        except Exception as e:
            print("sync_mempools(self.nodes,timeout = 30) not done")
        if tx1 and tx2:
            wait_until(lambda: tx1 not in self.node2.getrawmempool(),
                       timeout=10)
            wait_until(lambda: tx1 in self.node1.getrawmempool(), timeout=10)
            if gen_blocks:
                # 因为tx2是主链交易,块同步后,可以找到合约的
                wait_until(lambda: tx2 in self.node1.getrawmempool(),
                           timeout=10)
            else:
                wait_until(lambda: tx2 not in self.node1.getrawmempool(),
                           timeout=10)
            wait_until(lambda: tx2 in self.node3.getrawmempool(), timeout=10)
        else:
            print('tx1 and tx2 is None')

        for i, n in enumerate(self.nodes):
            try:
                n.generate(2)
            except Exception as e:
                self.log.info(
                    "Don't know why!!node{} generate failed,reason:{}".format(
                        i, repr(e)))
                raise

            print("node{} generate done".format(i))
            sync_blocks(self.nodes)
    def test_mix_contract_transaction_fork(self, gen_blocks=False):
        '''
        在2条分叉链中,混合执行各种交易,然后:
        1.不产生块,合并网络
        2.产生块,合并网络

        :return:
        '''
        self.sync_all()
        self.node1.generate(2)
        assert_equal(self.node1.getrawmempool(), [])  # make sure mempool empty
        assert_equal(self.node0.getrawmempool(), [])  # make sure mempool empty
        ct = Contract(self.node0, self.options.tmpdir, debug=False)
        ct2 = Contract(self.node0, self.options.tmpdir, debug=False)
        ct2.call_payable(amount=1000)
        print(ct.publish_txid)
        self.sync_all()
        self.node0.generate(2)
        self.sync_all()
        blocks_num = self.node0.getblockcount()

        # split mgc network
        self.split_network()
        self.node0.generate(2)  # fork
        self.node2.generate(8)  # fork
        balances = [n.getbalance() for n in self.nodes]

        # in group 1
        # normal transaction
        sendtxs_a = [
            self.node0.sendtoaddress(self.node3.getnewaddress(), 1000)
            for i in range(5)
        ]

        # publish contract transaction
        ccontracts_a = [
            Contract(self.node0, self.options.tmpdir, debug=False)
            for i in range(5)
        ]

        # call contract transaction
        call_contract_txs_a = [
            ct.call_payable(amount=1000).txid for ct in ccontracts_a
        ]
        call_contract_txs_a1 = [
            ct.call_callOtherContractTest(ccontracts_a[0].contract_id,
                                          'callOtherContractTest',
                                          ccontracts_a[-1].contract_id,
                                          "contractDataTest").txid
            for ct in ccontracts_a
        ]

        # long mempool chain transaction
        for i in range(8):
            result = ccontracts_a[1].call_reentrancyTest(throw_exception=False)

        ccontracts_a[2].call_maxContractCallTest(2).txid
        self.sync_all([self.nodes[:2], self.nodes[2:]])

        # in group 2
        sendtxs_b = [
            self.node2.sendtoaddress(self.node1.getnewaddress(), 1000)
            for i in range(5)
        ]

        # publish contract transaction
        ccontracts_b = [
            Contract(self.node2, self.options.tmpdir, debug=False)
            for i in range(5)
        ]

        # call contract transaction
        call_contract_txs_b = [
            ct.call_payable(amount=1000).txid for ct in ccontracts_b
        ]
        call_contract_txs_b1 = [
            ct.call_callOtherContractTest(ccontracts_b[0].contract_id,
                                          'callOtherContractTest',
                                          ccontracts_b[-1].contract_id,
                                          "contractDataTest").txid
            for ct in ccontracts_b
        ]

        # long mempool chain transaction

        for i in range(8):
            result = ccontracts_b[1].call_reentrancyTest(throw_exception=False)

        ccontracts_b[2].call_maxContractCallTest(2).txid
        self.sync_all([self.nodes[:2], self.nodes[2:]])

        # join network
        if gen_blocks:
            blocks_a = self.node0.generate(2)
            blocks_b = self.node2.generate(6)
            more_work_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))
                print("mempool:", self.nodes[i].getrawmempool())

        print("join network")
        connect_nodes_bi(self.nodes, 1, 2)
        try:
            print("sync_mempools.......")
            # sync_mempools(self.nodes, timeout=30)
            print("sync_mempools done")
        except Exception as e:
            print("sync mempool failed,ignore!")

        sync_blocks(self.nodes)

        if gen_blocks:
            for i in range(4):
                print("mempool:", self.nodes[i].getrawmempool())
        for i in range(4):
            print(i, self.nodes[i].getblockcount(),
                  int(self.nodes[i].getchaintipwork(), 16))
        tips = self.nodes[0].getchaintips()
        print("tips:", tips)
        assert_equal(len(tips), self.tips_num + 1)
        self.tips_num += 1

        # 合并后,节点再次调用合约,该交易应该回被不同组的节点抛弃,因为合约不存在
        result = ccontracts_a[2].call_reentrancyTest()
        if not result.reason():
            tx1 = result.txid
        result = ccontracts_b[2].call_reentrancyTest()
        if not result.reason():
            tx2 = result.txid
        # tx1 = ccontracts_a[2].call_reentrancyTest().txid
        # tx2 = ccontracts_b[2].call_reentrancyTest().txid
        try:
            sync_mempools(self.nodes, timeout=30)
        except Exception as e:
            print("sync_mempools(self.nodes,timeout = 30) not done")
        # wait_until(lambda: tx1 not in self.node2.getrawmempool(), timeout=10)
        # wait_until(lambda: tx1 in self.node1.getrawmempool(), timeout=10)
        # wait_until(lambda: tx2 not in self.node1.getrawmempool(), timeout=10)
        # wait_until(lambda: tx2 in self.node3.getrawmempool(), timeout=10)

        for i, n in enumerate(self.nodes):
            n.generate(2)
            print("node{} generate done".format(i))
            sync_blocks(self.nodes)