def check_get_bulk_payments(self): print('Checking get_bulk_payments') daemon = Daemon() res = daemon.get_info() height = res.height self.wallet[0].refresh() res = self.wallet[0].get_bulk_payments() assert len(res.payments) >= 83 # at least 83 coinbases res = self.wallet[0].get_bulk_payments(payment_ids = ['1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde']) assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[0].get_bulk_payments(min_block_height = height) assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[0].get_bulk_payments(min_block_height = height - 40) assert len(res.payments) >= 39 # coinbases self.wallet[1].refresh() res = self.wallet[1].get_bulk_payments() assert len(res.payments) >= 3 # two txes to standard address were sent, plus one to integrated address res = self.wallet[1].get_bulk_payments(payment_ids = ['1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde']) assert len(res.payments) >= 2 # two txes were sent with that payment id res = self.wallet[1].get_bulk_payments(payment_ids = ['ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff']) assert 'payments' not in res or len(res.payments) == 0 # none with that payment id res = self.wallet[1].get_bulk_payments(payment_ids = ['1111111122222222' + '0'*48]) assert len(res.payments) >= 1 # one tx to integrated address self.wallet[2].refresh() res = self.wallet[2].get_bulk_payments() assert len(res.payments) >= 1 # one tx was sent res = self.wallet[2].get_bulk_payments(payment_ids = ['1'*64, '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde', '2'*64]) assert len(res.payments) >= 1 # one tx was sent
def check_get_bulk_payments(self): print('Checking get_bulk_payments') daemon = Daemon() res = daemon.get_info() height = res.height self.wallet[0].refresh() res = self.wallet[0].get_bulk_payments() assert len(res.payments) >= 83 # at least 83 coinbases res = self.wallet[0].get_bulk_payments(payment_ids = ['1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde']) assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[0].get_bulk_payments(min_block_height = height) assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[0].get_bulk_payments(min_block_height = height - 40) assert len(res.payments) >= 39 # coinbases self.wallet[1].refresh() res = self.wallet[1].get_bulk_payments() assert len(res.payments) >= 3 # two txes to standard address were sent, plus one to integrated address res = self.wallet[1].get_bulk_payments(payment_ids = ['1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde']) assert not 'payments' in res or len(res.payments) == 0 # long payment IDs are now ignored on receipt res = self.wallet[1].get_bulk_payments(payment_ids = ['ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff']) assert 'payments' not in res or len(res.payments) == 0 # none with that payment id res = self.wallet[1].get_bulk_payments(payment_ids = ['1111111122222222' + '0'*48]) assert len(res.payments) >= 1 # one tx to integrated address self.wallet[2].refresh() res = self.wallet[2].get_bulk_payments() assert len(res.payments) >= 1 # one tx was sent res = self.wallet[2].get_bulk_payments(payment_ids = ['1'*64, '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde', '2'*64]) assert not 'payments' in res or len(res.payments) == 0 # long payment IDs are now ignored res = self.wallet[1].get_bulk_payments(["1111111122222222"]) assert len(res.payments) >= 1 # we have one of these
def _test_get_info(self): print('Test get_info') daemon = Daemon() res = daemon.get_info() # difficulty should be set to 1 for this test assert 'difficulty' in res.keys() assert res.difficulty == 1; # nettype should not be TESTNET assert 'testnet' in res.keys() assert res.testnet == False; # nettype should not be STAGENET assert 'stagenet' in res.keys() assert res.stagenet == False; # nettype should be FAKECHAIN assert 'nettype' in res.keys() assert res.nettype == "fakechain"; # free_space should be > 0 assert 'free_space' in res.keys() assert res.free_space > 0 # height should be greater or equal to 1 assert 'height' in res.keys() assert res.height >= 1
def check_get_payments(self): print('Checking get_payments') daemon = Daemon(idx=2) res = daemon.get_info() height = res.height self.wallet[0].refresh() self.wallet[1].refresh() res = self.wallet[0].get_payments( '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde') assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[1].get_payments( '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde') assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[1].get_payments( 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') assert 'payments' not in res or len(res.payments) == 0 res = self.wallet[1].get_payments(payment_id='1111111122222222' + '0' * 48) assert len(res.payments) >= 1 # one tx to integrated address
def _test_get_info(self): print('Test get_info') daemon = Daemon() res = daemon.get_info() # difficulty should be set to 1 for this test assert 'difficulty' in res.keys() assert res.difficulty == int(os.environ['DIFFICULTY']) # nettype should not be TESTNET assert 'testnet' in res.keys() assert res.testnet == False # nettype should not be STAGENET assert 'stagenet' in res.keys() assert res.stagenet == False # nettype should be FAKECHAIN assert 'nettype' in res.keys() assert res.nettype == "fakechain" # free_space should be > 0 assert 'free_space' in res.keys() assert res.free_space > 0 # height should be greater or equal to 1 assert 'height' in res.keys() assert res.height >= 1
def test_access_payment(self): print('Testing access payment') daemon = Daemon(idx=1) wallet = Wallet(idx=3) # Try random nonces till we find one that's valid so we get a load of credits res = daemon.rpc_access_info(client = self.get_signature()) credits = res.credits cookie = res.cookie nonce = 0 while credits <= 100: nonce += 1 try: res = daemon.rpc_access_submit_nonce(nonce = nonce, cookie = cookie, client = self.get_signature()) break except: pass assert nonce < 1000 # can't find both valid and invalid -> the RPC probably fails res = daemon.rpc_access_info(client = self.get_signature()) credits = res.credits assert credits > 0 res = daemon.get_info(client = self.get_signature()) assert res.credits == credits - 1 credits = res.credits res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 100) block_hashes = res.blocks # ask for 1 block -> 1 credit res = daemon.getblockheadersrange(0, 0, client = self.get_signature()) assert res.credits == credits - 1 credits = res.credits # ask for 100 blocks -> >1 credit res = daemon.getblockheadersrange(1, 100, client = self.get_signature()) assert res.credits < credits - 1 credits = res.credits # external users res = daemon.rpc_access_pay(payment = 1, paying_for = 'foo', client = self.get_signature()) assert res.credits == credits - 1 res = daemon.rpc_access_pay(payment = 4, paying_for = 'bar', client = self.get_signature()) assert res.credits == credits - 5 res = daemon.rpc_access_pay(payment = credits, paying_for = 'baz', client = self.get_signature()) assert "PAYMENT REQUIRED" in res.status res = daemon.rpc_access_pay(payment = 2, paying_for = 'quux', client = self.get_signature()) assert res.credits == credits - 7 res = daemon.rpc_access_pay(payment = 3, paying_for = 'bar', client = self.get_signature()) assert res.credits == credits - 10 # that should be rejected because its cost is massive ok = False try: res = daemon.get_output_histogram(amounts = [], client = self.get_signature()) except Exception as e: print('e: ' + str(e)); ok = "PAYMENT REQUIRED" in e.status assert ok or "PAYMENT REQUIRED" in res.status
def mine(self): print("Mining some blocks") daemon = Daemon() res = daemon.get_info() height = res.height daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 80) for i in range(len(self.wallet)): self.wallet[i].refresh() res = self.wallet[i].get_height() assert res.height == height + 80
def mine(self): print("Mining some blocks") daemon = Daemon() res = daemon.get_info() height = res.height daemon.generateblocks( 'Sumoo1aLd1yKkerxdjbXggMf3mdy5m9tZeWpYU913LSmZuUdMjJnoa67vp2WB7sV2ZHCBZbh2MekDK2emfWCxZZ997WpRfimvjq', 80) for i in range(len(self.wallet)): self.wallet[i].refresh() res = self.wallet[i].get_height() assert res.height == height + 80
def test_free_access(self): print('Testing free access') daemon = Daemon(idx=0) wallet = Wallet(idx=0) res = daemon.rpc_access_info(client = self.get_signature()) assert res.credits_per_hash_found == 0 assert res.diff == 0 assert res.credits == 0 res = daemon.get_info(client = self.get_signature()) assert res.credits == 0 # any nonce will do here res = daemon.rpc_access_submit_nonce(nonce = 0, cookie = 0, client = self.get_signature()) assert res.credits == 0
def mine(self): print("Test mining") daemon = Daemon() wallet = Wallet() # check info/height/balance before generating blocks res_info = daemon.get_info() prev_height = res_info.height res_getbalance = wallet.get_balance() prev_balance = res_getbalance.balance res_status = daemon.mining_status() res = daemon.start_mining( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count=1) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == False assert res_status.block_reward >= 600000000000 # wait till we mined a few of them timeout = 5 timeout_height = prev_height while True: time.sleep(1) res_info = daemon.get_info() height = res_info.height if height >= prev_height + 5: break if height > timeout_height: timeout = 5 timeout_height = height else: timeout -= 1 assert timeout >= 0 res = daemon.stop_mining() res_status = daemon.mining_status() assert res_status.active == False res_info = daemon.get_info() new_height = res_info.height wallet.refresh() res_getbalance = wallet.get_balance() balance = res_getbalance.balance assert balance >= prev_balance + (new_height - prev_height) * 600000000000 res = daemon.start_mining( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count=1, do_background_mining=True) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == True assert res_status.block_reward >= 600000000000 # don't wait, might be a while if the machine is busy, which it probably is res = daemon.stop_mining() res_status = daemon.mining_status() assert res_status.active == False
def _test_generateblocks(self, blocks): assert blocks >= 2 print "Test generating", blocks, 'blocks' daemon = Daemon() # check info/height before generating blocks res_info = daemon.get_info() height = res_info.height prev_block = res_info.top_block_hash res_height = daemon.get_height() assert res_height.height == height assert int(res_info.wide_cumulative_difficulty) == (res_info.cumulative_difficulty_top64 << 64) + res_info.cumulative_difficulty cumulative_difficulty = int(res_info.wide_cumulative_difficulty) # we should not see a block at height ok = False try: daemon.getblock(height) except: ok = True assert ok # generate blocks res_generateblocks = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks) # check info/height after generateblocks blocks assert res_generateblocks.height == height + blocks - 1 res_info = daemon.get_info() assert res_info.height == height + blocks assert res_info.top_block_hash != prev_block res_height = daemon.get_height() assert res_height.height == height + blocks # get the blocks, check they have the right height res_getblock = [] for n in range(blocks): res_getblock.append(daemon.getblock(height + n)) block_header = res_getblock[n].block_header assert abs(block_header.timestamp - time.time()) < 10 # within 10 seconds assert block_header.height == height + n assert block_header.orphan_status == False assert block_header.depth == blocks - n - 1 assert block_header.prev_hash == prev_block, prev_block assert int(block_header.wide_difficulty) == (block_header.difficulty_top64 << 64) + block_header.difficulty assert int(block_header.wide_cumulative_difficulty) == (block_header.cumulative_difficulty_top64 << 64) + block_header.cumulative_difficulty assert block_header.reward >= 600000000000 # tail emission cumulative_difficulty += int(block_header.wide_difficulty) assert cumulative_difficulty == int(block_header.wide_cumulative_difficulty) assert block_header.block_size > 0 assert block_header.block_weight >= block_header.block_size assert block_header.long_term_weight > 0 prev_block = block_header.hash # we should not see a block after that ok = False try: daemon.getblock(height + blocks) except: ok = True assert ok # getlastblockheader and by height/hash should return the same block res_getlastblockheader = daemon.getlastblockheader() assert res_getlastblockheader.block_header == block_header res_getblockheaderbyhash = daemon.getblockheaderbyhash(prev_block) assert res_getblockheaderbyhash.block_header == block_header res_getblockheaderbyheight = daemon.getblockheaderbyheight(height + blocks - 1) assert res_getblockheaderbyheight.block_header == block_header # getting a block template after that should have the right height, etc res_getblocktemplate = daemon.getblocktemplate('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm') assert res_getblocktemplate.height == height + blocks assert res_getblocktemplate.reserved_offset > 0 assert res_getblocktemplate.prev_hash == res_info.top_block_hash assert res_getblocktemplate.expected_reward >= 600000000000 assert len(res_getblocktemplate.blocktemplate_blob) > 0 assert len(res_getblocktemplate.blockhashing_blob) > 0 assert int(res_getblocktemplate.wide_difficulty) == (res_getblocktemplate.difficulty_top64 << 64) + res_getblocktemplate.difficulty # diff etc should be the same assert res_getblocktemplate.prev_hash == res_info.top_block_hash res_getlastblockheader = daemon.getlastblockheader() # pop a block res_popblocks = daemon.pop_blocks(1) assert res_popblocks.height == height + blocks - 1 res_info = daemon.get_info() assert res_info.height == height + blocks - 1 # getlastblockheader and by height/hash should return the previous block block_header = res_getblock[blocks - 2].block_header block_header.depth = 0 # this will be different, ignore it res_getlastblockheader = daemon.getlastblockheader() assert res_getlastblockheader.block_header == block_header res_getblockheaderbyhash = daemon.getblockheaderbyhash(block_header.hash) assert res_getblockheaderbyhash.block_header == block_header res_getblockheaderbyheight = daemon.getblockheaderbyheight(height + blocks - 2) assert res_getblockheaderbyheight.block_header == block_header # we should not see the popped block anymore ok = False try: daemon.getblock(height + blocks - 1) except: ok = True assert ok
def mine(self, via_daemon): print("Test mining via " + ("daemon" if via_daemon else "wallet")) cores_init = multiprocessing.cpu_count() # RX init uses all cores cores_mine = 1 # Mining uses a parametric number of cores is_mining_measurent = 'MINING_NO_MEASUREMENT' not in os.environ if is_mining_measurent: # A dynamic calculation of the CPU power requested time_pi_single_cpu = self.measure_cpu_power_get_time(cores_mine) time_pi_all_cores = self.measure_cpu_power_get_time(cores_init) # This is the last measurement, since it takes very little time and can be placed timewise-closer to the mining itself. available_ram = self.get_available_ram( ) # So far no ideas how to use this var, other than printing it start = monotonic.monotonic() daemon = Daemon() wallet = Wallet() # check info/height/balance before generating blocks res_info = daemon.get_info() initial_height = res_info.height res_getbalance = wallet.get_balance() prev_balance = res_getbalance.balance res_status = daemon.mining_status() if via_daemon: res = daemon.start_mining( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count=1) else: res = wallet.start_mining(threads_count=cores_mine) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == cores_mine assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == False assert res_status.block_reward >= 600000000000 # wait till we mined a few of them target_height = initial_height + 5 height = initial_height if not is_mining_measurent: timeout_init = 600 timeout_mine = 300 else: """ Randomx init has high variance on CI machines due to noisy neighbors, taking up resources in parallel (including by our own jobs). Mining is organized in the following scheme: 1) first loop's pass: RandomX init and mining 2) every next pass: only mining Pass 1) takes much more time than pass 2) Pass 1) uses all cores, pass 2) just one (currently) For the above reasons both passes need separate timeouts and adjustments. After the first pass, the timeout is being reset to a lower value. """ def calc_timeout(seconds_constant, time_pi, cores): """ The time it took to calculate pi under certain conditions is proportional to the time it will take to calculate the real job. The number of cores used decreases the time almost linearly. """ timeout = float(seconds_constant) * time_pi / float(cores) return timeout timeout_base_init = 60 # RX init needs more time timeout_base_mine = 20 timeout_init = calc_timeout(timeout_base_init, time_pi_all_cores, cores_init) timeout_mine = calc_timeout(timeout_base_mine, time_pi_single_cpu, cores_mine) msg_timeout_src = "adjusted for the currently available CPU power" if is_mining_measurent else "selected to have the default value" msg = "Timeout for {} {}, is {:.1f} s" self.print_mining_info( msg.format("init, ", msg_timeout_src, timeout_init)) self.print_mining_info( msg.format("mining,", msg_timeout_src, timeout_mine)) timeout = timeout_init rx_inited = False # Gets initialized in the first pass of the below loop while height < target_height: seen_height = height for _ in range(int(math.ceil(timeout))): time.sleep(1) seconds_passed = monotonic.monotonic() - start height = daemon.get_info().height if height > seen_height: break else: assert False, 'Failed to mine successor to block %d (initial block = %d) after %d s. RX initialized = %r' % ( seen_height, initial_height, round(seconds_passed), rx_inited) if not rx_inited: rx_inited = True timeout = timeout_mine # Resetting the timeout after first mined block and RX init self.print_time_taken(start, "RX init + mining 1st block") else: self.print_time_taken(start, "mining iteration") self.print_time_taken(start, "mining total") if via_daemon: res = daemon.stop_mining() else: res = wallet.stop_mining() res_status = daemon.mining_status() assert res_status.active == False res_info = daemon.get_info() new_height = res_info.height wallet.refresh() res_getbalance = wallet.get_balance() balance = res_getbalance.balance assert balance >= prev_balance + (new_height - initial_height) * 600000000000 if via_daemon: res = daemon.start_mining( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count=1, do_background_mining=True) else: res = wallet.start_mining(threads_count=1, do_background_mining=True) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == True assert res_status.block_reward >= 600000000000 # don't wait, might be a while if the machine is busy, which it probably is if via_daemon: res = daemon.stop_mining() else: res = wallet.stop_mining() res_status = daemon.mining_status() assert res_status.active == False
def test_randomx(self): print("Test RandomX") daemon = Daemon() wallet = Wallet() res = daemon.get_height() daemon.pop_blocks(res.height - 1) daemon.flush_txpool() epoch = int(os.environ['SEEDHASH_EPOCH_BLOCKS']) lag = int(os.environ['SEEDHASH_EPOCH_LAG']) address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' # check we can generate blocks, and that the seed hash changes when expected res = daemon.getblocktemplate(address) first_seed_hash = res.seed_hash daemon.generateblocks(address, 1 + lag) res = daemon.mining_status() assert res.active == False assert res.pow_algorithm == 'RandomX' res = daemon.getblocktemplate(address) seed_hash = res.seed_hash t0 = time.time() daemon.generateblocks(address, epoch - 3) t0 = time.time() - t0 res = daemon.get_info() assert res.height == lag + epoch - 1 res = daemon.getblocktemplate(address) assert seed_hash == res.seed_hash t0 = time.time() daemon.generateblocks(address, 1) t0 = time.time() - t0 res = daemon.get_info() assert res.height == lag + epoch daemon.generateblocks(address, 1) res = daemon.getblocktemplate(address) assert seed_hash != res.seed_hash new_seed_hash = res.seed_hash t0 = time.time() daemon.generateblocks(address, epoch - 1) t0 = time.time() - t0 res = daemon.getblocktemplate(address) assert new_seed_hash == res.seed_hash daemon.generateblocks(address, 1) res = daemon.getblocktemplate(address) assert new_seed_hash != res.seed_hash new_seed_hash = res.seed_hash t0 = time.time() daemon.generateblocks(address, epoch - 1) t0 = time.time() - t0 res = daemon.getblocktemplate(address) assert new_seed_hash == res.seed_hash daemon.generateblocks(address, 1) res = daemon.getblocktemplate(address) assert new_seed_hash != res.seed_hash #print('First mining: ' + str(t0)) # pop all these blocks, and feed them again to monerod print('Recreating the chain') res = daemon.get_info() height = res.height assert height == lag + epoch * 3 + 1 block_hashes = [ x.hash for x in daemon.getblockheadersrange(0, height - 1).headers ] assert len(block_hashes) == height blocks = [] for i in range(len(block_hashes)): res = daemon.getblock(height=i) assert res.block_header.hash == block_hashes[i] blocks.append(res.blob) daemon.pop_blocks(height) res = daemon.get_info() assert res.height == 1 res = daemon.getblocktemplate(address) assert first_seed_hash == res.seed_hash t0 = time.time() for h in range(len(block_hashes)): res = daemon.submitblock(blocks[h]) t0 = time.time() - t0 res = daemon.get_info() assert height == res.height res = daemon.getblocktemplate(address) assert new_seed_hash != res.seed_hash res = daemon.pop_blocks(1) res = daemon.getblocktemplate(address) assert new_seed_hash == res.seed_hash #print('Submit: ' + str(t0)) # start mining from the genesis block again print('Mining from genesis block again') res = daemon.get_height() top_hash = res.hash res = daemon.getblockheaderbyheight(0) genesis_block_hash = res.block_header.hash t0 = time.time() daemon.generateblocks(address, height - 2, prev_block=genesis_block_hash) t0 = time.time() - t0 res = daemon.get_info() assert res.height == height - 1 assert res.top_block_hash == top_hash #print('Second mining: ' + str(t0)) # that one will cause a huge reorg print('Adding one to reorg') res = daemon.generateblocks(address, 1) assert len(res.blocks) == 1 new_top_hash = res.blocks[0] res = daemon.get_info() assert res.height == height assert res.top_block_hash == new_top_hash
def check_txpool(self): daemon = Daemon() wallet = Wallet() res = daemon.get_info() height = res.height txpool_size = res.tx_pool_size self.check_empty_pool() txes = self.create_txes('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 5) res = daemon.get_info() assert res.tx_pool_size == txpool_size + 5 txpool_size = res.tx_pool_size res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size total_bytes = 0 total_fee = 0 min_bytes = 99999999999999 max_bytes = 0 for txid in txes.keys(): x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == False assert x.last_failed_id_hash == '0'*64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob total_bytes += x.blob_size total_fee += x.fee min_bytes = min(min_bytes, x.blob_size) max_bytes = max(max_bytes, x.blob_size) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(txes.keys()) res = daemon.get_transaction_pool_stats() assert res.pool_stats.bytes_total == total_bytes assert res.pool_stats.bytes_min == min_bytes assert res.pool_stats.bytes_max == max_bytes assert res.pool_stats.bytes_med >= min_bytes and res.pool_stats.bytes_med <= max_bytes assert res.pool_stats.fee_total == total_fee assert res.pool_stats.txs_total == len(txes) assert res.pool_stats.num_failing == 0 assert res.pool_stats.num_10m == 0 assert res.pool_stats.num_not_relayed == 0 assert res.pool_stats.num_double_spends == 0 print('Flushing 2 transactions') txes_keys = list(txes.keys()) daemon.flush_txpool([txes_keys[1], txes_keys[3]]) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0 assert len([x for x in res.transactions if x.id_hash == txes_keys[3]]) == 0 new_keys = list(txes.keys()) new_keys.remove(txes_keys[1]) new_keys.remove(txes_keys[3]) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) res = daemon.get_transaction_pool() assert len(res.transactions) == len(new_keys) total_bytes = 0 total_fee = 0 min_bytes = 99999999999999 max_bytes = 0 for txid in new_keys: x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == False assert x.last_failed_id_hash == '0'*64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob total_bytes += x.blob_size total_fee += x.fee min_bytes = min(min_bytes, x.blob_size) max_bytes = max(max_bytes, x.blob_size) res = daemon.get_transaction_pool_stats() assert res.pool_stats.bytes_total == total_bytes assert res.pool_stats.bytes_min == min_bytes assert res.pool_stats.bytes_max == max_bytes assert res.pool_stats.bytes_med >= min_bytes and res.pool_stats.bytes_med <= max_bytes assert res.pool_stats.fee_total == total_fee assert res.pool_stats.txs_total == len(new_keys) assert res.pool_stats.num_failing == 0 assert res.pool_stats.num_10m == 0 assert res.pool_stats.num_not_relayed == 0 assert res.pool_stats.num_double_spends == 0 print('Flushing unknown transactions') unknown_txids = ['1'*64, '2'*64, '3'*64] daemon.flush_txpool(unknown_txids) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 print('Mining transactions') daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.get_transaction_pool() assert not 'transactions' in res or len(res.transactions) == txpool_size - 5 res = daemon.get_transaction_pool_hashes() assert not 'tx_hashes' in res or len(res.tx_hashes) == 0 self.check_empty_pool() print('Popping block') daemon.pop_blocks(1) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 for txid in new_keys: x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == True assert x.last_failed_id_hash == '0'*64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob print('Checking relaying txes') res = daemon.get_transaction_pool_hashes() assert len(res.tx_hashes) > 0 txid = res.tx_hashes[0] daemon.relay_tx([txid]) res = daemon.get_transactions([txid]) assert len(res.txs) == 1 assert res.txs[0].tx_hash == txid assert res.txs[0].in_pool assert res.txs[0].relayed daemon.flush_txpool() self.check_empty_pool()
def test_p2p_reorg(self): print('Testing P2P reorg') daemon2 = Daemon(idx=2) daemon3 = Daemon(idx=3) # give sync some time time.sleep(1) res = daemon2.get_info() height = res.height assert height > 0 top_block_hash = res.top_block_hash assert len(top_block_hash) == 64 res = daemon3.get_info() assert res.height == height assert res.top_block_hash == top_block_hash # disconnect daemons and mine separately on both daemon2.out_peers(0) daemon3.out_peers(0) res = daemon2.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 2) res = daemon3.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 3) res = daemon2.get_info() assert res.height == height + 2 daemon2_top_block_hash = res.top_block_hash assert daemon2_top_block_hash != top_block_hash res = daemon3.get_info() assert res.height == height + 3 daemon3_top_block_hash = res.top_block_hash assert daemon3_top_block_hash != top_block_hash assert daemon3_top_block_hash != daemon2_top_block_hash # reconnect, daemon2 will now switch to daemon3's chain daemon2.out_peers(8) daemon3.out_peers(8) time.sleep(10) res = daemon2.get_info() assert res.height == height + 3 assert res.top_block_hash == daemon3_top_block_hash # disconect, mine on daemon2 again more than daemon3 daemon2.out_peers(0) daemon3.out_peers(0) res = daemon2.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 3) res = daemon3.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 2) res = daemon2.get_info() assert res.height == height + 6 daemon2_top_block_hash = res.top_block_hash assert daemon2_top_block_hash != top_block_hash res = daemon3.get_info() assert res.height == height + 5 daemon3_top_block_hash = res.top_block_hash assert daemon3_top_block_hash != top_block_hash assert daemon3_top_block_hash != daemon2_top_block_hash # reconnect, daemon3 will now switch to daemon2's chain daemon2.out_peers(8) daemon3.out_peers(8) time.sleep(5) res = daemon3.get_info() assert res.height == height + 6 assert res.top_block_hash == daemon2_top_block_hash # disconnect and mine a lot on daemon3 daemon2.out_peers(0) daemon3.out_peers(0) res = daemon3.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 500) # reconnect and wait for sync daemon2.out_peers(8) daemon3.out_peers(8) loops = 100 while True: res2 = daemon2.get_info() res3 = daemon3.get_info() if res2.top_block_hash == res3.top_block_hash: break time.sleep(10) loops -= 1 assert loops >= 0
def _test_generateblocks(self, blocks): assert blocks >= 2 print("Test generating", blocks, 'blocks') daemon = Daemon() # check info/height before generating blocks res_info = daemon.get_info() height = res_info.height prev_block = res_info.top_block_hash res_height = daemon.get_height() assert res_height.height == height assert int(res_info.wide_cumulative_difficulty) == ( res_info.cumulative_difficulty_top64 << 64) + res_info.cumulative_difficulty cumulative_difficulty = int(res_info.wide_cumulative_difficulty) # we should not see a block at height ok = False try: daemon.getblock(height) except: ok = True assert ok # generate blocks res_generateblocks = daemon.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks) # check info/height after generateblocks blocks assert res_generateblocks.height == height + blocks - 1 res_info = daemon.get_info() assert res_info.height == height + blocks assert res_info.top_block_hash != prev_block res_height = daemon.get_height() assert res_height.height == height + blocks # get the blocks, check they have the right height res_getblock = [] for n in range(blocks): res_getblock.append(daemon.getblock(height + n)) block_header = res_getblock[n].block_header assert abs(block_header.timestamp - time.time()) < 10 # within 10 seconds assert block_header.height == height + n assert block_header.orphan_status == False assert block_header.depth == blocks - n - 1 assert block_header.prev_hash == prev_block, prev_block assert int(block_header.wide_difficulty) == ( block_header.difficulty_top64 << 64) + block_header.difficulty assert int(block_header.wide_cumulative_difficulty) == ( block_header.cumulative_difficulty_top64 << 64) + block_header.cumulative_difficulty assert block_header.reward >= 600000000000 # tail emission cumulative_difficulty += int(block_header.wide_difficulty) assert cumulative_difficulty == int( block_header.wide_cumulative_difficulty) assert block_header.block_size > 0 assert block_header.block_weight >= block_header.block_size assert block_header.long_term_weight > 0 prev_block = block_header.hash # we should not see a block after that ok = False try: daemon.getblock(height + blocks) except: ok = True assert ok # getlastblockheader and by height/hash should return the same block res_getlastblockheader = daemon.getlastblockheader() assert res_getlastblockheader.block_header == block_header res_getblockheaderbyhash = daemon.getblockheaderbyhash(prev_block) assert res_getblockheaderbyhash.block_header == block_header res_getblockheaderbyheight = daemon.getblockheaderbyheight(height + blocks - 1) assert res_getblockheaderbyheight.block_header == block_header # getting a block template after that should have the right height, etc res_getblocktemplate = daemon.getblocktemplate( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' ) assert res_getblocktemplate.height == height + blocks assert res_getblocktemplate.reserved_offset > 0 assert res_getblocktemplate.prev_hash == res_info.top_block_hash assert res_getblocktemplate.expected_reward >= 600000000000 assert len(res_getblocktemplate.blocktemplate_blob) > 0 assert len(res_getblocktemplate.blockhashing_blob) > 0 assert int(res_getblocktemplate.wide_difficulty) == ( res_getblocktemplate.difficulty_top64 << 64) + res_getblocktemplate.difficulty # diff etc should be the same assert res_getblocktemplate.prev_hash == res_info.top_block_hash res_getlastblockheader = daemon.getlastblockheader() # pop a block res_popblocks = daemon.pop_blocks(1) assert res_popblocks.height == height + blocks - 1 res_info = daemon.get_info() assert res_info.height == height + blocks - 1 # getlastblockheader and by height/hash should return the previous block block_header = res_getblock[blocks - 2].block_header block_header.depth = 0 # this will be different, ignore it res_getlastblockheader = daemon.getlastblockheader() assert res_getlastblockheader.block_header == block_header res_getblockheaderbyhash = daemon.getblockheaderbyhash( block_header.hash) assert res_getblockheaderbyhash.block_header == block_header res_getblockheaderbyheight = daemon.getblockheaderbyheight(height + blocks - 2) assert res_getblockheaderbyheight.block_header == block_header # we should not see the popped block anymore ok = False try: daemon.getblock(height + blocks - 1) except: ok = True assert ok # get transactions res = daemon.get_info() assert res.height == height + blocks - 1 nblocks = height + blocks - 1 res = daemon.getblockheadersrange(0, nblocks - 1) assert len(res.headers) == nblocks assert res.headers[-1] == block_header txids = [x.miner_tx_hash for x in res.headers] res = daemon.get_transactions(txs_hashes=txids) assert len(res.txs) == nblocks assert not 'missed_txs' in res or len(res.missed_txs) == 0 running_output_index = 0 for i in range(len(txids)): tx = res.txs[i] assert tx.tx_hash == txids[i] assert not tx.double_spend_seen assert not tx.in_pool assert tx.block_height == i if i > 0: for idx in tx.output_indices: assert idx == running_output_index running_output_index += 1 res_out = daemon.get_outs([{ 'amount': 0, 'index': idx } for idx in tx.output_indices], get_txid=True) assert len(res_out.outs) == len(tx.output_indices) for out in res_out.outs: assert len(out.key) == 64 assert len(out.mask) == 64 assert not out.unlocked assert out.height == i assert out.txid == txids[i] for i in range(height + nblocks - 1): res_sum = daemon.get_coinbase_tx_sum(i, 1) res_header = daemon.getblockheaderbyheight(i) assert res_sum.emission_amount == res_header.block_header.reward res = daemon.get_coinbase_tx_sum(0, 1) assert res.emission_amount == 17592186044415 assert res.fee_amount == 0 sum_blocks = height + nblocks - 1 res = daemon.get_coinbase_tx_sum(0, sum_blocks) extrapolated = 17592186044415 + 17592186044415 * 2 * (sum_blocks - 1) assert res.emission_amount < extrapolated and res.emission_amount > extrapolated - 1e12 assert res.fee_amount == 0 sum_blocks_emission = res.emission_amount res = daemon.get_coinbase_tx_sum(1, sum_blocks) assert res.emission_amount == sum_blocks_emission - 17592186044415 assert res.fee_amount == 0 res = daemon.get_output_distribution([0, 1, 17592186044415], 0, 0) assert len(res.distributions) == 3 for a in range(3): assert res.distributions[a].amount == [0, 1, 17592186044415][a] assert res.distributions[a].start_height == 0 assert res.distributions[a].base == 0 assert len( res.distributions[a].distribution) == height + nblocks - 1 assert res.distributions[a].binary == False for i in range(height + nblocks - 1): assert res.distributions[a].distribution[i] == ( 1 if i > 0 and a == 0 else 1 if a == 2 and i == 0 else 0) res = daemon.get_output_histogram([], min_count=0, max_count=0) assert len(res.histogram) == 2 for i in range(2): assert res.histogram[i].amount in [0, 17592186044415] assert res.histogram[i].total_instances in [ height + nblocks - 2, 1 ] assert res.histogram[i].unlocked_instances == 0 assert res.histogram[i].recent_instances == 0
def _test_alt_chains(self): print('Testing alt chains') daemon = Daemon() res = daemon.get_alt_blocks_hashes() starting_alt_blocks = res.blks_hashes if 'blks_hashes' in res else [] res = daemon.get_info() root_block_hash = res.top_block_hash height = res.height prev_hash = res.top_block_hash res_template = daemon.getblocktemplate( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' ) nonce = 0 # 5 siblings alt_blocks = [None] * 5 for i in range(len(alt_blocks)): res = daemon.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1, prev_block=prev_hash, starting_nonce=nonce) assert res.height == height assert len(res.blocks) == 1 txid = res.blocks[0] res = daemon.getblockheaderbyhash(txid) nonce = res.block_header.nonce print('mined ' + ('alt' if res.block_header.orphan_status else 'tip') + ' block ' + str(height) + ', nonce ' + str(nonce)) assert res.block_header.prev_hash == prev_hash assert res.block_header.orphan_status == (i > 0) alt_blocks[i] = txid nonce += 1 print('mining 3 on 1') # three more on [1] chain1 = [] res = daemon.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 3, prev_block=alt_blocks[1], starting_nonce=nonce) assert res.height == height + 3 assert len(res.blocks) == 3 blk_hash = res.blocks[2] res = daemon.getblockheaderbyhash(blk_hash) nonce = res.block_header.nonce assert not res.block_header.orphan_status nonce += 1 chain1.append(blk_hash) chain1.append(res.block_header.prev_hash) print('Checking alt blocks match') res = daemon.get_alt_blocks_hashes() assert len(res.blks_hashes) == len(starting_alt_blocks) + 4 for txid in alt_blocks: assert txid in res.blks_hashes or txid == alt_blocks[1] print('mining 4 on 3') # 4 more on [3], the chain will reorg when we mine the 4th top_block_hash = blk_hash prev_block = alt_blocks[3] for i in range(4): res = daemon.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1, prev_block=prev_block) assert res.height == height + 1 + i assert len(res.blocks) == 1 prev_block = res.blocks[-1] res = daemon.getblockheaderbyhash(res.blocks[-1]) assert res.block_header.orphan_status == (i < 3) res = daemon.get_info() assert res.height == ((height + 4) if i < 3 else height + 5) assert res.top_block_hash == (top_block_hash if i < 3 else prev_block) res = daemon.get_info() assert res.height == height + 5 assert res.top_block_hash == prev_block print('Checking alt blocks match') res = daemon.get_alt_blocks_hashes() blks_hashes = res.blks_hashes assert len(blks_hashes) == len(starting_alt_blocks) + 7 for txid in alt_blocks: assert txid in blks_hashes or txid == alt_blocks[3] for txid in chain1: assert txid in blks_hashes res = daemon.get_alternate_chains() assert len(res.chains) == 4 tips = [chain.block_hash for chain in res.chains] for txid in tips: assert txid in blks_hashes for chain in res.chains: assert chain.length in [1, 4] assert chain.length == len(chain.block_hashes) assert chain.height == height + chain.length - 1 # all happen start at the same height assert chain.main_chain_parent_block == root_block_hash for txid in [alt_blocks[0], alt_blocks[2], alt_blocks[4]]: assert len([ chain for chain in res.chains if chain.block_hash == txid ]) == 1
def transfer(self): daemon = Daemon() print("Creating transfer to self") dst = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} payment_id = '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde' start_balances = [0] * len(self.wallet) running_balances = [0] * len(self.wallet) for i in range(len(self.wallet)): res = self.wallet[i].get_balance() start_balances[i] = res.balance running_balances[i] = res.balance assert res.unlocked_balance <= res.balance if i == 0: assert res.blocks_to_unlock == 59 # we've been mining to it else: assert res.blocks_to_unlock == 0 print ('Checking short payment IDs cannot be used when not in an integrated address') ok = False try: self.wallet[0].transfer([dst], ring_size = 11, payment_id = '1234567812345678', get_tx_key = False) except: ok = True assert ok print ('Checking empty destination is rejected') ok = False try: self.wallet[0].transfer([], ring_size = 11, get_tx_key = False) except: ok = True assert ok res = self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 0 assert res.amount > 0 amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) == 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 unsigned_txset = res.unsigned_txset self.wallet[0].refresh() res = daemon.get_info() height = res.height res = self.wallet[0].get_transfers() assert len(res['in']) == height - 1 # coinbases assert not 'out' in res or len(res.out) == 0 # not mined yet assert len(res.pending) == 1 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 for e in res['in']: assert e.type == 'block' e = res.pending[0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'pending' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert e.double_spend_seen == False assert e.confirmations == 0 running_balances[0] -= 1000000000000 + fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward self.wallet[0].refresh() running_balances[0] += 1000000000000 res = self.wallet[0].get_transfers() assert len(res['in']) == height # coinbases assert len(res.out) == 1 # not mined yet assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 for e in res['in']: assert e.type == 'block' e = res.out[0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'out' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert e.double_spend_seen == False assert e.confirmations == 1 res = self.wallet[0].get_height() wallet_height = res.height res = self.wallet[0].get_transfer_by_txid(txid) assert len(res.transfers) == 1 assert res.transfers[0] == res.transfer t = res.transfer assert t.txid == txid assert t.payment_id == payment_id assert t.height == wallet_height - 1 assert t.timestamp > 0 assert t.amount == 0 # to self, so it's just "pay a fee" really assert t.fee == fee assert t.note == '' assert len(t.destinations) == 1 assert t.destinations[0] == {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} assert t.type == 'out' assert t.unlock_time == 0 assert t.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert t.double_spend_seen == False assert t.confirmations == 1 res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 print("Creating transfer to another, manual relay") dst = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1000000000000} res = self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = True, do_not_relay = True, get_tx_hex = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 32*2 assert res.amount == 1000000000000 amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) > 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 tx_blob = res.tx_blob res = daemon.send_raw_transaction(tx_blob) assert res.not_relayed == False assert res.low_mixin == False assert res.double_spend == False assert res.invalid_input == False assert res.invalid_output == False assert res.too_big == False assert res.overspend == False assert res.fee_too_low == False assert res.not_rct == False self.wallet[0].refresh() res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_transfers() assert not 'in' in res or len(res['in']) == 0 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert len(res.pool) == 1 assert not 'failed' in res or len(res.failed) == 0 e = res.pool[0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'pool' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' assert e.double_spend_seen == False assert e.confirmations == 0 assert e.amount == amount assert e.fee == fee daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] -= 1000000000000 + fee running_balances[0] += res.block_header.reward self.wallet[1].refresh() running_balances[1] += 1000000000000 res = self.wallet[1].get_transfers() assert len(res['in']) == 1 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 e = res['in'][0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == amount assert e.fee == fee res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 print('Creating multi out transfer') self.wallet[0].refresh() dst0 = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} dst1 = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1100000000000} dst2 = {'address': '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 'amount': 1200000000000} res = self.wallet[0].transfer([dst0, dst1, dst2], ring_size = 11, payment_id = payment_id, get_tx_key = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 32*2 assert res.amount == 1000000000000 + 1100000000000 + 1200000000000 amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) == 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 unsigned_txset = res.unsigned_txset running_balances[0] -= 1000000000000 + 1100000000000 + 1200000000000 + fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward running_balances[0] += 1000000000000 running_balances[1] += 1100000000000 running_balances[2] += 1200000000000 self.wallet[0].refresh() res = self.wallet[0].get_transfers() assert len(res['in']) == height + 2 assert len(res.out) == 3 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 1 assert not 'failed' in res or len(res.failed) == 0 e = [o for o in res.out if o.txid == txid] assert len(e) == 1 e = e[0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'out' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == amount assert e.fee == fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_transfers() assert len(res['in']) == 2 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 e = [o for o in res['in'] if o.txid == txid] assert len(e) == 1 e = e[0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == 1100000000000 assert e.fee == fee res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 self.wallet[2].refresh() res = self.wallet[2].get_transfers() assert len(res['in']) == 1 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 e = [o for o in res['in'] if o.txid == txid] assert len(e) == 1 e = e[0] assert e.txid == txid assert e.payment_id == payment_id assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == 1200000000000 assert e.fee == fee res = self.wallet[2].get_balance() assert res.balance == running_balances[2] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 print('Sending to integrated address') self.wallet[0].refresh() res = self.wallet[0].get_balance() i_pid = '1111111122222222' res = self.wallet[0].make_integrated_address(standard_address = '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', payment_id = i_pid) i_address = res.integrated_address res = self.wallet[0].transfer([{'address': i_address, 'amount': 200000000}]) assert len(res.tx_hash) == 32*2 i_txid = res.tx_hash assert len(res.tx_key) == 32*2 assert res.amount == 200000000 i_amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) == 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 running_balances[0] -= 200000000 + fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward running_balances[1] += 200000000 self.wallet[0].refresh() res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 self.wallet[2].refresh() res = self.wallet[2].get_balance() assert res.balance == running_balances[2] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 8 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward self.wallet[0].refresh() res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 8 self.wallet[2].refresh() res = self.wallet[2].get_balance() assert res.balance == running_balances[2] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 7
def check_txpool(self): daemon = Daemon() wallet = Wallet() res = daemon.get_info() height = res.height txpool_size = res.tx_pool_size txes = self.create_txes('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 5) res = daemon.get_info() assert res.tx_pool_size == txpool_size + 5 txpool_size = res.tx_pool_size res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size for txid in txes.keys(): x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == False assert x.last_failed_id_hash == '0'*64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(txes.keys()) print('Flushing 2 transactions') txes_keys = list(txes.keys()) daemon.flush_txpool([txes_keys[1], txes_keys[3]]) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0 assert len([x for x in res.transactions if x.id_hash == txes_keys[3]]) == 0 new_keys = list(txes.keys()) new_keys.remove(txes_keys[1]) new_keys.remove(txes_keys[3]) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) print('Flushing unknown transactions') unknown_txids = ['1'*64, '2'*64, '3'*64] daemon.flush_txpool(unknown_txids) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 print('Mining transactions') daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.get_transaction_pool() assert not 'transactions' in res or len(res.transactions) == txpool_size - 5 res = daemon.get_transaction_pool_hashes() assert not 'tx_hashes' in res or len(res.tx_hashes) == 0 print('Popping block') daemon.pop_blocks(1) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 for txid in new_keys: x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == True assert x.last_failed_id_hash == '0'*64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob
def check_txpool(self): daemon = Daemon() wallet = Wallet() res = daemon.get_info() height = res.height txpool_size = res.tx_pool_size txes = self.create_txes( '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 5) res = daemon.get_info() assert res.tx_pool_size == txpool_size + 5 txpool_size = res.tx_pool_size res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size for txid in txes.keys(): x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == False assert x.last_failed_id_hash == '0' * 64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(txes.keys()) print('Flushing 2 transactions') txes_keys = list(txes.keys()) daemon.flush_txpool([txes_keys[1], txes_keys[3]]) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0 assert len([x for x in res.transactions if x.id_hash == txes_keys[3]]) == 0 new_keys = list(txes.keys()) new_keys.remove(txes_keys[1]) new_keys.remove(txes_keys[3]) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) print('Flushing unknown transactions') unknown_txids = ['1' * 64, '2' * 64, '3' * 64] daemon.flush_txpool(unknown_txids) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 print('Mining transactions') daemon.generateblocks( '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.get_transaction_pool() assert not 'transactions' in res or len( res.transactions) == txpool_size - 5 res = daemon.get_transaction_pool_hashes() assert not 'tx_hashes' in res or len(res.tx_hashes) == 0 print('Popping block') daemon.pop_blocks(1) res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size - 2 for txid in new_keys: x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 x = x[0] assert x.kept_by_block == True assert x.last_failed_id_hash == '0' * 64 assert x.double_spend_seen == False assert x.weight >= x.blob_size assert x.blob_size * 2 == len(txes[txid].tx_blob) assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob
def mine(self, via_daemon): print("Test mining via " + ("daemon" if via_daemon else "wallet")) daemon = Daemon() wallet = Wallet() # check info/height/balance before generating blocks res_info = daemon.get_info() prev_height = res_info.height res_getbalance = wallet.get_balance() prev_balance = res_getbalance.balance res_status = daemon.mining_status() if via_daemon: res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1) else: res = wallet.start_mining(threads_count = 1) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == False assert res_status.block_reward >= 600000000000 # wait till we mined a few of them target_height = prev_height + 5 height = prev_height timeout = 60 # randomx is slow to init while height < target_height: seen_height = height for _ in range(timeout): time.sleep(1) height = daemon.get_info().height if height > seen_height: break else: assert False, 'Failed to mine successor to block %d (initial block = %d)' % (seen_height, prev_height) timeout = 5 if via_daemon: res = daemon.stop_mining() else: res = wallet.stop_mining() res_status = daemon.mining_status() assert res_status.active == False res_info = daemon.get_info() new_height = res_info.height wallet.refresh() res_getbalance = wallet.get_balance() balance = res_getbalance.balance assert balance >= prev_balance + (new_height - prev_height) * 600000000000 if via_daemon: res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1, do_background_mining = True) else: res = wallet.start_mining(threads_count = 1, do_background_mining = True) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == True assert res_status.block_reward >= 600000000000 # don't wait, might be a while if the machine is busy, which it probably is if via_daemon: res = daemon.stop_mining() else: res = wallet.stop_mining() res_status = daemon.mining_status() assert res_status.active == False
def transfer(self): daemon = Daemon() print("Creating transfer to self") dst = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} payment_id = '1234500000012345abcde00000abcdeff1234500000012345abcde00000abcde' start_balances = [0] * len(self.wallet) running_balances = [0] * len(self.wallet) for i in range(len(self.wallet)): res = self.wallet[i].get_balance() start_balances[i] = res.balance running_balances[i] = res.balance assert res.unlocked_balance <= res.balance if i == 0: assert res.blocks_to_unlock == 59 # we've been mining to it else: assert res.blocks_to_unlock == 0 print ('Checking short payment IDs cannot be used when not in an integrated address') ok = False try: self.wallet[0].transfer([dst], ring_size = 11, payment_id = '1234567812345678', get_tx_key = False) except: ok = True assert ok print ('Checking long payment IDs are rejected') ok = False try: self.wallet[0].transfer([dst], ring_size = 11, payment_id = payment_id, get_tx_key = False, get_tx_hex = True) except: ok = True assert ok print ('Checking empty destination is rejected') ok = False try: self.wallet[0].transfer([], ring_size = 11, get_tx_key = False) except: ok = True assert ok res = self.wallet[0].transfer([dst], ring_size = 11, get_tx_key = False, get_tx_hex = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 0 assert res.amount > 0 amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) > 0 tx_weight = res.weight assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 unsigned_txset = res.unsigned_txset res = daemon.get_fee_estimate(10) assert res.fee > 0 assert res.quantization_mask > 0 expected_fee = (res.fee * 1 * tx_weight + res.quantization_mask - 1) // res.quantization_mask * res.quantization_mask assert abs(1 - fee / expected_fee) < 0.01 self.wallet[0].refresh() res = daemon.get_info() height = res.height res = self.wallet[0].get_transfers() assert len(res['in']) == height - 1 # coinbases assert not 'out' in res or len(res.out) == 0 # not mined yet assert len(res.pending) == 1 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 for e in res['in']: assert e.type == 'block' e = res.pending[0] assert e.txid == txid assert e.payment_id in ['', '0000000000000000'] assert e.type == 'pending' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert e.double_spend_seen == False assert not 'confirmations' in e or e.confirmations == 0 running_balances[0] -= fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward self.wallet[0].refresh() res = self.wallet[0].get_transfers() assert len(res['in']) == height # coinbases assert len(res.out) == 1 # not mined yet assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 for e in res['in']: assert e.type == 'block' e = res.out[0] assert e.txid == txid assert e.payment_id in ['', '0000000000000000'] assert e.type == 'out' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert e.double_spend_seen == False assert e.confirmations == 1 res = self.wallet[0].get_height() wallet_height = res.height res = self.wallet[0].get_transfer_by_txid(txid) assert len(res.transfers) == 1 assert res.transfers[0] == res.transfer t = res.transfer assert t.txid == txid assert t.payment_id in ['', '0000000000000000'] assert t.height == wallet_height - 1 assert t.timestamp > 0 assert t.amount == 0 # to self, so it's just "pay a fee" really assert t.fee == fee assert t.note == '' assert len(t.destinations) == 1 assert t.destinations[0] == {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} assert t.type == 'out' assert t.unlock_time == 0 assert t.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert t.double_spend_seen == False assert t.confirmations == 1 res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 print("Creating transfer to another, manual relay") dst = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1000000000000} res = self.wallet[0].transfer([dst], ring_size = 11, get_tx_key = True, do_not_relay = True, get_tx_hex = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 32*2 assert res.amount == 1000000000000 amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) > 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 tx_blob = res.tx_blob res = daemon.send_raw_transaction(tx_blob) assert res.not_relayed == False assert res.low_mixin == False assert res.double_spend == False assert res.invalid_input == False assert res.invalid_output == False assert res.too_big == False assert res.overspend == False assert res.fee_too_low == False self.wallet[0].refresh() res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_transfers() assert not 'in' in res or len(res['in']) == 0 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert len(res.pool) == 1 assert not 'failed' in res or len(res.failed) == 0 e = res.pool[0] assert e.txid == txid assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'pool' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' assert e.double_spend_seen == False assert not 'confirmations' in e or e.confirmations == 0 assert e.amount == amount assert e.fee == fee daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] -= 1000000000000 + fee running_balances[0] += res.block_header.reward self.wallet[1].refresh() running_balances[1] += 1000000000000 res = self.wallet[1].get_transfers() assert len(res['in']) == 1 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 e = res['in'][0] assert e.txid == txid assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == amount assert e.fee == fee res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 print('Creating multi out transfer') self.wallet[0].refresh() dst0 = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000} dst1 = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1100000000000} dst2 = {'address': '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 'amount': 1200000000000} res = self.wallet[0].transfer([dst0, dst1, dst2], ring_size = 11, get_tx_key = True) assert len(res.tx_hash) == 32*2 txid = res.tx_hash assert len(res.tx_key) == 32*2 assert res.amount == 1000000000000 + 1100000000000 + 1200000000000 amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) == 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 unsigned_txset = res.unsigned_txset running_balances[0] -= 1100000000000 + 1200000000000 + fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward running_balances[1] += 1100000000000 running_balances[2] += 1200000000000 self.wallet[0].refresh() res = self.wallet[0].get_transfers() assert len(res['in']) == height + 2 assert len(res.out) == 3 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 1 assert not 'failed' in res or len(res.failed) == 0 e = [o for o in res.out if o.txid == txid] assert len(e) == 1 e = e[0] assert e.txid == txid assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'out' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == amount assert e.fee == fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_transfers() assert len(res['in']) == 2 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 e = [o for o in res['in'] if o.txid == txid] assert len(e) == 1 e = e[0] assert e.txid == txid assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == 1100000000000 assert e.fee == fee res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 self.wallet[2].refresh() res = self.wallet[2].get_transfers() assert len(res['in']) == 1 assert not 'out' in res or len(res.out) == 0 assert not 'pending' in res or len(res.pending) == 0 assert not 'pool' in res or len(res.pool) == 0 assert not 'failed' in res or len(res.failed) == 0 e = [o for o in res['in'] if o.txid == txid] assert len(e) == 1 e = e[0] assert e.txid == txid assert e.payment_id in ["", "0000000000000000"] # long payment IDs are now ignored assert e.type == 'in' assert e.unlock_time == 0 assert e.subaddr_index.major == 0 assert e.subaddr_indices == [{'major': 0, 'minor': 0}] assert e.address == '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK' assert e.double_spend_seen == False assert e.confirmations == 1 assert e.amount == 1200000000000 assert e.fee == fee res = self.wallet[2].get_balance() assert res.balance == running_balances[2] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 print('Sending to integrated address') self.wallet[0].refresh() res = self.wallet[0].get_balance() i_pid = '1111111122222222' res = self.wallet[0].make_integrated_address(standard_address = '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', payment_id = i_pid) i_address = res.integrated_address res = self.wallet[0].transfer([{'address': i_address, 'amount': 200000000}]) assert len(res.tx_hash) == 32*2 i_txid = res.tx_hash assert len(res.tx_key) == 32*2 assert res.amount == 200000000 i_amount = res.amount assert res.fee > 0 fee = res.fee assert len(res.tx_blob) == 0 assert len(res.tx_metadata) == 0 assert len(res.multisig_txset) == 0 assert len(res.unsigned_txset) == 0 running_balances[0] -= 200000000 + fee res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward running_balances[1] += 200000000 self.wallet[0].refresh() res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 9 self.wallet[2].refresh() res = self.wallet[2].get_balance() assert res.balance == running_balances[2] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 8 daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1) res = daemon.getlastblockheader() running_balances[0] += res.block_header.reward self.wallet[0].refresh() res = self.wallet[0].get_balance() assert res.balance == running_balances[0] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 59 self.wallet[1].refresh() res = self.wallet[1].get_balance() assert res.balance == running_balances[1] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 8 self.wallet[2].refresh() res = self.wallet[2].get_balance() assert res.balance == running_balances[2] assert res.unlocked_balance <= res.balance assert res.blocks_to_unlock == 7
def mine(self): print("Test mining") daemon = Daemon() wallet = Wallet() # check info/height/balance before generating blocks res_info = daemon.get_info() prev_height = res_info.height res_getbalance = wallet.get_balance() prev_balance = res_getbalance.balance res_status = daemon.mining_status() res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == False assert res_status.block_reward >= 600000000000 # wait till we mined a few of them timeout = 5 timeout_height = prev_height while True: time.sleep(1) res_info = daemon.get_info() height = res_info.height if height >= prev_height + 5: break if height > timeout_height: timeout = 5 timeout_height = height else: timeout -= 1 assert timeout >= 0 res = daemon.stop_mining() res_status = daemon.mining_status() assert res_status.active == False res_info = daemon.get_info() new_height = res_info.height wallet.refresh() res_getbalance = wallet.get_balance() balance = res_getbalance.balance assert balance >= prev_balance + (new_height - prev_height) * 600000000000 res = daemon.start_mining('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', threads_count = 1, do_background_mining = True) res_status = daemon.mining_status() assert res_status.active == True assert res_status.threads_count == 1 assert res_status.address == '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm' assert res_status.is_background_mining_enabled == True assert res_status.block_reward >= 600000000000 # don't wait, might be a while if the machine is busy, which it probably is res = daemon.stop_mining() res_status = daemon.mining_status() assert res_status.active == False