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 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 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()