def reindex(self, justchainstate=False, with_contract=False): self.nodes[0].generate(3) if with_contract: # make some contract transactions cid = self.nodes[0].publishcontract( generate_contract(self.options.tmpdir))['contractaddress'] self.nodes[0].callcontract(True, 10, cid, self.nodes[0].getnewaddress(), 'payable') for i in range(10): self.nodes[0].callcontract(True, 0, cid, self.nodes[0].getnewaddress(), 'dustChangeTest', self.nodes[0].getnewaddress()) self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) self.nodes[0].generate(2) # TODO 还需要测试跨链交易的情况 blockcount = self.nodes[0].getblockcount() self.stop_nodes() extra_args = [[ "-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1" ]] self.start_nodes(extra_args) while self.nodes[0].getblockcount() < blockcount: print(self.nodes[0].getblockcount(), blockcount) time.sleep(0.1) assert_equal(self.nodes[0].getblockcount(), blockcount) self.log.info("Success")
def __init__(self, node, contract_path=None, sender=None, immediate=True, debug=True): ''' :param node: :param contract_path: :param sender: :param immediate: ''' self.bind_node = node self.debug = debug if contract_path is None: contract_path = tempfile.mkdtemp(prefix="contract_") self.contract_path = generate_contract(contract_path) if sender is not None: self.publisher = sender self.has_publish = False if immediate: # if true than publish it right now self.publish()
def run_test(self): """Main test logic""" # prepare for n in self.nodes: n.generate(2) # make some coins self.sync_all() # main test self.contract_file = generate_contract(self.options.tmpdir) self.tips_num = 1 self.log.info("start test_publish_fork_with_utxo,normal utxo") self.test_publish_fork_with_utxo() self.log.info("start test_publish_fork_with_utxo,contract utxo") self.test_publish_fork_with_utxo(is_contract_output=True) self.log.info("start double publish on both chain") self.test_double_publish() self.log.info("start test_callcontract_fork,without send") self.test_callcontract_fork() self.log.info("start test_callcontract_fork,with send, crash point 1") self.test_callcontract_fork(with_send=True, crash_point=1) self.log.info("start test_callcontract_fork,with send,crash point 2") self.test_callcontract_fork(with_send=True, crash_point=2) self.log.info("start mix transaction reorg test,no generate") self.test_mix_contract_transaction_fork() self.log.info("start mix transaction reorg test,with generate") self.test_mix_contract_transaction_fork(gen_blocks=True)
def run_test(self): """Main test logic""" # prepare node = self.nodes[0] node2 = self.nodes[1] node.generate(nblocks=2) # make some coins self.sync_all() # publish contract = generate_contract(self.options.tmpdir) result = node.publishcontract(contract) contract_id = result['contractaddress'] sender = result['senderaddress'] call_contract = caller_factory(self, contract_id, sender) # call # no coins assert_contains(call_contract(PAYABLE, amount=10000000), "Insufficient funds") # # 非法的入参 for amount in [10000000000, -1, 0, Decimal("0.00000009").quantize(Decimal("0.000000"))]: call_contract(PAYABLE, amount=amount) # 非法sender for sender_addr in [sender + "x", contract_id]: assert_contains(caller_factory(self, contract_id, sender_addr)(PAYABLE), "Invalid sender address") # # 合约不存在 assert_contains(caller_factory(self, "2PPWpHssgXjA8yEgfd3Vo36Hhx1eimbGCcP", sender)(PAYABLE), "GetContractInfo fail") # # 地址错误 for addr in [contract_id + 'x', sender]: caller_factory(self, addr, sender)(PAYABLE) # 函数不存在 if not SKIP: assert_contains(call_contract("payable2"), "can not find function") # send不能被裸调用 # bug被修复前,暂时跳过 if not SKIP: assert_contains(call_contract("send",sender,0),'can not call lua internal function directly') assert_contains(call_contract("rpcSendTest"), 'can not call lua internal function directly') # when not commit transaction, make sure contract tx is not in mempool if not SKIP: mempool = node.getrawmempool() node.callcontract(False, 1, contract_id, sender, PAYABLE) assert mempool == node.getrawmempool() # recharge to contract txid = call_contract(PAYABLE,amount = 1000)['txid'] sync_mempools(self.nodes) assert txid in node.getrawmempool() assert txid in node2.getrawmempool() assert_equal(node.getbalanceof(contract_id), 0) #合约的余额只会在一定的确认数之后才可以查看,在内存池中是不生效的 node.generate(nblocks=1) self.sync_all() assert txid not in node.getrawmempool() assert txid not in node2.getrawmempool() assert_equal(node.getbalanceof(contract_id), 1000) # 确认合约余额 # doubleSpendTest self.test_double_spend(mineblock=False) self.test_double_spend() call_contract("doubleSpendTest", node.getnewaddress(),throw_exception = True) # cmsgpackTest if not SKIP: assert_contains(call_contract("cmsgpackTest", node.getnewaddress(), 0), 'cmsgpack => sc >= LUACMSGPACK_MAX_NESTING') self.sync_all() # # tailLoopTest call_contract("tailLoopTest", 896) # v452,594 is the limit assert_contains(call_contract("tailLoopTest", 897), "run out of limit instruction") # # tailLoopTest2 call_contract("tailLoopTest2", 11) assert_contains(call_contract("tailLoopTest2", 12), "Too many args in lua function") # # unpackTest assert_contains(call_contract("unpackTest"), "too many results to unpack") # localFuncTest if not SKIP: assert_contains(call_contract("localFuncTest"), "can not find function") # longReturnTest if not SKIP: c = generate_contract(self.options.tmpdir, err_type="long_string_return") addre = node.publishcontract(c)['contractaddress'] node.callcontract(True,1,addre,sender,'longReturnTest') # contractDataTest call_contract("contractDataTest") assert_equal(call_contract("get", "size")['return'][0], 127) # make sure node1 mempool is empty node.generate(nblocks=2) assert_equal([], node.getrawmempool()) # sendCoinTest # send to mgc address new_address = node.getnewaddress() txid = call_contract("sendCoinTest", new_address, 1)['txid'] assert txid in node.getrawmempool() call_contract("sendCoinTest", new_address, "1e-3") assert_contains(call_contract("sendCoinTest", new_address, 2 ** 31 - 1), "not enough amount ") assert_contains(call_contract("sendCoinTest", new_address, 0.1), "JSON integer out of range") assert_contains(call_contract("sendCoinTest", new_address, 0), "SendCoins => amount(0) out of range") assert_contains(call_contract("sendCoinTest", new_address, -1), "SendCoins => amount(-100000000) out of range") # send all balance tmp_id = node.publishcontract(contract)["contractaddress"] tmp_caller = caller_factory(self, tmp_id, sender) tmp_caller(PAYABLE, amount=Decimal("1")) tmp_txid = tmp_caller("sendCoinTest", new_address, 1, amount=Decimal("0"),throw_exception = True)['txid'] # 利用节点2挖矿,确保节点1的交易可以打包的块 self.sync_all() node2.generate(nblocks=2) # 这里需要挖2个,因为send的输出需要达到成熟度才可以使用 self.sync_all() # make sure two transactions not in mempool # if assert failed it should be bug here assert txid not in node.getrawmempool() assert tmp_txid not in node.getrawmempool() self.sync_all() assert_equal(node.getbalanceof(tmp_id), 0) assert_equal(node.getbalanceof(new_address), 2) assert_equal(node2.getbalanceof(new_address), 2) assert_equal(node2.getbalanceof(tmp_id), 0) assert_contains(tmp_caller("sendCoinTest", new_address, 1), "not enough amount ") # send to contract tmp_id = node.publishcontract(contract)["contractaddress"] assert_contains(call_contract("sendCoinTest", tmp_id, 100), "Invalid destination address") node.generate(nblocks=1) # batchSendTest # 12个参数是上限,除去内部调用之后,实际能用的就只有7个参数位,并且不支持数组 for to in range(4): to_list = [node.getnewaddress() for i in range(7)] call_contract("addWithdrawList", *to_list) call_contract("batchSendTest") node.generate(nblocks=2) for addr in to_list: assert_equal(node.getbalanceof(addr), 1) # updateContractTest call_contract("updateContract", "self", "weigun") assert_equal(call_contract("get", "self")['return'][0], "weigun") node.generate(1) assert_equal([],node.getrawmempool()) # make sure mempool is empty # cycleSelfTest self.log.info("begin cycleSelfTest") if not SKIP: for i in range(100): call_contract("cycleSelf",throw_exception = False) call_contract("updateContract", "this", "",throw_exception = False) if i % 5 == 0: # print("generate block at :",i) node.generate(1) node.generate(1) # assert_equal([], node.getrawmempool()) # make sure mempool is empty # maxContractCallTest call_contract("maxContractCallTest", 15) # 15 is the limit assert_contains(call_contract("maxContractCallTest", 16), "run out of limit instruction") # callOtherContractTest # cycle call # step1 create contracts ca_id = contract_id cb_id = node.publishcontract(contract)["contractaddress"] cc_id = node.publishcontract(contract)["contractaddress"] caller_b = caller_factory(self, cb_id, sender) node.generate(nblocks=1) # step2 a->b->c->a(send will be call in last a) new_address = node.getnewaddress() if not SKIP: call_contract(CYCLE_CALL, cb_id, CYCLE_CALL, cc_id, CYCLE_CALL, ca_id, "sendCoinTest", new_address,throw_exception = True) node.generate(nblocks=1) assert_equal(node.getbalanceof(new_address), 1) # step3 a->b->c->b,modify PersistentData if not SKIP: caller_b("contractDataTest") # after called,size should be 127 assert_equal(caller_b("get", "size")['return'][0], 127) call_contract(CYCLE_CALL, cb_id, CYCLE_CALL, cc_id, CYCLE_CALL, cb_id, "reentrancyTest", new_address,throw_exception = True) # after called,size should be 127,because of replace dump call_contract(CYCLE_CALL, cb_id, CYCLE_CALL, cc_id, CYCLE_CALL, cb_id, "contractDataTest", new_address,throw_exception = True) # after called,size should be 127,because of replace dump node.generate(nblocks=1) assert_equal(caller_b("get", "size")['return'][0], 127) # lots of dust vin in contract's send transaction # TODO:maybe need to set payfee param in magnachaind if not SKIP: cd_id = node.publishcontract(contract)["contractaddress"] caller_d = caller_factory(self, cd_id, sender) for i in range(2000): caller_d(PAYABLE, amount=Decimal("1"),throw_exception = True) if i % 30 == 0: node.generate(nblocks=1) new_address = node.getnewaddress() caller_d("sendCoinTest", new_address, 1900, amount=Decimal("0")) node.generate(nblocks=2) assert_equal(node.getbalanceof(new_address), 1900) # dust change vout in send # node.sendtoaddress(new_sender,2) if not SKIP: tmp_id = node.publishcontract(contract)['contractaddress'] caller_tmp = caller_factory(self, tmp_id, sender) senders = [node.getnewaddress() for i in range(101)] i = 0 for _ in senders: # 充值101次,每次1个MGC caller_tmp(PAYABLE, amount=1,throw_exception = True) if i % 30 == 0: node.generate(1) i += 1 node.generate(2) assert_equal(node.getbalanceof(tmp_id), 101) i = 0 for to in senders: # 向每个地址发送cell - 999(最小单位),cell = 100000000。这里应该有101个微交易的找零 assert_equal(isinstance(caller_tmp("dustChangeTest", to, amount=Decimal("0"),throw_exception = True), dict), True) if i % 30 == 0: node.generate(1) i += 1 node.generate(nblocks=2) assert_equal(node.getbalanceof(tmp_id) * COIN, 101 * COIN - (COIN - 999 ) * 101) #因为lua没有浮点数,所以小数部分会截断掉 bal = node.getbalanceof(tmp_id) print(bal) tmp_sender = node.getnewaddress() assert_equal(isinstance(caller_tmp("sendCoinTest2", tmp_sender,amount=Decimal("0"),throw_exception = True), dict), True) # 组合所有微交易的找零,应该足够0.001个MGC的 node.generate(nblocks=2) assert_equal(node.getbalanceof(tmp_sender), Decimal("0.001")) assert_equal(node.getbalanceof(tmp_id), bal - Decimal("0.001")) # reentrancyTest last_id = node.publishcontract(contract)['contractaddress'] caller_last = caller_factory(self, last_id, sender) if not SKIP: caller_last("reentrancyTest") node.generate(nblocks=1) assert_equal(caller_last("get", "this")['return'], []) # 疲劳测试 if not SKIP: to_list = [node.getnewaddress() for i in range(1000)] for i,to in enumerate(to_list): caller_last(PAYABLE, amount=10) caller_last(CYCLE_CALL, last_id, "contractDataTest",amount=0) caller_last(CYCLE_CALL, last_id, "dustChangeTest",to,amount=0) caller_last(CYCLE_CALL, last_id, "addWithdrawList",to,amount=0) # caller_last(CYCLE_CALL, last_id, "batchSendTest",amount=0) if random.randint(1,100) > 70: node.generate(nblocks=1) else: if i % 30 == 0: node.generate(nblocks=1)
def run_test(self): self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] base_fee = self.relayfee * 1000 # prepare node0, node1 = self.nodes[0:2] node0.generate(2) # make some coins self.sync_all() contract = generate_contract(self.options.tmpdir) # '''' # 测试发布合约的交易 self.log.info("Test contract publish transaction") contract = generate_contract(self.options.tmpdir) infos = gen_lots_of_contracts(node0, contract, MAX_CONTRACT_NUM) node0.prioritisetransaction(txid=infos[-1]['txid'], fee_delta=int(3 * base_fee * COIN)) mempool_len = len(node0.getrawmempool()) print(mempool_len) print(len(node0.getrawmempool()), len(node1.getrawmempool())) self.sync_all() print(len(node0.getrawmempool()), len(node1.getrawmempool())) node0.generate(1) sync_blocks(self.nodes) block_txnum = int(node0.getblock(node0.getbestblockhash())['tx_num']) mempool = node0.getrawmempool() print(block_txnum, len(node0.getrawmempool()), len(node1.getrawmempool())) assert infos[-1]['txid'] not in mempool # should be mined assert_equal(len(node0.getrawmempool()), MAX_CONTRACT_NUM - block_txnum + 1) # can not locate the tx index in infos node0.generate(1) # clear mempool sync_blocks(self.nodes, timeout=600) assert_equal(len(node0.getrawmempool()), 0) # make sure mempool is clean # 测试调用合约的交易 self.log.info("Test call contract transaction") # node0_call_contract = caller_factory(self, infos[-1]['address'], node0.getnewaddress()) infos = infos + gen_lots_of_contracts( node0, contract, MAX_CONTRACT_CALL_NUM - MAX_CONTRACT_NUM) print(len(node0.getrawmempool()), len(node1.getrawmempool())) self.sync_all(timeout=6000, show_max_height=True) print(len(node0.getrawmempool()), len(node1.getrawmempool())) node0.generate(10) print("sync blocks....") sync_blocks(self.nodes, timeout=6000) assert_equal(len(node0.getrawmempool()), 0) # make sure mempool is clean print("info size: %d" % (len(infos))) txids = [ node0.callcontract(True, 0, infos[i]['address'], node0.getnewaddress(), 'payable')['txid'] for i in range(MAX_CONTRACT_CALL_NUM) ] node0.prioritisetransaction(txid=txids[-1], fee_delta=int(3 * base_fee * COIN)) print("mempool size after change priority: %d" % (len(node0.getrawmempool()))) node0.generate(1) print("mempool size after generate block: %d" % (len(node0.getrawmempool()))) self.sync_all(timeout=6000, show_max_height=True) block_txnum = int(node0.getblock(node0.getbestblockhash())['tx_num']) print(block_txnum, len(node0.getrawmempool())) mempool = node0.getrawmempool() assert txids[-1] not in mempool # should be mined # assert infos[-2]['txid'] in mempool assert len( node0.getrawmempool()) < 5 # can not locate the tx index in infos node0.generate(1) # clear mempool sync_blocks(self.nodes, timeout=600) assert len(node0.getrawmempool()) == 0 # make sure mempool is clean # 测试有依赖的合约交易的优先级,依赖方式为调用同一合约 publish_transaction = gen_lots_of_contracts(node0, contract, 1) print(publish_transaction) txid = node0.callcontract(True, 0, publish_transaction[0]['address'], node0.getnewaddress(), 'payable')['txid'] mempool_old = node0.getrawmempool() node0.prioritisetransaction(txid=txid, fee_delta=int(30 * base_fee * COIN)) mempool_new = node0.getrawmempool() # print(mempool_old,mempool_new) assert mempool_old == mempool_new # 因为有依赖关系,所以内存池顺序应该是一致的 node0.generate(2) sync_blocks(self.nodes, timeout=600) to = node0.getnewaddress() txid1 = node0.callcontract(True, 1, publish_transaction[0]['address'], node0.getnewaddress(), 'payable')['txid'] print("txid1:", txid1) txid2 = node0.callcontract(True, 0, publish_transaction[0]['address'], node0.getnewaddress(), 'sendCoinTest', to, 1)['txid'] print("txid2:", txid2) mempool_old = node0.getrawmempool() node0.prioritisetransaction(txid=txid2, fee_delta=int(30 * base_fee * COIN)) mempool_new = node0.getrawmempool() assert mempool_old == mempool_new # 因为有依赖关系,所以内存池顺序应该是一致的 self.sync_all(timeout=6000, show_max_height=True) assert mempool_old == node1.getrawmempool( ) # prioritisetransaction不会影响其他节点交易的优先级 node0.generate(2) assert node0.getbalanceof(to) == 1 # 调整有依赖的合约交易的优先级,依赖方式为输入有依赖 node0.sendtoaddress(node1.getnewaddress(), 100) self.sync_all() node0.generate(1) print(node1.getbalance(), node0.getbalance()) publish_transaction = gen_lots_of_contracts(node0, contract, 1) self.sync_all() to = node0.getnewaddress() txid3 = node1.callcontract(True, 1, publish_transaction[0]['address'], node1.getnewaddress(), 'payable')['txid'] txid4 = node1.sendtoaddress(to, 1) mempool_old = node1.getrawmempool() node1.prioritisetransaction(txid=txid4, fee_delta=int(30 * base_fee * COIN)) mempool_new = node1.getrawmempool() assert mempool_old == mempool_new # 因为有依赖关系,所以内存池顺序应该是一致的 self.sync_all(timeout=6000, show_max_height=True) assert mempool_old == node0.getrawmempool( ) # prioritisetransaction不会影响其他节点交易的优先级 node0.generate(2) assert node0.getbalanceof(to) == 1 # ''' # 调整有依赖的合约交易的优先级,依赖方式为跨合约调用 # 目前还不能确认顺序,所以先屏蔽这个用例 infos = gen_lots_of_contracts(node0, contract, 2) print(infos) txid5 = node0.callcontract(True, 1, infos[0]['address'], node0.getnewaddress(), 'payable')['txid'] txid6 = node0.callcontract(True, 1, infos[1]['address'], node0.getnewaddress(), 'payable')['txid'] print(txid5, txid6) mempool_old = node0.getrawmempool(True) node0.prioritisetransaction(txid=txid6, fee_delta=int(30 * base_fee * COIN)) mempool_new = node0.getrawmempool(True) print(mempool_old) print(mempool_new)
def run_test(self): """Main test logic""" # prepare node = self.nodes[0] node2 = self.nodes[1] node2.generate(2) # make some coins self.sync_all() # no coins try: contract = generate_contract(self.options.tmpdir) result = node.publishcontract(contract) except Exception as e: assert "GetSenderAddr" in repr(e) # make sure not in mempool when the tx failed assert_equal([],node.getrawmempool()) node.generate(2) # make some coins self.sync_all() # 错误的合约 contract = generate_contract(self.options.tmpdir,err_type = "syntax_err") try: result = node.publishcontract(contract) except Exception as e: assert 'expected near' in repr(e) # 超大合约 contract = generate_contract(self.options.tmpdir,err_type = "bigfile") # should be bigfile try: result = node.publishcontract(contract) except Exception as e: assert 'code is too large' in repr(e) # 测试sdk发布合约的接口 # TODO 需要单独测试prepublishcode接口 # prepublishcodeTest contract = generate_contract(self.options.tmpdir) with open(contract) as fh: content = "".join(fh.readlines()) hex_content = bytes_to_hex_str(bytes(content,encoding='utf-8')) coster = node.getnewaddress() for i in range(10): node.sendtoaddress(coster, 1000) node.generate(2) sender = coster amount = 1 changeaddress = node.getnewaddress() result = node.prepublishcode(hex_content,coster,sender,amount,changeaddress) print(result) # syntax_err hex content contract = generate_contract(self.options.tmpdir,err_type = "syntax_err") with open(contract) as fh: content = "".join(fh.readlines()) hex_content_tmp = bytes_to_hex_str(bytes(content,encoding='utf-8')) try: result = node.prepublishcode(hex_content_tmp, coster, sender, amount, changeaddress) except Exception as e: assert 'expected near' in repr(e) # empty content hex_content_tmp = bytes_to_hex_str(bytes("",encoding='utf-8')) try: result = node.prepublishcode(hex_content_tmp, coster, sender, amount, changeaddress) except Exception as e: assert 'code data can not empty' in repr(e) # not hex hex_content_tmp = "not hex data" try: result = node.prepublishcode(hex_content_tmp, coster, sender, amount, changeaddress) except Exception as e: assert 'code data must hex data' in repr(e) # coster test # Invalid address contract = generate_contract(self.options.tmpdir) contract_id = node.publishcontract(contract)["contractaddress"] node1_newaddress = self.nodes[1].getnewaddress() self.nodes[1].sendtoaddress(node1_newaddress, 100) self.nodes[1].generate(2) sync_blocks(self.nodes) for coster_tmp in ["","DFGHJK12316547645",contract_id,node1_newaddress]: try: result = node.prepublishcode(hex_content, coster_tmp, sender, amount, changeaddress) except Exception as e: assert 'Invalid MagnaChain public key address' in repr(e) or "Invalid MagnaChain fund address" in repr(e) continue node.generate(1) # sender test # Invalid address for sender_tmp in ["", "DFGHJK12316547645", contract_id, node1_newaddress]: try: result = node.prepublishcode(hex_content, coster, sender_tmp, amount, changeaddress) except Exception as e: assert 'Invalid MagnaChain public key address' in repr(e) or "Invalid MagnaChain sender address" in repr(e) continue node.generate(1) # amount test for amount_tmp in [10000000000, "10",-1, 0, Decimal("0.0009").quantize(Decimal("0.0000"))]: try: result = node.prepublishcode(hex_content, coster, sender, amount_tmp, changeaddress) except Exception as e: assert 'Invalid amount for send' in repr(e) or "Amount out of range" in repr(e) or "Invalid amount" in repr(e) continue node.generate(1) # changeaddress test for changeaddress_tmp in ["", "DFGHJK12316547645", contract_id, node1_newaddress]: try: result = node.prepublishcode(hex_content, coster, sender, amount_tmp, changeaddress) except Exception as e: assert 'Invalid MagnaChain public key address' in repr(e) or "Invalid MagnaChain change address" in repr(e) continue node.generate(1) # test fee # encrypt wallet test with contract node.node_encrypt_wallet('test') self.stop_node(1) self.start_nodes() connect_nodes_bi(self.nodes, 0, 1) node.walletpassphrase("test", 1) time.sleep(2) # wait for timeout assert_raises_rpc_error(-13,'Please enter the wallet passphrase with walletpassphrase first',node.publishcontract,contract) node.walletpassphrase("test", 300) payfee = node.getinfo()['paytxfee'] relayfee = node.getinfo()['relayfee'] txid = node.publishcontract(contract)['txid'] txfee = node.gettransaction(txid)['fee'] tx_size = count_bytes(node.getrawtransaction(txid)) node.settxfee(20) txid = node.publishcontract(contract)['txid'] print(txfee,node.gettransaction(txid)['fee']) assert abs(node.gettransaction(txid)['fee']) > abs(txfee) and abs(node.gettransaction(txid)['fee']) == 100 assert_equal(node.gettransaction(txid)['confirmations'],0) self.sync_all() node2.generate(1) self.sync_all() assert_equal(node.gettransaction(txid)['confirmations'], 1) node.settxfee(payfee) # 正确的合约,并且进行重复测试 j = 2 contract = generate_contract(self.options.tmpdir) for i in range(200): balance = node.getbalance() result = node.publishcontract(contract) diff = balance - node.getbalance() assert diff > 0 and diff < 13 ,"publish fee too much:%s"%(diff) # 该合约的费用基本是固定的,避免修改数值出现比较大的偏差 self.log.info("publish cost:%s"%(balance - node.getbalance())) if i % j == 0: # 每个多少个交易后才打一次包 self.sync_all() node.generate(1) j = min(64,j * 2) node.generate(1)