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()
def run_test(self): txouts = gen_return_txouts() relayfee = self.nodes[0].getnetworkinfo()['relayfee'] txids = [] utxos = create_confirmed_utxos(relayfee, self.nodes[0], 91) # create a mempool tx that will be evicted us0 = utxos.pop() inputs = [{"txid": us0["txid"], "vout": us0["vout"]}] outputs = {self.nodes[0].getnewaddress(): 0.1} tx = self.nodes[0].createrawtransaction(inputs, outputs) self.nodes[0].settxfee( relayfee) # specifically fund this tx with low fee txF = self.nodes[0].fundrawtransaction(tx) self.nodes[0].settxfee(0) # return to automatic fee selection txFS = self.nodes[0].signrawtransaction(txF['hex']) txid = self.nodes[0].sendrawtransaction(txFS['hex']) relayfee = self.nodes[0].getnetworkinfo()['relayfee'] base_fee = relayfee * 100 for i in range(3): txids.append([]) txids[i] = create_lots_of_big_transactions( self.nodes[0], txouts, utxos[30 * i:30 * i + 30], 30, (i + 1) * base_fee) # by now, the tx should be evicted, check confirmation state assert (txid not in self.nodes[0].getrawmempool()) txdata = self.nodes[0].gettransaction(txid) assert (txdata['confirmations'] == 0) # confirmation should still be 0 # 存在依赖关系的合约交易,内存池满时的情况 self.nodes[0].generate(5) assert_equal(self.nodes[0].getrawmempool(), []) cts = [] for i in range(1600): ct = Contract(self.nodes[0], self.options.tmpdir, debug=False) cts.append(ct) for ct in cts: ct.call_payable(amount=100) for ct in cts: # print(self.nodes[0].getmempoolinfo()) reason = ct.call_doubleSpendTest(self.nodes[0].getnewaddress(), amount=0, throw_exception=False).reason() if reason: # 这里表示mempool满了,把payable的交易都移除了,call_doubleSpendTest里边有send调用,所以没钱 assert_contains(reason, "mempool full")
def test_double_spend(self,mineblock = True): self.log.info("test double spend") node = self.nodes[0] ct = Contract(node) [ct.call_payable(amount = 100) for i in range(10)] node.generate(2) self.sync_all() addr = self.nodes[1].getnewaddress() addr2 = self.nodes[1].getnewaddress() contract_balance = ct.get_balance() for i in range(10): ct.call_reorgTest(addr,addr2,amount = 0,debug = False) # print("before:",ct.get_balance(), node.getbalanceof(addr), node.getbalanceof(addr2)) # self.sync_all() if mineblock: self.nodes[1].generate(random.randint(1,4)) self.sync_all() # print("after:",ct.get_balance(), node.getbalanceof(addr), node.getbalanceof(addr2)) self.sync_all() node.generate(2) self.sync_all() print(ct.get_balance(),node.getbalanceof(addr),node.getbalanceof(addr2)) addr_balance = node.getbalanceof(addr) addr2_balance = node.getbalanceof(addr2) if not mineblock: if addr_balance == 0: assert_equal(addr2_balance, 10) else: assert_equal(addr_balance, 10) assert_equal(ct.get_balance(),contract_balance - 10) else: assert_equal(ct.get_balance(), contract_balance - addr_balance - addr2_balance)
def run_test(self): #prepare some coins for multiple *rawtransaction commands self.nodes[2].generate(10) self.sync_all() self.nodes[0].generate(10) self.sync_all() self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.5) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),1.0) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(),5.0) self.sync_all() self.nodes[0].generate(5) self.sync_all() ######################################### # 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) # This will raise an exception since there are missing inputs assert_raises_rpc_error(-26, "vin-not-found", self.nodes[2].sendrawtransaction, rawtx['hex']) ######################### # 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.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), bal+Decimal('1.20000000')) #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) txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) decTx = self.nodes[0].gettransaction(txId) rawTx = self.nodes[0].decoderawtransaction(decTx['hex']) self.sync_all() self.nodes[0].generate(1) self.sync_all() #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.20000000'): vout = outpoint break self.nodes[0].generate(1) self.sync_all() bal = self.nodes[0].getbalance() inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex']}] outputs = { self.nodes[0].getnewaddress() : 2.19 } 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.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('2600085.00000000')+Decimal('2.19000000')) #block reward + tx # 2of2 test for combining transactions bal = self.nodes[2].getbalance() addr1 = self.nodes[1].getnewaddress() addr2 = self.nodes[2].getnewaddress() addr1Obj = self.nodes[1].validateaddress(addr1) addr2Obj = self.nodes[2].validateaddress(addr2) self.nodes[1].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) mSigObj = self.nodes[2].addmultisigaddress(2, [addr1Obj['pubkey'], addr2Obj['pubkey']]) mSigObjValid = self.nodes[2].validateaddress(mSigObj) txId = self.nodes[0].sendtoaddress(mSigObj, 2.2) decTx = self.nodes[0].gettransaction(txId) rawTx2 = self.nodes[0].decoderawtransaction(decTx['hex']) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[2].getbalance(), bal) # the funds of a 2of2 multisig tx should not be marked as spendable txDetails = self.nodes[0].gettransaction(txId, True) rawTx2 = self.nodes[0].decoderawtransaction(txDetails['hex']) vout = False for outpoint in rawTx2['vout']: if outpoint['value'] == Decimal('2.20000000'): vout = outpoint break self.nodes[0].generate(1) self.sync_all() bal = self.nodes[0].getbalance() inputs = [{ "txid" : txId, "vout" : vout['n'], "scriptPubKey" : vout['scriptPubKey']['hex'], "redeemScript" : mSigObjValid['hex']}] outputs = { self.nodes[0].getnewaddress() : 2.19 } rawTx2 = self.nodes[2].createrawtransaction(inputs, outputs) rawTxPartialSigned1 = self.nodes[1].signrawtransaction(rawTx2, inputs) self.log.info(rawTxPartialSigned1) assert_equal(rawTxPartialSigned['complete'], False) #node1 only has one key, can't comp. sign the tx rawTxPartialSigned2 = self.nodes[2].signrawtransaction(rawTx2, inputs) self.log.info(rawTxPartialSigned2) assert_equal(rawTxPartialSigned2['complete'], False) #node2 only has one key, can't comp. sign the tx rawTxComb = self.nodes[2].combinerawtransaction([rawTxPartialSigned1['hex'], rawTxPartialSigned2['hex']]) self.log.info(rawTxComb) self.nodes[2].sendrawtransaction(rawTxComb) rawTx2 = self.nodes[0].decoderawtransaction(rawTxComb) self.sync_all() self.nodes[0].generate(1) self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('2600085.00000000')+Decimal('2.19000000')) #block reward + tx # getrawtransaction tests # 1. valid parameters - only supply txid txHash = rawTx["hash"] assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex']) # 2. valid parameters - supply txid and 0 for non-verbose assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex']) # 3. valid parameters - supply txid and False for non-verbose assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex']) # 4. valid parameters - supply txid and 1 for verbose. # We only check the "hex" field of the output so we don't need to update this test every time the output format changes. assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"], rawTxSigned['hex']) # 5. valid parameters - supply txid and True for non-verbose assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex']) # 6. invalid parameters - supply txid and string "Flase" assert_raises_rpc_error(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, "Flase") # 7. invalid parameters - supply txid and empty array assert_raises_rpc_error(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, []) # 8. invalid parameters - supply txid and empty dict assert_raises_rpc_error(-3,"Invalid type", self.nodes[0].getrawtransaction, txHash, {}) 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) # 9. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : -1}] outputs = { self.nodes[0].getnewaddress() : 1 } assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) # 10. invalid parameters - sequence number out of range inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967296}] outputs = { self.nodes[0].getnewaddress() : 1 } assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range', self.nodes[0].createrawtransaction, inputs, outputs) inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 4294967294}] 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'], 4294967294) # 普通交易不能使用合约的UTXO node = self.nodes[0] ct = Contract(node) txid = ct.call_payable(amount = 100).txid vout = node.getrawtransaction(txid, 1)["vout"] nA = next(i for i, vout in enumerate(node.getrawtransaction(txid, 1)["vout"]) if vout["value"] == Decimal("100")) inputs = [] inputs.append({"txid": txid, "vout": nA}) outputs = {} addr = self.nodes[0].getnewaddress() outputs[addr] = Decimal("10") signed = self.nodes[0].signrawtransaction(self.nodes[0].createrawtransaction(inputs, outputs)) assert_raises_rpc_error(-26, 'mandatory-script-verify-flag-failed (Opcode missing or not understood)', self.nodes[0].sendrawtransaction, signed["hex"])
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_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 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
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_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)
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 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()