def run_test(self): """Main test logic""" from pypoptools.pypopminer import MockMiner self.apm = MockMiner() node = self.nodes[0] addr = node.getnewaddress() # stop 1 block behind activation self.log.info("Mining blocks until activation -5 blocks") self.log.info("Current node[0] height {}".format(node.getblockcount())) mine_until_pop_active(node, addr, delta=-5) self.log.info("Current node[0] height {}".format(node.getblockcount())) # check that getblocktemplate does NOT have pop-related fields before POP activation self.log.info("Check that getblocktemplate does not have POP fields") resp = self.getblocktemplate() assert_no_field(resp, 'pop_data') assert_no_field(resp, 'pop_data_root') assert_no_field(resp, 'pop_first_previous_keystone') assert_no_field(resp, 'pop_second_previous_keystone') assert_no_field(resp, 'pop_rewards') self.log.info("Mining blocks until activation +5 blocks") self.log.info("Current node[0] height {}".format(node.getblockcount())) mine_until_pop_active(node, addr, delta=+5) self.log.info("Current node[0] height {}".format(node.getblockcount())) self.log.info("Mine chain of {} consecutive endorsed blocks".format( POP_PAYOUT_DELAY)) create_endorsed_chain(node, self.apm, POP_PAYOUT_DELAY, addr) self.log.info("Current node[0] height {}".format(node.getblockcount())) endorse_block(self.nodes[0], self.apm, node.getblockcount() - 5, addr) self.log.info("Current node[0] height {}".format(node.getblockcount())) self.log.info("Check that getblocktemplate does have POP fields") resp = self.getblocktemplate() is_dict = lambda x: isinstance(x, dict) is_list = lambda x: isinstance(x, list) is_int = lambda x: isinstance(x, int) is_hex = lambda x: bytes.fromhex(x) is_payload = lambda x: is_dict(x) and "id" in x and "serialized" in x is_payload_list = lambda x: is_list(x) and all( is_payload(p) for p in x) assert_field_exists(resp, 'pop_data', type=is_dict) assert_field_exists(resp['pop_data'], 'atvs', type=is_payload_list) assert_field_exists(resp['pop_data'], 'vtbs', type=is_payload_list) assert_field_exists(resp['pop_data'], 'vbkblocks', type=is_payload_list) assert_field_exists(resp['pop_data'], 'version', type=is_int) assert_field_exists(resp, 'pop_data_root', type=is_hex) assert_field_exists(resp, 'pop_first_previous_keystone', type=is_hex) assert_field_exists(resp, 'pop_second_previous_keystone', type=is_hex) assert_field_exists(resp, 'pop_rewards', type=is_list) for reward in resp['pop_rewards']: assert_field_exists(reward, 'amount', type=is_int) assert_field_exists(reward, 'payout_info', type=is_hex) self.log.info("Current node[0] height {}".format(node.getblockcount()))
def _one_by_one(self): for node in self.nodes: # VBK block self.log.info("Submitting VBK") block = self.apm.mineVbkBlocks(1) response = node.submitpopvbk(block.toVbkEncodingHex()) assert response['accepted'], response self.log.info("VBK accepted to mempool") sync_pop_mempools(self.nodes, timeout=30) # VTB self.log.info("Submitting VTB") lastBtc = node.getbtcbestblockhash() vtb = self.apm.endorseVbkBlock( block, # endorsed vbk block lastBtc) response = node.submitpopvtb(vtb.toVbkEncodingHex()) assert response['accepted'], response self.log.info("VTB accepted to mempool") sync_pop_mempools(self.nodes, timeout=100) # ATV self.log.info("Submitting ATV") tip = self.nodes[0].getbestblockhash() altblock = self.nodes[0].getblock(tip) endorse_block(self.nodes[0], self.apm, altblock['height'], self.nodes[0].getnewaddress()) self.log.info("ATV accepted to mempool") sync_pop_mempools(self.nodes, timeout=100) self.nodes[2].generate(nblocks=1) self.sync_all()
def _check_pop_sync(self): self.log.info("running _check_pop_sync()") height = self.nodes[0].getblockcount() topheight = height + 52 addr0 = self.nodes[0].getnewaddress() addr1 = self.nodes[1].getnewaddress() addr2 = self.nodes[2].getnewaddress() keystoneInterval = get_keystone_interval(self.nodes[0]) while height < topheight: self.nodes[0].generate(nblocks=1) # endorse every block self.nodes[2].waitforblockheight(height) node2_txid = endorse_block(self.nodes[2], self.apm, height, addr2) self.log.info("node2 endorsing block {} by miner {}: {}".format( height, addr2, node2_txid)) # endorse each keystone if height % keystoneInterval == 0: self.nodes[0].waitforblockheight(height) node0_txid = endorse_block(self.nodes[0], self.apm, height, addr0) self.log.info( "node0 endorsing block {} by miner {}: {}".format( height, addr0, node0_txid)) self.nodes[1].waitforblockheight(height) node1_txid = endorse_block(self.nodes[1], self.apm, height, addr1) self.log.info( "node1 endorsing block {} by miner {}: {}".format( height, addr1, node1_txid)) # wait until node[1] gets relayed pop tx sync_pop_mempools_atvs(self.nodes, timeout=100) self.log.info("transactions relayed") # mine a block on node[1] with this pop tx containingblockhash = self.nodes[1].generate(nblocks=1)[0] containingblock = self.nodes[1].getblock(containingblockhash) self.log.info("node1 mined containing block={}".format( containingblock['hash'])) self.nodes[0].waitforblockheight(containingblock['height']) self.nodes[2].waitforblockheight(containingblock['height']) self.log.info("node0 and node2 got containing block over p2p") # assert that all txids exist in this block for node in self.nodes: self.assert_atvs_in_node( node, containingblockhash, [node0_txid, node1_txid, node2_txid]) # assert that node height matches assert self.nodes[0].getblockcount() == self.nodes[ 1].getblockcount() == self.nodes[2].getblockcount() height += 1 self.log.info("success! _check_pop_sync()")
def run_test(self): """Main test logic""" self.sync_all(self.nodes) from pypopminer import MockMiner self.apm = MockMiner() addr0 = self.nodes[0].getnewaddress() self.log.info("node0 endorses block 5") self.nodes[0].generate(nblocks=10) atvid = endorse_block(self.nodes[0], self.apm, 5, addr0) self.sync_pop_mempools(self.nodes, timeout=20) self.log.info("nodes[0,1] have syncd pop mempools") rawpopmempool1 = self.nodes[1].getrawpopmempool() assert atvid in rawpopmempool1['atvs'] self.log.info("node1 contains atv1 in its pop mempool") self.restart_node(1) self.log.info("node1 has been restarted") rawpopmempool1 = self.nodes[1].getrawpopmempool() assert atvid not in rawpopmempool1['atvs'] self.log.info("node1 does not contain atv1 in its pop mempool after restart") connect_nodes(self.nodes[0], 1) self.log.info("node1 connect to node0") self.sync_pop_mempools(self.nodes, timeout=20) self.log.info("nodes[0,1] have syncd pop mempools") rawpopmempool1 = self.nodes[1].getrawpopmempool() assert atvid in rawpopmempool1['atvs']
def _run_case3(self): bn = BaseNode() self.nodes[0].add_p2p_connection(bn) self.log.warning("running case3 for pop data sending") # endorse block 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block 5 on node0 by miner {}".format(addr)) atv_id = endorse_block(self.nodes[0], self.apm, 5, addr) raw_atv = self.nodes[0].getrawatv(atv_id) assert len(self.nodes[0].getpeerinfo()) == 1 peerinfo = self.nodes[0].getpeerinfo()[0] assert (not 'noban' in peerinfo['permissions']) assert peerinfo['banscore'] == 0 # spaming node1 self.log.info("send to node0 that it has not requested...") msg = msg_atv(raw_atv) # Send message is used to send a P2P message to the node over our P2PInterface self.nodes[0].p2p.send_message(msg) time.sleep(1) peerinfo = self.nodes[0].getpeerinfo()[0] assert peerinfo['banscore'] == 20
def _run_case2(self): bn = BaseNode() self.nodes[0].add_p2p_connection(bn) self.log.warning("running case for pop data sending") # endorse block 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block 5 on node0 by miner {}".format(addr)) atv_id = endorse_block(self.nodes[0], self.apm, 5, addr) raw_atv = self.nodes[0].getrawatv(atv_id) assert len(self.nodes[0].getpeerinfo()) == 1 peerinfo = self.nodes[0].getpeerinfo()[0] assert (not 'noban' in peerinfo['permissions']) # spaming node1 self.log.info("spaming node0 ...") disconnected = False for i in range(10000): try: msg = msg_atv(raw_atv) # Send message is used to send a P2P message to the node over our P2PInterface self.nodes[0].p2p.send_message(msg) except IOError: disconnected = True self.log.info("node0 banned our peer") assert disconnected assert_equal(len(self.nodes[0].getpeerinfo()), 0)
def _can_endorse(self): self.log.warning("starting _can_endorse()") connect_nodes(self.nodes[0], 1) self.sync_all() disconnect_nodes(self.nodes[1], 0) mine_until_pop_enabled(self.nodes[0]) lastblock = self.nodes[0].getblockcount() # endorse block 200 (fork A tip) addr0 = self.nodes[0].getnewaddress() txid = endorse_block(self.nodes[0], self.apm, lastblock, addr0) self.log.info("node0 endorsed block {} (fork A tip)".format(lastblock)) # mine pop tx on node0 self.nodes[0].generate(nblocks=1) tip = self.get_best_block(self.nodes[0]) self.log.info("node0 tip is {}".format(tip['height'])) self.nodes[1].generate(nblocks=250) tip2 = self.get_best_block(self.nodes[1]) self.log.info("node1 tip is {}".format(tip2['height'])) connect_nodes(self.nodes[0], 1) self.sync_all() bestblocks = [self.get_best_block(x) for x in self.nodes] assert_equal(bestblocks[0]['hash'], bestblocks[1]['hash']) self.log.info("all nodes switched to common block") for i in range(len(bestblocks)): assert bestblocks[i]['height'] == tip['height'], \ "node[{}] expected to select shorter chain ({}) with higher pop score\n" \ "but selected longer chain ({})".format(i, tip['height'], bestblocks[i]['height']) self.log.info("all nodes selected fork A as best chain") self.log.warning("_can_endorse() succeeded!")
def _run_sync_case(self): self.log.info("running _run_sync_case") # endorse block 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block 5 on node0 by miner {}".format(addr)) atv_id = endorse_block(self.nodes[0], self.apm, 5, addr) bn = BaseNode(self.log) self.nodes[0].add_p2p_connection(bn) time.sleep(2) assert bn.executed_msg_atv == 0 assert bn.executed_msg_offer_atv == 1 assert bn.executed_msg_offer_vbk == 1 msg = msg_get_atv([atv_id]) self.nodes[0].p2p.send_message(msg) self.nodes[0].p2p.send_message(msg) self.nodes[0].p2p.send_message(msg) time.sleep(2) assert bn.executed_msg_atv == 3 self.log.info("_run_sync_case successful")
def _test_case_atv(self, payloads_amount): self.log.info("running _test_case_vbk()") # endorse block 5 addr = self.nodes[0].getnewaddress() for i in range(payloads_amount): self.log.info( "endorsing block 5 on node0 by miner {}".format(addr)) endorse_block(self.nodes[0], self.apm, 5, addr) # mine a block on node[1] with this pop tx containingblockhash = self.nodes[0].generate(nblocks=1)[0] containingblock = self.nodes[0].getblock(containingblockhash) assert len(containingblock['pop']['data']['atvs']) == payloads_amount self.log.info("success! _test_case_atv()")
def _invalidate_works(self): self.log.warning("starting _invalidate_works()") self.lastblock = self.nodes[0].getblockcount() # start with lastblock + 100 blocks self.chainAtiphash = self.nodes[0].generate(nblocks=100)[-1] self.log.info("node mined 100 blocks") self.assert_tip(self.chainAtiphash) # endorse block 300 (fork A tip) addr0 = self.nodes[0].getnewaddress() txid = endorse_block(self.nodes[0], self.apm, self.lastblock + 100, addr0) self.log.info("node endorsed block %d (fork A tip)", self.lastblock + 100) # mine pop tx on node0 self.chainAtiphash = self.nodes[0].generate(nblocks=1)[-1] self.assert_tip(self.chainAtiphash) containingblock = self.nodes[0].getblock(self.chainAtiphash) tip = self.get_best_block(self.nodes[0]) assert txid in containingblock['pop']['data'][ 'atvs'], "pop tx is not in containing block" self.log.info("node tip is {}".format(tip['height'])) self.chainAtiphash = self.nodes[0].generate(nblocks=19)[-1] self.chainAtipheight = self.nodes[0].getblock( self.chainAtiphash)['height'] self.forkheight = self.lastblock + 50 self.forkhash = self.nodes[0].getblockhash(self.forkheight) self.log.info("tip={}:{}, fork={}:{}".format(self.chainAtipheight, self.chainAtiphash, self.forkheight, self.forkhash)) self.invalidatedheight = self.forkheight + 1 self.invalidated = self.nodes[0].getblockhash(self.invalidatedheight) self.log.info("invalidating block next to fork block {}:{}".format( self.invalidatedheight, self.invalidated)) self.nodes[0].invalidateblock(self.invalidated) tip = self.get_best_block(self.nodes[0]) assert tip['height'] == self.forkheight assert tip['hash'] == self.forkhash tip = self.nodes[0].getblock(tip['hash']) assert not tip['pop']['state'][ 'endorsedBy'], "block should not be endorsed after invalidation" # rewrite invalid block with generatetoaddress # otherwise next block will be a duplicate addr1 = self.nodes[0].getnewaddress() self.chainBtiphash = self.nodes[0].generatetoaddress(nblocks=1, address=addr1)[-1]
def _run_sync_after_generating(self): self.log.info("running _run_sync_after_generating") bn = BaseNode(self.log) self.nodes[0].add_p2p_connection(bn) # endorse block 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block 5 on node0 by miner {}".format(addr)) tipheight = self.nodes[0].getblock( self.nodes[0].getbestblockhash())['height'] endorse_block(self.nodes[0], self.apm, tipheight - 5, addr) time.sleep(20) assert_equal(bn.executed_msg_offer_atv, 1) assert_equal(bn.executed_msg_offer_vbk, 1) self.log.info("_run_sync_after_generating successful")
def run_test(self): from pypoptools.pypopminer import MockMiner apm = MockMiner() mock_address = "bcrt1quc5k7w4692g0t0sfxc9xgcc25rzngu55zsfwp0" self.nodes[0].generatetoaddress(nblocks=900, address=mock_address) assert self.nodes[0].getblockcount() == 900 assert_raises_rpc_error(-1, 'POP protocol is not enabled. Current=900, bootstrap height=1000', endorse_block, self.nodes[0], apm, 800, mock_address) connect_nodes(self.nodes[0], 1) self.sync_blocks() assert self.nodes[1].getblockcount() == 900 assert_raises_rpc_error(-1, 'POP protocol is not enabled. Current=900, bootstrap height=1000', endorse_block, self.nodes[1], apm, 800, mock_address) disconnect_nodes(self.nodes[0], 1) self.nodes[0].generatetoaddress(nblocks=200, address=mock_address) assert self.nodes[0].getblockcount() == 1100 assert_raises_rpc_error(-1, 'POP protocol is not active. Current=1100, activation height=1200', endorse_block, self.nodes[0], apm, 1100, mock_address) connect_nodes(self.nodes[0], 1) self.sync_blocks() assert self.nodes[1].getblockcount() == 1100 assert_raises_rpc_error(-1, 'POP protocol is not active. Current=1100, activation height=1200', endorse_block, self.nodes[1], apm, 1100, mock_address) disconnect_nodes(self.nodes[0], 1) self.nodes[0].generatetoaddress(nblocks=200, address=mock_address) assert self.nodes[0].getblockcount() == 1300 endorse_block(self.nodes[0], apm, 1300, mock_address) connect_nodes(self.nodes[0], 1) self.sync_blocks() assert self.nodes[1].getblockcount() == 1300 endorse_block(self.nodes[1], apm, 1300, mock_address)
def _case1_endorse_keystone_get_paid(self): self.log.warning("running _case1_endorse_keystone_get_paid()") # endorse block 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block 5 on node0 by miner {}".format(addr)) atv_id = endorse_block(self.nodes[0], self.apm, 5, addr) # wait until node[1] gets relayed pop tx self.sync_pop_mempools(self.nodes) self.log.info("node1 got relayed transaction") # mine a block on node[1] with this pop tx containingblockhash = self.nodes[1].generate(nblocks=1)[0] containingblock = self.nodes[1].getblock(containingblockhash) self.log.info("node1 mined containing block={}".format(containingblock['hash'])) self.nodes[0].waitforblockheight(containingblock['height']) self.log.info("node0 got containing block over p2p") # assert that txid exists in this block block = self.nodes[0].getblock(containingblockhash) assert atv_id in block['pop']['data']['atvs'] # target height is 5 + POP_PAYOUT_DELAY + 1 n = POP_PAYOUT_DELAY + 6 - block['height'] payoutblockhash = self.nodes[1].generate(nblocks=n)[-1] self.sync_blocks(self.nodes) self.log.info("pop rewards paid") # check that expected block pays for this endorsement block = self.nodes[0].getblock(payoutblockhash) coinbasetxhash = block['tx'][0] coinbasetx = self.nodes[0].getrawtransaction(coinbasetxhash, 1) outputs = coinbasetx['vout'] assert len(outputs) > 3, "block with payout does not contain pop payout: {}".format(outputs) assert outputs[1]['n'] == 1 assert outputs[1]['value'] > 0, "expected non-zero output at n=1, got: {}".format(outputs[1]) # mine 100 blocks and check balance self.nodes[0].generate(nblocks=100) balance = self.nodes[0].getbalance() # node[0] has 11 mature coinbases and single pop payout assert balance == POW_PAYOUT * 10 + outputs[1]['value'] self.log.warning("success! _case1_endorse_keystone_get_paid()")
def _cannot_endorse(self): self.log.warning("starting _cannot_endorse()") # node0 start with 100 blocks self.nodes[0].generate(nblocks=100) self.nodes[0].waitforblockheight(100) assert self.get_best_block(self.nodes[0])['height'] == 100 self.log.info("node0 mined 100 blocks") # endorse block 100 (fork A tip) addr0 = self.nodes[0].getnewaddress() self.log.info( 'Should not accept POP data before activation block height') assert_raises_rpc_error( -1, 'POP protocol is not active. Current=100, activation height=200', lambda: endorse_block(self.nodes[0], self.apm, 100, addr0)) self.log.warning("_cannot_endorse() succeeded!")
def _cannot_endorse(self): self.log.warning("starting _cannot_endorse()") # node0 start with 100 blocks self.nodes[0].generate(nblocks=100) self.nodes[0].waitforblockheight(100) assert self.get_best_block(self.nodes[0])['height'] == 100 self.log.info("node0 mined 100 blocks") # endorse block 100 (fork A tip) addr0 = self.nodes[0].getnewaddress() txid = endorse_block(self.nodes[0], self.apm, 100, addr0) self.log.info("node0 endorsed block 100 (fork A tip)") # mine pop tx on node0 self.log.info( 'Should not accept POP data before activation block height') assert_raises_rpc_error( -1, 'block contains PopData before PopSecurity has been enabled', lambda: self.nodes[0].generate(nblocks=1)) self.log.warning("_cannot_endorse() succeeded!")
def _run_sync_after_generating(self): self.log.info("running _run_sync_after_generating") bn = BaseNode(self.log) self.nodes[0].add_p2p_connection(bn) # endorse block 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block 5 on node0 by miner {}".format(addr)) atv_id = endorse_block(self.nodes[0], self.apm, 5, addr) msg = msg_get_atv([atv_id]) self.nodes[0].p2p.send_message(msg) time.sleep(5) assert_equal(bn.executed_msg_atv, 1) assert_equal(bn.executed_msg_offer_vbk, 2) self.log.info("_run_sync_after_generating successful")
def _shorter_endorsed_chain_wins(self): self.log.warning("starting _shorter_endorsed_chain_wins()") lastblock = self.nodes[3].getblockcount() # stop node3 self.stop_node(3) self.log.info("node3 stopped with block height %d", lastblock) # all nodes start with lastblock + 103 blocks self.nodes[0].generate(nblocks=103) self.log.info("node0 mined 103 blocks") self.sync_blocks([self.nodes[0], self.nodes[1], self.nodes[2]], timeout=20) assert self.get_best_block(self.nodes[0])['height'] == lastblock + 103 assert self.get_best_block(self.nodes[1])['height'] == lastblock + 103 assert self.get_best_block(self.nodes[2])['height'] == lastblock + 103 self.log.info("nodes[0,1,2] synced are at block %d", lastblock + 103) # node2 is disconnected from others disconnect_nodes(self.nodes[2], 0) disconnect_nodes(self.nodes[2], 1) self.log.info("node2 is disconnected") # node2 mines another 97 blocks, so total height is lastblock + 200 self.nodes[2].generate(nblocks=97) # fork A is at 303 (lastblock = 200) # fork B is at 400 self.nodes[2].waitforblockheight(lastblock + 200) self.log.info("node2 mined 97 more blocks, total height is %d", lastblock + 200) bestblocks = [self.get_best_block(x) for x in self.nodes[0:3]] assert bestblocks[0] != bestblocks[2], "node[0,2] have same best hashes" assert bestblocks[0] == bestblocks[ 1], "node[0,1] have different best hashes: {} vs {}".format( bestblocks[0], bestblocks[1]) # mine a keystone interval of blocks to fork A self.nodes[0].generate(nblocks=self.keystoneInterval) self.sync_all(self.nodes[0:2]) self.log.info( "nodes[0,1] are in sync and are at fork A (%d...%d blocks)", lastblock + 103, lastblock + 103 + self.keystoneInterval) # fork B is at 400 assert bestblocks[2][ 'height'] == lastblock + 200, "unexpected tip: {}".format( bestblocks[2]) self.log.info("node2 is at fork B (%d...%d blocks)", lastblock + 103, lastblock + 200) assert 200 > 103 + self.keystoneInterval + 10, "keystone interval is set too high" # endorse block 303 + keystone interval (fork A tip) addr0 = self.nodes[0].getnewaddress() txid = endorse_block(self.nodes[0], self.apm, lastblock + 103 + self.keystoneInterval, addr0) self.log.info("node0 endorsed block %d (fork A tip)", lastblock + 103 + self.keystoneInterval) # mine pop tx on node0 containinghash = self.nodes[0].generate(nblocks=10) self.log.info("node0 mines 10 more blocks") self.sync_all(self.nodes[0:2]) containingblock = self.nodes[0].getblock(containinghash[0]) assert_equal(self.nodes[1].getblock(containinghash[0])['hash'], containingblock['hash']) tip = self.get_best_block(self.nodes[0]) assert txid in containingblock['pop']['data'][ 'atvs'], "pop tx is not in containing block" self.sync_blocks(self.nodes[0:2]) self.log.info( "nodes[0,1] are in sync, pop tx containing block is {}".format( containingblock['height'])) self.log.info("node0 tip is {}".format(tip['height'])) connect_nodes(self.nodes[0], 2) connect_nodes(self.nodes[1], 2) self.log.info("node2 connected to nodes[0,1]") self.start_node(3) connect_nodes(self.nodes[3], 0) connect_nodes(self.nodes[3], 2) self.log.info("node3 started with 0 blocks, connected to nodes[0,2]") self.sync_blocks(self.nodes, timeout=30) self.log.info("nodes[0,1,2,3] are in sync") # expected best block hash is fork A (has higher pop score) bestblocks = [self.get_best_block(x) for x in self.nodes] assert_equal(bestblocks[0]['hash'], bestblocks[1]['hash']) assert_equal(bestblocks[0]['hash'], bestblocks[2]['hash']) assert_equal(bestblocks[0]['hash'], bestblocks[3]['hash']) self.log.info("all nodes switched to common block") for i in range(len(bestblocks)): assert bestblocks[i]['height'] == tip['height'], \ "node[{}] expected to select shorter chain ({}) with higher pop score\n" \ "but selected longer chain ({})".format(i, tip['height'], bestblocks[i]['height']) # get best headers view blockchaininfo = [x.getblockchaininfo() for x in self.nodes] for n in blockchaininfo: assert_equal(n['blocks'], n['headers']) self.log.info("all nodes selected fork A as best chain") self.log.warning("_shorter_endorsed_chain_wins() succeeded!")
def _case1_endorse_keystone_get_paid(self): self.log.warning("running _case1_endorse_keystone_get_paid()") lastblock = self.nodes[0].getblockcount() self.nodes[0].generate(nblocks=10) self.nodes[0].waitforblockheight(lastblock + 10) lastblock = self.nodes[0].getblockcount() self.log.info("node0 mined 10 more blocks") # endorse block 5 assert lastblock >= 5 addr = self.nodes[0].getnewaddress() self.log.info("endorsing block {} on node0 by miner {}".format( lastblock - 5, addr)) atv_id = endorse_block(self.nodes[0], self.apm, lastblock - 5, addr) # wait until node[1] gets relayed pop tx self.sync_pop_mempools(self.nodes) self.log.info("node1 got relayed transaction") # mine a block on node[1] with this pop tx containingblockhash = self.nodes[1].generate(nblocks=1)[0] containingblock = self.nodes[1].getblock(containingblockhash) self.log.info("node1 mined containing block={}".format( containingblock['hash'])) self.nodes[0].waitforblockheight(containingblock['height']) self.log.info("node0 got containing block over p2p") # assert that txid exists in this block block = self.nodes[0].getblock(containingblockhash) assert atv_id in block['pop']['data']['atvs'] # target height is lastblock - 5 + POP_PAYOUT_DELAY + 1 n = lastblock - 5 + POP_PAYOUT_DELAY + 1 - block['height'] payoutblockhash = self.nodes[1].generate(nblocks=n)[-1] self.sync_blocks(self.nodes) self.log.info("pop rewards paid") # check that expected block pays for this endorsement block = self.nodes[0].getblock(payoutblockhash) coinbasetxhash = block['tx'][0] coinbasetx = self.nodes[0].getrawtransaction(coinbasetxhash, 1) outputs = coinbasetx['vout'] assert len( outputs ) > 3, "block with payout does not contain pop payout: {}".format( outputs) assert outputs[1]['n'] == 1 assert outputs[1][ 'value'] > 0, "expected non-zero output at n=1, got: {}".format( outputs[1]) # mine 100 blocks and check balance self.nodes[0].generate(nblocks=100) balance = self.nodes[0].getbalance() # node[0] has 210 (lastblock) mature coinbases and a single pop payout assert lastblock == 210, "calculation below are only valid for POP activation height = 210" pop_payout = float(outputs[1]['value']) half_payout = POW_PAYOUT / 2 assert balance == POW_PAYOUT * 149 + half_payout * 50 + half_payout * .6 * 11 + pop_payout self.log.warning("success! _case1_endorse_keystone_get_paid()")