forked from townforge/townforge
5689 lines
266 KiB
Python
Executable File
5689 lines
266 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#encoding=utf-8
|
|
|
|
# Copyright (c) 2019 Crypto City
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without modification, are
|
|
# permitted provided that the following conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
# conditions and the following disclaimer.
|
|
#
|
|
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
# of conditions and the following disclaimer in the documentation and/or other
|
|
# materials provided with the distribution.
|
|
#
|
|
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
# used to endorse or promote products derived from this software without specific
|
|
# prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
from __future__ import print_function
|
|
import json
|
|
import time
|
|
import math
|
|
import os
|
|
import copy
|
|
import itertools
|
|
|
|
"""Test CC RPC
|
|
"""
|
|
|
|
from framework.daemon import Daemon
|
|
from framework.wallet import Wallet
|
|
from framework.daemon_util import get_daemon_state
|
|
|
|
FIRST_CITY_X = 0
|
|
FIRST_CITY_Y = 0
|
|
ITEM_STONE = 1
|
|
ITEM_MEDIUM_STONE = 2
|
|
ITEM_WOOD = 4
|
|
ITEM_VEGETATION = 7
|
|
ITEM_RUNESTONE = 8
|
|
MATERIAL_VARIANT_PLOUGHED_FIELD = 32
|
|
MATERIAL_LOCKED_PINE = 26
|
|
ITEM_LABOUR = 256
|
|
ITEM_FIREWOOD = 257
|
|
ITEM_FIRST_PATENT = 4096
|
|
ITEM_FIRST_FOOD = 1024
|
|
ITEM_FIRST_GEMSTONE = 2048
|
|
ITEM_FOOD_VEGETABLES = ITEM_FIRST_FOOD
|
|
ITEM_FOOD_GRAIN = ITEM_FIRST_FOOD + 1
|
|
ITEM_FOOD_MEAT = ITEM_FIRST_FOOD + 2
|
|
ITEM_AMETHYST = 2048
|
|
NUM_PREDEFINED_ITEMS = ITEM_FIRST_PATENT + 4096
|
|
ITEM_FIRST_USER = NUM_PREDEFINED_ITEMS
|
|
ITEM_LAST_USER = 65536 + 1048576 - 1
|
|
ORIGIN_RESOURCE_RADIUS = 500
|
|
ROLE_EMPTY = 0
|
|
ROLE_AGRICULTURAL = 1
|
|
ROLE_CRAFT = 2
|
|
ROLE_RESIDENTIAL1 = 5
|
|
ROLE_SAWMILL = 11
|
|
ROLE_STONECUTTER = 10
|
|
ROLE_WORKFORCE = 14
|
|
MAX_DISTANCE_PERCENTAGE = 1600
|
|
MAX_CC_NAME_LENGTH = 64
|
|
account_creation_fee = 100000000
|
|
GAME_UPDATE_FREQUENCY = 720
|
|
BUILD_RATIO_ACTIVE_THRESHOLD_PERCENT = 0
|
|
MIN_TRADE_EXPIRATION = (86400 // 30)
|
|
MIN_RESEARCH_AMOUNT = 10000000
|
|
LABOUR_LAST_RESORT_PRICE = 40000
|
|
STONE_LAST_RESORT_PRICE = 600000
|
|
RUNESTONE_LAST_RESORT_PRICE = 100000000
|
|
WOOD_LAST_RESORT_PRICE = 100000
|
|
NEW_ITEM_FEE = 100000000
|
|
NEW_MORTGAGE_FEE = 100000000
|
|
DISCOVERY_RESEARCH_EFFICIENCY = 12
|
|
DISCOVERY_RESEARCH_PRODUCTIVITY = 13
|
|
DISCOVERY_RESEARCH_EXPERTISE = 14
|
|
DISCOVERY_RESEARCH_MASTERY = 15
|
|
DISCOVERY_BUCKET_BRIGADE = 29
|
|
IGNORE_ACCOUNT = 0
|
|
IGNORE_FLAG = 1
|
|
IGNORE_ITEM = 2
|
|
IGNORE_CITY = 3
|
|
CROP_NONE = 0
|
|
CROP_VEGETABLES = 1
|
|
CROP_GRAIN = 2
|
|
NUM_STARTING_MOOSE = 1000
|
|
NUM_STARTING_BEARS = 250
|
|
GAME_ACCOUNT = 2
|
|
FORECLOSURE_ACCOUNT = 3
|
|
COINS_ITEM_GROUP = ITEM_FIRST_USER
|
|
MORTGAGE_ITEM_GROUP = ITEM_FIRST_USER + 1
|
|
COIN_ITEM_SETTLEMENT = COINS_ITEM_GROUP + 2
|
|
COIN_MINTING_FEE = 10000000
|
|
COIN_SMELTING_FEE = 1000000
|
|
COIN_GOLD_CONTENT = 5000000000
|
|
COIN_MINTING_WINDOW = (7 * 86400 // 30)
|
|
NONCE_CANCELLATION_FEE = 10000000
|
|
collectible_coin_type_players = 1
|
|
collectible_coin_type_city = 2
|
|
collectible_coin_type_yearly = 3
|
|
collectible_coin_type_event = 4
|
|
NUM_CUSTOM_ITEM_USER_DATA = 4
|
|
CHOP_WOOD_LABOUR_PER_100_WOOD = 5
|
|
PINE_HEATING_POINTS = 5
|
|
OAK_HEATING_POINTS = 8
|
|
AUCTION_TYPE_FLAG = 0
|
|
AUCTION_TIME = (7 * 86400 // 30)
|
|
CUSTOM_ITEM_GOLD_GILDING_FEE_PER_THOUSAND = 5
|
|
CUSTOM_ITEM_GOLD_RECOVERY_FEE_PER_THOUSAND = 5
|
|
AUCTION_TYPE_FLAG = 0
|
|
AUCTION_TYPE_ITEM = 1
|
|
NEW_AUCTION_FEE = 100000000
|
|
AUCTION_BID_FEE = 100000000
|
|
MIN_AUCTION_BASE_TICKS = 8
|
|
MAX_AUCTION_BASE_TICKS = 56
|
|
BADGE_COSMOPOLITAN = 49
|
|
|
|
def COIN_TYPE(x):
|
|
return x[0] >> 56
|
|
|
|
def get_gold_content(coin_type):
|
|
if coin_type == collectible_coin_type_players:
|
|
return 35
|
|
if coin_type == collectible_coin_type_city:
|
|
return 20
|
|
if coin_type == collectible_coin_type_yearly:
|
|
return 10
|
|
if coin_type == collectible_coin_type_event:
|
|
return 50
|
|
assert False
|
|
return 0
|
|
|
|
def get_distance(ax0, ay0, ax1, ay1, bx0, by0, bx1, by1):
|
|
left = ax1 < bx0
|
|
right = ax0 > bx1
|
|
top = ay1 < by0
|
|
bottom = ay0 > by1
|
|
if left:
|
|
if top:
|
|
return max(bx0 - ax1, by0 - ay1)
|
|
if bottom:
|
|
return max(bx0 - ax1, ay0 - by1)
|
|
return bx0 - ax1
|
|
if right:
|
|
if top:
|
|
return max(ax0 - bx1, by0 - ay1)
|
|
if bottom:
|
|
return max(ax0 - bx1, ay0 - by1)
|
|
return ax0 - bx1
|
|
if top:
|
|
return by0 - ay1
|
|
if bottom:
|
|
return ay0 - by1
|
|
return 0
|
|
|
|
def feq(x, y):
|
|
return math.fabs(x - y) < 0.01
|
|
|
|
class CCTest():
|
|
def run_test(self):
|
|
self.reset()
|
|
self.create()
|
|
state0 = self.get_state()
|
|
self.mine()
|
|
self.recordreorg_root()
|
|
self.check_no_items()
|
|
self.check_predefined_items()
|
|
self.check_gold_consistency()
|
|
self.check_item_count_consistency()
|
|
self.test_get_new_nonces()
|
|
self.test_cc_account_creation()
|
|
self.check_gold_consistency()
|
|
self.test_names()
|
|
self.test_cc_transfers()
|
|
self.check_gold_consistency()
|
|
self.check_event_balances()
|
|
self.test_buy_land()
|
|
self.test_buy_items()
|
|
self.test_firewood()
|
|
self.test_build()
|
|
self.test_trading()
|
|
self.test_interacting_trades()
|
|
self.test_accrual_trades()
|
|
self.test_trade_third_party_matching()
|
|
self.test_cancel_nonce()
|
|
self.test_giving()
|
|
self.test_discoveries()
|
|
self.check_gold_consistency()
|
|
self.check_item_count_consistency()
|
|
self.check_event_balances()
|
|
self.test_game_update()
|
|
self.test_revert()
|
|
self.check_gold_consistency()
|
|
self.test_script_variables()
|
|
self.test_scripts()
|
|
self.test_runestones()
|
|
self.test_custom_items()
|
|
self.check_gold_consistency()
|
|
self.check_item_count_consistency()
|
|
self.test_mortgages()
|
|
self.test_auctions()
|
|
self.check_gold_consistency()
|
|
self.check_event_balances()
|
|
self.test_badges()
|
|
self.test_resize_flag()
|
|
self.test_attributes()
|
|
self.test_dice_roll()
|
|
self.test_hunt()
|
|
self.test_invitation()
|
|
self.test_chat()
|
|
self.test_ignore()
|
|
self.test_minting()
|
|
self.check_gold_consistency()
|
|
self.test_farming()
|
|
self.check_item_count_consistency()
|
|
self.test_cities()
|
|
self.check_gold_consistency()
|
|
self.check_item_count_consistency()
|
|
self.check_event_balances()
|
|
self.test_reorg()
|
|
self.check_item_count_consistency()
|
|
self.check_gold_consistency()
|
|
self.check_event_balances()
|
|
self.reset_and_check_states()
|
|
state1 = self.get_state()
|
|
assert state0 == state1, self.get_diff(state0, state1)
|
|
self.check_no_items()
|
|
self.check_gold_consistency()
|
|
self.check_event_balances()
|
|
self.reset()
|
|
|
|
def assert_exception(self, f):
|
|
ok = False
|
|
try:
|
|
f()
|
|
except Exception as e:
|
|
ok = True
|
|
assert ok
|
|
|
|
def reset(self):
|
|
print('Resetting blockchain')
|
|
for idx in [2, 3, 4]:
|
|
daemon = Daemon(idx = idx)
|
|
res = daemon.get_height()
|
|
daemon.pop_blocks(res.height - 1)
|
|
daemon.flush_txpool()
|
|
self.states = []
|
|
self.deposits = 0
|
|
|
|
def reset_and_check_states(self):
|
|
print('Resetting blockchain step by step and checking states after revert')
|
|
daemon = self.daemon
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
while len(self.states) > 0 and self.states[-1][0]+1 >= height:
|
|
self.states = self.states[0:-1]
|
|
while len(self.states) > 0:
|
|
pop_height = self.states[-1][0]
|
|
pop_state = self.states[-1][1]
|
|
self.states = self.states[0:-1]
|
|
assert height-1 > pop_height
|
|
pop_blocks = height-1 - pop_height
|
|
daemon.pop_blocks(pop_blocks)
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
assert height-1 == pop_height
|
|
state = self.get_state()
|
|
assert state == pop_state, self.get_diff(state, pop_state)
|
|
self.deposits = 0
|
|
|
|
def generate_blocks(self, address, nblocks, skip_update = False):
|
|
daemon = self.daemon
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
while len(self.states) > 0 and self.states[-1][0]+1 >= height:
|
|
self.states = self.states[0:-1]
|
|
self.states.append((height - 1, self.get_state()))
|
|
res = daemon.generateblocks(address, nblocks)
|
|
if skip_update and (res.height - 1) % GAME_UPDATE_FREQUENCY == 0:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
def create(self):
|
|
print('Creating wallets')
|
|
seeds = [
|
|
'teardrop owls later width skater gadget different pegs yard ahead onslaught dynamite thorn espionage dwelt rural eels aimless shipped toaster shocking rounded maverick mystery thorn',
|
|
'geek origin industrial payment friendly physics width putty beyond addicted rogue metro midst anvil unplugs tequila efficient feast elapse liquid degrees smuggled also bawled tequila',
|
|
'tidy heron aching outbreak terminal inorganic nexus umpire economics auctions hope soapy hive vigilant hunter tadpoles hippo southern observant rabbits asked vector gimmick godfather heron',
|
|
'aimless zesty juvenile hedgehog sash eden inflamed faxed abbey piloted silk gigantic affair snout guarded inquest utmost tunnel remedy sighting otherwise alley illness jubilee gigantic',
|
|
'journal vitals technical dying dice taken evicted essential pepper dented psychic vaults oatmeal pairing wrong request damp rugged buffet lids bias pouch ladder leisure rugged',
|
|
]
|
|
self.wallet = [None] * len(seeds)
|
|
self.pkeys = [None] * len(seeds)
|
|
for i in range(len(seeds)):
|
|
self.wallet[i] = Wallet(idx = i)
|
|
# close the wallet if any, will throw if none is loaded
|
|
try: self.wallet[i].close_wallet()
|
|
except: pass
|
|
res = self.wallet[i].restore_deterministic_wallet(seed = seeds[i])
|
|
ok = False
|
|
try: res = self.wallet[i].cc_get_info()
|
|
except: ok = True
|
|
assert ok
|
|
self.wallet[i].set_daemon('127.0.0.1:18182')
|
|
self.daemon = Daemon(idx = 2)
|
|
|
|
global FIRST_CITY_X
|
|
global FIRST_CITY_Y
|
|
res = self.daemon.cc_get_city(0)
|
|
FIRST_CITY_X = res.ox
|
|
FIRST_CITY_Y = res.oy
|
|
|
|
def mine(self):
|
|
print("Mining many blocks")
|
|
daemon = self.daemon
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
blocks_mined = 0
|
|
for data in [
|
|
['TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 30], # wallet[0]
|
|
['TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 30], # wallet[1]
|
|
['TF1MMCHHDFKYSQ1DkLWskTxU2fC7jtZLwcATXHP3uvJo4dV757dtGwUE9ZL6SE9DJhxrvzThAsG4drVmAPHzEvh6TCq19AbzTo4', 660], # wallet[3]
|
|
['TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1000], # wallet[2]
|
|
['TF1MMA4mMyUGkR373BQYWhkssgXWPuWdSauDXiRLJEmSXiJKbw3um94tDxogJShqXHt51a8UBotBRXuMvjFjaxSumjRXDrY7wSm', 0], # wallet[4]
|
|
]:
|
|
self.generate_blocks(data[0], data[1])
|
|
blocks_mined += data[1]
|
|
# get past the next update so we don't get balance changes fucking the tests up
|
|
res = daemon.get_info()
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - res.height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
blocks_mined += blocks
|
|
for i in range(len(self.wallet)):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].get_height()
|
|
assert res.height == height + blocks_mined
|
|
|
|
def recordreorg_root(self):
|
|
daemon = self.daemon
|
|
res = daemon.get_info()
|
|
self.reorg_root_hash = res.top_block_hash
|
|
assert len(self.reorg_root_hash) == 64
|
|
self.reorg_root_height = res.height - 1
|
|
assert self.reorg_root_height > 0
|
|
|
|
def check_no_items(self):
|
|
daemon = self.daemon
|
|
print('Checking there are no items')
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)] + [x + ITEM_FIRST_USER for x in range(256)])
|
|
if 'count' in res:
|
|
for x in res.count:
|
|
assert x == 0
|
|
self.check_item_count_consistency()
|
|
|
|
def check_predefined_items(self):
|
|
daemon = self.daemon
|
|
print('Checking predefined items info')
|
|
|
|
self.assert_exception(lambda: daemon.cc_get_predefined_item_info([0]))
|
|
self.assert_exception(lambda: daemon.cc_get_predefined_item_info([0, 1]))
|
|
self.assert_exception(lambda: daemon.cc_get_predefined_item_info([1, 0]))
|
|
self.assert_exception(lambda: daemon.cc_get_predefined_item_info([11111111]))
|
|
self.assert_exception(lambda: daemon.cc_get_predefined_item_info([ITEM_FIRST_USER]))
|
|
|
|
res = daemon.cc_get_predefined_item_info([ITEM_STONE, ITEM_WOOD, ITEM_LABOUR, ITEM_AMETHYST, ITEM_FOOD_GRAIN])
|
|
assert len(res.items_) == 5
|
|
e = res.items_[0]
|
|
assert e.id == ITEM_STONE
|
|
assert len(e.name) > 0
|
|
assert e.amount == 0
|
|
assert e.is_block
|
|
assert e.is_stone
|
|
assert not e.is_wood
|
|
assert not e.is_gemstone
|
|
assert not e.is_food
|
|
assert not e.is_patent
|
|
assert e.food == 0
|
|
assert e.heating == 0
|
|
|
|
e = res.items_[1]
|
|
assert e.id == ITEM_WOOD
|
|
assert len(e.name) > 0
|
|
assert e.amount == 0
|
|
assert e.is_block
|
|
assert not e.is_stone
|
|
assert e.is_wood
|
|
assert not e.is_gemstone
|
|
assert not e.is_food
|
|
assert not e.is_patent
|
|
assert e.food == 0
|
|
assert e.heating > 0
|
|
|
|
e = res.items_[2]
|
|
assert e.id == ITEM_LABOUR
|
|
assert len(e.name) > 0
|
|
assert e.amount == 0
|
|
assert not e.is_block
|
|
assert not e.is_stone
|
|
assert not e.is_wood
|
|
assert not e.is_gemstone
|
|
assert not e.is_food
|
|
assert not e.is_patent
|
|
assert e.food == 0
|
|
assert e.heating == 0
|
|
|
|
e = res.items_[3]
|
|
assert e.id == ITEM_AMETHYST
|
|
assert len(e.name) > 0
|
|
assert e.amount == 0
|
|
assert not e.is_block
|
|
assert not e.is_stone
|
|
assert not e.is_wood
|
|
assert e.is_gemstone
|
|
assert not e.is_food
|
|
assert not e.is_patent
|
|
assert e.food == 0
|
|
assert e.heating == 0
|
|
|
|
e = res.items_[4]
|
|
assert e.id == ITEM_FOOD_GRAIN
|
|
assert len(e.name) > 0
|
|
assert e.amount == 0
|
|
assert not e.is_block
|
|
assert not e.is_stone
|
|
assert not e.is_wood
|
|
assert not e.is_gemstone
|
|
assert e.is_food
|
|
assert not e.is_patent
|
|
assert e.food > 0
|
|
assert e.heating == 0
|
|
|
|
def test_get_new_nonces(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing getting new nonces")
|
|
|
|
self.assert_exception(lambda: daemon.cc_get_new_nonces(1024))
|
|
res = daemon.cc_get_new_nonces(0)
|
|
assert not 'nonces' in res or len(res.nonces) == 0
|
|
res = daemon.cc_get_new_nonces(2)
|
|
assert len(res.nonces) == 2
|
|
assert res.nonces[0] != 0
|
|
assert res.nonces[1] != 0
|
|
assert res.nonces[0] != res.nonces[1]
|
|
|
|
def test_cc_account_creation(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing CC account creation")
|
|
|
|
n_wallets = 3
|
|
|
|
self.wallet[0].refresh()
|
|
res = self.wallet[0].get_balance()
|
|
balance0 = res.balance
|
|
assert res.cc_balance == 0
|
|
res = self.wallet[0].cc_deposit(amount = 100000000, name = 'wallet 0')
|
|
self.deposits += 100000000
|
|
assert len(res.fee_list) == 1
|
|
fee0 = res.fee_list[0]
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].get_balance()
|
|
balance1 = res.balance
|
|
assert res.cc_balance == 0
|
|
res = self.wallet[1].cc_deposit(amount = 200000000, name = 'wallet 1')
|
|
self.deposits += 200000000
|
|
assert len(res.fee_list) == 1
|
|
fee1 = res.fee_list[0]
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[0].refresh()
|
|
res = self.wallet[0].get_balance()
|
|
assert res.balance == balance0 - 100000000 - fee0
|
|
assert res.cc_balance == 100000000 - account_creation_fee
|
|
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].get_balance()
|
|
assert res.balance == balance1 - 200000000 - fee1
|
|
assert res.cc_balance == 200000000 - account_creation_fee
|
|
|
|
for i in range(2):
|
|
res = self.wallet[i].cc_get_info()
|
|
self.pkeys[i] = res.cc_pkey
|
|
|
|
def test_cc_transfers(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing CC account deposits/withdrawals")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
n_wallets = 3
|
|
balance = [None] * n_wallets
|
|
cc_balance = [None] * n_wallets
|
|
for i in range(n_wallets):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].get_balance()
|
|
balance[i] = res.balance
|
|
cc_balance[i] = res.cc_balance
|
|
|
|
res = self.wallet[1].cc_withdraw(amount = 25000000)
|
|
self.deposits -= 25000000
|
|
balance[1] += 25000000 - res.fee_list[0]
|
|
cc_balance[1] -= 25000000
|
|
|
|
res = self.wallet[2].cc_deposit(amount = 500000000, name = 'wallet 2')
|
|
self.deposits += 500000000
|
|
balance[2] -= 500000000 + res.fee_list[0]
|
|
cc_balance[2] += 500000000 - account_creation_fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
for i in range(n_wallets):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].get_balance()
|
|
assert res.balance == balance[i]
|
|
assert res.cc_balance == cc_balance[i]
|
|
|
|
# try to withdraw more
|
|
ok = False
|
|
try: res = self.wallet[0].cc_withdraw(amount = 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
for i in range(n_wallets):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].get_balance()
|
|
assert res.balance == balance[i]
|
|
assert res.cc_balance == cc_balance[i]
|
|
|
|
# down to 0
|
|
res = self.wallet[1].cc_withdraw(amount = cc_balance[1])
|
|
self.deposits -= cc_balance[1]
|
|
balance[1] += cc_balance[1] - res.fee_list[0]
|
|
cc_balance[1] = 0
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
for i in range(n_wallets):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].get_balance()
|
|
assert res.balance == balance[i]
|
|
assert res.cc_balance == cc_balance[i]
|
|
|
|
# re-deposit on empty address, and transfer to it
|
|
res = self.wallet[1].cc_deposit(amount = 1200000000)
|
|
self.deposits += 1200000000
|
|
balance[1] -= 1200000000 + res.fee_list[0]
|
|
cc_balance[1] += 1200000000
|
|
res = self.wallet[2].cc_transfer(self.pkeys[0], amount = 18000000)
|
|
cc_balance[2] -= 18000000 + res.fee_list[0]
|
|
cc_balance[0] += 18000000
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# and add lots of balance to the third wallet so we can do interesting stuff later on
|
|
res = self.wallet[2].cc_deposit(amount = 450000000000)
|
|
self.deposits += 450000000000
|
|
balance[2] -= 450000000000 + res.fee_list[0]
|
|
cc_balance[2] += 450000000000
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_deposit(amount = 450000000000)
|
|
self.deposits += 450000000000
|
|
balance[2] -= 450000000000 + res.fee_list[0]
|
|
cc_balance[2] += 450000000000
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_deposit(amount = 450000000000)
|
|
self.deposits += 450000000000
|
|
balance[2] -= 450000000000 + res.fee_list[0]
|
|
cc_balance[2] += 450000000000
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_deposit(amount = 450000000000)
|
|
self.deposits += 450000000000
|
|
balance[2] -= 450000000000 + res.fee_list[0]
|
|
cc_balance[2] += 450000000000
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
for i in range(n_wallets):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].get_balance()
|
|
assert res.balance == balance[i]
|
|
assert res.cc_balance == cc_balance[i]
|
|
res = self.wallet[i].cc_get_info()
|
|
assert res.cc_balance == cc_balance[i]
|
|
assert not 'flags' in res or len(res.flags) == 0
|
|
assert not 'item_balances' in res or res.item_balances == 0
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_buy_land(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing buying land")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
cc_balance = res.cc_balance
|
|
account_id = res.account_id
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, 800, 400, 800 + 32 - 1, 400 + 24 - 1)
|
|
self.assert_exception(lambda: self.wallet[2].cc_buy_land(800, 400, 800 + 32 - 1, 400 + 24 - 1))
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X + 800, FIRST_CITY_Y + 400, FIRST_CITY_X + 800 + 32 - 1, FIRST_CITY_Y + 400 + 24 - 1)
|
|
cost = res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X+ 800, FIRST_CITY_Y + 400, FIRST_CITY_X + 800 + 32 - 1, FIRST_CITY_Y + 400 + 24 - 1)
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
assert res.cc_balance == cc_balance - cost - fee
|
|
cc_balance = res.cc_balance
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert len(res.flags) == 1
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.owner == account_id
|
|
assert res.city == 0
|
|
assert res.x0 == FIRST_CITY_X + 800
|
|
assert res.y0 == FIRST_CITY_Y + 400
|
|
assert res.x1 == FIRST_CITY_X + 800 + 32 - 1
|
|
assert res.y1 == FIRST_CITY_Y + 400 + 24 - 1
|
|
assert res.repair == 0
|
|
|
|
cost = 0
|
|
fee = 0
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X + 400, FIRST_CITY_Y + 400, FIRST_CITY_X + 400 + 90 - 1, FIRST_CITY_Y + 400 + 90 - 1)
|
|
cost += res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X + 400, FIRST_CITY_Y + 400, FIRST_CITY_X + 400 + 90 - 1, FIRST_CITY_Y + 400 + 90 - 1)
|
|
fee += res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X + 400, FIRST_CITY_Y + 500, FIRST_CITY_X + 400 + 90 - 1, FIRST_CITY_Y + 500 + 90 - 1)
|
|
cost += res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X + 400, FIRST_CITY_Y + 500, FIRST_CITY_X + 400 + 90 - 1, FIRST_CITY_Y + 500 + 90 - 1)
|
|
fee += res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X + 500, FIRST_CITY_Y + 400, FIRST_CITY_X + 500 + 90 - 1, FIRST_CITY_Y + 400 + 90 - 1)
|
|
cost += res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X + 500, FIRST_CITY_Y + 400, FIRST_CITY_X + 500 + 90 - 1, FIRST_CITY_Y + 400 + 90 - 1)
|
|
fee += res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X + 500, FIRST_CITY_Y + 500, FIRST_CITY_X + 500 + 90 - 1, FIRST_CITY_Y + 500 + 90 - 1)
|
|
cost += res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X + 500, FIRST_CITY_Y + 500, FIRST_CITY_X + 500 + 90 - 1, FIRST_CITY_Y + 500 + 90 - 1)
|
|
fee += res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert len(res.flags) == 5
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.owner == account_id
|
|
assert res.city == 0
|
|
assert res.x0 == FIRST_CITY_X + 800
|
|
assert res.y0 == FIRST_CITY_Y + 400
|
|
assert res.x1 == FIRST_CITY_X + 800 + 32 - 1
|
|
assert res.y1 == FIRST_CITY_Y + 400 + 24 - 1
|
|
assert res.repair == 0
|
|
|
|
self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
assert res.cc_balance == cc_balance - cost - fee
|
|
|
|
print('Checking we can not buy overlapping land')
|
|
ok = False
|
|
try: res = self.wallet[2].cc_buy_land(FIRST_CITY_X + 460, FIRST_CITY_Y + 460, FIRST_CITY_X + 550, FIRST_CITY_Y + 550)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def add_item(self, item_balances, type, amount):
|
|
if amount == 0:
|
|
return item_balances
|
|
for i in range(len(item_balances)):
|
|
if item_balances[i]['type'] == type:
|
|
item_balances[i]['amount'] += amount
|
|
if item_balances[i]['amount'] == 0:
|
|
del item_balances[i]
|
|
return item_balances
|
|
item_balances.append({u'type': type, u'amount': amount})
|
|
item_balances = sorted(item_balances, key=lambda x: x['type'])
|
|
return item_balances
|
|
|
|
def remove_item(self, item_balances, type):
|
|
for i in range(len(item_balances)):
|
|
if item_balances[i]['type'] == type:
|
|
del item_balances[i]
|
|
break;
|
|
return item_balances
|
|
|
|
def remove_wood(self, item_balances):
|
|
item_balances = self.remove_item(item_balances, ITEM_WOOD)
|
|
item_balances = self.remove_item(item_balances, ITEM_FIREWOOD)
|
|
return item_balances
|
|
|
|
def test_buy_items(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing buying items")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
cc_balance = res.cc_balance
|
|
account_id = res.account_id
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert not 'item_balances' in res or len(res.item_balances) == 0
|
|
item_balances = []
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 15}, {'type': ITEM_WOOD, 'amount': 40}])
|
|
item_balances = self.add_item(item_balances, ITEM_STONE, 15)
|
|
item_balances = self.add_item(item_balances, ITEM_WOOD, 40)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.item_balances == item_balances
|
|
|
|
item_counts[ITEM_STONE] += 15
|
|
item_counts[ITEM_WOOD] += 40
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
ok = False
|
|
try: res = self.wallet[2].cc_buy_items(entries = [{'type': 0, 'amount': 15}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: res = self.wallet[2].cc_buy_items(entries = [{'type': 255, 'amount': 15}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 0}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 0xffffffff}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8*650}, {'type': ITEM_WOOD, 'amount': 8*4660}, {'type': ITEM_MEDIUM_STONE, 'amount': 8*50}, {'type': ITEM_LABOUR, 'amount': 8*100000}])
|
|
item_balances = self.add_item(item_balances, ITEM_STONE, 8*650)
|
|
item_balances = self.add_item(item_balances, ITEM_MEDIUM_STONE, 8*50)
|
|
item_balances = self.add_item(item_balances, ITEM_WOOD, 8*4660)
|
|
item_balances = self.add_item(item_balances, ITEM_LABOUR, 8*100000)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.item_balances == item_balances
|
|
|
|
item_counts[ITEM_STONE] += 8*650
|
|
item_counts[ITEM_WOOD] += 8*4660
|
|
item_counts[ITEM_MEDIUM_STONE] += 8*50
|
|
item_counts[ITEM_LABOUR] += 8*100000
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_firewood(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing firewood")
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 38}, {'type': ITEM_WOOD + 1, 'amount': 2}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': (CHOP_WOOD_LABOUR_PER_100_WOOD * 40 + 99) // 100}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_chop_wood([{'type': ITEM_STONE, 'amount': 1}]))
|
|
self.assert_exception(lambda: self.wallet[2].cc_chop_wood([{'type': ITEM_LABOUR, 'amount': 1}]))
|
|
self.assert_exception(lambda: self.wallet[2].cc_chop_wood([{'type': ITEM_WOOD, 'amount': 100000000}]))
|
|
self.assert_exception(lambda: self.wallet[2].cc_chop_wood([{'type': ITEM_WOOD, 'amount': 0}]))
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
cc_balance = res.cc_balance
|
|
account_id = res.account_id
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert len(res.item_balances) > 0
|
|
item_balances = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
item_balances = self.add_item(item_balances, e.type, e.amount)
|
|
|
|
res = self.wallet[2].cc_chop_wood([{'type': ITEM_WOOD, 'amount': 38}, {'type': ITEM_WOOD + 1, 'amount': 2}])
|
|
item_balances = self.add_item(item_balances, ITEM_WOOD, -38)
|
|
item_counts[ITEM_WOOD] -= 38
|
|
item_balances = self.add_item(item_balances, ITEM_WOOD + 1, -2)
|
|
item_counts[ITEM_WOOD + 1] -= 2
|
|
item_balances = self.add_item(item_balances, ITEM_FIREWOOD, 38 * PINE_HEATING_POINTS + 2 * OAK_HEATING_POINTS)
|
|
item_counts[ITEM_FIREWOOD] += 38 * PINE_HEATING_POINTS + 2 * OAK_HEATING_POINTS
|
|
item_balances = self.add_item(item_balances, ITEM_LABOUR, -((40 * CHOP_WOOD_LABOUR_PER_100_WOOD + 99) // 100))
|
|
item_counts[ITEM_LABOUR] -= (40 * CHOP_WOOD_LABOUR_PER_100_WOOD + 99) // 100
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_chop_wood([{'type': ITEM_FIREWOOD, 'amount': 1}]))
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.item_balances == item_balances
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_build(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing building")
|
|
|
|
flag_id = 3
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
|
|
# good in theory, but no role set yet
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't set role 0 (empty)
|
|
ok = False
|
|
try: self.wallet[2].cc_building_settings(flag_id, 0, 100, construction_height)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't set large out of range role
|
|
ok = False
|
|
try: self.wallet[2].cc_building_settings(flag_id, 254, 100, construction_height)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't set 0 economic power
|
|
ok = False
|
|
try: self.wallet[2].cc_building_settings(flag_id, 1, 0, construction_height)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't set silly large economic power
|
|
ok = False
|
|
try: self.wallet[2].cc_building_settings(flag_id, 1, 100000, construction_height)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# 150 is the last one we can use before we research civil engineering
|
|
ok = False
|
|
try: self.wallet[2].cc_building_settings(flag_id, 1, 160, construction_height)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# ok
|
|
res = self.wallet[2].cc_building_settings(flag_id, 1, 100, construction_height, name = 'test building')
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# not our flag
|
|
ok = False
|
|
try: self.wallet[0].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# good
|
|
res = self.wallet[2].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
# out of the flag
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 252, 252, 1, 1, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# out of the flag 2
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 254, 254, block_data = [0, ITEM_STONE], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# empty data
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 2, 2, block_data = [], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# too few blocks
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 2, 2, block_data = [1, 0], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid block type
|
|
ok = False
|
|
try: self.wallet[2].cc_build(flag_id, 0, 0, 1, 1, block_data = [0, 250], encoded = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check tile state - should be just one
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
|
|
res = daemon.cc_get_flag(flag_id, get_unpacked_tiles = True)
|
|
assert res.owner == account_id
|
|
assert res.city == 0
|
|
assert res.x0 == FIRST_CITY_X + 400
|
|
assert res.y0 == FIRST_CITY_Y + 400
|
|
assert res.x1 == FIRST_CITY_X + 400 + 90 - 1
|
|
assert res.y1 == FIRST_CITY_Y + 400 + 90 - 1
|
|
assert res.repair == 1000000
|
|
assert len(res.tiles) == 90 * 90
|
|
for i in range(90*90):
|
|
if i == 0:
|
|
assert res.tiles[i].data == [ITEM_STONE], res.tiles[i].data
|
|
else:
|
|
assert not 'data' in res.tiles[i]
|
|
|
|
# build nearby, no height
|
|
res = self.wallet[2].cc_build(flag_id, 0, 0, 2, 2, block_data = [3, 0, 0, ITEM_STONE, 0], encoded = True)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# build on top, with height
|
|
res = self.wallet[2].cc_build(flag_id, 0, 0, 2, 2, block_data = [3, ITEM_STONE, 0, 0, 0], build_height = 1, encoded = True)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id, get_unpacked_tiles = True)
|
|
assert res.owner == account_id
|
|
assert res.city == 0
|
|
assert res.x0 == FIRST_CITY_X + 400
|
|
assert res.y0 == FIRST_CITY_Y + 400
|
|
assert res.x1 == FIRST_CITY_X + 400 + 90 - 1
|
|
assert res.y1 == FIRST_CITY_Y + 400 + 90 - 1
|
|
assert res.repair == 1000000
|
|
assert len(res.tiles) == 90*90
|
|
for i in range(90*90):
|
|
if i == 0:
|
|
assert res.tiles[i].data == [ITEM_STONE, ITEM_STONE]
|
|
elif i == 90:
|
|
assert res.tiles[i].data == [ITEM_STONE]
|
|
else:
|
|
assert not 'data' in res.tiles[i]
|
|
|
|
# build with build_height
|
|
res = self.wallet[2].cc_build(flag_id, 0, 0, 1, 3, block_data = [ITEM_WOOD, ITEM_WOOD, ITEM_VEGETATION], encoded = False, build_height = 2)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id, get_unpacked_tiles = True)
|
|
assert res.owner == account_id
|
|
assert res.city == 0
|
|
assert res.x0 == FIRST_CITY_X + 400
|
|
assert res.y0 == FIRST_CITY_Y + 400
|
|
assert res.x1 == FIRST_CITY_X + 400 + 90 - 1
|
|
assert res.y1 == FIRST_CITY_Y + 400 + 90 - 1
|
|
assert res.repair == 1000000
|
|
assert len(res.tiles) == 90*90
|
|
for i in range(90*90):
|
|
if i == 0:
|
|
assert res.tiles[i].data == [ITEM_STONE, ITEM_STONE, ITEM_WOOD]
|
|
elif i == 90:
|
|
assert res.tiles[i].data == [ITEM_STONE, 0, ITEM_WOOD]
|
|
elif i == 180:
|
|
assert res.tiles[i].data == [0, 0, ITEM_VEGETATION]
|
|
else:
|
|
assert not 'data' in res.tiles[i]
|
|
|
|
# embedded palette changes
|
|
res = self.wallet[2].cc_build(flag_id, 0, 3, 3, 1, block_data = [9, 0, 9], encoded = False, palette = [{'index': 9, 'variant_delta': MATERIAL_VARIANT_PLOUGHED_FIELD}])
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id, get_unpacked_tiles = True)
|
|
assert len(res.tiles) == 90*90
|
|
assert res.tiles[270].data == [9]
|
|
assert 'data' not in res.tiles[271] or res.tiles[271].data == []
|
|
assert res.tiles[272].data == [9]
|
|
|
|
# locked materials
|
|
self.assert_exception(lambda: self.wallet[2].cc_build(flag_id, 0, 3, 3, 1, block_data = [10, 0, 10], encoded = False, palette = [{'index': 10, 'variant_delta': MATERIAL_LOCKED_PINE}]))
|
|
|
|
print("Testing assign items")
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 10}, {'type': ITEM_STONE, 'amount': 10}, {'type': ITEM_LABOUR, 'amount': 1}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
self.assert_exception(lambda self: self.wallet[2].cc_assign_items(flag_id, [{'type': ITEM_STONE, 'amount': 2000000000}]))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_assign_items(flag_id, [{'type': ITEM_WOOD, 'amount': 0}]))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_assign_items(flag_id, [{'type': 0, 'amount': 1}]))
|
|
self.wallet[2].cc_assign_items(flag_id, [{'type': ITEM_WOOD, 'amount': 1}, {'type': ITEM_STONE, 'amount': 10}, {'type': ITEM_LABOUR, 'amount': 10}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
print("Testing renaming flag")
|
|
self.assert_exception(lambda self: self.wallet[2].cc_rename_flag(flag_id, old_name = 'nope', new_name = 'good name'))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_rename_flag(flag_id, old_name = 'test building', new_name = 'bad\rname'))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_rename_flag(flag_id, old_name = 'test building', new_name = 'long name' + 'a'*128))
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'test building', new_name = 'good name')
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
print("Testing invalid demolishing")
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
service_price = res.service_price if 'service_price' in res else 0
|
|
tiles = res.tiles if 'tiles' in res else []
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = ROLE_CRAFT, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = 130, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair - 1, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height + 1, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height + 1, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price + 1, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = "oops", ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = not res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = not res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = 2-res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height + 1, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks + 1, budget = res.budget, tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget + [{'type': ITEM_GRANITE, 'amount': 1}], tiles = tiles))
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = service_price, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = tiles + [1]))
|
|
|
|
|
|
def test_runestones(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing runestones")
|
|
|
|
flag_id = 3
|
|
|
|
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_RUNESTONE, 'amount': 2}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
self.wallet[2].cc_assign_items(flag_id, [{'type': ITEM_RUNESTONE, 'amount': 2}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = self.wallet[2].cc_build(flag_id, 2, 4, 1, 1, block_data = [ITEM_RUNESTONE], encoded = False, build_height = 1)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# bad flag
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id + 1, 2, 4, 1, "", "", 0))
|
|
# bad owner
|
|
self.assert_exception(lambda: self.wallet[1].cc_carve_runestone(flag_id, 2, 4, 1, "", "", 0))
|
|
# out of the flag
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id, 200, 4, 1, "", "", 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id, 2, 149, 1, "", "", 0))
|
|
# no block
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 199, "", "", 0))
|
|
# block without a runestone
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id, 0, 1, 1, "", "", 0))
|
|
# bad message
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "foo", "", 0))
|
|
# no change
|
|
self.assert_exception(lambda: self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "", "", 0))
|
|
|
|
res = self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "", "foo", 0)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "foo", "bar", 0)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# can't be demolished with a carved runestone on it
|
|
res = daemon.cc_get_flag(flag_id)
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, res.role, res.economic_power, res.repair, res.construction_height, res.last_service_height, res.service_price if 'service_price' in res else 0, res.name if 'name' in res else '', res.ignore, res.active, res.crop, res.sow_height, res.num_missed_ticks, res.budget, res.packed_tiles if 'packed_tiles' in res else []))
|
|
# remove the runestone - it can only be removed manually
|
|
res = daemon.cc_get_runestones([{'flag': flag_id, 'x': 2, 'y': 4, 'h': 1}])
|
|
assert len(res.runestones) == 1
|
|
self.assert_exception(lambda: self.wallet[2].cc_build(flag_id, 2, 4, 1, 1, block_data = [ITEM_RUNESTONE], encoded = False, build_height = 1, remove = True))
|
|
res = self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "bar", "", 0)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.assert_exception(lambda: daemon.cc_get_runestones([{'flag': flag_id, 'x': 2, 'y': 4, 'h': 1}]))
|
|
self.wallet[2].cc_build(flag_id, 2, 4, 1, 1, block_data = [ITEM_RUNESTONE], encoded = False, build_height = 1, remove = True)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.assert_exception(lambda: daemon.cc_get_runestones([{'flag': flag_id, 'x': 2, 'y': 4, 'h': 1}]))
|
|
|
|
# now it can be removed
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
self.wallet[2].cc_demolish(flag_id, res.role, res.economic_power, res.repair, res.construction_height, res.last_service_height, res.service_price if 'service_price' in res else 0, res.name if 'name' in res else '', res.ignore, res.active, res.crop, res.sow_height, res.num_missed_ticks, res.budget, res.packed_tiles if 'packed_tiles' in res else [])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.assert_exception(lambda: daemon.cc_get_runestones([{'flag': flag_id, 'x': 2, 'y': 4, 'h': 1}]))
|
|
|
|
# revert the destruction
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool()
|
|
|
|
# add it back
|
|
res = self.wallet[2].cc_build(flag_id, 2, 4, 1, 1, block_data = [ITEM_RUNESTONE], encoded = False, build_height = 1)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.assert_exception(lambda: daemon.cc_get_runestones([{'flag': flag_id, 'x': 2, 'y': 4, 'h': 1}]))
|
|
res = self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "", "bar", 0)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_runestones([{'flag': flag_id, 'x': 2, 'y': 4, 'h': 1}])
|
|
assert len(res.runestones) == 1
|
|
|
|
def test_mortgages(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing mortgages")
|
|
|
|
expected_balances = [None, None, None, None]
|
|
expected_item_balances = [None, None, None, None]
|
|
account_id = [None, None, None, None]
|
|
account_public_key = [None, None, None, None]
|
|
for i in range(4):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = daemon.cc_get_account(account_id[3])
|
|
assert len(res.flags) > 0
|
|
other_flag_id = res.flags[-1]
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert len(res.flags) > 0
|
|
flag_id = res.flags[-1]
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.mortgage == 0
|
|
|
|
# wrong account
|
|
self.assert_exception(lambda: self.wallet[1].cc_create_mortgage(flag_id, "test", "test", ITEM_LABOUR, 2, 10, 0, 1, 100))
|
|
# not a flag
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_mortgage(99999, "test", "test", ITEM_LABOUR, 2, 10, 0, 1, 100))
|
|
# a flag we do not own
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_mortgage(other_flag_id, "test", "test", ITEM_LABOUR, 2, 10, 0, 1, 100))
|
|
# too many shares
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_mortgage(flag_id, "test", "test", ITEM_LABOUR, 2, 10, 0, 1, 1000000000))
|
|
# paying invalid item
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_mortgage(flag_id, "test", "test", 999999, 2, 10, 0, 1, 100))
|
|
# paying 0 per tick for at least one tick
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_mortgage(flag_id, "test", "test", ITEM_LABOUR, 0, 10, 0, 1, 100))
|
|
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
res = self.wallet[2].cc_create_mortgage(flag_id, "test", "test", ITEM_LABOUR, 2, 10, 0, 1, 100)
|
|
expected_balances[2] -= res.fee + NEW_MORTGAGE_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) > 0
|
|
custom_item = res.items_[-1]
|
|
custom_item_id = custom_item.id
|
|
assert custom_item.id > 0
|
|
assert custom_item.creator == account_id[2]
|
|
assert custom_item.creation_height == height
|
|
assert custom_item.amount == 100
|
|
assert not custom_item.is_group
|
|
assert custom_item.group == MORTGAGE_ITEM_GROUP
|
|
assert not custom_item.ignore
|
|
assert custom_item.name == "test"
|
|
assert custom_item.pdesc == "test"
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], custom_item_id, 100)
|
|
|
|
res = daemon.cc_get_item_count([custom_item_id])
|
|
assert res.counts == [100], res
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.mortgage == custom_item_id
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = self.wallet[2].cc_give(account_public_key[1], [{'type': custom_item_id, 'amount': 25}])
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], custom_item_id, -25)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], custom_item_id, 25)
|
|
|
|
# pass an update - tick
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -25 * 2)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 25 * 2)
|
|
|
|
# check item balances (gold/wood balances are unknown past the update)
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (self.remove_wood(res.item_balances if 'item_balances' in res else [])) == self.remove_wood(expected_item_balances[i])
|
|
|
|
# can't demolish a mortgaged flag
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
self.assert_exception(lambda: self.wallet[2].cc_demolish(flag_id, role = res.role, economic_power = res.economic_power, repair = res.repair, construction_height = res.construction_height, last_service_height = res.last_service_height, service_price = res.service_price if 'service_price' in res else 0, name = res.name, ignore = res.ignore, active = res.active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = res.budget, tiles = res.packed_tiles if 'packed_tiles' in res else []))
|
|
|
|
# nor give it
|
|
self.assert_exception(lambda: self.wallet[2].cc_give(account_public_key[0], flag = flag_id))
|
|
|
|
# not trade it
|
|
res = daemon.get_height()
|
|
current_height = res.height
|
|
self.assert_exception(lambda: self.wallet[2].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, expiration = current_height + MIN_TRADE_EXPIRATION + 1000))
|
|
|
|
# pass an update - maturity
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -25 * 10)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 25 * 10)
|
|
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], custom_item_id, -75)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], custom_item_id, -25)
|
|
|
|
# check item balances (gold/wood balances are unknown past the update)
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (self.remove_wood(res.item_balances if 'item_balances' in res else [])) == self.remove_wood(expected_item_balances[i])
|
|
|
|
# pass an update - no further changes
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# check item balances (gold/wood balances are unknown past the update)
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (self.remove_wood(res.item_balances if 'item_balances' in res else [])) == self.remove_wood(expected_item_balances[i])
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.mortgage == 0
|
|
|
|
res = daemon.cc_get_item_count([custom_item_id])
|
|
assert res.counts == [0], res
|
|
|
|
# a defaulting mortgage on the same flag
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.mortgage == 0
|
|
|
|
# get rid of all labour, buy a known amount
|
|
res = daemon.cc_get_account(account_id[2])
|
|
labour = 0
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
if e['type'] == ITEM_LABOUR:
|
|
labour += int(e['amount'])
|
|
if labour > 0:
|
|
res = self.wallet[2].cc_give(account_public_key[1], [{'type': ITEM_LABOUR, 'amount': labour}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': 159}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
for i in range(4):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
res = self.wallet[2].cc_create_mortgage(flag_id, "test2", "test2", ITEM_LABOUR, 2, 10, 0, 1, 100)
|
|
expected_balances[2] -= res.fee + NEW_MORTGAGE_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) > 0
|
|
custom_item = res.items_[-1]
|
|
custom_item_id = custom_item.id
|
|
assert custom_item.id > 0
|
|
assert custom_item.creator == account_id[2]
|
|
assert custom_item.creation_height == height
|
|
assert custom_item.amount == 100
|
|
assert not custom_item.is_group
|
|
assert custom_item.group == MORTGAGE_ITEM_GROUP
|
|
assert not custom_item.ignore
|
|
assert custom_item.name == "test2"
|
|
assert custom_item.pdesc == "test2"
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], custom_item_id, 100)
|
|
|
|
res = daemon.cc_get_item_count([custom_item_id])
|
|
assert res.counts == [100], res
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.mortgage == custom_item_id
|
|
|
|
res = self.wallet[2].cc_give(account_public_key[1], [{'type': custom_item_id, 'amount': 80}])
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], custom_item_id, -80)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], custom_item_id, 80)
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# we need 160 labour, and only have 159, we will default after spending 80
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -80)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 80)
|
|
|
|
res = daemon.get_info()
|
|
mortgage_default_height = res.height - 1
|
|
|
|
# check balances, gold/wood are unknown after the tick
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (self.remove_wood(res.item_balances if 'item_balances' in res else [])) == self.remove_wood(expected_item_balances[i])
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert 'flags' not in res or flag_id not in res.flags
|
|
|
|
res = daemon.cc_get_account(FORECLOSURE_ACCOUNT)
|
|
assert res.flags == [flag_id]
|
|
|
|
# give back labour we got earlier
|
|
if labour > 0:
|
|
res = self.wallet[1].cc_give(account_public_key[2], [{'type': ITEM_LABOUR, 'amount': labour}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# there should be an auction now
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == 1
|
|
assert res.auctions[0].seller == account_id[2]
|
|
assert res.auctions[0].type == AUCTION_TYPE_FLAG
|
|
assert len(res.auctions[0].entries) == 1
|
|
assert res.auctions[0].entries[0].object == flag_id
|
|
assert res.auctions[0].entries[0].amount == 1
|
|
assert res.auctions[0].mortgage == custom_item_id
|
|
assert res.auctions[0].creation_height == mortgage_default_height
|
|
assert res.auctions[0].bid_account == 0 # none yet
|
|
assert res.auctions[0].bid_price == 0 # none yet
|
|
assert res.auctions[0].bid_height == 0 # none yet
|
|
|
|
# wait for the lifetime, but if no bids, it should not end yet
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
blocks = AUCTION_TIME + GAME_UPDATE_FREQUENCY
|
|
while blocks > 0:
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
blocks -= GAME_UPDATE_FREQUENCY
|
|
|
|
# there should be an auction now
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == 1
|
|
assert res.auctions[0].mortgage == custom_item_id
|
|
|
|
# bid once
|
|
self.wallet[2].cc_auction_bid(1, 500)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == 1
|
|
assert res.auctions[0].mortgage == custom_item_id
|
|
assert res.auctions[0].bid_price == 500
|
|
assert res.auctions[0].bid_account == account_id[2]
|
|
assert res.auctions[0].bid_height == height - 1
|
|
|
|
# invalid bids
|
|
self.assert_exception(lambda: self.wallet[1].cc_auction_bid(2, 600)) # bad auction
|
|
self.assert_exception(lambda: self.wallet[1].cc_auction_bid(1, 6000000000000)) # too expensive
|
|
self.assert_exception(lambda: self.wallet[1].cc_auction_bid(1, 400)) # lower
|
|
self.assert_exception(lambda: self.wallet[1].cc_auction_bid(1, 500)) # no higher
|
|
|
|
# bid again
|
|
self.wallet[0].cc_auction_bid(1, 550)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == 1
|
|
assert res.auctions[0].mortgage == custom_item_id
|
|
assert res.auctions[0].bid_price == 550
|
|
assert res.auctions[0].bid_account == account_id[0]
|
|
assert res.auctions[0].bid_height == height - 1
|
|
|
|
# wait a couple updates
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY * 2)
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.owner == account_id[0]
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert 'auctions' not in res or len(res.auctions) == 0
|
|
|
|
# can't bid anymore
|
|
self.assert_exception(lambda: self.wallet[0].cc_auction_bid(1, 850))
|
|
|
|
def test_auctions(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing auctions")
|
|
|
|
expected_balances = [None, None, None, None]
|
|
expected_item_balances = [None, None, None, None]
|
|
account_id = [None, None, None, None]
|
|
account_public_key = [None, None, None, None]
|
|
for i in range(4):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = daemon.cc_get_auctions()
|
|
num_auctions_at_start = len(res.auctions) if 'auctions' in res else 0
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 100}, {'type': ITEM_RUNESTONE, 'amount': 10}, {'type': ITEM_LABOUR, 'amount': 25}])
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_STONE, 100)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_RUNESTONE, 10)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, 25)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= 100 * STONE_LAST_RESORT_PRICE
|
|
expected_balances[2] -= 10 * RUNESTONE_LAST_RESORT_PRICE
|
|
expected_balances[2] -= 25 * LABOUR_LAST_RESORT_PRICE
|
|
res = self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 30}])
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, 30)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] -= 30 * STONE_LAST_RESORT_PRICE
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
num_stone = 0
|
|
for e in res.item_balances:
|
|
if e.type == ITEM_STONE:
|
|
assert num_stone == 0
|
|
num_stone += e.amount
|
|
assert num_stone >= 10
|
|
|
|
# invalid type
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(90, [{'object': ITEM_STONE, 'amount': 1}], 8))
|
|
# invalid item
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_LAST_USER + 1, 'amount': 1}], 8))
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': 255, 'amount': 1}], 8))
|
|
# 0 items
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 0}], 8))
|
|
# too many items
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': num_stone + 1}], 8))
|
|
# too short
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], MIN_AUCTION_BASE_TICKS - 1))
|
|
# too long
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], MAX_AUCTION_BASE_TICKS + 1))
|
|
# bad name
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, "aaaa\n"))
|
|
# bad description
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, "", "\01"))
|
|
# unsorted items
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_LABOUR, 'amount': 10}, {'object': ITEM_STONE, 'amount': 10}]))
|
|
# duplicated item
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}, {'object': ITEM_STONE, 'amount': 10}]))
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 8, "title", "This is\nits description")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_AUCTION_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_STONE, -10) # goes to reserve
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
for e in res.item_balances:
|
|
if e.type == ITEM_STONE:
|
|
assert e.amount == num_stone - 10
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == num_auctions_at_start + 1
|
|
auction_id = res.auctions[-1].id
|
|
assert res.auctions[-1].title == "title"
|
|
assert res.auctions[-1].description == "This is\nits description"
|
|
|
|
# wait till past timeout
|
|
for i in range(8 + 1):
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
|
|
# if no bids, the auction carries over for another tick
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == num_auctions_at_start + 1
|
|
|
|
# buy it on the cheap
|
|
res = self.wallet[2].cc_auction_bid(auction_id, 12345)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= 12345
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert (len(res.auctions) if 'auctions' in res else 0) == num_auctions_at_start
|
|
|
|
# not sold (well, sold back to seller), goes back from reserve
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_STONE, 10)
|
|
|
|
# check item balances (gold/wood balances are unknown past the update)
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (self.remove_wood(res.item_balances if 'item_balances' in res else [])) == self.remove_wood(expected_item_balances[i])
|
|
|
|
print('Testing overlapping auctions')
|
|
|
|
res = self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 30}, {'object': ITEM_LABOUR, 'amount': 15}], 8)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
auction_2_stone30_id = auction_id + 1
|
|
expected_balances[2] -= res.fee + NEW_AUCTION_FEE
|
|
|
|
res = self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_RUNESTONE, 'amount': 2}], 10)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
auction_2_runestone2_id = auction_id + 2
|
|
expected_balances[2] -= res.fee + NEW_AUCTION_FEE
|
|
|
|
res = self.wallet[1].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 5}, {'object': ITEM_LABOUR, 'amount': 1}], 8)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
auction_1_stone5_id = auction_id + 3
|
|
expected_balances[1] -= res.fee + NEW_AUCTION_FEE
|
|
|
|
res = self.wallet[1].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': ITEM_STONE, 'amount': 10}], 9)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
auction_1_stone10_id = auction_id + 4
|
|
expected_balances[1] -= res.fee + NEW_AUCTION_FEE
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert len(res.auctions) == num_auctions_at_start + 4
|
|
|
|
# sanity - give 500 leeway since we might have got prestige income
|
|
self.assert_exception(lambda: self.wallet[2].cc_auction_bid(auction_2_stone30_id, expected_balances[2] + 100000000 * 500))
|
|
|
|
# 2 bid a few times
|
|
res = self.wallet[2].cc_auction_bid(auction_1_stone10_id, 1000)
|
|
expected_balances[2] -= res.fee
|
|
res = self.wallet[2].cc_auction_bid(auction_2_stone30_id, 500)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 2)
|
|
|
|
# lower bids now forbidden
|
|
self.assert_exception(lambda: self.wallet[2].cc_auction_bid(auction_2_stone30_id, 499))
|
|
self.assert_exception(lambda: self.wallet[2].cc_auction_bid(auction_2_stone30_id, 498))
|
|
self.assert_exception(lambda: self.wallet[1].cc_auction_bid(auction_2_stone30_id, 499))
|
|
self.assert_exception(lambda: self.wallet[1].cc_auction_bid(auction_2_stone30_id, 498))
|
|
|
|
# 1 then bids too
|
|
res = self.wallet[1].cc_auction_bid(auction_1_stone10_id, 1200)
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[1].cc_auction_bid(auction_2_stone30_id, 700)
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[1].cc_auction_bid(auction_2_runestone2_id, 2600)
|
|
expected_balances[1] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 3)
|
|
|
|
# 2 bids back
|
|
res = self.wallet[2].cc_auction_bid(auction_1_stone10_id, 1250)
|
|
expected_balances[2] -= res.fee
|
|
res = self.wallet[2].cc_auction_bid(auction_2_stone30_id, 900)
|
|
expected_balances[2] -= res.fee
|
|
res = self.wallet[2].cc_auction_bid(auction_2_runestone2_id, 3000)
|
|
expected_balances[2] -= res.fee
|
|
res = self.wallet[2].cc_auction_bid(auction_1_stone5_id, 150)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 4)
|
|
|
|
# 1 wins on some
|
|
res = self.wallet[1].cc_auction_bid(auction_2_stone30_id, 940)
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[1].cc_auction_bid(auction_2_runestone2_id, 3500)
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[1].cc_auction_bid(auction_1_stone5_id, 3500)
|
|
expected_balances[1] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 3)
|
|
|
|
# wait till the end of all auctions
|
|
for i in range(10 + 1):
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
|
|
res = daemon.cc_get_auctions()
|
|
assert (len(res.auctions) if 'auctions' in res else 0) == num_auctions_at_start
|
|
|
|
# end state: 1 wins the two auctions from 2 and one of theirs, 2 wins one auction from 1
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_STONE, -30)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, 30)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -15)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 15)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_RUNESTONE, -2)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_RUNESTONE, 2)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, -10)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_STONE, 10)
|
|
|
|
# check item balances (gold/wood balances are unknown past the update)
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (self.remove_wood(res.item_balances if 'item_balances' in res else [])) == self.remove_wood(expected_item_balances[i])
|
|
|
|
def test_trading(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing trading")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert not 'offers' in res or len(res.offers) == 0
|
|
assert not 'bids' in res or len(res.bids) == 0
|
|
|
|
# 2 has blocks, set some of them up for sale
|
|
res = self.wallet[2].cc_trade_item(False, 1, 5, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
offer_1_5_80_nonce = res.cc_nonce
|
|
assert offer_1_5_80_nonce > 0
|
|
offer_1_5_80_fee = res.fee
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert not 'bids' in res or len(res.bids) == 0
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert trade.account == account_id[2]
|
|
assert not trade.mined
|
|
assert not trade.bid
|
|
assert trade.type == 1
|
|
assert trade.id == 1
|
|
assert trade.amount == 5
|
|
assert trade.matchable == 5
|
|
assert trade.price == 80
|
|
assert trade.expiration == base_height + MIN_TRADE_EXPIRATION + 1000
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert not 'bids' in res or len(res.bids) == 0
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert not trade.mined # not matched, stays in the txpool
|
|
|
|
# add a compatible bid, but do not match, they'll coexist
|
|
res = self.wallet[1].cc_trade_item(True, 1, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
bid_1_2_80_a_nonce = res.cc_nonce
|
|
assert bid_1_2_80_a_nonce > 0
|
|
bid_1_2_80_a_fee = res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert len(res.bids) == 1
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert trade.account == account_id[2]
|
|
assert not trade.mined # not matched, stays in the txpool
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce
|
|
assert trade.account == account_id[1]
|
|
assert not trade.mined # not matched, stays in the txpool
|
|
|
|
# add a matching one - first matching too few
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_item(True, 1, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}], cost = 80 * 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# then matching enough
|
|
res = self.wallet[1].cc_trade_item(True, 1, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 2}], cost = 80 * 2)
|
|
assert len(res.tx_hash) == 64
|
|
bid_1_2_80_b_nonce = res.cc_nonce
|
|
assert bid_1_2_80_b_nonce > 0
|
|
bid_1_2_80_b_fee = res.fee
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert len(res.bids) == 2
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert not trade.mined # not matched yet
|
|
assert trade.amount == 5
|
|
assert trade.matchable == 5
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce or trade.nonce == bid_1_2_80_b_nonce
|
|
assert not trade.mined # not matched, stays in the txpool
|
|
|
|
# test filtering
|
|
res2 = daemon.cc_get_order_book(True, False)
|
|
assert res2.bids == res.bids
|
|
assert not 'offers' in res2
|
|
res2 = daemon.cc_get_order_book(False, True)
|
|
assert not 'bids' in res2
|
|
assert res2.offers == res.offers
|
|
res2 = daemon.cc_get_order_book(True, True, type=[234])
|
|
assert not 'offers' in res2
|
|
assert not 'bids' in res2
|
|
res2 = daemon.cc_get_order_book(True, True, id=[234])
|
|
assert not 'offers' in res2
|
|
assert not 'bids' in res2
|
|
res2 = daemon.cc_get_order_book(True, True, type=[1])
|
|
assert res2.offers == res.offers
|
|
assert res2.bids == res.bids
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= offer_1_5_80_fee
|
|
expected_balances[1] -= bid_1_2_80_b_fee
|
|
|
|
matched_amount = 2
|
|
matched_price = 80
|
|
expected_balances[1] -= matched_amount * matched_price
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, matched_amount)
|
|
expected_balances[2] += matched_amount * matched_price
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], 1, -matched_amount)
|
|
|
|
# the offer should still be around, with 2 used and 3 left, and the last bid is gone
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert len(res.bids) == 1
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert trade.account == account_id[2]
|
|
assert trade.mined # but mined, and partially matched
|
|
assert trade.amount == 5
|
|
assert trade.matchable == 3
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce
|
|
assert trade.account == account_id[1]
|
|
assert not trade.mined # still not matched
|
|
assert trade.amount == 2
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# current orders
|
|
# 2 sells 3 at 80
|
|
# 1 buys 2 at 80
|
|
|
|
# matching to a non existing tx
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 1, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'txid': "4"*64, 'amount': 1}], cost = 80)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching to an existing tx that's not a trade command
|
|
res = daemon.getblockheaderbyheight(50)
|
|
miner_tx_hash = res.block_header.miner_tx_hash
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 1, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': miner_tx_hash, 'amount': 1}], cost = 80)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching with non matching price
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 1, 79, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}], cost = 80)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching too much
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 5, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 5}], cost = 800)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching nothing
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 1, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 0}], cost = 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching the same tx twice
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}, {'nonce': offer_1_5_80_nonce, 'amount': 1}], cost = 160)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching with oneself's order
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(True, 1, 1, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}], cost = 80)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# matching with a better price uses the matched trade's price
|
|
res = self.wallet[0].cc_trade_item(True, 1, 1, 140, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}], cost = 80)
|
|
assert len(res.tx_hash) == 64
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= 80
|
|
expected_balances[2] += 80
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], 1, -1)
|
|
|
|
res = self.wallet[2].cc_trade_item(False, 1, 1, 40, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': bid_1_2_80_a_nonce, 'amount': 1}], cost = 0)
|
|
assert len(res.tx_hash) == 64
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] += 80
|
|
expected_balances[1] -= 80
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], 1, -1)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, 1)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] -= bid_1_2_80_a_fee # finally!
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# the offer should still be around, with 3 used and 2 left, and the last bid is gone
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
assert len(res.bids) == 1
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert trade.mined
|
|
assert trade.amount == 5
|
|
assert trade.matchable == 2
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce
|
|
assert trade.mined
|
|
assert trade.amount == 2
|
|
assert trade.matchable == 1
|
|
|
|
# current orders
|
|
# 2 sells 2 at 80
|
|
# 1 buys 1 at 80
|
|
|
|
# add several offers in a ladder
|
|
res = self.wallet[2].cc_trade_item(False, 1, 1, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
offer_1_1_100_nonce = res.cc_nonce
|
|
assert offer_1_1_100_nonce > 0
|
|
offer_1_1_100_fee = res.fee
|
|
res = self.wallet[1].cc_trade_item(False, 1, 3, 85, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
offer_1_3_85_nonce = res.cc_nonce
|
|
assert offer_1_3_85_nonce > 0
|
|
offer_1_3_85_fee = res.fee
|
|
res = self.wallet[2].cc_trade_item(False, 1, 2, 90, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
offer_1_2_90_nonce = res.cc_nonce
|
|
assert offer_1_2_90_nonce > 0
|
|
offer_1_2_90_fee = res.fee
|
|
|
|
# the new offer should all be there, sorted by price
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 4
|
|
assert len(res.bids) == 1
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_5_80_nonce
|
|
assert trade.account == account_id[2]
|
|
assert trade.mined
|
|
assert trade.amount == 5
|
|
assert trade.matchable == 2
|
|
trade = res.offers[1]
|
|
assert trade.nonce == offer_1_3_85_nonce
|
|
assert trade.account == account_id[1]
|
|
assert not trade.mined
|
|
assert trade.amount == 3
|
|
trade = res.offers[2]
|
|
assert trade.nonce == offer_1_2_90_nonce
|
|
assert trade.account == account_id[2]
|
|
assert not trade.mined
|
|
assert trade.amount == 2
|
|
trade = res.offers[3]
|
|
assert trade.nonce == offer_1_1_100_nonce
|
|
assert trade.account == account_id[2]
|
|
assert not trade.mined
|
|
assert trade.amount == 1
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce
|
|
assert trade.account == account_id[1]
|
|
assert trade.mined
|
|
assert trade.amount == 2
|
|
assert trade.matchable == 1
|
|
|
|
# we can't match more than one unmined tx
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 4, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_3_85_nonce, 'amount': 3}, {'nonce': offer_1_2_90_nonce, 'amount': 1}], cost = 85 * 3 + 90 * 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# we can't grab only part of one while leaving some for another
|
|
ok = False
|
|
try: self.wallet[0].cc_trade_item(True, 1, 4, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 1}, {'nonce': offer_1_2_90_nonce, 'amount': 1}], cost = 85 + 90)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# nibble at offer_1_3_85_nonce so it gets mined
|
|
res = self.wallet[0].cc_trade_item(True, 1, 1, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_3_85_nonce, 'amount': 1}], cost = 85)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= 85
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 1)
|
|
expected_balances[1] -= offer_1_3_85_fee
|
|
expected_balances[1] += 85
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, -1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# match several txes, once of them partially
|
|
res = self.wallet[0].cc_trade_item(True, 1, 5, 100, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_5_80_nonce, 'amount': 2}, {'nonce': offer_1_2_90_nonce, 'amount': 2}, {'nonce': offer_1_3_85_nonce, 'amount': 1}], cost = 2 * 80 + 2 * 90 + 1 * 85)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= 2 * 80 + 2 * 90 + 1 * 85
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 5)
|
|
expected_balances[2] -= offer_1_2_90_fee
|
|
expected_balances[2] += 2 * 80 + 2 * 90
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], 1, -4)
|
|
expected_balances[1] += 1 * 85
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, -1)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# expiration too high
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, 821500)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# expiration in the past
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, 10)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# expiration too low
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, res.height + 100)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# current orders
|
|
# 2 sells 1 at 100
|
|
# 1 sells 1 at 85
|
|
# 1 buys 1 at 80
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 2
|
|
trade = res.offers[0]
|
|
assert trade.nonce == offer_1_3_85_nonce
|
|
assert trade.mined
|
|
assert trade.account == account_id[1]
|
|
assert trade.amount == 3
|
|
assert trade.matchable == 1
|
|
assert trade.price == 85
|
|
assert len(res.bids) == 1
|
|
trade = res.offers[1]
|
|
assert trade.nonce == offer_1_1_100_nonce
|
|
assert not trade.mined
|
|
assert trade.account == account_id[2]
|
|
assert trade.amount == 1
|
|
assert trade.matchable == 1
|
|
assert trade.price == 100
|
|
assert len(res.bids) == 1
|
|
trade = res.bids[0]
|
|
assert trade.nonce == bid_1_2_80_a_nonce
|
|
assert trade.mined
|
|
assert trade.account == account_id[1]
|
|
assert trade.amount == 2
|
|
assert trade.matchable == 1
|
|
assert trade.price == 80
|
|
|
|
# matching a tx from an account that does not have money to back it anymore
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].cc_withdraw(amount = expected_balances[1])
|
|
self.deposits -= expected_balances[1]
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] = 0
|
|
|
|
self.wallet[1].refresh()
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert res.balance == 0
|
|
|
|
ok = False
|
|
try: res = self.wallet[2].cc_trade_item(False, 1, 1, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': bid_1_2_80_a_nonce, 'amount': 1}], cost = 0)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].cc_deposit(amount = 1000000000)
|
|
self.deposits += 1000000000
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] = 1000000000
|
|
|
|
self.wallet[1].refresh()
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert res.balance == expected_balances[1]
|
|
|
|
# matching a tx from an account that does not have the blocks anymore
|
|
res = self.wallet[1].cc_trade_item(False, 1, 1, 90, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
nonce = res.cc_nonce
|
|
assert nonce > 0
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[0].cc_trade_item(True, 1, 1, 90, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': nonce, 'amount': 1}], cost = 90)
|
|
assert len(res.tx_hash) == 64
|
|
expected_balances[0] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] += 90
|
|
expected_balances[0] -= 90
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, -1)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], 1, 1)
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(True, 1, 1, 85, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': offer_1_3_85_nonce, 'amount': 1}], cost = 85)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# sell a flag we do not have
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert len(res.flags) >= 1
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# sell a flag we do have
|
|
res = self.wallet[2].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
flag_nonce = res.cc_nonce
|
|
assert flag_nonce > 0
|
|
expected_balances[2] -= res.fee
|
|
|
|
# try to buy a different one
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_flag(True, flag_id + 1, 1000, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# buy it
|
|
res = self.wallet[1].cc_trade_flag(True, flag_id, 1001, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
assert len(res.tx_hash) == 64
|
|
expected_balances[1] -= res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
expected_balances[2] += 1000
|
|
expected_balances[1] -= 1000
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert flag_id not in res.flags
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert len(res.flags) >= 1
|
|
assert flag_id in res.flags
|
|
|
|
# cannot buy twice
|
|
for i in [0, 1]:
|
|
ok = False
|
|
try: self.wallet[1].cc_trade_flag(True, flag_id, 1001, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_interacting_trades(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing interacting trades")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
|
|
# sell a flag, two others buy it
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert len(res.flags) >= 1
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
|
|
res = self.wallet[1].cc_trade_flag(False, flag_id, 1000, 0, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
assert len(res.tx_hash) == 64
|
|
flag_nonce = res.cc_nonce
|
|
assert flag_nonce > 0
|
|
|
|
res = self.wallet[0].cc_trade_flag(True, flag_id, 1000, 0, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
# we can now, it just won't get mined
|
|
# ok = False
|
|
# try: self.wallet[2].cc_trade_flag(True, flag_id, 1000, 0, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 1000)
|
|
# except: ok = True
|
|
# assert ok
|
|
|
|
# sell blocks, many people try to buy, overflowing the sold amount
|
|
daemon.get_connections()
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
res = daemon.cc_get_account(res.account_id)
|
|
res = self.wallet[2].cc_trade_item(False, 1, 10, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000)
|
|
nonce = res.cc_nonce
|
|
res = self.wallet[1].cc_trade_item(True, 1, 8, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': nonce, 'amount': 8}], cost = 8*80)
|
|
res = self.wallet[0].cc_trade_item(True, 1, 4, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': nonce, 'amount': 4}], cost = 4*80)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
|
|
daemon.flush_txpool()
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_giving(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing giving")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_id = [None, None, None]
|
|
account_public_key = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8}, {'type': ITEM_WOOD, 'amount': 4}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, 8)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_WOOD, 4)
|
|
item_counts[ITEM_STONE] += 8
|
|
item_counts[ITEM_WOOD] += 4
|
|
|
|
# first try to give more
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_STONE, 'amount': 9}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_WOOD, 'amount': 5}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_LABOUR, 'amount': 100}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_STONE, 'amount': 1}, {'type': ITEM_WOOD, 'amount': 5}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[1].cc_give(account_public_key[0], [{'type': ITEM_STONE, 'amount': 3}, {'type': ITEM_WOOD, 'amount': 2}])
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, -3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_STONE, 3)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_WOOD, -2)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_WOOD, 2)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
# give a flag
|
|
res = daemon.cc_get_account(account_id[2])
|
|
flags2 = res.flags if 'flags' in res else []
|
|
assert len(flags2) > 0
|
|
res = daemon.cc_get_account(account_id[0])
|
|
flags0 = res.flags if 'flags' in res else []
|
|
flag_id = flags2[-1]
|
|
self.wallet[2].cc_give(account_public_key[0], flag = flag_id)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
flags2new = res.flags if 'flags' in res else []
|
|
assert len(flags2) > 0
|
|
res = daemon.cc_get_account(account_id[0])
|
|
flags0new = res.flags if 'flags' in res else []
|
|
|
|
assert flag_id not in flags2new
|
|
assert flag_id in flags0new
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.owner == account_id[0]
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
# give back
|
|
self.wallet[0].cc_give(account_public_key[2], flag = flag_id)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
flags2new = res.flags if 'flags' in res else []
|
|
assert len(flags2) > 0
|
|
res = daemon.cc_get_account(account_id[0])
|
|
flags0new = res.flags if 'flags' in res else []
|
|
|
|
assert flag_id in flags2new
|
|
assert flag_id not in flags0new
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.owner == account_id[2]
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_accrual_trades(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing accrual trades")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
|
|
res = self.wallet[0].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': 1}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
item_counts[ITEM_LABOUR] += 1
|
|
|
|
# sell a flag, it should become buyable after a couple updates
|
|
res = daemon.cc_get_account(account_id[0])
|
|
assert len(res.flags) >= 1
|
|
flag_id = res.flags[0]
|
|
assert flag_id > 0
|
|
|
|
res = self.wallet[0].cc_trade_flag(False, flag_id, 1000, base_height + 1, -1, 0, 0, base_height + MIN_TRADE_EXPIRATION + 10000)
|
|
assert len(res.tx_hash) == 64
|
|
flag_nonce = res.cc_nonce
|
|
assert flag_nonce > 0
|
|
|
|
# sell an item too
|
|
res = self.wallet[0].cc_trade_item(False, ITEM_LABOUR, 1, 90, base_height + 1, -1, 0, base_height + MIN_TRADE_EXPIRATION + 10000)
|
|
labour_nonce = res.cc_nonce
|
|
|
|
# they should not be matchable at a lower price yet
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_flag(True, flag_id, 998, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 998)
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(True, ITEM_LABOUR, 1, 88, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': labour_nonce, 'amount': 1}], cost = 88)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
# pass an update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# the update might have spoiled food, etc
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
# they should still not be matchable at a lower price yet
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_flag(True, flag_id, 998, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 998)
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: self.wallet[2].cc_trade_item(True, ITEM_LABOUR, 1, 88, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': labour_nonce, 'amount': 1}], cost = 88)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
# pass an update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# the update might have spoiled food, etc
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
# they should now be matchable
|
|
self.wallet[2].cc_trade_flag(True, flag_id, 998, 0, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, match_nonce = flag_nonce, cost = 998)
|
|
self.wallet[2].cc_trade_item(True, ITEM_LABOUR, 1, 88, 0, 0, 0, expiration = base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': labour_nonce, 'amount': 1}], cost = 88)
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 2)
|
|
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
daemon.flush_txpool()
|
|
|
|
def test_trade_third_party_matching(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing trade third party matching")
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
# give wallet 0 some more money to buy test stuff
|
|
res = self.wallet[2].cc_transfer(self.pkeys[0], amount = 150000000)
|
|
assert len(res.fee_list) == 1
|
|
expected_balances[2] -= res.fee_list[0]
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= 150000000
|
|
expected_balances[0] += 150000000
|
|
|
|
res = self.wallet[0].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': 25}, {'type': ITEM_STONE, 'amount': 10}])
|
|
expected_balances[0] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, 25)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_STONE, 10)
|
|
expected_balances[0] -= 25 * LABOUR_LAST_RESORT_PRICE + 10 * STONE_LAST_RESORT_PRICE
|
|
item_counts[ITEM_LABOUR] += 25
|
|
item_counts[ITEM_STONE] += 10
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# a sell and a buy at the same price, without specifying a match
|
|
res = self.wallet[0].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_0 = res.tx_hash
|
|
nonce_0 = res.cc_nonce
|
|
fee_0 = res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_1_0 = res.tx_hash
|
|
nonce_1_0 = res.cc_nonce
|
|
fee_1_0 = res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_1_1 = res.tx_hash
|
|
nonce_1_1 = res.cc_nonce
|
|
fee_1_1 = res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 2, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
txid_1_2 = res.tx_hash
|
|
nonce_1_2 = res.cc_nonce
|
|
fee_1_2 = res.fee
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# they should still be in the txpool
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid_0 in res.tx_hashes
|
|
assert txid_1_0 in res.tx_hashes
|
|
assert txid_1_1 in res.tx_hashes
|
|
assert txid_1_2 in res.tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# match too much
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1, 'amount': 6}])
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_1, matches = [{'nonce': nonce_0, 'amount': 6}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# match 0 amount
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1, 'amount': 0}])
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_1, matches = [{'nonce': nonce_0, 'amount': 0}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# match one
|
|
res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1_0, 'amount': 2}])
|
|
txid_M = res.tx_hash
|
|
fee_M = res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, -2)
|
|
expected_balances[0] += 2 * 80
|
|
expected_balances[0] -= fee_0
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 2)
|
|
expected_balances[1] -= 2 * 80
|
|
expected_balances[1] -= fee_1_0
|
|
expected_balances[2] -= fee_M
|
|
|
|
# they should not be in the txpool anymore, except for the two unused bids
|
|
res = daemon.get_transaction_pool_hashes()
|
|
tx_hashes = res.tx_hashes if 'tx_hashes' in res else []
|
|
assert not txid_M in tx_hashes
|
|
assert not txid_0 in tx_hashes
|
|
assert not txid_1_0 in tx_hashes
|
|
assert txid_1_1 in tx_hashes
|
|
assert txid_1_2 in tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# we can still match some of it
|
|
res = self.wallet[2].cc_match(match = nonce_1_1, cost = 2 * 80, matches = [{'nonce': nonce_0, 'amount': 2}])
|
|
txid_M = res.tx_hash
|
|
fee_M = res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, -2)
|
|
expected_balances[0] += 2 * 80
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 2)
|
|
expected_balances[1] -= 2 * 80
|
|
expected_balances[1] -= fee_1_1
|
|
expected_balances[2] -= fee_M
|
|
|
|
# they should not be in the txpool anymore, except the last one
|
|
res = daemon.get_transaction_pool_hashes()
|
|
tx_hashes = res.tx_hashes if 'tx_hashes' in res else []
|
|
assert not txid_M in tx_hashes
|
|
assert not txid_0 in tx_hashes
|
|
assert not txid_1_0 in tx_hashes
|
|
assert not txid_1_1 in tx_hashes
|
|
assert txid_1_2 in tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# match too much for what is left (1)
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_0, matches = [{'nonce': nonce_1, 'amount': 2}])
|
|
except: ok = True
|
|
assert ok
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(match = nonce_1, matches = [{'nonce': nonce_0, 'amount': 2}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
daemon.flush_txpool()
|
|
|
|
def test_cancel_nonce(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing nonce cancellation")
|
|
|
|
account_id = [None, None, None]
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_public_key = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
daemon.flush_txpool()
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
res = self.wallet[2].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
txid = res.tx_hash
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
res = daemon.get_transactions([txid], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
e = res.txs[0]
|
|
assert e.tx_hash == txid
|
|
assert e.in_pool
|
|
nonce = e.cc_nonce
|
|
|
|
# not mined yet
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert not res.used
|
|
|
|
# other accounts may cancel, but this will not prevent the trade from being mined
|
|
res = self.wallet[1].cc_cancel_nonce(nonce)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert res.accounts == [account_id[1]]
|
|
assert res.txid == '0' * 64
|
|
|
|
self.assert_exception(lambda: self.wallet[1].cc_cancel_nonce(nonce))
|
|
|
|
res = self.wallet[0].cc_cancel_nonce(nonce)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert sorted(res.accounts) == sorted([account_id[1], account_id[0]])
|
|
assert res.txid == '0' * 64
|
|
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 10, matches = [{'nonce': nonce, 'amount': 5}], cost = 80*5)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[2] -= fee
|
|
expected_balances[1] -= 80 * 5
|
|
expected_balances[2] += 80 * 5
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 5)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -5)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or not txid in res.tx_hashes
|
|
|
|
# now points to the mined tx, the other accounts' cancellations are still there
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert sorted(res.accounts) == sorted([account_id[1], account_id[0]])
|
|
assert res.txid == txid
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i], "balance diff: " + str(res.balance - expected_balances[i])
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# again, with actual cancellation of an unmined tx
|
|
res = self.wallet[2].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
txid = res.tx_hash
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
res = daemon.get_transactions([txid], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
e = res.txs[0]
|
|
assert e.tx_hash == txid
|
|
assert e.in_pool
|
|
nonce = e.cc_nonce
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert not res.used
|
|
|
|
res = self.wallet[2].cc_cancel_nonce(nonce)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert res.used
|
|
assert res.accounts == [account_id[2]]
|
|
assert res.txid == '0' * 64
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or not txid in res.tx_hashes
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# and cancellation of a partially matched tx
|
|
res = self.wallet[2].cc_trade_item(False, ITEM_LABOUR, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
txid = res.tx_hash
|
|
fee = res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
res = daemon.get_transactions([txid], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
e = res.txs[0]
|
|
assert e.tx_hash == txid
|
|
assert e.in_pool
|
|
nonce = e.cc_nonce
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
|
|
res = daemon.cc_is_nonce_used(nonce)
|
|
assert not res.used
|
|
assert not 'accounts' in res or len(res.accounts) == 0
|
|
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 1, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 10, matches = [{'nonce': nonce, 'amount': 1}], cost = 80*1)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[2] -= fee
|
|
expected_balances[1] -= 80 * 1
|
|
expected_balances[2] += 80 * 1
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or not txid in res.tx_hashes
|
|
|
|
res = self.wallet[2].cc_cancel_nonce(nonce)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NONCE_CANCELLATION_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# the trade tx is mined, but further matches can be prevented
|
|
self.assert_exception(lambda: self.wallet[1].cc_trade_item(True, ITEM_LABOUR, 1, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 10, matches = [{'nonce': nonce, 'amount': 1}], cost = 80*1))
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# someone else can't cancel it now
|
|
self.assert_exception(lambda: self.wallet[0].cc_cancel_nonce(nonce))
|
|
# nor ourselves
|
|
self.assert_exception(lambda: self.wallet[2].cc_cancel_nonce(nonce))
|
|
|
|
# keep balances as we found them
|
|
res = self.wallet[1].cc_give(account_public_key[2], [{'type': ITEM_LABOUR, 'amount': 6}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
def test_game_update(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing game update")
|
|
|
|
# mine enough to pass one update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 100, FIRST_CITY_Y - 100, FIRST_CITY_X - 100 + 64 - 1, FIRST_CITY_Y - 100 + 64 - 1)
|
|
cost = res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 100, FIRST_CITY_Y - 100, FIRST_CITY_X - 100 + 64 - 1, FIRST_CITY_Y - 100 + 64 - 1)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 180, FIRST_CITY_Y - 180, FIRST_CITY_X - 180 + 64 - 1, FIRST_CITY_Y - 180 + 64 - 1)
|
|
cost = res.cost
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 180, FIRST_CITY_Y - 180, FIRST_CITY_X - 180 + 64 - 1, FIRST_CITY_Y - 180 + 64 - 1)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flag0_id = res.flags[-1]
|
|
assert flag0_id > 0
|
|
flag1_id = res.flags[-2]
|
|
assert flag1_id > 0
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 2943}, {'type': ITEM_WOOD, 'amount': 2150}, {'type': ITEM_LABOUR, 'amount': 50000}])
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag0_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(flag0_id, ROLE_AGRICULTURAL, 100, construction_height)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag1_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(flag1_id, ROLE_AGRICULTURAL, 100, construction_height)
|
|
assert len(res.tx_hash) == 64
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].refresh()
|
|
|
|
# buildings start off inactive
|
|
res = daemon.cc_get_flag(flag0_id)
|
|
assert not res.active
|
|
res = daemon.cc_get_flag(flag1_id)
|
|
assert not res.active
|
|
|
|
res = self.wallet[2].cc_build(flag0_id, 0, 0, 8, 8, block_data = [0x80 | (64-1), ITEM_WOOD], encoded = True)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].refresh()
|
|
|
|
# mine enough to pass one update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# the building with enough built blocks should now be active, but the other should not be, unless BUILD_RATIO_ACTIVE_THRESHOLD_PERCENT is 0
|
|
res = daemon.cc_get_flag(flag0_id)
|
|
assert res.active
|
|
res = daemon.cc_get_flag(flag1_id)
|
|
assert res.active == (BUILD_RATIO_ACTIVE_THRESHOLD_PERCENT == 0)
|
|
|
|
def get_state(self):
|
|
daemon = self.daemon
|
|
return get_daemon_state(daemon)
|
|
|
|
def copy(self, state):
|
|
return copy.deepcopy(state)
|
|
|
|
def remove_height(self, state):
|
|
new_state = self.copy(state)
|
|
del new_state['info.height']
|
|
return new_state
|
|
|
|
def remove_used_nonces(self, state):
|
|
new_state = self.copy(state)
|
|
del new_state['used_nonces']
|
|
return new_state
|
|
|
|
def remove_crop_temperature(self, state):
|
|
new_state = self.copy(state)
|
|
for key in new_state.keys():
|
|
if key.startswith('flag_') and 'crop_temperature' in new_state[key]:
|
|
del new_state[key]['crop_temperature']
|
|
return new_state
|
|
|
|
def get_diff(self, state0, state1):
|
|
s = ""
|
|
s += "state0: " + str(state0) + '\n'
|
|
s += "state1: " + str(state1) + '\n'
|
|
if state0.keys() != state1.keys():
|
|
s += 'Keys are different:\n'
|
|
s += 'state0 keys: ' + str(state0.keys()) + '\n'
|
|
s += 'state1 keys: ' + str(state1.keys()) + '\n'
|
|
else:
|
|
for key in state0.keys():
|
|
if state0[key] != state1[key]:
|
|
s += 'Data at key ' + str(key) + ' are different:\n'
|
|
s += 'state0[' + str(key) + ']: ' + str(state0[key]) + '\n'
|
|
s += 'state1[' + str(key) + ']: ' + str(state1[key]) + '\n'
|
|
return s
|
|
|
|
def test_revert_cmd(self, daemon, f, redo = True, mined = True):
|
|
state0 = self.get_state()
|
|
self.wallet[3].refresh()
|
|
res = f(self)
|
|
assert ('tx_hash' in res and len(res.tx_hash) == 64) or ('tx_hash_list' in res and len(res.tx_hash_list) > 0)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state1 = self.get_state()
|
|
state0_clean = self.remove_crop_temperature(self.remove_height(state0))
|
|
state1_clean = self.remove_crop_temperature(self.remove_height(state1))
|
|
if mined:
|
|
assert state0_clean != state1_clean, self.get_diff(state0_clean, state1_clean)
|
|
else:
|
|
assert state0_clean == state1_clean, self.get_diff(state0_clean, state1_clean)
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool()
|
|
state2 = self.get_state()
|
|
assert state0 == state2, self.get_diff(state0, state2)
|
|
self.wallet[3].rescan_blockchain()
|
|
if redo:
|
|
res = f(self)
|
|
assert ('tx_hash' in res and len(res.tx_hash) == 64) or ('tx_hash_list' in res and len(res.tx_hash_list) > 0)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state3 = self.get_state()
|
|
state1_clean = self.remove_crop_temperature(self.remove_used_nonces(state1))
|
|
state3_clean = self.remove_crop_temperature(self.remove_used_nonces(state3))
|
|
assert state1_clean == state3_clean, self.get_diff(state1_clean, state3_clean)
|
|
self.wallet[3].refresh()
|
|
|
|
def test_revert(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing reverting commands")
|
|
|
|
daemon.flush_txpool()
|
|
|
|
# sanity
|
|
state0 = self.get_state()
|
|
state1 = self.get_state()
|
|
assert state0 == state1, str(state0) + ', ' + str(state1)
|
|
|
|
# create account
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_deposit(amount = 450000000000, name = 'revert-test', inviting_account = 4))
|
|
self.deposits += 450000000000
|
|
|
|
# deposit on an existing account
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_deposit(amount = 450000000000))
|
|
self.deposits += 450000000000
|
|
|
|
# transfer
|
|
res = self.wallet[2].cc_get_info()
|
|
public_key = res.cc_pkey
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_transfer(public_key = public_key, amount = 5000000000))
|
|
|
|
# buy items
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8 * 1500}, {'type': ITEM_STONE + 1, 'amount': 8 * 350}, {'type': ITEM_STONE + 2, 'amount': 8 * 25}, {'type': ITEM_WOOD, 'amount': 8 * 2400}, {'type': ITEM_LABOUR, 'amount': 8 * 66000}]))
|
|
|
|
# buy land
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_buy_land(FIRST_CITY_X + 100, FIRST_CITY_Y - 100, FIRST_CITY_X + 100 + 30 - 1, FIRST_CITY_Y - 100 + 30 - 1))
|
|
|
|
# building settings
|
|
res = self.wallet[3].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
assert len(res.flags) == 1
|
|
flag_id = res.flags[-1]
|
|
assert flag_id > 0
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_building_settings(flag_id, ROLE_RESIDENTIAL1, 150, construction_height, name = 'some test building'))
|
|
|
|
# build
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_build(flag_id, 0, 0, 2, 2, block_data = [3, ITEM_STONE, 0, ITEM_STONE, 0], encoded = True))
|
|
|
|
# trade
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = self.wallet[3].cc_trade_item(False, 1, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100)
|
|
nonce = res.cc_nonce
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_trade_item(True, 1, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100), mined = False)
|
|
res = self.wallet[3].cc_trade_item(True, 1, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 1000)
|
|
nonce = res.cc_nonce
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_trade_item(False, 1, 5, 80, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100), mined = False)
|
|
res = self.wallet[3].cc_trade_flag(False, flag_id, 5000, 0, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 1000)
|
|
nonce = res.cc_nonce
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_trade_flag(True, flag_id, 5000, 0, 0, 0, 0, height + MIN_TRADE_EXPIRATION + 100), mined = False)
|
|
daemon.flush_txpool()
|
|
|
|
# assign_items
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_assign_items(flag_id, [{'type': ITEM_STONE, 'amount': 2}]))
|
|
|
|
# rename
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_rename_flag(flag_id, old_name = 'some test building', new_name = 'test-name'))
|
|
|
|
# demolish
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
flag_width = res.x1 - res.x0 + 1
|
|
flag_height = res.y1 - res.y0 + 1
|
|
flag_role = res.role
|
|
flag_economic_power = res.economic_power
|
|
flag_repair = res.repair
|
|
flag_construction_height = res.construction_height
|
|
flag_last_service_height = res.last_service_height
|
|
flag_service_price = res.service_price if 'service_price' in res else 0
|
|
flag_name = res.name
|
|
flag_ignore = res.ignore
|
|
flag_active = res.active
|
|
flag_budget = res.budget
|
|
assert 'packed_tiles' in res
|
|
flag_tiles = res.packed_tiles
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_demolish(flag_id, role = flag_role, economic_power = flag_economic_power, repair = flag_repair, construction_height = flag_construction_height, last_service_height = flag_last_service_height, service_price = flag_service_price, name = flag_name, ignore = flag_ignore, active = flag_active, crop = res.crop, sow_height = res.sow_height, num_missed_ticks = res.num_missed_ticks, budget = flag_budget, tiles = flag_tiles))
|
|
|
|
# research
|
|
res = daemon.cc_get_discoveries()
|
|
assert res.discoveries[DISCOVERY_BUCKET_BRIGADE].name == "Bucket brigade"
|
|
difficulty = res.discoveries[DISCOVERY_BUCKET_BRIGADE].difficulty
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_research(DISCOVERY_BUCKET_BRIGADE, difficulty * 5))
|
|
|
|
# new item
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_new_item(8, "Test item for testing revert", False, False, 0, "primary desc", "secondary desc"))
|
|
|
|
# dividend (monetary and item)
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) > 0
|
|
custom_item_id = res.items_[-1].id
|
|
assert res.items_[-1].amount == 8
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(custom_item_id, 0, 100))
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(custom_item_id, ITEM_STONE, 16))
|
|
|
|
# new event badge
|
|
res = self.wallet[0].cc_get_info()
|
|
account_id = res.account_id
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_event_badge(0, "Test badge for testing revert", "Event badge desc", [{"account_id": account_id, "from_level": 0, "to_level": 2}]))
|
|
|
|
# assign event badge
|
|
from_timestamp = 0
|
|
res = daemon.cc_get_account(account_id)
|
|
for e in res.badges if 'badges' in res else []:
|
|
if e.type == 4096:
|
|
assert e.level == 2
|
|
from_timestamp = e.timestamp
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_event_badge(4096, "", "", [{"account_id": account_id, "from_level": 2, "to_level": 3, "from_timestamp": from_timestamp}]))
|
|
|
|
# destroy items
|
|
res = daemon.cc_get_custom_items()
|
|
item_id = res.items_[-1].id
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_destroy_items(item_id, 2))
|
|
|
|
# define attribute
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_define_attribute('Test attribute', 'foo'))
|
|
|
|
# increase attribute
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[0].cc_increase_attribute(1, 1))
|
|
|
|
# dice roll
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dice_roll("x", 10, 20))
|
|
|
|
# hunt
|
|
res = daemon.cc_get_city(0)
|
|
moose = res.moose
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_hunt(target = 0, city = 0, population = moose), redo = False)
|
|
bears = res.bears
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_hunt(target = 1, city = 0, population = bears), redo = False)
|
|
|
|
# destroy_flag
|
|
res = self.wallet[3].cc_buy_land(FIRST_CITY_X + 500, FIRST_CITY_Y, FIRST_CITY_X + 500 + 8 - 1, FIRST_CITY_Y + 8 - 1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[3].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flag_id = res.flags[-1]
|
|
res = daemon.cc_get_flag(flag_id)
|
|
palette = res.palette if 'palette' in res else []
|
|
crop = res.crop
|
|
sow_height = res.sow_height
|
|
vegetables_nutrients = res.vegetables_nutrients
|
|
grain_nutrients = res.grain_nutrients
|
|
construction_height = res.construction_height
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_destroy_flag(flag_id, 0, FIRST_CITY_X + 500, FIRST_CITY_Y, FIRST_CITY_X + 500 + 8 - 1, FIRST_CITY_Y + 8 - 1, construction_height, crop, sow_height, vegetables_nutrients, grain_nutrients, palette))
|
|
|
|
def test_custom_items(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing custom items")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
account_public_key = [None, None, None]
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
account_public_key[i] = res.cc_pkey
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
existing_items = 0 if 'items_' not in res else len(res.items_)
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_new_item(0, "name", False, False, 0, "primary desc", "secondary desc")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_new_item(100, "", False, False, 0, "primary desc", "secondary desc")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_new_item(100, "name", False, False, 0, "primary desc", "secondary desc", hash = "1212121212121212")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_new_item(100, "name", False, False, 0, "primary desc", "secondary desc", gold = 9999999999999)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_new_item(184467440738, "name", False, False, 0, "primary desc", "secondary desc", gold = 100000000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_new_item(100, "name", True, False, 0, "primary desc", "secondary desc", gold = 100000000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
assert (0 if 'items_' not in res else len(res.items_)) == existing_items
|
|
|
|
res = self.wallet[2].cc_new_item(100, "Test item 1", False, False, 0, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) == existing_items + 1
|
|
item = res.items_[-1]
|
|
assert item.id == ITEM_FIRST_USER + existing_items
|
|
assert item.creator == account_id[2]
|
|
assert item.creation_height == height - 1
|
|
assert item.amount == 100
|
|
assert item.name == "Test item 1"
|
|
assert item.pdesc == "primary desc"
|
|
assert item.sdesc == "secondary desc"
|
|
assert not item.is_group
|
|
assert item.group == 0
|
|
assert item.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
assert item.hash == ""
|
|
assert item.gold == 0
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items, 100)
|
|
|
|
# no fractional gold
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_item(30, "Test item 2", False, False, 0, "primary desc", "secondary desc", hash = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", gold = 150000000))
|
|
|
|
res = self.wallet[2].cc_new_item(30, "Test item 2", False, False, 0, "primary desc", "secondary desc", hash = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", gold = 100000000)
|
|
expected_balances[2] -= 30 * (100000000 * (1000 + CUSTOM_ITEM_GOLD_GILDING_FEE_PER_THOUSAND) // 1000)
|
|
expected_balances[2] -= res.fee
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) == existing_items + 2
|
|
item = res.items_[-1]
|
|
assert item.id == ITEM_FIRST_USER + existing_items + 1
|
|
assert item.creator == account_id[2]
|
|
assert item.creation_height == height - 1 + 1
|
|
assert item.amount == 30
|
|
assert item.name == "Test item 2"
|
|
assert item.pdesc == "primary desc"
|
|
assert item.sdesc == "secondary desc"
|
|
assert not item.is_group
|
|
assert item.group == 0
|
|
assert item.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
assert item.hash == "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"
|
|
assert item.gold == 100000000
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 1, 30)
|
|
|
|
res = daemon.cc_is_custom_item_data("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd")
|
|
assert res.id == ITEM_FIRST_USER + existing_items + 1
|
|
assert not res.ignore
|
|
res = daemon.cc_is_custom_item_data("abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabce")
|
|
assert res.id == 0
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
res = daemon.cc_get_item_count([ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 1])
|
|
assert res.counts == [100, 30]
|
|
|
|
print('Testing dividends')
|
|
|
|
# first give some to others
|
|
res = self.wallet[2].cc_give(account_public_key[0], [{'type': ITEM_FIRST_USER + existing_items + 1, 'amount': 3}])
|
|
expected_balances[2] -= res.fee
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 1, -3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_FIRST_USER + existing_items + 1, 3)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].cc_give(account_public_key[1], [{'type': ITEM_FIRST_USER + existing_items + 1, 'amount': 2}])
|
|
expected_balances[2] -= res.fee
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 1, -2)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_FIRST_USER + existing_items + 1, 2)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# invalid dividend item
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + 1919, 100))
|
|
# group custom item
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER, 100))
|
|
# no items
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + existing_items + 1, 0))
|
|
# too many items
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + existing_items + 1, 111111111111))
|
|
# too much money
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, 0, 1111111111111111))
|
|
|
|
# money dividend
|
|
res = self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, 0, 100 * 30)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 100 * 5
|
|
expected_balances[0] += 100 * 3
|
|
expected_balances[1] += 100 * 2
|
|
|
|
# item dividend
|
|
res = self.wallet[2].cc_dividend(ITEM_FIRST_USER + existing_items + 1, ITEM_LABOUR, 5 * 30 + 29)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_LABOUR, -5 * 5)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_LABOUR, 5 * 3)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_LABOUR, 5 * 2)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
print('Testing item destruction')
|
|
|
|
res = daemon.cc_get_item_ownership(ITEM_FIRST_USER + existing_items + 1)
|
|
user_item_supply = res.supply
|
|
assert len(res.ownership) == 3
|
|
assert res.ownership[0].account == account_id[0]
|
|
assert res.ownership[0].amount == 3
|
|
assert res.ownership[1].account == account_id[1]
|
|
assert res.ownership[1].amount == 2
|
|
assert res.ownership[2].account == account_id[2]
|
|
assert res.ownership[2].amount == 25
|
|
assert res.supply == 30
|
|
|
|
res = daemon.cc_get_item_ownership(ITEM_WOOD)
|
|
wood_supply = res.supply
|
|
assert len(res.ownership) >= 1
|
|
for i in range(len(res.ownership)):
|
|
if res.ownership[i].account == account_id[2]:
|
|
wood_owned = res.ownership[i].amount
|
|
assert wood_owned > 0
|
|
assert wood_owned <= wood_supply
|
|
|
|
# testing destruction
|
|
res = self.wallet[0].cc_destroy_items(ITEM_FIRST_USER + existing_items + 1, 1)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] += 1 * 100000000 * (1000 - CUSTOM_ITEM_GOLD_RECOVERY_FEE_PER_THOUSAND) // 1000
|
|
res = self.wallet[2].cc_destroy_items(ITEM_FIRST_USER + existing_items + 1, 3)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] += 3 * 100000000 * (1000 - CUSTOM_ITEM_GOLD_RECOVERY_FEE_PER_THOUSAND) // 1000
|
|
res = self.wallet[2].cc_destroy_items(ITEM_WOOD, 2)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 3)
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_FIRST_USER + existing_items + 1, -1)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 1, -3)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_WOOD, -2)
|
|
item_counts[ITEM_WOOD] -= 2
|
|
|
|
# check total amount
|
|
res = daemon.cc_get_custom_items()
|
|
items = [x for x in res.items_ if x['id'] == ITEM_FIRST_USER + existing_items + 1]
|
|
assert len(items) == 1
|
|
assert items[0].amount == 30 - 3 - 1
|
|
|
|
res = daemon.cc_get_item_ownership(ITEM_FIRST_USER + existing_items + 1)
|
|
user_item_supply = res.supply
|
|
assert len(res.ownership) == 3
|
|
assert res.ownership[0].account == account_id[0]
|
|
assert res.ownership[0].amount == 2
|
|
assert res.ownership[1].account == account_id[1]
|
|
assert res.ownership[1].amount == 2
|
|
assert res.ownership[2].account == account_id[2]
|
|
assert res.ownership[2].amount == 22
|
|
assert res.supply == 26
|
|
|
|
res = daemon.cc_get_item_ownership(ITEM_WOOD)
|
|
assert len(res.ownership) >= 1
|
|
for i in range(len(res.ownership)):
|
|
if res.ownership[i].account == account_id[2]:
|
|
assert res.ownership[i].amount == wood_owned - 2
|
|
assert res.supply == wood_supply - 2
|
|
|
|
# these can't
|
|
ok = False
|
|
try: self.wallet[2].cc_destroy_items(ITEM_FIRST_USER + existing_items + 100, 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: self.wallet[2].cc_destroy_items(ITEM_FIRST_USER + existing_items + 1, 3000000)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
res = daemon.cc_get_item_count([ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 1])
|
|
assert res.counts == [100, 30 - 4]
|
|
|
|
print('Testing item groups')
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
for e in res.items_:
|
|
assert not e.is_group or e.id == COINS_ITEM_GROUP or e.id == MORTGAGE_ITEM_GROUP
|
|
# we have a settlement and a year coin at start
|
|
if e.id <= COIN_ITEM_SETTLEMENT + 1:
|
|
assert e.group == 0 or e.id == COIN_ITEM_SETTLEMENT or e.id == COIN_ITEM_SETTLEMENT + 1
|
|
|
|
# group with non zero amount
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_item(30, "Group", True, False, 0, "primary desc", "secondary desc"))
|
|
|
|
# group with group to a non custom item
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_item(0, "Group", True, False, ITEM_WOOD, "primary desc", "secondary desc"))
|
|
|
|
res = self.wallet[2].cc_new_item(0, "Group", True, False, 0, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert e.is_group
|
|
assert not e.is_public
|
|
assert e.group == 0
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
group_id = e.id
|
|
|
|
res = self.wallet[2].cc_new_item(1, "Group member 1", False, False, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 3, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.group == group_id
|
|
group_member_1_id = e.id
|
|
assert e.id == ITEM_FIRST_USER + existing_items + 3
|
|
res = self.wallet[2].cc_new_item(1, "Group member 2", False, False, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 4, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.group == group_id
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
group_member_2_id = e.id
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
res = daemon.cc_get_item_count(list(range(ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 4 + 1)))
|
|
assert res.counts == [100, 30 - 4, 2, 1, 1]
|
|
|
|
res = self.wallet[2].cc_new_item(0, "Subgroup", True, False, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert e.is_group
|
|
assert not e.is_public
|
|
assert e.group == group_id
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
subgroup_id = e.id
|
|
|
|
res = self.wallet[2].cc_new_item(4, "Subgroup member 1", False, False, subgroup_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 6, 4)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.group == subgroup_id
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
subgroup_member_1_id = e.id
|
|
res = self.wallet[2].cc_new_item(8, "Subgroup member 2", False, False, subgroup_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_FIRST_USER + existing_items + 7, 8)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.group == subgroup_id
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
subgroup_member_2_id = e.id
|
|
|
|
# wrong owner
|
|
self.assert_exception(lambda: self.wallet[1].cc_new_item(1, "Invalid", False, False, group_id, "primary desc", "secondary desc"))
|
|
|
|
# groups is not a group
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_item(1, "Invalid", False, False, group_member_1_id, "primary desc", "secondary desc"))
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
res = daemon.cc_get_item_count(list(range(ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 7 + 1)))
|
|
assert res.counts == [100, 30 - 4, 14, 1, 1, 12, 4, 8]
|
|
|
|
# others can add to public groups
|
|
res = self.wallet[2].cc_new_item(0, "Public group", True, True, group_id, "primary desc", "secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert e.is_group
|
|
assert e.is_public
|
|
assert e.group == group_id
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
public_group_id = e.id
|
|
|
|
res = self.wallet[1].cc_new_item(4, "In a public group", False, False, public_group_id, "primary desc", "secondary desc")
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] -= NEW_ITEM_FEE
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], public_group_id + 1, 4)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = res.items_[-1]
|
|
assert e.id >= ITEM_FIRST_USER and e.id <= ITEM_LAST_USER
|
|
assert not e.is_group
|
|
assert not e.is_public
|
|
assert e.user_data == [0] * NUM_CUSTOM_ITEM_USER_DATA
|
|
assert e.group == public_group_id
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
res = daemon.cc_get_item_count(list(range(ITEM_FIRST_USER + existing_items, ITEM_FIRST_USER + existing_items + 7 + 3)))
|
|
assert res.counts == [100, 30 - 4, 18, 1, 1, 12, 4, 8, 4, 4]
|
|
|
|
print('Testing updating item')
|
|
|
|
# invalid
|
|
self.assert_exception(lambda: self.wallet[2].cc_update_item(0, "", ""))
|
|
# non custom
|
|
self.assert_exception(lambda: self.wallet[2].cc_update_item(ITEM_WOOD, "", ""))
|
|
# not owned
|
|
self.assert_exception(lambda: self.wallet[1].cc_update_item(ITEM_FIRST_USER + existing_items + 1, "", ""))
|
|
# wrong previous desc
|
|
self.assert_exception(lambda: self.wallet[2].cc_update_item(ITEM_FIRST_USER + existing_items + 1, "secondary desc - not", ""))
|
|
# wrong previous desc
|
|
self.assert_exception(lambda: self.wallet[2].cc_update_item(ITEM_FIRST_USER + existing_items + 1, "primary desc", ""))
|
|
|
|
# that one should work
|
|
self.wallet[2].cc_update_item(ITEM_FIRST_USER + existing_items + 1, "secondary desc", "new secondary desc")
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
e = [x for x in res.items_ if x.id == ITEM_FIRST_USER + existing_items + 1][0]
|
|
assert e.id == ITEM_FIRST_USER + existing_items + 1
|
|
assert e.sdesc == "new secondary desc"
|
|
|
|
def test_badges(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing badges")
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
|
|
self.wallet[3].cc_event_badge(0, "Some test badge", "Event badge desc", [{"account_id": account_id[0], "from_level": 0, "to_level": 2}, {"account_id": account_id[2], "from_level": 0, "to_level": 1}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
res = daemon.cc_get_badge([])
|
|
badge = res.badges[-1]
|
|
assert badge.id > 0
|
|
assert badge.name == "Some test badge"
|
|
assert badge.description == "Event badge desc"
|
|
badge_id = badge.id
|
|
res = daemon.cc_get_account(account_id[0])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 2
|
|
assert res.badges[-1].timestamp == height - 1
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 1
|
|
assert res.badges[-1].timestamp == height - 1
|
|
|
|
from_timestamp = [0, 0, 0]
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
for e in res.badges if 'badges' in res else []:
|
|
if e.type == badge_id:
|
|
from_timestamp[i] = e.timestamp
|
|
|
|
self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 2, "to_level": 4, "from_timestamp": from_timestamp[0]}, {"account_id": account_id[1], "from_level": 0, "to_level": 2, "from_timestamp": from_timestamp[1]}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id[0])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 4
|
|
assert res.badges[-1].timestamp == height
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 1
|
|
assert res.badges[-1].timestamp == height - 1
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert res.badges[-1].type == badge_id
|
|
assert res.badges[-1].level == 2
|
|
assert res.badges[-1].timestamp == height
|
|
|
|
# invalid: does not change
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 4, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: wrong from
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 3, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: goes down
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 3, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: goes too high
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 6, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: both id and name
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "not empty", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: not an event badge
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(1, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: unallocated event badge
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(4096 + 1024, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": from_timestamp[0]}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# valid: new event badge, no recipients
|
|
self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", [])
|
|
|
|
# invalid: bad from timestamp
|
|
ok = False
|
|
try: self.wallet[3].cc_event_badge(badge_id, "", "", [{"account_id": account_id[0], "from_level": 4, "to_level": 5, "from_timestamp": 999999}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
assert res.counts == item_counts
|
|
|
|
def test_resize_flag(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing resizing flags")
|
|
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X + 200, FIRST_CITY_Y + 500, FIRST_CITY_X + 200 + 12 - 1, FIRST_CITY_Y + 500 + 12 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X + 200, FIRST_CITY_Y + 500, FIRST_CITY_X + 200 + 12 - 1, FIRST_CITY_Y + 500 + 12 - 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
flag_id = res.flags[-1]
|
|
assert flag_id > 0
|
|
res = daemon.cc_get_flag(flag_id)
|
|
x0 = res.x0
|
|
y0 = res.y0
|
|
x1 = res.x1
|
|
y1 = res.y1
|
|
w = x1 - x0 + 1
|
|
h = y1 - y0 + 1
|
|
tmpx0 = x0
|
|
tmpy0 = y0
|
|
tmpx1 = x1
|
|
tmpy1 = y1
|
|
|
|
# increase to the right
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0, tmpy0, tmpx1 + 1, tmpy1)
|
|
self.wallet[2].cc_resize_flag(flag_id, 0, 0, 1, 0, res.cost)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.x0 == x0 and res.y0 == y0 and res.x1 == x1 + 1 and res.y1 == y1
|
|
tmpx1 += 1
|
|
|
|
# increase to the left
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0 - 1, tmpy0, tmpx1, tmpy1)
|
|
self.wallet[2].cc_resize_flag(flag_id, -1, 0, 0, 0, res.cost)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.x0 == x0 - 1 and res.y0 == y0 and res.x1 == x1 + 1 and res.y1 == y1
|
|
tmpx0 -= 1
|
|
|
|
# increase to the top
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0, tmpy0 - 1, tmpx1, tmpy1)
|
|
self.wallet[2].cc_resize_flag(flag_id, 0, -1, 0, 0, res.cost)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.x0 == x0 - 1 and res.y0 == y0 - 1 and res.x1 == x1 + 1 and res.y1 == y1
|
|
tmpy0 -= 1
|
|
|
|
# increase to the bottom
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0, tmpy0, tmpx1, tmpy1 + 1)
|
|
self.wallet[2].cc_resize_flag(flag_id, 0, 0, 0, 1, res.cost)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.x0 == x0 - 1 and res.y0 == y0 - 1 and res.x1 == x1 + 1 and res.y1 == y1 + 1
|
|
tmpy1 += 1
|
|
|
|
# increase all
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0 - 2, tmpy0 - 1, tmpx1 + 3, tmpy1 + 2)
|
|
self.wallet[2].cc_resize_flag(flag_id, -2, -1, 3, 2, res.cost)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.x0 == x0 - 3 and res.y0 == y0 - 2 and res.x1 == x1 + 4 and res.y1 == y1 + 3
|
|
tmpx0 -= 2
|
|
tmpy0 -= 1
|
|
tmpx1 += 3
|
|
tmpy1 += 2
|
|
|
|
# increase back to start
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0 + 3, tmpy0 + 2, tmpx1 - 4, tmpy1 - 3)
|
|
self.wallet[2].cc_resize_flag(flag_id, 3, 2, -4, -3, res.cost)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.x0 == x0 and res.y0 == y0 and res.x1 == x1 and res.y1 == y1
|
|
tmpx0 += 3
|
|
tmpy0 += 2
|
|
tmpx1 -= 4
|
|
tmpy1 -= 3
|
|
assert tmpx0 == x0
|
|
assert tmpy0 == y0
|
|
assert tmpx1 == x1
|
|
assert tmpy1 == y1
|
|
|
|
# invalid: increase width past 256
|
|
ok = False
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0 - 128, tmpy0, tmpx1 + 127, tmpy1)
|
|
try: self.wallet[2].cc_resize_flag(flag_id, -128, 0, 127, 0, res.cost)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: increase height past 256
|
|
ok = False
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0, tmpy0 - 128, tmpx1, tmpy1 + 127)
|
|
try: self.wallet[2].cc_resize_flag(flag_id, 0, -128, 0, 127, res.cost)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# invalid: move with no intersection
|
|
ok = False
|
|
res = daemon.cc_get_flag_resizing_cost(0, tmpx0, tmpy0, tmpx1, tmpy1, tmpx0 + 127, tmpy0 + 127, tmpx1 + 127, tmpy1 + 127)
|
|
try: self.wallet[2].cc_resize_flag(flag_id, 127, 127, 127, 127, res.cost)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
def test_names(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing valid names")
|
|
for name in ["foo", "a" * MAX_CC_NAME_LENGTH, "a b", "a1", "a'."]:
|
|
res = self.wallet[2].cc_deposit(amount = 100000000, name = name)
|
|
self.deposits += 100000000
|
|
txid = res.tx_hash_list[0]
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.name == name, res
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool(txid)
|
|
self.wallet[2].rescan_blockchain()
|
|
self.deposits -= 100000000
|
|
|
|
print("Testing invalid names")
|
|
for name in ["", "a\0", " ", "a ", " a", "1", "a&", "\xff\xff", "a" * (MAX_CC_NAME_LENGTH + 1), u"いちりゅう", "\0f", u"いちりゅういちりゅういちりゅういちりゅういちりゅう"]:
|
|
ok = False
|
|
try:
|
|
res = self.wallet[2].cc_deposit(amount = 100000000, name = name)
|
|
except:
|
|
ok = True
|
|
assert ok
|
|
|
|
print("Testing conflicting names")
|
|
res = self.wallet[2].cc_deposit(amount = 100000000, name = 'Foo')
|
|
self.deposits += 100000000
|
|
txid = res.tx_hash_list[0]
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.name == "Foo", res
|
|
for name in ["foo", "foO", "FOO"]:
|
|
ok = False
|
|
try:
|
|
res = self.wallet[3].cc_deposit(amount = 100000000, name = name)
|
|
except:
|
|
ok = True
|
|
assert ok
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool(txid)
|
|
self.wallet[2].rescan_blockchain()
|
|
self.deposits -= 100000000
|
|
|
|
def test_script_variables(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing script variables")
|
|
|
|
res = daemon.cc_get_script_variables()
|
|
assert 'script_variables' not in res or len(res.script_variables) == 0
|
|
|
|
res = daemon.cc_get_script_variable("test")
|
|
assert res.value == 0
|
|
|
|
self.assert_exception(lambda: self.wallet[1].cc_set_script_variable('other', 1, 42))
|
|
|
|
res = self.wallet[3].cc_set_script_variable('other', 0, 42)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_script_variable("test")
|
|
assert res.value == 0
|
|
res = daemon.cc_get_script_variable("other")
|
|
assert res.value == 42
|
|
|
|
res = daemon.cc_get_script_variables()
|
|
assert len(res.script_variables) == 1
|
|
assert res.script_variables[0].name == "other"
|
|
assert res.script_variables[0].value == 42
|
|
|
|
res = self.wallet[3].cc_set_script_variable('test', 0, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_script_variables()
|
|
assert len(res.script_variables) == 2
|
|
res = daemon.cc_get_script_variable("test")
|
|
assert res.value == 1
|
|
res = daemon.cc_get_script_variable("other")
|
|
assert res.value == 42
|
|
|
|
res = self.wallet[3].cc_set_script_variable('test', 1, 0)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_script_variables()
|
|
assert len(res.script_variables) == 1
|
|
res = daemon.cc_get_script_variable("other")
|
|
assert res.value == 42
|
|
res = daemon.cc_get_script_variable("test")
|
|
assert res.value == 0
|
|
|
|
res = self.wallet[3].cc_set_script_variable('other', 42, 18)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_script_variables()
|
|
assert len(res.script_variables) == 1
|
|
res = daemon.cc_get_script_variable("other")
|
|
assert res.value == 18
|
|
|
|
res = self.wallet[3].cc_set_script_variable('other', 18, 0)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_script_variables()
|
|
assert 'script_variables' not in res or len(res.script_variables) == 0
|
|
res = daemon.cc_get_script_variable("other")
|
|
assert res.value == 0
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'script_variables' not in res or len(res.script_variables) == 0
|
|
|
|
def test_attributes(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing attributes")
|
|
|
|
res = daemon.cc_get_attributes()
|
|
assert len(res.attributes) == 1 # from revert test
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_define_attribute('', 'desc')
|
|
except: ok = True
|
|
assert ok
|
|
|
|
description = 'The quality of that which is evanescent (duh)'
|
|
res = self.wallet[3].cc_define_attribute('Evanescence', description)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_attributes()
|
|
assert len(res.attributes) == 2
|
|
assert res.attributes[1].name == 'Evanescence'
|
|
assert res.attributes[1].description == description
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_define_attribute('Evanescence', description)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
for e in res.attributes if 'attributes' in res else []:
|
|
assert e.value == 0
|
|
|
|
self.wallet[2].cc_increase_attribute(2, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_increase_attribute(3, 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_increase_attribute(2, 5)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
ok = False
|
|
try: res = self.wallet[3].cc_increase_attribute(2, 0xffffffff)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
for e in res.attributes if 'attributes' in res else []:
|
|
assert e.value == 1 if e.type == 2 else 0
|
|
|
|
def test_dice_roll(self):
|
|
daemon= self.daemon
|
|
|
|
print("Testing dice roll")
|
|
|
|
self.assert_exception(lambda: self.wallet[3].cc_dice_roll('foo!\n', 6, 10, 0))
|
|
self.assert_exception(lambda: self.wallet[3].cc_dice_roll('foo!', 11, 10, 0))
|
|
self.assert_exception(lambda: self.wallet[3].cc_dice_roll('foo!', 6, 10, 111))
|
|
self.assert_exception(lambda: self.wallet[3].cc_dice_roll('foo!', 6, 10, 1, 100))
|
|
res = self.wallet[3].cc_dice_roll('foo!', 6, 10, 1, 1)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
def test_hunt(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing hunt")
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
moose_killed = res.moose_killed
|
|
bears_killed = res.bears_killed
|
|
starting_meat = 0
|
|
for x in res.item_balances:
|
|
if x['type'] == ITEM_FOOD_MEAT:
|
|
starting_meat = x['amount']
|
|
|
|
res = daemon.cc_get_city(0)
|
|
population = res.moose
|
|
starting_moose = res.moose
|
|
starting_bears = res.bears
|
|
|
|
# bad population
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 0, city = 0, population = population + 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad city
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 0, city = 9, population = population)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad target
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 2, city = 0, population = population)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[2].cc_hunt(target = 0, city = 0, population = population)
|
|
|
|
# only one at a time
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 1, city = 0, population = population)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.moose_killed > moose_killed
|
|
moose_killed = res.moose_killed
|
|
assert bears_killed == res.bears_killed
|
|
meat = 0
|
|
for x in res.item_balances:
|
|
if x['type'] == ITEM_FOOD_MEAT:
|
|
meat = x['amount']
|
|
assert meat > starting_meat
|
|
|
|
starting_meat = meat
|
|
res = daemon.cc_get_city(0)
|
|
population = res.bears
|
|
self.wallet[2].cc_hunt(target = 1, city = 0, population = population)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert moose_killed == res.moose_killed
|
|
assert res.bears_killed > bears_killed
|
|
bears_killed = res.bears_killed
|
|
meat = 0
|
|
for x in res.item_balances:
|
|
if x['type'] == ITEM_FOOD_MEAT:
|
|
meat = x['amount']
|
|
assert meat > starting_meat
|
|
|
|
res = daemon.cc_get_city(0)
|
|
new_moose = res.moose
|
|
assert new_moose == starting_moose - moose_killed
|
|
new_bears = res.bears
|
|
assert new_bears == starting_bears - bears_killed
|
|
|
|
# mine enough to pass one update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# check regeneration
|
|
res = daemon.cc_get_city(0)
|
|
assert res.moose > new_moose
|
|
assert res.bears > new_bears
|
|
|
|
# with lower population
|
|
res = daemon.cc_get_city(0)
|
|
old_moose = res.moose
|
|
self.wallet[2].cc_hunt(target = 0, city = 0, population = 100)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(0)
|
|
new_moose = res.moose
|
|
assert new_moose < old_moose
|
|
|
|
def test_invitation(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing invitations")
|
|
|
|
res = self.wallet[2].cc_create_invitation(amount = 250000000)
|
|
invitation = res.invitation
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
ok = False
|
|
try: res = self.wallet[4].cc_get_info()
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can't redeem if we already have an account
|
|
ok = False
|
|
try: self.wallet[0].cc_redeem_account(invitation, "invited account 2")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad name
|
|
ok = False
|
|
try: self.wallet[4].cc_redeem_account(invitation, "")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[4].cc_redeem_account(invitation, "invited account")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[4].refresh()
|
|
res = self.wallet[4].cc_get_info()
|
|
account_id = res.account_id
|
|
assert account_id != 0
|
|
res = self.wallet[4].get_address()
|
|
recipient = res.address
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.balance == 250000000
|
|
|
|
res = self.wallet[4].get_balance()
|
|
assert res.cc_balance == 250000000
|
|
|
|
# pop, the account disappears
|
|
daemon.pop_blocks(1)
|
|
|
|
ok = False
|
|
try: res = daemon.cc_get_account(account_id)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[4].refresh()
|
|
ok = False
|
|
try: res = self.wallet[4].cc_get_info()
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# can do it again if popped
|
|
daemon.flush_txpool()
|
|
self.wallet[4].cc_redeem_account(invitation, "invited account after pop")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[4].refresh()
|
|
res = self.wallet[4].cc_get_info()
|
|
account_id = res.account_id
|
|
assert account_id != 0
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.balance == 250000000
|
|
|
|
res = self.wallet[4].get_balance()
|
|
assert res.cc_balance == 250000000
|
|
|
|
# can't do it twice
|
|
ok = False
|
|
try: self.wallet[4].cc_redeem_account(invitation, "invited account 2")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# nor from another account
|
|
ok = False
|
|
try: self.wallet[3].cc_redeem_account(invitation, "invited account 2")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# pop and try with invitation with a recipient
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool()
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_invitation(amount = 250000000, recipient = 'invalid'))
|
|
res = self.wallet[2].cc_create_invitation(amount = 250000000, recipient = recipient)
|
|
invitation = res.invitation
|
|
assert len(invitation) > 0
|
|
|
|
# only the intended recipient can redeem
|
|
self.assert_exception(lambda: self.wallet[3].cc_redeem_account(invitation, "invited account with recipient"))
|
|
res = self.wallet[4].cc_redeem_account(invitation, "invited account with recipient")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[4].refresh()
|
|
res = self.wallet[4].cc_get_info()
|
|
account_id = res.account_id
|
|
assert account_id != 0
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.balance == 250000000
|
|
|
|
res = self.wallet[4].get_balance()
|
|
assert res.cc_balance == 250000000
|
|
|
|
def test_chat(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing chat")
|
|
|
|
# empty line
|
|
ok = False
|
|
try: self.wallet[2].cc_chat("")
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad color
|
|
ok = False
|
|
try: self.wallet[2].cc_chat("foo", color = 200)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# locked color
|
|
ok = False
|
|
try: self.wallet[2].cc_chat("foo", color = 10)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[2].cc_chat("foo", color = 1)
|
|
txid = res.tx_hash
|
|
assert len(txid) == 64
|
|
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 5)
|
|
|
|
# not mined
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
|
|
res = self.wallet[2].cc_chat("foo2")
|
|
txid2 = res.tx_hash
|
|
assert len(txid2) == 64
|
|
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 5)
|
|
|
|
# not mined
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
assert txid2 in res.tx_hashes
|
|
|
|
daemon.flush_txpool([txid, txid2])
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or len(tx_hashes) == 0
|
|
|
|
def test_ignore(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing ignore")
|
|
|
|
# wrong type
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = 5, id = [4], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# wrong account
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = IGNORE_ACCOUNT, id = [444], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# wrong city
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = IGNORE_CITY, id = [444], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# wrong flag
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = IGNORE_FLAG, id = [444], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# wrong item
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = IGNORE_ITEM, id = [444], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# wrong sender
|
|
ok = False
|
|
try: self.wallet[2].cc_ignore(type = IGNORE_ACCOUNT, id = [4], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# duplicate id
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = IGNORE_ACCOUNT, id = [4, 4], ignore = True)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_ACCOUNT, id = [4], ignore = True)
|
|
|
|
res = daemon.cc_get_account(4)
|
|
assert not res.ignore
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(4)
|
|
assert res.ignore
|
|
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_ACCOUNT, id = [4], ignore = False)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(4)
|
|
assert not res.ignore
|
|
|
|
# does not change state
|
|
ok = False
|
|
try: self.wallet[3].cc_ignore(type = IGNORE_ACCOUNT, id = [4], ignore = False)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# flag
|
|
flag_id = 2
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert not res.ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_FLAG, id = [flag_id], ignore = True)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_FLAG, id = [flag_id], ignore = False)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert not res.ignore
|
|
|
|
# city
|
|
res = daemon.cc_get_city(0)
|
|
assert not res.ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_CITY, id = [0], ignore = True)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(0)
|
|
assert res.ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_CITY, id = [0], ignore = False)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(0)
|
|
assert not res.ignore
|
|
|
|
# custom item
|
|
res = daemon.cc_get_custom_items()
|
|
assert len(res.items_) > 0
|
|
item_id = res.items_[0].id
|
|
assert not res.items_[0].ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_ITEM, id = [item_id], ignore = True)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
assert res.items_[0].id == item_id
|
|
assert res.items_[0].ignore
|
|
res = self.wallet[3].cc_ignore(type = IGNORE_ITEM, id = [item_id], ignore = False)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
assert res.items_[0].id == item_id
|
|
assert not res.items_[0].ignore
|
|
|
|
def test_minting(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing minting")
|
|
|
|
# get past the point where the genesis coin can still be minted
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
if height + 2 <= COIN_MINTING_WINDOW:
|
|
blocks = COIN_MINTING_WINDOW - height + 2 # to be sure
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', blocks)
|
|
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
account_id = [None, None, None]
|
|
for i in range(3):
|
|
self.wallet[i].refresh()
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
res = daemon.cc_get_account(account_id[i])
|
|
expected_balances[i] = res.balance
|
|
expected_item_balances[i] = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_item_balances[i] = self.add_item(expected_item_balances[i], e.type, e.amount)
|
|
|
|
# there should be a preexisting coin, without any instances
|
|
res = daemon.cc_get_custom_items([COINS_ITEM_GROUP, COIN_ITEM_SETTLEMENT])
|
|
assert len(res.items_) == 2
|
|
assert res.items_[0].id == COINS_ITEM_GROUP
|
|
assert res.items_[0].group == 0
|
|
assert res.items_[0].is_group
|
|
assert res.items_[0].amount == 0
|
|
assert res.items_[0].creator == GAME_ACCOUNT
|
|
assert res.items_[0].creation_height == 0
|
|
assert res.items_[1].id == COIN_ITEM_SETTLEMENT
|
|
assert res.items_[1].group == COINS_ITEM_GROUP
|
|
assert not res.items_[1].is_group
|
|
assert res.items_[1].amount == 0
|
|
assert res.items_[1].creator == GAME_ACCOUNT
|
|
assert res.items_[1].creation_height == 0
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
n_existing_custom_items = len(res.items_)
|
|
|
|
# but it's too late to mint any
|
|
self.assert_exception(lambda: self.wallet[2].cc_mint(COIN_ITEM_SETTLEMENT, 1))
|
|
|
|
# or smelt any either
|
|
self.assert_exception(lambda: self.wallet[2].cc_smelt(COIN_ITEM_SETTLEMENT, 1))
|
|
|
|
# can't mint the group either
|
|
self.assert_exception(lambda: self.wallet[2].cc_mint(COINS_ITEM_GROUP, 1))
|
|
|
|
# create a fresh one, and a new coin item
|
|
res = self.wallet[3].cc_new_item(0, "Test coin", False, False, COINS_ITEM_GROUP, "primary desc", "secondary desc")
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 2)
|
|
res = self.wallet[3].cc_new_item(1, "Test non-coin", False, False, 0, "primary desc", "secondary desc")
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 2)
|
|
|
|
res = daemon.cc_get_custom_items()
|
|
assert n_existing_custom_items + 2 == len(res.items_)
|
|
test_coin = res.items_[-2]
|
|
assert test_coin.group == COINS_ITEM_GROUP
|
|
test_non_coin = res.items_[-1]
|
|
assert test_non_coin.group == 0
|
|
|
|
# we can mint the coin, but not the coin group
|
|
res = self.wallet[2].cc_mint(test_coin.id, 3)
|
|
gold_content = get_gold_content(COIN_TYPE(test_coin.user_data))
|
|
assert gold_content > 0
|
|
expected_balances[2] -= res.fee + COIN_MINTING_FEE * 3 + gold_content * 100000000 * 3
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], test_coin.id, 3)
|
|
self.assert_exception(lambda: self.wallet[2].cc_mint(test_non_coin.id, 1))
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# can't destroy the coin, it can only be smelted
|
|
ok = False
|
|
try: self.wallet[2].cc_destroy_items(test_coin.id, 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# smelt two
|
|
res = self.wallet[2].cc_smelt(test_coin.id, 2)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] += COIN_GOLD_CONTENT * 2 - COIN_SMELTING_FEE * 2
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], test_coin.id, -2)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# can't smelt 2 more though, we don't have that many
|
|
self.assert_exception(lambda: self.wallet[2].cc_smelt(test_coin.id, 2))
|
|
|
|
# can't smelt the group either
|
|
self.assert_exception(lambda: self.wallet[2].cc_smelt(test_non_coin.id, 1))
|
|
|
|
# wallet 1 can't smelt anything
|
|
self.assert_exception(lambda: self.wallet[1].cc_smelt(test_coin.id, 1))
|
|
|
|
# check balances
|
|
for i in range(3):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i]
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# wait a week
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', COIN_MINTING_WINDOW)
|
|
|
|
# can't mint anymore
|
|
self.assert_exception(lambda: self.wallet[2].cc_mint(test_coin.id, 1))
|
|
|
|
def test_farming(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing farming")
|
|
|
|
# get some more money first
|
|
self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_deposit(amount = 100000000000)
|
|
self.deposits += 100000000000
|
|
assert len(res.fee_list) == 1
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
|
|
# build a new farm
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 350, FIRST_CITY_Y - 350, FIRST_CITY_X - 350 + 64 - 1, FIRST_CITY_Y - 350 + 64 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 350, FIRST_CITY_Y - 350, FIRST_CITY_X - 350 + 64 - 1, FIRST_CITY_Y - 350 + 64 - 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
flag_id = res.flags[-1]
|
|
assert flag_id
|
|
|
|
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8000}, {'type': ITEM_WOOD, 'amount': 8000}, {'type': ITEM_LABOUR, 'amount': 1}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(flag_id, ROLE_AGRICULTURAL, 100, construction_height, name = 'test building')
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_calendar()
|
|
if res.vegetables_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_vegetables_sowing_season_end)
|
|
res = daemon.cc_get_calendar()
|
|
assert not res.vegetables_sowing_season
|
|
if res.grain_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_grain_sowing_season_end)
|
|
res = daemon.cc_get_calendar()
|
|
assert not res.vegetables_sowing_season and not res.grain_sowing_season
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
num_missed_ticks = res.num_missed_ticks
|
|
if res.repair < 500000:
|
|
# drive by check for repair range
|
|
self.assert_exception(lambda: self.wallet[1].cc_repair([flag_id, 0]))
|
|
self.assert_exception(lambda: self.wallet[1].cc_repair([flag_id, 1000000 + 1 - res.repair]))
|
|
self.wallet[1].cc_repair([flag_id, 1000000 - res.repair])
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_NONE))
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_GRAIN))
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, 255))
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_NONE, 0, 0, num_missed_ticks))
|
|
|
|
# get into sowing season
|
|
res = daemon.cc_get_calendar()
|
|
if not res.vegetables_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_vegetables_sowing_season_start)
|
|
res = daemon.cc_get_calendar()
|
|
assert res.vegetables_sowing_season
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
if res.repair < 500000:
|
|
self.wallet[1].cc_repair([flag_id, 1000000 - res.repair])
|
|
|
|
# now we can sow
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_NONE))
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, 255))
|
|
res = self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# but not twice
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_GRAIN))
|
|
|
|
# we cannot harvest yet
|
|
res = daemon.cc_get_flag(flag_id)
|
|
sow_height = res.sow_height
|
|
vegetables_nutrients = res.vegetables_nutrients
|
|
num_missed_ticks = res.num_missed_ticks
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients, num_missed_ticks))
|
|
|
|
# leave sowing season
|
|
res = daemon.cc_get_calendar()
|
|
if res.vegetables_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_vegetables_sowing_season_end)
|
|
res = daemon.cc_get_calendar()
|
|
assert not res.vegetables_sowing_season
|
|
# sowing ends after harvest starts for vegetables
|
|
assert res.vegetables_harvest_season
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
num_missed_ticks = res.num_missed_ticks
|
|
if res.repair < 500000:
|
|
self.wallet[1].cc_repair([{'flag': flag_id, 'delta_repair': 1000000 - res.repair}])
|
|
|
|
# still cannot sow
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_GRAIN))
|
|
|
|
# but we can harvest now
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id - 1, CROP_VEGETABLES, sow_height, vegetables_nutrients, num_missed_ticks))
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_GRAIN, sow_height, vegetables_nutrients, num_missed_ticks))
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height - 1, vegetables_nutrients, num_missed_ticks))
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height + 1, vegetables_nutrients, num_missed_ticks))
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients - 1, num_missed_ticks))
|
|
|
|
res = self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients, num_missed_ticks)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# not twice
|
|
self.assert_exception(lambda: self.wallet[2].cc_harvest(flag_id, CROP_VEGETABLES, sow_height, vegetables_nutrients, num_missed_ticks))
|
|
|
|
# and we can't sow right afterwards either (we could sow grain as seasons overlap though)
|
|
self.assert_exception(lambda: self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES))
|
|
|
|
# nutrients should have gone down for vegetables, stayed at 100 for grain
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.vegetables_nutrients < 100
|
|
assert res.grain_nutrients == 100
|
|
vegetables_nutrients = res.vegetables_nutrients
|
|
|
|
# get into sowing season
|
|
res = daemon.cc_get_calendar()
|
|
if not res.vegetables_sowing_season:
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', res.blocks_till_vegetables_sowing_season_start)
|
|
res = daemon.cc_get_calendar()
|
|
assert res.vegetables_sowing_season
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
if res.repair < 500000:
|
|
self.wallet[2].cc_repair([{'flag': flag_id, 'delta_repair': 1000000 - res.repair}])
|
|
|
|
# vegetables nutrients should have recovered somewhat, but not fully, grain nutrients should not have gone past 100
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.vegetables_nutrients < 100
|
|
assert res.vegetables_nutrients > vegetables_nutrients
|
|
assert res.grain_nutrients == 100
|
|
|
|
# sow
|
|
self.wallet[2].cc_sow(flag_id, CROP_VEGETABLES)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# drop all wood so we miss ticks
|
|
res = daemon.cc_get_account(account_id)
|
|
for e in res.item_balances:
|
|
if e.type == ITEM_WOOD or e.type == ITEM_FIREWOOD:
|
|
res = self.wallet[2].cc_destroy_items(e.type, e.amount)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# wait past harvest time so the crop gets lost
|
|
while True:
|
|
res = daemon.cc_get_calendar()
|
|
if not res.vegetables_sowing_season and not res.vegetables_harvest_season:
|
|
break
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
|
|
# delete the flag, to check state gets restored on pop
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
flag_role = res.role
|
|
flag_economic_power = res.economic_power
|
|
flag_repair = res.repair
|
|
flag_construction_height = res.construction_height
|
|
flag_last_service_height = res.last_service_height
|
|
flag_service_price = res.service_price if 'service_price' in res else 0
|
|
flag_name = res.name
|
|
flag_ignore = res.ignore
|
|
flag_active = res.active
|
|
flag_budget = res.budget
|
|
flag_tiles = res.packed_tiles if 'packed_tiles' in res else []
|
|
flag_crop = res.crop
|
|
flag_sow_height = res.sow_height
|
|
flag_num_missed_ticks = res.num_missed_ticks
|
|
self.wallet[2].cc_demolish(flag_id, role = flag_role, economic_power = flag_economic_power, repair = flag_repair, construction_height = flag_construction_height, last_service_height = flag_last_service_height, service_price = flag_service_price, name = flag_name, ignore = flag_ignore, active = flag_active, crop = flag_crop, sow_height = flag_sow_height, num_missed_ticks = flag_num_missed_ticks, budget = flag_budget, tiles = flag_tiles)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
x0 = res.x0
|
|
y0 = res.y0
|
|
x1 = res.x1
|
|
y1 = res.y1
|
|
palette = res.palette if 'palette' in res else []
|
|
construction_height = res.construction_height
|
|
crop = res.crop
|
|
sow_height = res.sow_height
|
|
vegetables_nutrients = res.vegetables_nutrients
|
|
grain_nutrients = res.grain_nutrients
|
|
self.wallet[2].cc_destroy_flag(flag_id, 0, x0, y0, x1, y1, construction_height, crop, sow_height, vegetables_nutrients, grain_nutrients, palette)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# now go back to where we still have crop, and demolish the building then, all state should be restored on rewind
|
|
while True:
|
|
res = daemon.cc_get_calendar()
|
|
if res.vegetables_harvest_season:
|
|
break
|
|
daemon.pop_blocks(GAME_UPDATE_FREQUENCY)
|
|
daemon.flush_txpool()
|
|
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
assert res.role == ROLE_AGRICULTURAL
|
|
assert res.crop == CROP_VEGETABLES
|
|
flag_role = res.role
|
|
flag_economic_power = res.economic_power
|
|
flag_repair = res.repair
|
|
flag_construction_height = res.construction_height
|
|
flag_last_service_height = res.last_service_height
|
|
flag_service_price = res.service_price if 'service_price' in res else 0
|
|
flag_name = res.name
|
|
flag_ignore = res.ignore
|
|
flag_active = res.active
|
|
flag_budget = res.budget
|
|
flag_tiles = res.packed_tiles if 'packed_tiles' in res else []
|
|
flag_crop = res.crop
|
|
flag_sow_height = res.sow_height
|
|
flag_num_missed_ticks = res.num_missed_ticks
|
|
assert flag_crop == CROP_VEGETABLES
|
|
assert flag_num_missed_ticks > 0
|
|
self.wallet[2].cc_demolish(flag_id, role = flag_role, economic_power = flag_economic_power, repair = flag_repair, construction_height = flag_construction_height, last_service_height = flag_last_service_height, service_price = flag_service_price, name = flag_name, ignore = flag_ignore, active = flag_active, crop = flag_crop, sow_height = flag_sow_height, num_missed_ticks = flag_num_missed_ticks, budget = flag_budget, tiles = flag_tiles)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# rebuild another on top, which should clear the previous agricultural data
|
|
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 4500}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
self.wallet[2].cc_building_settings(flag_id, ROLE_AGRICULTURAL, 100, construction_height)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(flag_id, get_packed_tiles = True)
|
|
assert res.crop == CROP_NONE
|
|
assert res.sow_height == 0
|
|
|
|
def test_cities(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing cities")
|
|
|
|
fast = False
|
|
try: fast = int(os.environ['CC_FIXED_COST_CITIES'])
|
|
except: pass
|
|
|
|
# get a lot more money
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 60)
|
|
for i in range(8 if fast else 200):
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 100)
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].cc_deposit(amount = 150000000000)
|
|
self.deposits += 150000000000
|
|
assert len(res.fee_list) == 1
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# build a lot
|
|
res = self.wallet[1].cc_get_info()
|
|
account_id = res.account_id
|
|
self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 500000 if fast else 5000000}, {'type': ITEM_WOOD, 'amount': 800000 if fast else 25000000}, {'type': ITEM_LABOUR, 'amount': 5000000 if fast else 350000000}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
farms = []
|
|
buildings = []
|
|
for i in range(1 if fast else 100):
|
|
self.wallet[1].cc_buy_land(FIRST_CITY_X + i * 128, FIRST_CITY_Y + 1500, FIRST_CITY_X + i * 128 + 127, FIRST_CITY_Y + 1500 + 127)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
last_flag = res.flags[-1]
|
|
role = [ROLE_AGRICULTURAL, ROLE_CRAFT, ROLE_SAWMILL, ROLE_STONECUTTER, ROLE_WORKFORCE, ROLE_AGRICULTURAL, ROLE_RESIDENTIAL1][i % 7]
|
|
if role == ROLE_AGRICULTURAL:
|
|
farms.append(last_flag)
|
|
buildings.append(last_flag)
|
|
res = daemon.cc_get_flag(last_flag)
|
|
construction_height = res.construction_height
|
|
self.wallet[1].cc_building_settings(last_flag, role, 100, construction_height)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# mine through updates, sowing and harvesting so flags get active and start counting towards city progress
|
|
current_crop = CROP_NONE
|
|
while not fast:
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
repair = []
|
|
for flag in buildings:
|
|
res = daemon.cc_get_flag(flag)
|
|
if res.repair < 500000:
|
|
repair.append({'flag': flag, 'delta_repair': 1000000 - res.repair})
|
|
if len(repair) > 0:
|
|
self.wallet[1].cc_repair(repair)
|
|
|
|
res = daemon.cc_get_calendar()
|
|
if res.vegetables_sowing_season and current_crop == CROP_NONE:
|
|
for flag in farms:
|
|
res = daemon.cc_get_flag(flag)
|
|
if res.crop == CROP_NONE:
|
|
self.wallet[1].cc_sow(flag, CROP_VEGETABLES)
|
|
current_crop = CROP_VEGETABLES
|
|
elif res.vegetables_harvest_season and (res.grain_sowing_season or res.blocks_till_grain_sowing_season_start <= GAME_UPDATE_FREQUENCY) and current_crop == CROP_VEGETABLES:
|
|
for flag in farms:
|
|
res = daemon.cc_get_flag(flag)
|
|
if res.crop == CROP_VEGETABLES:
|
|
vegetables_nutrients = res.vegetables_nutrients
|
|
sow_height = res.sow_height
|
|
num_missed_ticks = res.num_missed_ticks
|
|
self.wallet[1].cc_harvest(flag, CROP_VEGETABLES, sow_height, vegetables_nutrients, num_missed_ticks)
|
|
current_crop = CROP_NONE
|
|
elif res.grain_sowing_season and current_crop == CROP_NONE:
|
|
for flag in farms:
|
|
res = daemon.cc_get_flag(flag)
|
|
if res.crop == CROP_NONE:
|
|
self.wallet[1].cc_sow(flag, CROP_GRAIN)
|
|
current_crop = CROP_GRAIN
|
|
elif res.grain_harvest_season and res.blocks_till_grain_harvest_season_end <= GAME_UPDATE_FREQUENCY and current_crop == CROP_GRAIN:
|
|
for flag in farms:
|
|
res = daemon.cc_get_flag(flag)
|
|
if res.crop == CROP_GRAIN:
|
|
grain_nutrients = res.grain_nutrients
|
|
sow_height = res.sow_height
|
|
num_missed_ticks = res.num_missed_ticks
|
|
self.wallet[1].cc_harvest(flag, CROP_GRAIN, sow_height, grain_nutrients, num_missed_ticks)
|
|
current_crop = CROP_NONE
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_cities()
|
|
cities = res.cities
|
|
assert len(cities) == 1
|
|
total_shares = res.total_shares
|
|
res = daemon.cc_get_new_city_cost()
|
|
cost = res.cost
|
|
res = daemon.cc_get_calendar()
|
|
res = daemon.cc_get_account(account_id)
|
|
|
|
res = daemon.cc_get_new_city_cost()
|
|
cost = res.cost
|
|
self.wallet[1].refresh()
|
|
res = self.wallet[1].get_balance()
|
|
if cost + 1e8 < res.cc_balance:
|
|
break
|
|
|
|
res = self.wallet[1].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
cosmopolitan_found = False
|
|
if 'badges' in res:
|
|
for e in res.badges:
|
|
if e.type == BADGE_COSMOPOLITAN:
|
|
cosmopolitan_found = True
|
|
assert not cosmopolitan_found
|
|
|
|
# create city
|
|
res = daemon.cc_get_new_city_cost()
|
|
cost = res.cost
|
|
self.wallet[1].cc_found_city(1, 42, 'Ur', cost)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_cities()
|
|
assert len(res.cities) == 2
|
|
assert res.cities[0].city_id == 0
|
|
assert res.cities[0].name == "Helsengaard"
|
|
assert res.cities[0].mayor == 1
|
|
assert res.cities[1].city_id == 1
|
|
assert res.cities[1].name == "Ur"
|
|
assert res.cities[1].mayor == account_id
|
|
assert res.cities[1].ox != res.cities[0].ox
|
|
assert res.cities[1].oy != res.cities[0].oy
|
|
|
|
res = daemon.cc_get_city(1)
|
|
assert res.name == 'Ur'
|
|
assert res.mayor == account_id
|
|
assert res.ox > 0
|
|
assert res.oy > 0
|
|
assert res.seed == 42
|
|
assert res.treasury == 10 or fast
|
|
assert res.specializations == 0
|
|
assert res.max_level == 0
|
|
assert res.moose == NUM_STARTING_MOOSE
|
|
assert res.bears == NUM_STARTING_BEARS
|
|
|
|
ur_ox = res.ox
|
|
ur_oy = res.oy
|
|
|
|
# build in this new city
|
|
self.wallet[1].cc_buy_land(ur_ox + i * 128, ur_oy + 1500, ur_ox + i * 128 + 127, ur_oy + 1500 + 127, city = 1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
flag = res.flags[-1]
|
|
res = daemon.cc_get_flag(flag)
|
|
construction_height = res.construction_height
|
|
self.wallet[1].cc_building_settings(flag, ROLE_AGRICULTURAL, 100, construction_height)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# get some food to feed buildings
|
|
for i in range(4):
|
|
res = daemon.cc_get_city(1)
|
|
moose = res.moose
|
|
bears = res.bears
|
|
self.wallet[1].cc_hunt(target = 0, city = 1, population = moose)
|
|
self.wallet[1].cc_hunt(target = 1, city = 1, population = bears)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# generate some city weight so the next game update gets us some of the block reward
|
|
for i in range(7 if fast else 20):
|
|
self.wallet[1].cc_buy_land(ur_ox + i * 128, ur_oy + 2500, ur_ox + i * 128 + 127, ur_oy + 2500 + 127, city = 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
last_flag = res.flags[-1]
|
|
role = [ROLE_AGRICULTURAL, ROLE_CRAFT, ROLE_SAWMILL, ROLE_STONECUTTER, ROLE_WORKFORCE, ROLE_AGRICULTURAL, ROLE_RESIDENTIAL1][i % 7]
|
|
res = daemon.cc_get_flag(last_flag)
|
|
construction_height = res.construction_height
|
|
self.wallet[1].cc_building_settings(last_flag, role, 100, construction_height)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# wait three game updates for influence to propagate
|
|
for i in range(3):
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
res = daemon.cc_get_shares(0)
|
|
shares_0 = res.weighted_shares
|
|
assert shares_0 > 0
|
|
assert sum([x.num_shares for x in res.shares]) > 0
|
|
assert sum([x.payout for x in res.shares]) > 0
|
|
res = daemon.cc_get_shares(1)
|
|
shares_1 = res.weighted_shares
|
|
assert shares_1 > 0
|
|
assert sum([x.num_shares for x in res.shares]) > 0
|
|
assert sum([x.payout for x in res.shares]) > 0
|
|
shares_ratio = shares_0 / float(shares_1)
|
|
|
|
res = daemon.cc_get_city(0)
|
|
treasury_balance_0 = res.treasury_balance
|
|
res = daemon.cc_get_city(1)
|
|
treasury_balance_1 = res.treasury_balance
|
|
|
|
# commands that share money between cities
|
|
self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 500000}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_city(0)
|
|
delta_treasury_balance_0 = res.treasury_balance - treasury_balance_0
|
|
treasury_balance_0 = res.treasury_balance
|
|
res = daemon.cc_get_city(1)
|
|
delta_treasury_balance_1 = res.treasury_balance - treasury_balance_1
|
|
treasury_balance_1 = res.treasury_balance
|
|
assert feq(delta_treasury_balance_0 / float(delta_treasury_balance_1), shares_ratio)
|
|
|
|
res = self.wallet[3].cc_new_item(0, "Other test coin", False, False, COINS_ITEM_GROUP, "primary desc", "secondary desc")
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
test_coin = res.items_[-1]
|
|
self.wallet[1].cc_mint(test_coin.id, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_city(0)
|
|
delta_treasury_balance_0 = res.treasury_balance - treasury_balance_0
|
|
treasury_balance_0 = res.treasury_balance
|
|
res = daemon.cc_get_city(1)
|
|
delta_treasury_balance_1 = res.treasury_balance - treasury_balance_1
|
|
treasury_balance_1 = res.treasury_balance
|
|
assert feq(delta_treasury_balance_0 / float(delta_treasury_balance_1), shares_ratio)
|
|
|
|
self.wallet[1].cc_smelt(test_coin.id, 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_city(0)
|
|
delta_treasury_balance_0 = res.treasury_balance - treasury_balance_0
|
|
treasury_balance_0 = res.treasury_balance
|
|
res = daemon.cc_get_city(1)
|
|
delta_treasury_balance_1 = res.treasury_balance - treasury_balance_1
|
|
treasury_balance_1 = res.treasury_balance
|
|
assert feq(delta_treasury_balance_0 / float(delta_treasury_balance_1), shares_ratio)
|
|
|
|
res = self.wallet[1].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
cosmopolitan_level = 0
|
|
if 'badges' in res:
|
|
for e in res.badges:
|
|
if e.type == BADGE_COSMOPOLITAN:
|
|
cosmopolitan_level = e.level
|
|
assert cosmopolitan_level == 1
|
|
|
|
# A third town
|
|
if not fast:
|
|
res = daemon.cc_get_new_city_cost()
|
|
cost = res.cost
|
|
self.wallet[2].cc_found_city(2, 43, 'Ururur', cost)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_cities()
|
|
assert len(res.cities) == 3
|
|
assert res.cities[0].city_id == 0
|
|
assert res.cities[0].name == "Helsengaard"
|
|
assert res.cities[0].mayor == 1
|
|
assert res.cities[1].city_id == 1
|
|
assert res.cities[1].name == "Ur"
|
|
assert res.cities[1].mayor == account_id
|
|
assert res.cities[1].ox != res.cities[0].ox
|
|
assert res.cities[1].oy != res.cities[0].oy
|
|
assert res.cities[2].name == "Ururur"
|
|
assert res.cities[2].mayor == account_id + 1
|
|
assert res.cities[2].ox != res.cities[0].ox and res.cities[2].ox != res.cities[1].ox
|
|
assert res.cities[2].oy != res.cities[0].oy and res.cities[2].oy != res.cities[0].oy
|
|
|
|
res = daemon.cc_get_city(2)
|
|
assert res.name == 'Ururur'
|
|
assert res.mayor == account_id + 1
|
|
assert res.ox > 0
|
|
assert res.oy > 0
|
|
assert res.seed == 43
|
|
assert res.treasury == 10 or fast
|
|
assert res.specializations == 0
|
|
assert res.max_level == 0
|
|
assert res.moose == NUM_STARTING_MOOSE
|
|
assert res.bears == NUM_STARTING_BEARS
|
|
|
|
res = daemon.cc_get_city(0)
|
|
delta_treasury_balance_0 = res.treasury_balance - treasury_balance_0
|
|
treasury_balance_0 = res.treasury_balance
|
|
res = daemon.cc_get_city(1)
|
|
delta_treasury_balance_1 = res.treasury_balance - treasury_balance_1
|
|
treasury_balance_1 = res.treasury_balance
|
|
assert feq(delta_treasury_balance_0 / float(delta_treasury_balance_1), shares_ratio)
|
|
|
|
# city specializations
|
|
print("Testing city specializations")
|
|
|
|
# out of range
|
|
self.assert_exception(lambda: self.wallet[1].cc_add_city_specialization(1, 1000))
|
|
|
|
self.wallet[1].cc_add_city_specialization(1, 4)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(1)
|
|
assert res.specializations == 1 << 4
|
|
|
|
# duplicate
|
|
self.assert_exception(lambda: self.wallet[1].cc_add_city_specialization(1, 4))
|
|
|
|
# can't add too many
|
|
rejected = False
|
|
try:
|
|
for s in [0, 1, 2, 3, 5, 6, 7, 8, 9]:
|
|
self.wallet[1].cc_add_city_specialization(1, s)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
except:
|
|
rejected = True
|
|
assert rejected
|
|
|
|
# cities can be traded
|
|
|
|
print("Testing city trading")
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
|
|
# invalid city
|
|
self.assert_exception(lambda: self.wallet[1].cc_trade_city(False, 5, 1234567, 0, 0, 0, height + 10000))
|
|
# not the mayor
|
|
self.assert_exception(lambda: self.wallet[1].cc_trade_city(False, 0, 1234567, 0, 0, 0, height + 10000))
|
|
|
|
res = self.wallet[1].cc_trade_city(False, 1, 1234567, 0, 0, 0, height + 10000)
|
|
assert len(res.tx_hash) == 64
|
|
nonce = res.cc_nonce
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_trade_city(True, 1, 12345678, 0, 0, 0, height + 10000, match_nonce = nonce, cost = 1234567)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_get_info()
|
|
account2_id = res.account_id
|
|
res = daemon.cc_get_city(1)
|
|
assert res.mayor == account2_id
|
|
|
|
def test_discoveries(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing discoveries")
|
|
|
|
res = daemon.cc_get_discoveries()
|
|
assert len(res.discoveries) > 0
|
|
for d in res.discoveries:
|
|
assert d.name != ""
|
|
assert d.difficulty > 0
|
|
assert d.discoverer == 0
|
|
assert d.discovery_height == 0
|
|
assert d.budget == 0
|
|
assert not d.enabled
|
|
|
|
# pick the last researchable one which is the single prerequisite of another, research it
|
|
discovery_index = None
|
|
second_discovery_index = None
|
|
for idx in range(len(res.discoveries)):
|
|
d = res.discoveries[idx]
|
|
if (not 'prerequisites' in d or len(d.prerequisites) == 0) and ('patent_time' in d and d.patent_time > 0):
|
|
for idx2 in range(len(res.discoveries)):
|
|
d2 = res.discoveries[idx2]
|
|
if 'prerequisites' in d2 and d2.prerequisites == [d.discovery]:
|
|
discovery_index = idx
|
|
second_discovery_index = idx2
|
|
if discovery_index != None:
|
|
break
|
|
assert discovery_index != None
|
|
assert second_discovery_index != None
|
|
discovery = res.discoveries[discovery_index].discovery
|
|
second_discovery = res.discoveries[second_discovery_index].discovery
|
|
|
|
# can't fund less than the minimum amount
|
|
ok = False
|
|
try: self.wallets[2].cc_research(discovery, MIN_RESEARCH_AMOUNT - 1)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
budget = 0
|
|
while True:
|
|
amount = 200000000000
|
|
blocks = amount // 1500000000
|
|
res = self.wallet[2].cc_deposit(amount = amount)
|
|
self.deposits += amount
|
|
res = self.wallet[2].cc_research(discovery, amount)
|
|
assert len(res.tx_hash) == 64
|
|
budget += amount
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
res = daemon.cc_get_discoveries()
|
|
d = res.discoveries[discovery_index]
|
|
if d.discoverer != 0:
|
|
break
|
|
assert d.discoverer == account_id
|
|
res = daemon.get_info()
|
|
assert d.discovery_height >= res.height - 1 - blocks and d.discovery_height < res.height
|
|
assert d.research_start_height == 0
|
|
assert d.budget == budget
|
|
|
|
# it should be available for us, but not for others
|
|
res = daemon.cc_get_discoveries(account_id)
|
|
assert res.discoveries[discovery_index].enabled
|
|
res = daemon.cc_get_discoveries(account_id + 1)
|
|
assert not res.discoveries[discovery_index].enabled
|
|
res = daemon.cc_get_discoveries(0)
|
|
assert not res.discoveries[discovery_index].enabled
|
|
res = daemon.cc_get_discoveries()
|
|
assert not res.discoveries[discovery_index].enabled
|
|
|
|
# it should have unlocked the original discoverery that had it as prerequisite
|
|
res = daemon.get_info()
|
|
blockchain_height = res.height
|
|
res = daemon.cc_get_discoveries(account_id)
|
|
d2 = res.discoveries[second_discovery_index]
|
|
assert d2.research_start_height >= blockchain_height - 1 - blocks and d2.research_start_height < blockchain_height
|
|
assert d2.discoverer == 0
|
|
assert d2.discovery_height == 0
|
|
|
|
# research a string of unlocking discoveries
|
|
for discovery in [DISCOVERY_RESEARCH_EFFICIENCY, DISCOVERY_RESEARCH_PRODUCTIVITY, DISCOVERY_RESEARCH_EXPERTISE, DISCOVERY_RESEARCH_MASTERY]:
|
|
while True:
|
|
amount = 200000000000
|
|
blocks = amount // 3000000000
|
|
res = self.wallet[2].refresh()
|
|
res = self.wallet[2].cc_deposit(amount = amount)
|
|
self.deposits += amount
|
|
res = self.wallet[2].cc_research(discovery, amount)
|
|
assert len(res.tx_hash) == 64
|
|
budget += amount
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
res = daemon.cc_get_discoveries()
|
|
discovered = False
|
|
for d in res.discoveries:
|
|
if d.discovery == discovery:
|
|
if d.discoverer:
|
|
discovered = True
|
|
if discovered:
|
|
break
|
|
|
|
def make_native_script(self, owner, states):
|
|
source = "script { name \"test script\" description \"description\" owner " + str(owner) + "\n"
|
|
state_idx = 0
|
|
for s in states:
|
|
source += "state \"state " + str(state_idx) + "\" { text \"state " + str(state_idx) + "\"\n"
|
|
choice_idx = 0
|
|
for choice in s:
|
|
next_state = "" if choice == -1 else ("state " + str(choice))
|
|
source += " choice { text \"choice " + str(choice_idx) + "\" next state \"" + next_state + "\"}\n"
|
|
choice_idx += 1
|
|
state_idx += 1
|
|
source += "}\n"
|
|
source += "}"
|
|
return source
|
|
|
|
def test_scripts(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing scripts")
|
|
|
|
res = daemon.cc_get_scripts()
|
|
assert 'scripts' not in res or len(res.scripts) == 0
|
|
self.assert_exception(lambda: daemon.cc_get_script(0))
|
|
self.assert_exception(lambda: daemon.cc_get_script(1))
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account2_id = res.account_id
|
|
res = self.wallet[3].cc_get_info()
|
|
account3_id = res.account_id
|
|
|
|
# no end state
|
|
self.assert_exception(lambda: self.wallet[3].cc_create_script(source = self.make_native_script(0, [])))
|
|
self.assert_exception(lambda: self.wallet[3].cc_create_script(source = self.make_native_script(0, [[0, 1], [2, 0]])))
|
|
|
|
self.wallet[3].cc_create_script(source = self.make_native_script(0, [[0, 1], [2, 0], [1, -1]]))
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_scripts(include_blob = True)
|
|
assert len(res.scripts) == 1
|
|
assert res.scripts[0].index == 1
|
|
blob = res.scripts[0].blob
|
|
|
|
res = daemon.cc_get_script(1)
|
|
assert res.name == "test script"
|
|
assert res.icon == ""
|
|
assert res.desc == "description"
|
|
assert len(res.blob) > 0
|
|
assert res.blob == blob
|
|
|
|
res = daemon.cc_get_script_state(account = 1, script = 1, state = 0, city = 0)
|
|
assert res.ui == ""
|
|
assert res.text == "state 0"
|
|
assert res.image == ""
|
|
assert len(res.choices) == 2
|
|
assert res.choices[0].id == 0
|
|
assert res.choices[0].text == "choice 0"
|
|
assert res.choices[1].id == 1
|
|
assert res.choices[1].text == "choice 1"
|
|
assert res.choices_ui == ""
|
|
|
|
res = daemon.cc_get_script_state(account = 1, script = 1, state = 1, city = 0)
|
|
assert res.ui == ""
|
|
assert res.text == "state 1"
|
|
assert res.image == ""
|
|
assert len(res.choices) == 2
|
|
assert res.choices[0].id == 0
|
|
assert res.choices[0].text == "choice 0"
|
|
assert res.choices[1].id == 1
|
|
assert res.choices[1].text == "choice 1"
|
|
assert res.choices_ui == ""
|
|
|
|
res = daemon.cc_get_script_state(account = 1, script = 1, state = 2, city = 0)
|
|
assert res.ui == ""
|
|
assert res.text == "state 2"
|
|
assert res.image == ""
|
|
assert len(res.choices) == 2
|
|
assert res.choices[0].id == 0
|
|
assert res.choices[0].text == "choice 0"
|
|
assert res.choices[1].id == 1
|
|
assert res.choices[1].text == "choice 1"
|
|
assert res.choices_ui == ""
|
|
|
|
# invalid city
|
|
self.assert_exception(lambda: self.wallet[2].cc_start_script(1, city = 11))
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 0
|
|
assert res.script_state == 0
|
|
assert res.script_city == 0
|
|
|
|
res = self.wallet[2].cc_start_script(1, city = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 1
|
|
assert res.script_state == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(0, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(2, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = 1, city = 0, owner = GAME_ACCOUNT, choice = 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = -1, city = 0, owner = GAME_ACCOUNT, choice = 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = 0, city = 11, owner = GAME_ACCOUNT, choice = 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = GAME_ACCOUNT, choice = -1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 11))
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = account3_id, choice = 0))
|
|
|
|
res = self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 1
|
|
assert res.script_state == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
res = self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 1
|
|
assert res.script_state == 1
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
res = self.wallet[2].cc_script_choice(1, state = 1, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 1
|
|
assert res.script_state == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
res = self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 1
|
|
assert res.script_state == 1
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
res = self.wallet[2].cc_script_choice(1, state = 1, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 1
|
|
assert res.script_state == 2
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
res = self.wallet[2].cc_script_choice(1, state = 2, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
assert res.script == 0
|
|
assert res.script_state == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(1, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0))
|
|
|
|
print('testing looping script')
|
|
script = """
|
|
script {
|
|
name "looping state test"
|
|
precondition global "allow" == 1
|
|
reserves {
|
|
owner gold 0.002
|
|
player gold 0.001
|
|
}
|
|
state "0" {
|
|
choice { text "0" next state "0" actions { set local "tc" 0 award gold 0.00000001 + random 16} }
|
|
choice { text "1" next state "0" actions { set local "tc" 1 pay gold 0.00000002 set player "x" player "x" + 1} }
|
|
choice { text "2" next state "0" actions { set local "tc" 2 } }
|
|
choice { text "second" next state "1" actions { set global "loop-done" 2 + global "loop-done" } }
|
|
}
|
|
state "1" {
|
|
choice { text "0" next state "2" enabled local "ready" != 0 }
|
|
choice { text "1" next state "1" actions { set local "ready" 8 } }
|
|
}
|
|
state "2" {
|
|
choice { text "0" next state ""}
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_scripts(include_blob = True)
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# it should not be available yet
|
|
res = daemon.cc_get_scripts(first_script = script_id, last_script = script_id, account = account2_id)
|
|
assert len(res.scripts) == 1
|
|
assert not res.scripts[0].available
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_start_script(script_id, city = 0))
|
|
|
|
res = self.wallet[3].cc_set_script_variable('allow', 0, 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# it should now be available
|
|
res = daemon.cc_get_scripts(first_script = script_id, last_script = script_id, account = account2_id)
|
|
assert len(res.scripts) == 1
|
|
assert res.scripts[0].available
|
|
|
|
# can't start if disabled
|
|
self.wallet[3].cc_enable_script(script_id, False)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
self.assert_exception(lambda: self.wallet[2].cc_start_script(script_id, city = 0))
|
|
|
|
self.wallet[3].cc_enable_script(script_id, True)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' in res
|
|
assert res.script == script_id
|
|
assert res.script_state == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
|
|
for i in [ 0, 1, 0, 2, 2, 1, 2, 2, 1, 0, 1, 0, 1, 1, 1, 2, 1, 0, 2, 1, 3]:
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = i)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' in res
|
|
assert res.script == script_id
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
if i == 3:
|
|
assert res.script_state == 1
|
|
assert len(res.script_local_variables) == 1
|
|
assert res.script_local_variables[0] == { 'name': 'tc', 'value': 1} # last before we changed state
|
|
else:
|
|
assert res.script_state == 0
|
|
if i == 0:
|
|
assert 'script_local_variables' not in res
|
|
else:
|
|
assert len(res.script_local_variables) == 1
|
|
assert res.script_local_variables[0] == { 'name': 'tc', 'value': i}
|
|
|
|
res = daemon.cc_get_script_variable('loop-done')
|
|
assert res.value == 2
|
|
res = daemon.cc_get_account(account2_id)
|
|
x = [x for x in res.script_variables if x.name == 'x'][0]
|
|
assert x.name == 'x'
|
|
assert x.value == 9
|
|
|
|
# we're in the second state now, we can't choose choice 0 until we chose choice 1
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(script_id, state = 1, city = 0, owner = GAME_ACCOUNT, choice = 0))
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 1, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 1, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script_state == 2
|
|
|
|
def check_gold_consistency(self):
|
|
daemon = self.daemon
|
|
|
|
print("Checking gold consistency")
|
|
|
|
# get all txes from the DB, get the ones with commands, accumulate fees, let the total be F
|
|
# get all the deposits/withdraws, sum it all, let the total be D
|
|
# sum up balances + coins and custom items of all accounts, let the total be B
|
|
# sum up all game subsity, let the total be S
|
|
# then D + S = B + F
|
|
|
|
game_fees = 0
|
|
game_txes = 0
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = daemon.get_block_headers_range(0, height - 1, False)
|
|
headers = res.headers
|
|
for h in headers:
|
|
if h.num_txes > 0:
|
|
res = daemon.get_block(hash = h.hash, fill_pow_hash = False, include_blob = False, include_json = False)
|
|
res = daemon.get_transactions(res.tx_hashes, decode_as_json = False, prune = True, get_cc_data = True)
|
|
for tx in res.txs:
|
|
game_txes += 1
|
|
game_fees += tx.cc_fee
|
|
|
|
gold_balance_available = 0
|
|
gold_balance_reserved = 0
|
|
gold_balance_in_coins = 0
|
|
gold_balance_in_custom_items = 0
|
|
for i in range(1, 16):
|
|
try:
|
|
res = daemon.cc_get_account(i)
|
|
gold_balance_available += res.balance
|
|
if 'reserve' in res:
|
|
for e in res.reserve:
|
|
gold_balance_reserved += e['balance']
|
|
for e in res.item_balances:
|
|
if e['type'] >= ITEM_FIRST_USER and e['type'] <= ITEM_LAST_USER:
|
|
res2 = daemon.cc_get_custom_items([e['type']])
|
|
assert len(res2.items_) == 1
|
|
if res2.items_[0].group == COINS_ITEM_GROUP and not res2.items_[0].is_group:
|
|
gold_content = get_gold_content(COIN_TYPE(res2.items_[0].user_data))
|
|
gold_balance_in_coins += e['amount'] * gold_content * 100000000
|
|
else:
|
|
gold_balance_in_custom_items += e['amount'] * res2.items_[0].gold
|
|
except:
|
|
pass
|
|
|
|
game_subsidy = 0
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = daemon.get_coinbase_tx_sum(0, height)
|
|
game_subsidy = res.game_subsidy
|
|
|
|
D = self.deposits
|
|
S = game_subsidy
|
|
B = gold_balance_available + gold_balance_reserved + gold_balance_in_coins + gold_balance_in_custom_items
|
|
F = game_fees
|
|
|
|
if D + S != B + F:
|
|
print('Game fees for ' + str(game_txes) + ' txes: ' + str(game_fees / 1e8))
|
|
print('Deposit/withdraw balance: ' + str(self.deposits / 1e8))
|
|
print('Gold in available balance: ' + str(gold_balance_available / 1e8))
|
|
print('Gold in reserved balance: ' + str(gold_balance_reserved / 1e8))
|
|
print('Gold in coins balance: ' + str(gold_balance_in_coins / 1e8))
|
|
print('Gold in custom items balance: ' + str(gold_balance_in_custom_items / 1e8))
|
|
print('Game subsidy: ' + str(game_subsidy / 1e8))
|
|
|
|
print('D: ' + str(D / 1e8))
|
|
print('S: ' + str(S / 1e8))
|
|
print('B: ' + str(B / 1e8))
|
|
print('F: ' + str(F / 1e8))
|
|
print('D + S: ' + str((D + S) / 1e8))
|
|
print('B + F: ' + str((B + F) / 1e8))
|
|
|
|
assert D + S == B + F
|
|
|
|
def check_event_balances(self):
|
|
daemon = self.daemon
|
|
|
|
print("Checking event balances")
|
|
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
|
|
for i in [0, 1, 2, 3, 4]:
|
|
try:
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
balance = res.balance
|
|
if 'reserve' in res:
|
|
for e in res.reserve:
|
|
balance += e.balance
|
|
except:
|
|
continue
|
|
res = daemon.cc_get_game_events(min_height = 0, max_height = height, account = account_id)
|
|
event_balance = 0
|
|
for e in res.events:
|
|
event_balance += e.balance
|
|
event_balance -= e.tx_fee
|
|
if balance != event_balance:
|
|
print('Event balance does not match actual balance for account ' + str(account_id) + ' (wallet ' + str(i) + ')')
|
|
print('balance: ' + str(balance))
|
|
print('event_balance: ' + str(event_balance))
|
|
assert balance == event_balance
|
|
|
|
def check_item_count_consistency(self):
|
|
daemon = self.daemon
|
|
|
|
print("Checking item count consistency")
|
|
|
|
item_balances = []
|
|
for account_id in range(256):
|
|
try:
|
|
res = daemon.cc_get_account(account_id)
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
item_balances = self.add_item(item_balances, e['type'], e['amount'])
|
|
except:
|
|
pass
|
|
|
|
item_count = []
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
if 'counts' in res:
|
|
for idx in range(len(res.counts)):
|
|
if res.counts[idx] > 0:
|
|
item_count = self.add_item(item_count, idx, res.counts[idx])
|
|
res = daemon.cc_get_custom_items()
|
|
items = res.items_ if 'items_' in res else []
|
|
res = daemon.cc_get_item_count([x + ITEM_FIRST_USER for x in range(256)])
|
|
if 'counts' in res:
|
|
for idx in range(len(res.counts)):
|
|
if res.counts[idx] > 0:
|
|
is_group = False
|
|
for e in items:
|
|
if e.id == idx + ITEM_FIRST_USER:
|
|
is_group = e.is_group
|
|
break
|
|
if not is_group:
|
|
item_count = self.add_item(item_count, idx + ITEM_FIRST_USER, res.counts[idx])
|
|
|
|
item_supply = []
|
|
for item in itertools.chain(range(280), range(ITEM_FIRST_FOOD, ITEM_FIRST_FOOD + 32), range(ITEM_FIRST_PATENT, ITEM_FIRST_PATENT + 256), range(ITEM_FIRST_GEMSTONE, ITEM_FIRST_GEMSTONE + 16), [x + ITEM_FIRST_USER for x in range(256)]):
|
|
res = daemon.cc_get_item_ownership(item)
|
|
if 'ownership' in res:
|
|
total = 0
|
|
for e in res.ownership:
|
|
assert e.amount > 0
|
|
total += e.amount
|
|
assert total == res.supply
|
|
item_supply = self.add_item(item_supply, item, total)
|
|
|
|
assert item_balances == item_count, "item_balances: expected " + str(item_balances) + ", got " + str(item_count) + ", supply " + str(item_supply)
|
|
assert item_supply == item_count, "item_supply: expected " + str(item_supply) + ", got " + str(item_count) + ", balances " + str(item_balances)
|
|
|
|
def test_reorg(self):
|
|
daemon = self.daemon
|
|
second_daemon = Daemon(idx = 3)
|
|
third_daemon = Daemon(idx = 4)
|
|
|
|
print('Testing reorg')
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
state0 = self.get_state()
|
|
|
|
assert len(self.reorg_root_hash) == 64
|
|
res = daemon.get_info()
|
|
assert len(res.top_block_hash) == 64
|
|
assert res.top_block_hash != self.reorg_root_hash
|
|
original_top_block = res.top_block_hash
|
|
res = daemon.getblockheaderbyheight(self.reorg_root_height + 1)
|
|
first_orphaned_block_hash = res.block_header.hash
|
|
assert len(first_orphaned_block_hash) == 64
|
|
assert not res.block_header.orphan_status
|
|
assert res.block_header.height == self.reorg_root_height + 1
|
|
|
|
# ensure synced
|
|
print('Syncing second and third daemons')
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
third_daemon.out_peers(8)
|
|
third_daemon.in_peers(8)
|
|
loops = 100
|
|
while True:
|
|
res0 = daemon.get_info()
|
|
res1 = second_daemon.get_info()
|
|
res2 = third_daemon.get_info()
|
|
if res0.top_block_hash == res1.top_block_hash and res0.top_block_hash == res2.top_block_hash:
|
|
break
|
|
time.sleep(30)
|
|
loops -= 1
|
|
assert loops >= 0
|
|
|
|
res = daemon.get_info()
|
|
cumulative_difficulty = res.cumulative_difficulty
|
|
|
|
# disconnect third daemon so it keeps the original chain
|
|
third_daemon.out_peers(0)
|
|
third_daemon.in_peers(0)
|
|
|
|
# mine
|
|
print('Mining on second daemon')
|
|
n_mined = 0
|
|
while True:
|
|
n_mined += 100
|
|
res = second_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 1)
|
|
res = second_daemon.get_info()
|
|
if res.cumulative_difficulty > cumulative_difficulty:
|
|
break
|
|
print('Mined %u blocks for a reorg' % n_mined)
|
|
|
|
# reconnect daemons 1 and 2
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
|
|
# wait while the reorg happens
|
|
print('Waiting for reorg on first daemon')
|
|
while True:
|
|
res = daemon.get_info()
|
|
if res.cumulative_difficulty > cumulative_difficulty:
|
|
break
|
|
time.sleep(10)
|
|
|
|
# disconnect daemons again
|
|
daemon.out_peers(0)
|
|
daemon.in_peers(0)
|
|
second_daemon.out_peers(0)
|
|
second_daemon.in_peers(0)
|
|
|
|
# mine on the third daemon, which still has the original chain
|
|
res = third_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', n_mined + 1)
|
|
res = third_daemon.get_info()
|
|
cumulative_difficulty = res.cumulative_difficulty
|
|
|
|
# reconnect all daemons
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
third_daemon.out_peers(8)
|
|
third_daemon.in_peers(8)
|
|
|
|
# wait while the reorg happens
|
|
print('Waiting for reorg on first daemon')
|
|
while True:
|
|
res = daemon.get_info()
|
|
if res.cumulative_difficulty == cumulative_difficulty:
|
|
break
|
|
time.sleep(10)
|
|
|
|
print('Back on the original chain')
|
|
|
|
# disconnect all daemons
|
|
daemon.out_peers(0)
|
|
daemon.in_peers(0)
|
|
second_daemon.out_peers(0)
|
|
second_daemon.in_peers(0)
|
|
third_daemon.out_peers(0)
|
|
third_daemon.in_peers(0)
|
|
|
|
state1 = self.get_state()
|
|
|
|
state0_clean = self.remove_crop_temperature(self.remove_height(state0))
|
|
state1_clean = self.remove_crop_temperature(self.remove_height(state1))
|
|
assert state0_clean == state1_clean, self.get_diff(state0_clean, state1_clean)
|
|
|
|
class Guard:
|
|
def __enter__(self):
|
|
for i in [2, 3, 4]:
|
|
Daemon(idx = i).out_peers(0)
|
|
Daemon(idx = i).in_peers(0)
|
|
for i in [0, 1, 2, 3, 4]:
|
|
Wallet(idx = i).auto_refresh(False)
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
for i in [2, 3, 4]:
|
|
Daemon(idx = i).out_peers(8)
|
|
Daemon(idx = i).in_peers(8)
|
|
for i in [0, 1, 2, 3, 4]:
|
|
Wallet(idx = i).set_daemon('127.0.0.1:18180')
|
|
Wallet(idx = i).auto_refresh(True)
|
|
|
|
if __name__ == '__main__':
|
|
with Guard() as guard:
|
|
CCTest().run_test()
|