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 test_publish_fork_with_utxo(self, is_contract_output=False): ''' ab0[utxo1] / \ aa1 [ca1] bb1 [cb1] | | aa2 bb2 | | aa3 bb3 | bb4 | ... :param contract_output: :return: ''' hex_content = get_contract_hex(self.contract_file) coster = self.node0.getnewaddress() if is_contract_output: ct = Contract(self.node0, self.options.tmpdir, debug=False) tmp_tx1 = ct.call_payable(amount=2000)['txid'] tmp_tx2 = ct.call_sendCoinTest(coster, 1000)['txid'] # print(ct.publish_txid, tmp_tx1, tmp_tx2) else: self.node0.sendtoaddress(coster, 1000) self.node0.generate(2) self.sync_all() blocks_num = self.node1.getblockcount() ''' 分割成2个网络,然后各自用同一个utxo发布合约 ''' self.split_network() sender_pub = self.node0.validateaddress(coster)['pubkey'] sender_pri = self.node0.dumpprivkey(coster) amount = 0 changeaddress = self.node0.getnewaddress() result = self.publish_contract(self.node0, hex_content, coster, sender_pub, sender_pri, amount, changeaddress) # print(result) txid_a1 = result['txid'] contract_a1 = result['contractaddress'] # 第一组节点同步,这是该组链高度应该为12 block_a1, block_a2 = self.node0.generate(2) self.sync_all([self.nodes[:2], self.nodes[2:]]) assert_equal(self.node1.getblockcount(), blocks_num + 2) assert_equal(self.node1.getbestblockhash(), block_a2) last_block_hash = block_a2 # 第二组开始发布合约 amount = 1 changeaddress = self.node2.getnewaddress() result = self.publish_contract(self.node2, hex_content, coster, sender_pub, sender_pri, amount, changeaddress) # print(result) txid_b1 = result['txid'] contract_b1 = result['contractaddress'] # 第二组节点同步,这是该组链高度应该为22 block_b13 = self.node2.generate(12)[11] self.sync_all([self.nodes[:2], self.nodes[2:]]) assert_equal(self.node2.getblockcount(), blocks_num + 12) assert_equal(self.node2.getbestblockhash(), block_b13) blocks = self.make_more_work_than(2, 0) # 合并网络 for i in range(4): print("before join:", i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) self.join_network() for i in range(4): print(i, self.nodes[i].getblockcount(), int(self.nodes[i].getchaintipwork(), 16)) # 确认存在分叉存在,并且主链为22个区块的 tips = self.nodes[0].getchaintips() # print(tips) assert_equal(len(tips), self.tips_num + 1) self.tips_num += 1 assert_equal(self.node2.getblockcount(), blocks_num + 12 + len(blocks)) assert_equal(self.node2.getbestblockhash(), block_b13 if not blocks else blocks[-1]) self.node0.gettransaction(txid_a1) # 确认分叉上的合约在主链上不能被调用 assert_raises_rpc_error( -1, "CallContractReal => GetContractInfo fail, contractid is " + contract_a1, self.node0.callcontract, True, 1, contract_a1, self.node0.getnewaddress(), "payable") # 主链合约是可以调用的 self.node0.callcontract(True, 1, contract_b1, self.node0.getnewaddress(), "payable") # 未完成的用例,下面的有问题,先屏蔽 # ''' # listsinceblock(lastblockhash) should now include txid_a1, as seen from nodes[0] # 这里只有node0节点才成功,换成其他节点时失败的,这不应该 # ''' lsbres = self.nodes[0].listsinceblock(last_block_hash) assert any( tx['txid'] == txid_a1 for tx in lsbres['removed']) # 这里只有node0节点才成功,换成其他节点时失败的,这不应该 # but it should not include 'removed' if include_removed=false lsbres2 = self.nodes[0].listsinceblock(blockhash=last_block_hash, include_removed=False) assert 'removed' not in lsbres2
def run_test(self): self.nodes[1].generate(2) sync_blocks(self.nodes) balance = self.nodes[0].getbalance() contract_obj = Contract(self.nodes[0], self.options.tmpdir) #构造合约 txA = contract_obj.publish_txid #发布合约的交易ID txB = contract_obj.call_payable(amount=1)['txid'] txC = contract_obj.call_payable(amount=1)['txid'] sync_mempools(self.nodes) self.nodes[1].generate(1) sync_blocks(self.nodes) newbalance = self.nodes[0].getbalance() print(balance - newbalance) assert (balance - newbalance < Decimal("19.67900001") ) # no more than fees lost balance = newbalance # Disconnect nodes so node0's transactions don't get into node1's mempool disconnect_nodes(self.nodes[0], 1) # Identify the contract outputs # 分别获取发布合约与调用合约的交易输出 nA, vA = next((i, vout["value"]) for i, vout in enumerate(self.nodes[0].getrawtransaction( txA, 1)["vout"]) if vout["value"] != Decimal("1")) nB, vB = next((i, vout["value"]) for i, vout in enumerate(self.nodes[0].getrawtransaction( txB, 1)["vout"]) if vout["value"] != Decimal("1")) nC, vC = next((i, vout["value"]) for i, vout in enumerate(self.nodes[0].getrawtransaction( txC, 1)["vout"]) if vout["value"] != Decimal("1")) # self.stop_node(0) # self.start_node(0, extra_args=["-minrelaytxfee=0.001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) inputs = [] # spend 9985.026 + 9997.646 mgc outputs from txD and txE # 花费掉vA和vB inputs.append({"txid": txA, "vout": nA}) inputs.append({"txid": txB, "vout": nB}) outputs = {} outputs[self.nodes[0].getnewaddress()] = Decimal(int(vA)) outputs[self.nodes[1].getnewaddress()] = Decimal(int(vB)) signed = self.nodes[0].signrawtransaction( self.nodes[0].createrawtransaction(inputs, outputs)) txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) # Identify the 9985mgc output # 找到va的输出 nAB, vAB = next((i, vout["value"]) for i, vout in enumerate( self.nodes[0].getrawtransaction(txAB1, 1)["vout"]) if vout["value"] == Decimal(int(vA))) # Create a child tx spending AB1 and C inputs = [] inputs.append({"txid": txAB1, "vout": nAB}) inputs.append({"txid": txC, "vout": nC}) outputs = {} addrABC2 = self.nodes[0].getnewaddress() outputs[addrABC2] = Decimal("19977") signed2 = self.nodes[0].signrawtransaction( self.nodes[0].createrawtransaction(inputs, outputs)) txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) # In mempool txs from self should increase balance from change newbalance = self.nodes[0].getbalance() print( newbalance, balance, balance - newbalance, newbalance - (balance - Decimal(str(vA + vB + vC)) + Decimal("19977"))) assert_equal(newbalance, balance - Decimal(str(vA + vB + vC)) + Decimal("19977")) balance = newbalance # Restart the node with a higher min relay fee so the parent tx is no longer in mempool # TODO: redo with eviction self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=10.00000"]) # Verify txs no longer in either node's mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[1].getrawmempool()), 0) # Not in mempool txs from self should only reduce balance # inputs are still spent, but change not received newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("19977")) # Unconfirmed received funds that are not in mempool, also shouldn't show # up in unconfirmed balance unconfbalance = self.nodes[0].getunconfirmedbalance( ) + self.nodes[0].getbalance() assert_equal(unconfbalance, newbalance) # Also shouldn't show up in listunspent x = self.nodes[0].listunspent(1, 9999999, [addrABC2]) assert (not txABC2 in [utxo["txid"] for utxo in x]) balance = newbalance # Abandon original transaction and verify inputs are available again # including that the child tx was also abandoned self.nodes[0].abandontransaction(txAB1) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance + Decimal(str(vA + vB + vC))) balance = newbalance # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=0.00001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) # But if its received again then it is unabandoned # And since now in mempool, the change is available # But its child tx remains abandoned # There is currently a bug around this and so this test doesn't work. See Issue #0060 in testin self.nodes[0].sendrawtransaction(signed["hex"]) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal(str(vA + vB)) + Decimal(int(vA))) balance = newbalance # Send child tx again so its unabandoned self.nodes[0].sendrawtransaction(signed2["hex"]) newbalance = self.nodes[0].getbalance() assert_equal( newbalance, balance - Decimal(int(vAB)) - Decimal(vC) + Decimal("19977")) balance = newbalance # Remove using high relay fee again self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=10.00000"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("19977")) balance = newbalance # Create a double spend of AB1 by spending again from only A's 10 output # Mine double spend from node 1 inputs = [] inputs.append({"txid": txA, "vout": nA}) inputs.append({"txid": txC, "vout": nC}) outputs = {} outputs[self.nodes[1].getnewaddress()] = Decimal("19950") tx = self.nodes[0].createrawtransaction(inputs, outputs) signed = self.nodes[0].signrawtransaction(tx) self.nodes[1].sendrawtransaction(signed["hex"]) self.nodes[1].generate(1) connect_nodes(self.nodes[0], 1) sync_blocks(self.nodes) # Verify that B and C's 10 MGC outputs are available for spending again because AB1 is now conflicted newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance + Decimal(vC)) balance = newbalance # There is currently a minor bug around this and so this test doesn't work. See Issue #7315 # Invalidate the block with the double spend and B's 10 MGC output should no longer be available # Don't think C's should either self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) newbalance = self.nodes[0].getbalance() # assert_equal(newbalance, balance - Decimal("10")) self.log.info( "If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer" ) self.log.info( "conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315" ) self.log.info(str(balance) + " -> " + str(newbalance) + " ?") self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=0.00001"]) disconnect_nodes(self.nodes[0], 1) node = self.nodes[0] node.generate(2) assert_equal([], node.getrawmempool()) # make sure mempool is empty new_address = node.getnewaddress() balance = node.getbalance() contract_balance = node.getbalanceof(contract_obj.contract_id) amount = 1 txD = contract_obj.call_sendCoinTest(new_address, amount, amount=0)['txid'] txE = contract_obj.call_sendCoinTest(new_address, amount, amount=0)['txid'] txD_fee = self.get_txfee(txD) txE_fee = self.get_txfee(txE) newbalance = node.getbalance() assert_equal(contract_balance, node.getbalanceof(contract_obj.contract_id)) # 放弃合约的sendcoin交易 self.stop_node(0) self.start_node(0, extra_args=["-minrelaytxfee=10.0000"]) assert_equal([], node.getrawmempool()) # make sure mempool is empty assert_equal(newbalance, balance + txD_fee + txE_fee) node.abandontransaction(txD) node.abandontransaction(txE) assert_equal(node.getbalance(), balance) node.generate(2) assert_equal(contract_balance, node.getbalanceof(contract_obj.contract_id))
def run_test(self): self.nodes[0].generate(2) # Simple send, 0 to 1: txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) self.sync_all() assert_array_result(self.nodes[0].listtransactions(), {"txid": txid}, { "category": "send", "account": "", "amount": Decimal("-10"), "confirmations": 0 }) assert_array_result(self.nodes[1].listtransactions(), {"txid": txid}, { "category": "receive", "account": "", "amount": Decimal("10"), "confirmations": 0 }) # mine a block, confirmations should change: self.nodes[0].generate(1) self.sync_all() array0 = [ o for i, o in enumerate(self.nodes[0].listtransactions("*", 1000, 0)) if o["txid"] == txid ] array1 = [ o for i, o in enumerate(self.nodes[1].listtransactions("*", 1000, 0)) if o["txid"] == txid ] assert_array_result(array0, {"txid": txid}, { "category": "send", "account": "", "amount": Decimal("-10"), "confirmations": 1 }) assert_array_result(array1, {"txid": txid}, { "category": "receive", "account": "", "amount": Decimal("10"), "confirmations": 1 }) # send-to-self: txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.2) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "send" }, {"amount": Decimal("-0.2")}) assert_array_result(self.nodes[0].listtransactions(), { "txid": txid, "category": "receive" }, {"amount": Decimal("0.2")}) # sendmany from node1: twice to self, twice to node2: send_to = { self.nodes[0].getnewaddress(): 0.11, self.nodes[1].getnewaddress(): 0.22, self.nodes[0].getaccountaddress("from1"): 0.33, self.nodes[1].getaccountaddress("toself"): 0.44 } sender = self.nodes[1].getnewaddress("1") for i in range(4): self.nodes[1].sendtoaddress(sender, 0.5) self.nodes[1].generate(1) txid = self.nodes[1].sendmany("1", send_to) self.sync_all() assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.11") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.11") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.22") }, {"txid": txid}) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.33") }, {"txid": txid}) assert_array_result(self.nodes[0].listtransactions(), { "category": "receive", "amount": Decimal("0.33") }, { "txid": txid, "account": "from1" }) assert_array_result(self.nodes[1].listtransactions(), { "category": "send", "amount": Decimal("-0.44") }, { "txid": txid, "account": "1" }) assert_array_result(self.nodes[1].listtransactions(), { "category": "receive", "amount": Decimal("0.44") }, { "txid": txid, "account": "toself" }) multisig = self.nodes[1].createmultisig( 1, [self.nodes[1].getnewaddress()]) self.nodes[0].importaddress(multisig["redeemScript"], "watchonly", False, True) txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1) self.nodes[1].generate(1) self.sync_all() assert (len(self.nodes[0].listtransactions("watchonly", 100, 0, False)) == 0) assert_array_result( self.nodes[0].listtransactions("watchonly", 100, 0, True), { "category": "receive", "amount": Decimal("0.1") }, { "txid": txid, "account": "watchonly" }) self.run_rbf_opt_in_test() # add contract test print(self.nodes[0].getbalance()) co = Contract(self.nodes[0], self.options.tmpdir) txid, contract_id = co.publish_txid, co.contract_id co.call_payable() self.sync_all() array0 = [ o for i, o in enumerate(self.nodes[0].listtransactions()) if o["txid"] == txid ] assert array0 != [] txid = co.call_sendCoinTest(self.nodes[1].getnewaddress(), 1)['txid'] self.sync_all() assert [ o for i, o in enumerate(self.nodes[1].listtransactions()) if o["txid"] == txid ] != []
def test_double_sendcoins(self): ''' 测试同一个合约,分别在主链与分叉链上转走全部金额到不同的地址 理论短链的交易不应该打回到内存池,因为合约没钱 ab0[contract_ab] / \ aa1 [cca1] bb1 [ccb1] | | aa2 bb2 | | aa3 bb3 | bb4 | ... :return: ''' self.sync_all() self.node0.generate(2) assert_equal(self.node0.getrawmempool(), []) # make sure mempool empty assert_equal(self.node1.getrawmempool(), []) # make sure mempool empty ct = Contract(self.node1, self.options.tmpdir, debug=False) ct.call_payable(amount=100) print(ct.publish_txid) self.sync_all() self.node0.generate(2) self.sync_all() blocks_num = self.node1.getblockcount() contract_balance = 100 # split mgc network self.split_network() self.node1.generate(2) # fork self.node3.generate(8) # fork # in group 1 addr_N1 = self.node1.getnewaddress() txid1 = ct.call_sendCoinTest(addr_N1, contract_balance, amount=0).txid self.node1.generate(2) self.sync_all([self.nodes[:2], self.nodes[2:]]) assert_equal(self.node1.getbalanceof(addr_N1), 100) assert_equal(ct.get_balance(), 0) # in group 2 addr_N3 = self.node3.getnewaddress() txid2 = ct.call_sendCoinTest(addr_N3, contract_balance, amount=0, exec_node=self.node3).txid self.node3.generate(3) self.sync_all([self.nodes[:2], self.nodes[2:]]) assert_equal(self.node3.getbalanceof(addr_N3), 100) assert_equal(ct.get_balance(exec_node=self.node3), 0) # join network print("join network") connect_nodes_bi(self.nodes, 1, 2) sync_blocks(self.nodes) for i in range(4): print("mempool:", self.nodes[i].getrawmempool()) # 确认存在分叉存在 tips = self.nodes[1].getchaintips() print(tips) assert_equal(len(tips), self.tips_num + 1) self.tips_num += 1 # assert assert_equal(self.node1.getbalanceof(addr_N1), 0) assert_equal(self.node3.getbalanceof(addr_N3), contract_balance) assert_equal(ct.get_balance(), 0) assert_equal(ct.get_balance(exec_node=self.node3), 0) assert txid1 not in self.node1.getrawmempool()