forked from townforge/townforge
8526 lines
412 KiB
Python
Executable File
8526 lines
412 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_GRANITE = ITEM_MEDIUM_STONE
|
|
ITEM_WOOD = 4
|
|
ITEM_OAK = 5
|
|
ITEM_VEGETATION = 7
|
|
ITEM_RUNESTONE = 8
|
|
MATERIAL_PLACEHOLDER = 1
|
|
MATERIAL_VARIANT_PLOUGHED_FIELD = 33
|
|
MATERIAL_LOCKED_PINE = 27
|
|
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_FOOD_SALTED_MEAT = ITEM_FIRST_FOOD + 3
|
|
ITEM_FOOD_FISH = ITEM_FIRST_FOOD + 4
|
|
ITEM_FOOD_SALTED_FISH = ITEM_FIRST_FOOD + 5
|
|
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_MILITARY = 8
|
|
ROLE_SAWMILL = 11
|
|
ROLE_STONECUTTER = 10
|
|
ROLE_WORKFORCE = 14
|
|
ROLE_FISHERY = 17
|
|
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
|
|
GRANITE_LAST_RESORT_PRICE = 2000000
|
|
RUNESTONE_LAST_RESORT_PRICE = 25000000
|
|
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
|
|
RESTRICTED_ITEM_GROUP = ITEM_FIRST_USER + 2
|
|
COIN_ITEM_SETTLEMENT = ITEM_FIRST_USER + 3
|
|
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
|
|
collectible_coin_type_newbie = 5
|
|
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 = 10000000
|
|
MIN_AUCTION_BASE_TICKS = 8
|
|
MAX_AUCTION_BASE_TICKS = 56
|
|
BADGE_COSMOPOLITAN = 49
|
|
CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE = 20
|
|
SPECIAL_EVENT_NONE = 0
|
|
SPECIAL_EVENT_FIRE = 14
|
|
SPECIAL_EVENT_MOOSE_DISEASE = 19
|
|
FIREFIGHTING_COVERAGE_PERCENT = 350
|
|
HUNT_LABOUR_COST = 6500
|
|
COIN_ITEM_FIRST_NEWBIE_VARIANT = ITEM_FIRST_USER + 5
|
|
NUM_NEWBIE_COINS = 6
|
|
MIN_FISHING_TICKS = 2
|
|
MAX_FISHING_TICKS = 8
|
|
FISHING_DISTANCE_CLOSE = 0
|
|
FISHING_DISTANCE_MEDIUM = 1
|
|
FISHING_DISTANCE_FAR = 2
|
|
NUM_STARTING_CLOSE_FISH = 100000
|
|
NUM_STARTING_MEDIUM_FISH = 200000
|
|
NUM_STARTING_FAR_FISH = 400000
|
|
DIFFICULTY_TARGET_V2 = 30
|
|
BLOCKS_PER_GAME_YEAR = (7 * 86400 // DIFFICULTY_TARGET_V2)
|
|
MAX_WHISPER_LIFETIME = ((BLOCKS_PER_GAME_YEAR) * 25)
|
|
MAX_WHISPER_MESSAGE_LENGTH = 256
|
|
NEW_USER_TEXTURE_FEE = 500000000
|
|
USER_TEXTURE_LICENCE_FEE = 50000000
|
|
MAX_USER_TEXTURE_TILES = 16
|
|
CITY_SPECIALIZATION_TAX_BREAK_ZONE = 23
|
|
SPECIAL_EVENT_MERCHANT_SHIP = 20
|
|
FIRST_CITY_TREASURY = 4
|
|
MAX_MERCHANT_SHIP_OFFERS = 8
|
|
|
|
def COIN_TYPE(x):
|
|
return x[0] >> 56
|
|
|
|
def get_gold_content(coin_type):
|
|
if coin_type == collectible_coin_type_players:
|
|
return 3500000000
|
|
if coin_type == collectible_coin_type_city:
|
|
return 2000000000
|
|
if coin_type == collectible_coin_type_yearly:
|
|
return 1000000000
|
|
if coin_type == collectible_coin_type_event:
|
|
return 5000000000
|
|
if coin_type == collectible_coin_type_newbie:
|
|
return 1000000
|
|
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_build()
|
|
self.test_firewood()
|
|
self.test_fisheries()
|
|
self.test_whispers()
|
|
self.test_name_place()
|
|
self.test_edit_player_profile()
|
|
self.test_user_textures()
|
|
self.check_gold_consistency()
|
|
self.check_item_count_consistency()
|
|
self.check_event_balances()
|
|
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_runestones()
|
|
self.test_custom_items()
|
|
self.check_gold_consistency()
|
|
self.check_item_count_consistency()
|
|
self.test_script_variables()
|
|
self.test_scripts()
|
|
self.test_background_scripts()
|
|
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.check_gold_consistency()
|
|
self.test_minting()
|
|
self.check_gold_consistency()
|
|
self.test_farming()
|
|
self.check_item_count_consistency()
|
|
self.test_derelict()
|
|
self.test_cities()
|
|
self.test_merchant_ships()
|
|
self.test_fire()
|
|
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, game_account_key = ""):
|
|
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, game_account_key = game_account_key)
|
|
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',
|
|
'foyer mittens gaze vocal dwindling unnoticed pimple foolish sword stacking unveil fuming husband bodies exit mugged omnibus jump whale sanity loincloth menu bite cactus vocal',
|
|
'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
|
|
if i == 3: # we're restoring the game account, which is pre-created
|
|
ok = not ok
|
|
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', 500], # wallet[1]
|
|
['TF1MMBerc1QPyAGKFnREmBkQZ8Ujg6ZVkdJNseCoHebyXpF4adjr8r8PfcbRrDP2LhcJ7KLZV5Efgxb7MiXwFsxw6h8eUxa8s7b', 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_perishables(self, item_balances):
|
|
item_balances = self.remove_item(item_balances, ITEM_WOOD)
|
|
item_balances = self.remove_item(item_balances, ITEM_FIREWOOD)
|
|
item_balances = self.remove_item(item_balances, ITEM_FOOD_VEGETABLES)
|
|
item_balances = self.remove_item(item_balances, ITEM_FOOD_GRAIN)
|
|
item_balances = self.remove_item(item_balances, ITEM_FOOD_MEAT)
|
|
item_balances = self.remove_item(item_balances, ITEM_FOOD_SALTED_MEAT)
|
|
item_balances = self.remove_item(item_balances, ITEM_FOOD_FISH)
|
|
item_balances = self.remove_item(item_balances, ITEM_FOOD_SALTED_FISH)
|
|
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 'item_balances' in res
|
|
assert len(res.item_balances) == 1
|
|
item_type = res.item_balances[0]['type']
|
|
assert item_type >= ITEM_FIRST_USER and item_type <= ITEM_LAST_USER # the newbie coin
|
|
item_balances = res.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:event:0')
|
|
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}]))
|
|
|
|
# can't build using placeholder
|
|
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_PLACEHOLDER}]))
|
|
|
|
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:event:0', new_name = 'good name')
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'good name', new_name = 'test:event:0')
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
print("Testing upgrading building")
|
|
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 6268}, {'type': ITEM_STONE, 'amount': 2611}, {'type': ITEM_LABOUR, 'amount': 101924}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
self.assert_exception(lambda self: self.wallet[2].cc_upgrade_building(flag_id, 0))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_upgrade_building(flag_id, -10))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_upgrade_building(flag_id, 310))
|
|
self.assert_exception(lambda self: self.wallet[2].cc_upgrade_building(flag_id, 110))
|
|
self.wallet[2].cc_upgrade_building(flag_id, 30)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.economic_power == 130
|
|
|
|
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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance + 1, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city + 1, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks + 1, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish + 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, budget = res.budget, tiles = tiles + [1]))
|
|
|
|
def test_name_place(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing naming places")
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flag = res.flags[0]
|
|
|
|
ox = FIRST_CITY_X
|
|
oy = FIRST_CITY_Y
|
|
|
|
# bad city
|
|
self.assert_exception(lambda: self.wallet[2].cc_name_place(1, flag, ox + 1200, oy + 1000, ox + 3800, oy + 4000, "This place"))
|
|
|
|
# bad flag
|
|
self.assert_exception(lambda: self.wallet[2].cc_name_place(0, 17857, ox + 1200, oy + 1000, ox + 3800, oy + 4000, "This place"))
|
|
|
|
# negative width
|
|
self.assert_exception(lambda: self.wallet[2].cc_name_place(0, flag, ox + 1200, oy + 1000, ox + 1000, oy + 4000, "This place"))
|
|
|
|
# negative height
|
|
self.assert_exception(lambda: self.wallet[2].cc_name_place(0, flag, ox + 1200, oy + 1000, ox + 3800, oy + 400, "This place"))
|
|
|
|
# too close to edge
|
|
self.assert_exception(lambda: self.wallet[2].cc_name_place(0, flag, 1200, 1000, 3800, 4000, "This place"))
|
|
|
|
# too far from building
|
|
self.assert_exception(lambda: self.wallet[2].cc_name_place(0, flag, ox + 11200, oy + 1000, ox + 13800, oy + 4000, "This place"))
|
|
|
|
# good
|
|
self.wallet[2].cc_name_place(0, flag, ox + 1200, oy + 1000, ox + 3800, oy + 4000, "This place")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_places(1)
|
|
assert 'places' not in res or len(res.places) == 0
|
|
res = daemon.cc_get_places(0)
|
|
assert len(res.places) == 1
|
|
p = res.places[0]
|
|
assert p.x0 == ox + 1200
|
|
assert p.y0 == oy + 1000
|
|
assert p.x1 == ox + 3800
|
|
assert p.y1 == oy + 4000
|
|
assert p.name == "This place"
|
|
|
|
def test_edit_player_profile(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing editing player profile")
|
|
|
|
account_id = [None, None, None]
|
|
profile = [None, None, None]
|
|
for i in [1, 2]:
|
|
res = self.wallet[i].cc_get_info()
|
|
account_id[i] = res.account_id
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.description == ""
|
|
|
|
# 1 does not have the level, 2 does
|
|
self.assert_exception(lambda: self.wallet[1].cc_edit_player_profile("", "new"))
|
|
|
|
self.wallet[2].cc_edit_player_profile("", "new")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.description == "new"
|
|
|
|
self.assert_exception(lambda: self.wallet[1].cc_edit_player_profile("", "newer"))
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.description == "new"
|
|
|
|
self.wallet[2].cc_edit_player_profile("new", "newer")
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account_id[2])
|
|
assert res.description == "newer"
|
|
|
|
res = daemon.cc_get_account(account_id[1])
|
|
assert res.description == ""
|
|
|
|
def test_user_textures(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing user textures")
|
|
|
|
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_user_textures(ITEM_WOOD, False)
|
|
assert 'textures' not in res or len(res.textures) == 0
|
|
|
|
dxt1 = "444453207c00000007100800000200000002000000000200000000000100000047494d502d4444535a090300000000000000000000000000000000000000000000000000000000000000000020000000040000004458543100000000000000000000000000000000000000000010000000000000000000000000000000000000" + "00000000aaaaaaaa" * 16384
|
|
dxt1_512_1024 = "444453207c00000007100800000400000002000000000400000000000100000047494d502d4444535a090300000000000000000000000000000000000000000000000000000000000000000020000000040000004458543100000000000000000000000000000000000000000010000000000000000000000000000000000000" + "00000000aaaaaaaa" * 32768
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(0, dxt1, "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_LABOUR, dxt1, "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_FIRST_USER, dxt1, "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1 + "x", "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1[:-1], "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, "", "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1_512_1024, "All black", 5, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1, "All black", 0, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1, "All black", MAX_USER_TEXTURE_TILES + 1, 9))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1, "All black", 5, 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1, "All black", 5, MAX_USER_TEXTURE_TILES + 1))
|
|
|
|
res = self.wallet[2].cc_new_texture(ITEM_WOOD, dxt1, "All black", 5, 9)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_USER_TEXTURE_FEE
|
|
nonce = res.cc_nonce
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_user_texture(1)
|
|
assert res.block == ITEM_WOOD
|
|
assert res.creator == account_id[2]
|
|
assert res.width == 512
|
|
assert res.height == 512
|
|
assert res.description == "All black"
|
|
assert res.hscale == 5
|
|
assert res.vscale == 9
|
|
assert res.data == dxt1
|
|
|
|
res = daemon.cc_get_user_texture_from_nonce(nonce)
|
|
assert res.texture == 1
|
|
|
|
res = daemon.cc_get_user_textures(ITEM_STONE, True)
|
|
assert 'textures' not in res or len(res.textures) == 0
|
|
res = daemon.cc_get_user_textures(ITEM_WOOD, True)
|
|
assert len(res.textures) == 1
|
|
t = res.textures[0]
|
|
assert t.texture == 1
|
|
assert t.nonce == nonce
|
|
assert t.block == ITEM_WOOD
|
|
assert t.creator == account_id[2]
|
|
assert t.width == 512
|
|
assert t.height == 512
|
|
assert t.description == "All black"
|
|
assert t.hscale == 5
|
|
assert t.vscale == 9
|
|
assert t.data == dxt1
|
|
|
|
self.assert_exception(lambda: daemon.cc_get_user_texture_from_nonce(nonce + 1))
|
|
self.assert_exception(lambda: daemon.cc_get_user_texture_from_nonce(1))
|
|
self.assert_exception(lambda: daemon.cc_get_user_texture_from_nonce(0))
|
|
self.assert_exception(lambda: daemon.cc_get_user_texture(0))
|
|
self.assert_exception(lambda: daemon.cc_get_user_texture(2))
|
|
self.assert_exception(lambda: daemon.cc_get_user_texture(nonce))
|
|
|
|
# wallet 2 can use it on a building
|
|
res = daemon.cc_get_account(account_id[2])
|
|
flags = res.flags
|
|
flag_id = None
|
|
for f_id in flags:
|
|
res = daemon.cc_get_flag(f_id)
|
|
if res.role != ROLE_EMPTY:
|
|
flag_id = f_id
|
|
break
|
|
assert flag_id
|
|
|
|
self.assert_exception(lambda: self.wallet[2].cc_build(flag_id, 6, 6, 1, 1, block_data = [10], encoded = False, palette = [{'index': 10, 'variant_delta': 32768 + 0 - 65536}]))
|
|
self.assert_exception(lambda: self.wallet[2].cc_build(flag_id, 6, 6, 1, 1, block_data = [10], encoded = False, palette = [{'index': 10, 'variant_delta': 32768 + 2 - 65536}]))
|
|
res = self.wallet[2].cc_build(flag_id, 5, 5, 1, 1, block_data = [10], encoded = False, palette = [{'index': 10, 'variant_delta': 32768 + 1 - 65536}])
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# get wallet some levels to be able to create a texture
|
|
res = self.wallet[1].cc_deposit(amount = 150000000000)
|
|
self.deposits += 150000000000
|
|
expected_balances[1] += 150000000000
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
items = res.items_
|
|
coins_minted = []
|
|
for cid in items:
|
|
if cid.is_group:
|
|
continue
|
|
if cid.group != COINS_ITEM_GROUP:
|
|
continue
|
|
if cid.id >= COIN_ITEM_FIRST_NEWBIE_VARIANT and cid.id < COIN_ITEM_FIRST_NEWBIE_VARIANT + NUM_NEWBIE_COINS:
|
|
continue
|
|
res = self.wallet[1].cc_mint(cid.id, 5)
|
|
gold_content = get_gold_content(COIN_TYPE(cid.user_data))
|
|
expected_balances[1] -= res.fee + 5 * (COIN_MINTING_FEE + gold_content)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], cid.id, 5)
|
|
coins_minted += [[cid.id, gold_content]]
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 100000}])
|
|
expected_balances[1] -= res.fee + 100000 * STONE_LAST_RESORT_PRICE
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, 100000)
|
|
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]
|
|
|
|
# pass an update to bump level
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# reset balances after the tick
|
|
for i in range(3):
|
|
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)
|
|
|
|
# have wallet 1 create a texture too
|
|
res = self.wallet[1].cc_new_texture(ITEM_WOOD, dxt1, "All black", 5, 5)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] -= NEW_USER_TEXTURE_FEE
|
|
nonce2 = res.cc_nonce
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# but cannot create another, not high enough level
|
|
self.assert_exception(lambda: self.wallet[1].cc_new_texture(ITEM_WOOD, dxt1, "All black", 5, 5))
|
|
|
|
# wallet 2 cannot use it
|
|
self.assert_exception(lambda: self.wallet[2].cc_build(flag_id, 6, 6, 1, 1, block_data = [11], encoded = False, palette = [{'index': 11, 'variant_delta': 32768 + 2 - 65536}]))
|
|
|
|
# but if it licences it
|
|
res = self.wallet[2].cc_licence_texture(2)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[1] += USER_TEXTURE_LICENCE_FEE
|
|
expected_balances[2] -= USER_TEXTURE_LICENCE_FEE
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# it can
|
|
res = self.wallet[2].cc_build(flag_id, 6, 6, 1, 1, block_data = [11], encoded = False, palette = [{'index': 11, 'variant_delta': 32768 + 2 - 65536}])
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# get rid of the temporary stone and coins
|
|
res = self.wallet[1].cc_destroy_items(ITEM_STONE, 100000)
|
|
expected_balances[1] -= res.fee
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, -100000)
|
|
for e in coins_minted:
|
|
coin_id = e[0]
|
|
gold_content = e[1]
|
|
res = self.wallet[1].cc_smelt(coin_id, 5)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] += 5 * (gold_content - COIN_SMELTING_FEE)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], coin_id, -5)
|
|
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]
|
|
|
|
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.fishing_distance, res.fishing_city, res.num_fishing_ticks, res.fish, 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.fishing_distance, res.fishing_city, res.num_fishing_ticks, res.fish, 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_perishables(res.item_balances if 'item_balances' in res else [])) == self.remove_perishables(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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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_perishables(res.item_balances if 'item_balances' in res else [])) == self.remove_perishables(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_perishables(res.item_balances if 'item_balances' in res else [])) == self.remove_perishables(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_perishables(res.item_balances if 'item_balances' in res else [])) == self.remove_perishables(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_perishables(res.item_balances if 'item_balances' in res else [])) == self.remove_perishables(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_perishables(res.item_balances if 'item_balances' in res else [])) == self.remove_perishables(expected_item_balances[i])
|
|
|
|
print('Testing maturing mortage auctions')
|
|
|
|
# create new flag
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 8192}, {'type': ITEM_WOOD, 'amount': 25000}, {'type': ITEM_LABOUR, 'amount': 250000}])
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 1200, FIRST_CITY_Y - 400, FIRST_CITY_X - 1200 + 64 - 1, FIRST_CITY_Y - 400 + 64 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 1200, FIRST_CITY_Y - 400, FIRST_CITY_X - 1200 + 64 - 1, FIRST_CITY_Y - 400 + 64 - 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id[2])
|
|
flag_id = res.flags[-1]
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(flag_id, ROLE_RESIDENTIAL1, 100, construction_height)
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# mortgage it
|
|
res = daemon.get_height()
|
|
height = res.height
|
|
res = self.wallet[2].cc_create_mortgage(flag_id, "test mortgage auction", "test", ITEM_LABOUR, 2, 10, 0, 2, 3)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id[2])
|
|
item_id = res.item_balances[-1]['type']
|
|
res = daemon.cc_get_custom_items([item_id])
|
|
assert 'items_' in res and len(res.items_) == 1
|
|
assert res.items_[0].id == item_id
|
|
assert res.items_[0].name == "test mortgage auction"
|
|
assert not res.items_[0].is_group
|
|
assert res.items_[0].group == MORTGAGE_ITEM_GROUP
|
|
assert res.items_[0].creator == account_id[2]
|
|
assert res.items_[0].amount == 3
|
|
|
|
# auction mortgage in three lots
|
|
auction_id = [0, 0, 0]
|
|
for i in range(3):
|
|
res = self.wallet[2].cc_create_auction(AUCTION_TYPE_ITEM, [{'object': item_id, 'amount': 1}], MIN_AUCTION_BASE_TICKS)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_auctions()
|
|
auction_id[i] = res.auctions[-1].id
|
|
|
|
# bid on one, have another bid on another, and leave the last one alone
|
|
res = self.wallet[2].cc_transfer(self.pkeys[1], amount = AUCTION_BID_FEE + 500)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
self.wallet[2].refresh()
|
|
self.wallet[2].cc_auction_bid(auction_id[2], 500)
|
|
self.wallet[1].refresh()
|
|
self.wallet[1].cc_auction_bid(auction_id[1], 500)
|
|
|
|
# wait till the end of the auctions
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
blocks = (MIN_AUCTION_BASE_TICKS + 2) * GAME_UPDATE_FREQUENCY + GAME_UPDATE_FREQUENCY
|
|
while blocks > 0:
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
blocks -= GAME_UPDATE_FREQUENCY
|
|
|
|
# they should all be over, including the one that did not get any bid, since the item is gone
|
|
res = daemon.cc_get_auctions()
|
|
auction_found = [False, False, False]
|
|
if 'auctions' in res:
|
|
for e in res.auctions:
|
|
for i in range(3):
|
|
if e.id == auction_id[i]:
|
|
print('found auction: ' + str(e))
|
|
assert not auction_found[i]
|
|
auction_found[i] = True
|
|
assert not auction_found[0]
|
|
assert not auction_found[1]
|
|
assert not auction_found[2]
|
|
|
|
# there should be no item left, and inventories/reserves should not have any either
|
|
res = daemon.cc_get_custom_items([item_id])
|
|
assert len(res.items_) == 1
|
|
assert res.items_[0].amount == 0
|
|
|
|
res = daemon.cc_get_item_count([item_id])
|
|
assert len(res.counts) == 1
|
|
assert res.counts[0] == 0
|
|
|
|
res = daemon.cc_get_item_ownership(item_id)
|
|
assert 'ownership' not in res or len(res.ownership) == 0
|
|
|
|
for i in range(len(account_id)):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
for e in res.item_balances:
|
|
assert e.type != item_id
|
|
if 'reserves' in res:
|
|
for f in res.reserves:
|
|
if 'items_' in f:
|
|
for e in f.items_:
|
|
assert e.type != item_id
|
|
|
|
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
|
|
trade = res.bids[1]
|
|
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]
|
|
|
|
# pop the block, we should get back to the same state
|
|
daemon.pop_blocks(1)
|
|
|
|
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
|
|
trade = res.bids[1]
|
|
assert not trade.mined # not matched, stays in the txpool
|
|
|
|
# mine a block again
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# 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 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
|
|
|
|
daemon.flush_txpool()
|
|
|
|
# current orders
|
|
# 1 sells 1 at 85
|
|
# 1 buys 1 at 80
|
|
|
|
# refill so out order can be matched
|
|
res = self.wallet[1].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 5}])
|
|
expected_balances[1] -= res.fee
|
|
item_counts[ITEM_STONE] += 5
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[1] -= 5 * STONE_LAST_RESORT_PRICE
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], 1, 5)
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
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.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
|
|
|
|
# match offer_1_3_85 a second time
|
|
res = 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)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 85
|
|
expected_balances[1] += 85
|
|
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)
|
|
|
|
# current orders
|
|
# 1 buys 1 at 80
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert 'offers' not in res or len(res.offers) == 0
|
|
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
|
|
|
|
# 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
|
|
|
|
# pop 1 block, we should have the order back, plus the yet unmined new one
|
|
daemon.pop_blocks(1)
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
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) == 2
|
|
bid_1_2_80_a_index = 0 if res.bids[0].nonce == bid_1_2_80_a_nonce else 1
|
|
trade = res.bids[bid_1_2_80_a_index]
|
|
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
|
|
trade = res.bids[1 - bid_1_2_80_a_index]
|
|
assert not trade.mined
|
|
assert trade.account == account_id[2]
|
|
assert trade.amount == 1
|
|
assert trade.matchable == 1
|
|
assert trade.price == 85
|
|
|
|
# pop another (the buy_items), we should have the same order book, except one cannot be matched anymore
|
|
daemon.pop_blocks(1)
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert len(res.offers) == 1
|
|
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 == 0
|
|
assert trade.price == 85
|
|
assert len(res.bids) == 2
|
|
bid_1_2_80_a_index = 0 if res.bids[0].nonce == bid_1_2_80_a_nonce else 1
|
|
trade = res.bids[bid_1_2_80_a_index]
|
|
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
|
|
trade = res.bids[1 - bid_1_2_80_a_index]
|
|
assert not trade.mined
|
|
assert trade.account == account_id[2]
|
|
assert trade.amount == 1
|
|
assert trade.matchable == 1
|
|
assert trade.price == 85
|
|
|
|
# pop another two (the flag trades)
|
|
daemon.pop_blocks(2)
|
|
|
|
# pop another two (the item trades)
|
|
daemon.pop_blocks(2)
|
|
|
|
# then mine all these again
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 6)
|
|
|
|
# current orders
|
|
# 1 buys 1 at 80
|
|
|
|
res = daemon.cc_get_order_book(True, True)
|
|
assert 'offers' not in res or len(res.offers) == 0
|
|
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
|
|
|
|
# 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)
|
|
|
|
stone = 0
|
|
res = daemon.cc_get_account(account_id[1])
|
|
for i in range(len(res.item_balances)):
|
|
if res.item_balances[i]['type'] == ITEM_STONE:
|
|
stone = res.item_balances[i]['amount']
|
|
if stone > 0:
|
|
res = self.wallet[1].cc_destroy_items(ITEM_STONE, stone)
|
|
item_counts[ITEM_STONE] -= stone
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_STONE, -stone)
|
|
expected_balances[1] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
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
|
|
|
|
ok = False
|
|
try: self.wallet[1].cc_give(account_public_key[1], [{'type': ITEM_STONE, 'amount': 1}])
|
|
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")
|
|
|
|
account_id = [None, None, None]
|
|
account_pkey = [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])
|
|
account_pkey[i] = res.public_key
|
|
|
|
# first make sure any trade that can go in has already gone in before we start tracking balances
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 25, game_account_key = account_pkey[0])
|
|
|
|
expected_balances = [None, None, None]
|
|
expected_item_balances = [None, None, None]
|
|
for i in range(3):
|
|
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()
|
|
base_height = res.height
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
# 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, 79, 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(matches = [{'buy_nonce': nonce_1_0, 'sell_nonce': nonce_0, 'amount': 6}])
|
|
except: ok = True
|
|
assert ok
|
|
# match 0 amount
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(matches = [{'buy_nonce': nonce_1_0, 'sell_nonce': nonce_0, 'amount': 0}])
|
|
except: ok = True
|
|
assert ok
|
|
# buy/sell switched
|
|
ok = False
|
|
try: res = self.wallet[2].cc_match(matches = [{'buy_nonce': nonce_0, 'sell_nonce': nonce_1_0, 'amount': 2}])
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# match one
|
|
res = self.wallet[2].cc_match(matches = [{'buy_nonce': nonce_1_0, 'sell_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 * 79
|
|
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
|
|
expected_balances[2] += 2 * 1
|
|
|
|
# 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(matches = [{'buy_nonce': nonce_1_1, 'sell_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 * 79
|
|
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
|
|
expected_balances[2] += 2 * 1
|
|
|
|
# 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(matches = [{'buy_nonce': nonce_1, 'sell_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()
|
|
|
|
print("Testing automated trade third party matching")
|
|
|
|
res = self.wallet[0].cc_buy_items(entries = [{'type': ITEM_GRANITE, 'amount': 20}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[0] -= res.fee
|
|
expected_balances[0] -= 20 * GRANITE_LAST_RESORT_PRICE
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_GRANITE, 20)
|
|
|
|
# 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.get_height()
|
|
base_height = res.height
|
|
res = self.wallet[0].cc_trade_item(False, ITEM_GRANITE, 5, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
nonce_1 = res.cc_nonce
|
|
expected_balances[0] -= res.fee
|
|
res = self.wallet[0].cc_trade_item(False, ITEM_GRANITE, 15, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100)
|
|
nonce_2 = res.cc_nonce
|
|
expected_balances[0] -= res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_GRANITE, 20, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100, matches = [{'nonce': nonce_1, 'amount': 5}], cost = 80 * 5)
|
|
expected_balances[1] -= res.fee
|
|
res = self.wallet[1].cc_trade_item(True, ITEM_GRANITE, 10, 80, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 100, matches = [{'nonce': nonce_2, 'amount': 10}], cost = 80 * 10)
|
|
expected_balances[1] -= res.fee
|
|
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_GRANITE, -15)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_GRANITE, 15)
|
|
expected_balances[0] += 80 * 15
|
|
expected_balances[1] -= 80 * 15
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 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]
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1, game_account_key = account_pkey[0])
|
|
|
|
expected_item_balances[0] = self.add_item(expected_item_balances[0], ITEM_GRANITE, -5)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_GRANITE, 5)
|
|
expected_balances[0] += 80 * 5
|
|
expected_balances[1] -= 80 * 5
|
|
|
|
# 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]
|
|
|
|
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_nonces([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_nonces([nonce]))
|
|
|
|
res = self.wallet[0].cc_cancel_nonces([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_nonces([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_nonces([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_nonces([nonce]))
|
|
# nor ourselves
|
|
self.assert_exception(lambda: self.wallet[2].cc_cancel_nonces([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': 2949}, {'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()
|
|
|
|
# hunt so the game update has data that depends on the seed
|
|
for i in range(3):
|
|
res = daemon.cc_get_city(0)
|
|
moose = res.moose
|
|
bears = res.bears
|
|
res = self.wallet[2].cc_hunt(target = 0, city = 0)
|
|
res = self.wallet[2].cc_hunt(target = 1, city = 0)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 2)
|
|
|
|
# mine a game update, pop it, state should be unchanged
|
|
state0 = self.get_state()
|
|
|
|
# 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)
|
|
|
|
state1 = self.get_state()
|
|
|
|
# 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)
|
|
|
|
# get the last game update nonce
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = daemon.get_block_header_by_height(height - 1)
|
|
res = daemon.get_transactions([res.block_header.miner_tx_hash], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
first_nonce = res.txs[0].cc_nonce
|
|
|
|
daemon.pop_blocks(1)
|
|
state2 = self.get_state()
|
|
state0_clean = self.remove_crop_temperature(self.remove_height(state0))
|
|
state2_clean = self.remove_crop_temperature(self.remove_height(state2))
|
|
assert state0_clean == state2_clean, self.get_diff(state0_clean, state2_clean)
|
|
|
|
# should be the same after the game update again, since the random seed was not popped
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state3 = self.get_state()
|
|
|
|
# get the new game update nonce
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = daemon.get_block_header_by_height(height - 1)
|
|
res = daemon.get_transactions([res.block_header.miner_tx_hash], get_cc_data = True)
|
|
assert len(res.txs) == 1
|
|
second_nonce = res.txs[0].cc_nonce
|
|
|
|
# remove first nonce from state1 and second nonce from state3
|
|
found_nonce = False
|
|
for i in range(len(state1['used_nonces'])):
|
|
if state1['used_nonces'][i].nonce == first_nonce:
|
|
del state1['used_nonces'][i]
|
|
found_nonce = True
|
|
break
|
|
assert found_nonce
|
|
|
|
found_nonce = False
|
|
for i in range(len(state3['used_nonces'])):
|
|
if state3['used_nonces'][i].nonce == second_nonce:
|
|
del state3['used_nonces'][i]
|
|
found_nonce = True
|
|
break
|
|
assert found_nonce
|
|
|
|
state1_clean = self.remove_crop_temperature(self.remove_height(state1))
|
|
state3_clean = self.remove_crop_temperature(self.remove_height(state3))
|
|
assert state1_clean == state3_clean, self.get_diff(state1_clean, state3_clean)
|
|
|
|
# destroy all meat to avoid messing with balance comparisons
|
|
res = daemon.cc_get_account(account_id)
|
|
meat = 0
|
|
if 'item_balances' in res:
|
|
for e in res['item_balances']:
|
|
if e.type == ITEM_FOOD_MEAT:
|
|
meat += e.amount
|
|
if meat > 0:
|
|
self.wallet[2].cc_destroy_items(ITEM_FOOD_MEAT, meat)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
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 collapse_newbie_coins(self, state):
|
|
new_state = self.copy(state)
|
|
for i in new_state['accounts']:
|
|
field = 'account_' + str(i['id'])
|
|
if 'item_balances' in new_state[field]:
|
|
item_balances = []
|
|
for e in new_state[field].item_balances:
|
|
item_type = e['type']
|
|
item_amount = e['amount']
|
|
if item_type >= COIN_ITEM_FIRST_NEWBIE_VARIANT and item_type < COIN_ITEM_FIRST_NEWBIE_VARIANT + NUM_NEWBIE_COINS:
|
|
item_type = COIN_ITEM_FIRST_NEWBIE_VARIANT
|
|
item_balances = self.add_item(item_balances, item_type, item_amount)
|
|
new_state[field]['item_balances'] = item_balances
|
|
for i in range(len(new_state['custom_items'].items_)):
|
|
e = new_state['custom_items'].items_[i]
|
|
if e['id'] >= COIN_ITEM_FIRST_NEWBIE_VARIANT and e.id < COIN_ITEM_FIRST_NEWBIE_VARIANT + NUM_NEWBIE_COINS:
|
|
new_state['custom_items'].items_[i]['amount'] = 1
|
|
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.collapse_newbie_coins(self.remove_crop_temperature(self.remove_used_nonces(state1)))
|
|
state3_clean = self.collapse_newbie_coins(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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, 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(True, custom_item_id, 0, 100, False))
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[3].cc_dividend(True, custom_item_id, ITEM_STONE, 16, False))
|
|
|
|
# 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[2].cc_hunt(target = 0, city = 0), redo = False)
|
|
bears = res.bears
|
|
self.test_revert_cmd(daemon, lambda self: self.wallet[2].cc_hunt(target = 1, city = 0), 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
|
|
assert not item.can_create_more
|
|
assert item.prestige_bonus == 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 below 1000
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_item(30, "Test item 2", False, False, 0, "primary desc", "secondary desc", hash = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", gold = 1500))
|
|
|
|
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)
|
|
|
|
# can't be the same item
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + existing_items + 1, 1, False))
|
|
# invalid dividend item
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + 1919, 100, False))
|
|
# group custom item
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER, 100, False))
|
|
# no items
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + existing_items + 1, 0, False))
|
|
# too many items
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, ITEM_FIRST_USER + existing_items + 1, 111111111111, False))
|
|
# too much money
|
|
self.assert_exception(lambda: self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, 0, 1111111111111111))
|
|
|
|
# money dividend
|
|
res = self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, 0, 100 * 30, False)
|
|
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(True, ITEM_FIRST_USER + existing_items + 1, ITEM_LABOUR, 5 * 30 + 29, False)
|
|
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
|
|
|
|
# test dividend split/exclude
|
|
# supply: 30, ownership: wallet0: 3, wallet1: 2, wallet2: 25
|
|
|
|
# split 30 among unowned, we spend 30, others gain 18 and 12
|
|
res = self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, 0, 30, True)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 30
|
|
expected_balances[0] += 18
|
|
expected_balances[1] += 12
|
|
|
|
# split 30 among all, we spend 5, others gain 3 and 2
|
|
res = self.wallet[2].cc_dividend(True, ITEM_FIRST_USER + existing_items + 1, 0, 30, False)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 5
|
|
expected_balances[0] += 3
|
|
expected_balances[1] += 2
|
|
|
|
# pay 30 to unowned, we spend 150, others gain 90 and 60
|
|
res = self.wallet[2].cc_dividend(False, ITEM_FIRST_USER + existing_items + 1, 0, 30, True)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 150
|
|
expected_balances[0] += 90
|
|
expected_balances[1] += 60
|
|
|
|
# pay 30 to all, we spend 150, others gain 90 and 60
|
|
res = self.wallet[2].cc_dividend(False, ITEM_FIRST_USER + existing_items + 1, 0, 30, False)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
expected_balances[2] -= 150
|
|
expected_balances[0] += 90
|
|
expected_balances[1] += 60
|
|
|
|
# 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 or e.id == RESTRICTED_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"))
|
|
|
|
# groups must have can_create_more set
|
|
self.assert_exception(lambda: self.wallet[2].cc_new_item(0, "Group", True, False, 0, "primary desc", "secondary desc"))
|
|
|
|
res = self.wallet[2].cc_new_item(0, "Group", True, False, 0, "primary desc", "secondary desc", can_create_more = True)
|
|
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
|
|
assert e.can_create_more
|
|
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
|
|
assert not e.can_create_more
|
|
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
|
|
assert not e.can_create_more
|
|
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", can_create_more = True)
|
|
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
|
|
assert e.can_create_more
|
|
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
|
|
assert not e.can_create_more
|
|
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
|
|
assert not e.can_create_more
|
|
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", can_create_more = True)
|
|
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
|
|
assert e.can_create_more
|
|
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
|
|
assert not e.can_create_more
|
|
|
|
# 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
|
|
res = self.wallet[2].cc_update_item(ITEM_FIRST_USER + existing_items + 1, "secondary desc", "new secondary desc")
|
|
expected_balances[2] -= res.fee
|
|
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"
|
|
|
|
print('Testing creating further items')
|
|
|
|
res = daemon.cc_get_item_count([x for x in range(NUM_PREDEFINED_ITEMS)])
|
|
item_counts = res.counts
|
|
|
|
# invalid cases
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(0, 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(0, 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(ITEM_WOOD, 0))
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(ITEM_WOOD, 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(ITEM_LAST_USER, 1))
|
|
|
|
# we can't create any more of the above items
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(ITEM_FIRST_USER + existing_items, 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(ITEM_FIRST_USER + existing_items + 1, 1))
|
|
|
|
# we need to create a new item that we specifically can create more of later
|
|
res = self.wallet[1].cc_new_item(250, "My item", False, False, public_group_id, "primary desc", "secondary desc", gold = 3000, can_create_more = True)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[1] -= NEW_ITEM_FEE
|
|
expected_balances[1] -= 250 * (3000 * (1000 + CUSTOM_ITEM_GOLD_GILDING_FEE_PER_THOUSAND) // 1000)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], ITEM_FIRST_USER + existing_items + 7 + 3, 250)
|
|
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.id == ITEM_FIRST_USER + existing_items + 7 + 3
|
|
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
|
|
assert e.amount == 250
|
|
assert e.gold == 3000
|
|
assert e.can_create_more
|
|
|
|
# too much
|
|
self.assert_exception(lambda: self.wallet[1].cc_create_items(e.id, 0xffffffff - 1000 + 1))
|
|
# not enough
|
|
self.assert_exception(lambda: self.wallet[1].cc_create_items(e.id, 0))
|
|
# someone else
|
|
self.assert_exception(lambda: self.wallet[2].cc_create_items(e.id, 1))
|
|
# too much money
|
|
self.assert_exception(lambda: self.wallet[1].cc_create_items(e.id, 10000000000))
|
|
|
|
# that one will work
|
|
res = self.wallet[1].cc_create_items(e.id, 12)
|
|
expected_balances[1] -= res.fee
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], e.id, 12)
|
|
expected_balances[1] -= 12 * (e.gold * (1000 + CUSTOM_ITEM_GOLD_GILDING_FEE_PER_THOUSAND) // 1000)
|
|
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]
|
|
|
|
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 + 1)))
|
|
assert group_id == ITEM_FIRST_USER + existing_items + 2
|
|
assert public_group_id == ITEM_FIRST_USER +existing_items + 8
|
|
assert res.counts == [100, 30 - 4, 262 + 18, 1, 1, 12, 4, 8, 262 + 4, 4, 262]
|
|
|
|
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
|
|
|
|
# invalid: bad number of thresholds
|
|
def make_thresholds(n):
|
|
thresholds = []
|
|
for i in range(n):
|
|
thresholds += [{'value': i + 1, 'text': ''}]
|
|
return thresholds
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", make_thresholds(1), []))
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", make_thresholds(2), []))
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", make_thresholds(3), []))
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", make_thresholds(4), []))
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", make_thresholds(6), []))
|
|
|
|
# invalid: first threshold is 0
|
|
thresholds = make_thresholds(5)
|
|
thresholds[0]['value'] = 0
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", thresholds, []))
|
|
|
|
# invalid: thresholds do not increase
|
|
thresholds = make_thresholds(5)
|
|
thresholds[4] = thresholds[3]
|
|
self.assert_exception(lambda: self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", thresholds, []))
|
|
|
|
# valid: new event badge, no recipients
|
|
thresholds = make_thresholds(5)
|
|
self.wallet[3].cc_event_badge(0, "Badge with no recipients", "desc", "", thresholds, [])
|
|
|
|
# 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&", "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[4].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_variables([{'name': 'other', 'old_value': 1, 'new_value': 42}]))
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_script_variables([]))
|
|
|
|
res = self.wallet[3].cc_set_script_variables([{'name': 'other', 'old_value': 0, 'new_value': 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_variables([{'name': 'test', 'old_value': 0, 'new_value': 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_variables([{'name': 'test', 'old_value': 1, 'new_value': 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_variables([{'name': 'other', 'old_value': 42, 'new_value': 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_variables([{'name': 'other', 'old_value': 18, 'new_value': 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, 10)
|
|
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)
|
|
starting_moose = res.moose
|
|
starting_bears = res.bears
|
|
|
|
# bad city
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 0, city = 9)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
# bad target
|
|
ok = False
|
|
try: self.wallet[2].cc_hunt(target = 2, city = 0)
|
|
except: ok = True
|
|
assert ok
|
|
|
|
self.wallet[2].cc_hunt(target = 0, city = 0)
|
|
|
|
# can do several at a time
|
|
self.wallet[2].cc_hunt(target = 1, city = 0)
|
|
self.wallet[2].cc_hunt(target = 1, city = 0)
|
|
self.wallet[2].cc_hunt(target = 1, city = 0)
|
|
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert res.moose_killed > moose_killed
|
|
moose_killed_now = 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)
|
|
self.wallet[2].cc_hunt(target = 1, city = 0)
|
|
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_now = 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_now
|
|
new_bears = res.bears
|
|
assert new_bears == starting_bears - bears_killed_now
|
|
|
|
# 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)
|
|
if res.special_event != SPECIAL_EVENT_MOOSE_DISEASE:
|
|
assert res.moose > new_moose
|
|
assert res.bears > new_bears
|
|
|
|
res = daemon.cc_get_city(0)
|
|
old_moose = res.moose
|
|
self.wallet[2].cc_hunt(target = 0, city = 0)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(0)
|
|
new_moose = res.moose
|
|
assert new_moose < old_moose
|
|
|
|
def test_fisheries(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing fisheries")
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
|
|
# build a fishery, needs to be partway in water
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 1843}, {'type': ITEM_WOOD, 'amount': 30720 + 500}, {'type': ITEM_LABOUR, 'amount': 137624}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 1600, FIRST_CITY_Y - 3200, FIRST_CITY_X - 1600 + 128 - 1, FIRST_CITY_Y - 3200 + 48 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 1600, FIRST_CITY_Y - 3200, FIRST_CITY_X - 1600 + 128 - 1, FIRST_CITY_Y - 3200 + 48 - 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
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(flag_id, ROLE_FISHERY, 100, construction_height, name = 'fishery')
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.role == ROLE_FISHERY
|
|
assert res.num_fishing_ticks == 0
|
|
assert res.fishing_distance == FISHING_DISTANCE_CLOSE
|
|
assert res.fishing_city == 0
|
|
assert res.fish == 0
|
|
assert res.underwater_area[0] >= 128 * 48 * 40 / 100 and res.underwater_area[0] <= 128 * 48 * 60 / 100
|
|
|
|
# can't fish before the flag activates
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_CLOSE, 0, MIN_FISHING_TICKS))
|
|
|
|
# pass an update to activate the fishery
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# out of range conditions
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_CLOSE, 0, MIN_FISHING_TICKS - 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_CLOSE, 0, MAX_FISHING_TICKS + 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, -1, 0, MAX_FISHING_TICKS))
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_FAR + 1, 0, MAX_FISHING_TICKS))
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_FAR, 1, MAX_FISHING_TICKS))
|
|
|
|
# only fisheries can fish
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 1
|
|
other_flag_id = res.flags[-2]
|
|
assert other_flag_id
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(other_flag_id, FISHING_DISTANCE_CLOSE, 0, MIN_FISHING_TICKS))
|
|
|
|
expected_fish_balance = 0
|
|
res = daemon.cc_get_account(account_id)
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
if e.type == ITEM_FOOD_FISH:
|
|
expected_fish_balance += e.amount
|
|
|
|
# start fishing
|
|
res = self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_CLOSE, 0, MIN_FISHING_TICKS)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# can't do it twice
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_CLOSE, 0, MIN_FISHING_TICKS))
|
|
|
|
last_fish = 0
|
|
for i in range(MIN_FISHING_TICKS):
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.role == ROLE_FISHERY
|
|
assert res.num_fishing_ticks == MIN_FISHING_TICKS - i
|
|
if i == 0:
|
|
assert res.fish == 0
|
|
else:
|
|
assert res.fish > last_fish
|
|
last_fish = res.fish
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# after the last update, the fleet is back with the fish
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.role == ROLE_FISHERY
|
|
assert res.num_fishing_ticks == 0
|
|
assert res.fish == 0
|
|
|
|
# and the city's close fishing grounds is below full
|
|
res = daemon.cc_get_city(0)
|
|
assert res.close_fish < NUM_STARTING_CLOSE_FISH
|
|
close_fish = res.close_fish
|
|
assert res.medium_fish == NUM_STARTING_MEDIUM_FISH
|
|
|
|
# work out how much fish we got
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = daemon.cc_get_game_events(min_height = height - 1, max_height = height, account = account_id)
|
|
for e in res.events:
|
|
if "A fishing expedition came back with " in e.event and e.flags == [flag_id]:
|
|
s = e.event[36:]
|
|
idx = s.find(" fish")
|
|
s = s[:idx]
|
|
expected_fish_balance += int(s)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
current_fish_balance = 0
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
if e.type == ITEM_FOOD_FISH:
|
|
current_fish_balance += e.amount
|
|
assert expected_fish_balance == current_fish_balance
|
|
|
|
res = daemon.cc_get_far_fish_population()
|
|
assert res.fish == NUM_STARTING_FAR_FISH
|
|
|
|
# we can now start fishing again
|
|
res = self.wallet[2].cc_fish(flag_id, FISHING_DISTANCE_FAR, 0, MIN_FISHING_TICKS + 1)
|
|
tx_hash = res.tx_hash
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
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_flag(flag_id)
|
|
assert res.num_fishing_ticks >= 0
|
|
assert res.fish >= 0
|
|
|
|
# close fishing grounds have recovered a bit
|
|
res = daemon.cc_get_city(0)
|
|
assert res.close_fish > close_fish
|
|
|
|
# far fishing grounds have decreased a bit
|
|
res = daemon.cc_get_far_fish_population()
|
|
assert res.fish < NUM_STARTING_FAR_FISH
|
|
|
|
# fisheries stand in for farms for influence need
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 3072}, {'type': ITEM_WOOD, 'amount': 8192}, {'type': ITEM_LABOUR, 'amount': 57344}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 1600, FIRST_CITY_Y - 3060, FIRST_CITY_X - 1600 + 32 - 1, FIRST_CITY_Y - 3060 + 32 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 1600, FIRST_CITY_Y - 3060, FIRST_CITY_X - 1600 + 32 - 1, FIRST_CITY_Y - 3060 + 32 - 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
craft_flag_id = res.flags[-1]
|
|
assert craft_flag_id
|
|
|
|
res = daemon.cc_get_flag(craft_flag_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(craft_flag_id, ROLE_CRAFT, 100, construction_height, name = 'test craft building near fishery')
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_account(account_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
res = daemon.cc_get_flag(craft_flag_id)
|
|
assert res.role == ROLE_CRAFT
|
|
assert not res.active
|
|
|
|
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_flag(craft_flag_id)
|
|
assert res.role == ROLE_CRAFT
|
|
assert res.active
|
|
|
|
# demolish them (the fishery while fishing)
|
|
for fid in [flag_id, craft_flag_id]:
|
|
res = daemon.cc_get_flag(fid, get_packed_tiles = True)
|
|
service_price = res.service_price if 'service_price' in res else 0
|
|
tiles = res.tiles if 'tiles' in res else []
|
|
assert res.num_fishing_ticks > 0 or fid != flag_id
|
|
res = self.wallet[2].cc_demolish(fid, 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, fishing_distance = res.fishing_distance, fishing_city = res.fishing_city, num_fishing_ticks = res.num_fishing_ticks, fish = res.fish, budget = res.budget, tiles = tiles)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.role == ROLE_EMPTY
|
|
assert res.num_fishing_ticks == 0
|
|
assert res.fishing_distance == 0
|
|
assert res.fish == 0
|
|
|
|
def test_whispers(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing whispers")
|
|
|
|
res = daemon.cc_get_whispers(0)
|
|
assert 'whispers' not in res or len(res.whispers) == 0
|
|
|
|
res = daemon.cc_get_whispers(1)
|
|
assert 'whispers' not in res or len(res.whispers) == 0
|
|
|
|
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_RUNESTONE, 'amount': 10}])
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# invalid cases
|
|
self.assert_exception(lambda: self.wallet[2].cc_whisper("a" * (MAX_WHISPER_MESSAGE_LENGTH + 1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_whisper("", 0, 0, 0, 0, 0, 0, 0, 0, 0, MAX_WHISPER_LIFETIME + 1))
|
|
self.assert_exception(lambda: self.wallet[2].cc_whisper("", 1, 0, 0, 0, 0, 0, 0, 0, 0, 1))
|
|
|
|
self.wallet[2].cc_whisper("test msg", 0, 6, 7, 8, 12, 16, 100, 255, 120, 1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_whispers(0)
|
|
assert len(res.whispers) == 1
|
|
w = res.whispers[0]
|
|
assert w.message == "test msg"
|
|
assert w.city == 0
|
|
assert w.x == 6
|
|
assert w.y == 7
|
|
assert w.z == 8
|
|
assert w.rx == 12
|
|
assert w.ry == 16
|
|
assert w.red == 100
|
|
assert w.green == 255
|
|
assert w.blue == 120
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
assert w.whisperer == account_id
|
|
|
|
# pass a block
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# the whisper has timed out
|
|
res = daemon.cc_get_whispers(0)
|
|
assert 'whispers' not in res or len(res.whispers) == 0
|
|
|
|
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
|
|
|
|
# it's not used yet
|
|
res = daemon.cc_is_invitation_used(invitation)
|
|
assert not res.used
|
|
assert res.expiration == 0
|
|
assert not res.expired
|
|
assert res.balance_ok
|
|
|
|
# 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)
|
|
|
|
# it's used now
|
|
res = daemon.cc_is_invitation_used(invitation)
|
|
assert res.used
|
|
|
|
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 = daemon.get_info()
|
|
height = res.height
|
|
res = self.wallet[2].cc_create_invitation(amount = 250000000, expiration = height + 2)
|
|
expiring_invitation = res.invitation
|
|
|
|
# it's not used yet
|
|
res = daemon.cc_is_invitation_used(expiring_invitation)
|
|
assert not res.used
|
|
assert res.expiration == height + 2
|
|
assert not res.expired
|
|
assert res.balance_ok
|
|
|
|
# mine two blocks and it's expired
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 2)
|
|
res = daemon.cc_is_invitation_used(expiring_invitation)
|
|
assert not res.used
|
|
assert res.expiration == height + 2
|
|
assert res.expired
|
|
assert res.balance_ok
|
|
|
|
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 == 4
|
|
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
|
|
|
|
# there should also be preexisting newbie coins, with one instance per account
|
|
num_newbie_coins = 0
|
|
res = daemon.cc_get_custom_items([i + COIN_ITEM_FIRST_NEWBIE_VARIANT for i in range(NUM_NEWBIE_COINS)])
|
|
assert len(res.items_) == NUM_NEWBIE_COINS
|
|
for i in range(NUM_NEWBIE_COINS):
|
|
assert res.items_[i].id == i + COIN_ITEM_FIRST_NEWBIE_VARIANT
|
|
assert res.items_[i].group == COINS_ITEM_GROUP
|
|
assert not res.items_[0].is_group
|
|
num_newbie_coins += res.items_[i].amount
|
|
assert res.items_[i].creator == GAME_ACCOUNT
|
|
assert res.items_[i].creation_height == 0
|
|
assert num_newbie_coins == 4
|
|
|
|
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 * 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': 25000}, {'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)
|
|
|
|
# pass next update to activate the farm
|
|
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_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[2].cc_repair([flag_id, 25000])
|
|
|
|
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[2].cc_repair([flag_id, 25000])
|
|
|
|
# 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[2].cc_repair([{'flag': flag_id, 'delta_repair': 25000}])
|
|
|
|
# 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': 25000}])
|
|
|
|
# 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
|
|
flag_fishing_distance = res.fishing_distance
|
|
flag_fishing_city = res.fishing_city
|
|
flag_num_fishing_ticks = res.num_fishing_ticks
|
|
flag_fish = res.fish
|
|
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, fishing_distance = flag_fishing_distance, fishing_city = flag_fishing_city, num_fishing_ticks = flag_num_fishing_ticks, fish = flag_fish, 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
|
|
flag_fishing_distance = res.fishing_distance
|
|
flag_fishing_city = res.fishing_city
|
|
flag_num_fishing_ticks = res.num_fishing_ticks
|
|
flag_fish = res.fish
|
|
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, fishing_distance = flag_fishing_distance, fishing_city = flag_fishing_city, num_fishing_ticks = flag_num_fishing_ticks, fish = flag_fish, 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_fire(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing fire")
|
|
|
|
flag_id = 3
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'test:event:0', new_name = 'good name')
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
flag_mil1_x0 = FIRST_CITY_X - 270
|
|
flag_mil1_y0 = FIRST_CITY_Y - 220
|
|
flag_mil1_x1 = flag_mil1_x0 + 32 - 1
|
|
flag_mil1_y1 = flag_mil1_y0 + 32 - 1
|
|
flag_mil2_x0 = FIRST_CITY_X - 520
|
|
flag_mil2_y0 = FIRST_CITY_Y - 150
|
|
flag_mil2_x1 = flag_mil2_x0 + 128 - 1
|
|
flag_mil2_y1 = flag_mil2_y0 + 128 - 1
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flags = res.flags
|
|
flag_id = None
|
|
flag_repair = 1000000
|
|
flag_distance = 99999999
|
|
flag_name = ""
|
|
flag_city = 0
|
|
for flag in flags:
|
|
res = daemon.cc_get_flag(flag)
|
|
d1 = get_distance(res.x0, res.y0, res.x1, res.y1, flag_mil1_x0, flag_mil1_y0, flag_mil1_x1, flag_mil1_y1)
|
|
d2 = get_distance(res.x0, res.y0, res.x1, res.y1, flag_mil2_x0, flag_mil2_y0, flag_mil2_x1, flag_mil2_y1)
|
|
if res.role != ROLE_EMPTY and max(d1, d2) < flag_distance:
|
|
flag_repair = res.repair
|
|
flag_id = flag
|
|
flag_name = res.name
|
|
flag_city = res.city
|
|
flag_distance = max(d1, d2)
|
|
assert flag_id != None
|
|
assert flag_repair > 0
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 500000}, {'type': ITEM_STONE + 1, 'amount': 13000}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 75000}, {'type': ITEM_WOOD + 1, 'amount': 42000}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': 4000000}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# ensure the fire fighting buildings are active
|
|
self.wallet[2].cc_buy_items(entries = [{'type': ITEM_WOOD, 'amount': 15000}])
|
|
for i in range(3):
|
|
self.wallet[2].cc_hunt(target = 0, city = 0)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# build a military
|
|
res = self.wallet[2].cc_buy_land(flag_mil1_x0, flag_mil1_y0, flag_mil1_x1, flag_mil1_y1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
flag_mil1_id = res.flags[-1]
|
|
res = daemon.cc_get_flag(flag_mil1_id)
|
|
construction_height = res.construction_height
|
|
self.wallet[2].cc_building_settings(flag_mil1_id, ROLE_MILITARY, 100, construction_height = construction_height)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = flag_name, new_name = 'test:event:' + str(SPECIAL_EVENT_NONE))
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
|
|
# start a fire (might have to wait two ticks first if there's a current event already)
|
|
res = daemon.cc_get_city(flag_city)
|
|
if res.special_event != SPECIAL_EVENT_NONE:
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
res = daemon.cc_get_city(flag_city)
|
|
assert res.special_event == SPECIAL_EVENT_NONE, str(res.special_event)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.fire_state == 0
|
|
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'test:event:' + str(SPECIAL_EVENT_NONE), new_name = 'test:event:' + str(SPECIAL_EVENT_FIRE))
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
|
|
# pass next 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_city(flag_city)
|
|
assert res.special_event == SPECIAL_EVENT_FIRE
|
|
|
|
# get close to next update, so we build a military right before it gets activated
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY - 5)
|
|
|
|
# build a military, it'll be pretty much powerless right after building
|
|
res = self.wallet[2].cc_buy_land(flag_mil2_x0, flag_mil2_y0, flag_mil2_x1, flag_mil2_y1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account_id)
|
|
flag_mil2_id = res.flags[-1]
|
|
res = daemon.cc_get_flag(flag_mil2_id)
|
|
construction_height = res.construction_height
|
|
self.wallet[2].cc_building_settings(flag_mil2_id, ROLE_MILITARY, 120, construction_height = construction_height)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.fire_state == 1
|
|
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'test:event:' + str(SPECIAL_EVENT_FIRE), new_name = flag_name)
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 5)
|
|
|
|
# try to fight fire with the new building, it'll fail
|
|
res = daemon.cc_get_flag(flag_id)
|
|
fire_state = res.fire_state
|
|
area = (res.x1 - res.x0 + 1) * (res.y1 - res.y0 + 1)
|
|
res = daemon.cc_get_flag(flag_mil2_id)
|
|
service_price = res.service_price if 'service_price' in res else 0
|
|
last_service_height = res.last_service_height
|
|
cost = service_price * area
|
|
res = self.wallet[2].cc_fight_fire(flag_id, fire_state, flag_mil2_id, last_service_height, cost)
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.fire_state > 0 and res.fire_state < 128
|
|
|
|
# this one might work
|
|
res = daemon.cc_get_flag(flag_id)
|
|
fire_state = res.fire_state
|
|
area = (res.x1 - res.x0 + 1) * (res.y1 - res.y0 + 1)
|
|
res = daemon.cc_get_flag(flag_mil1_id)
|
|
service_price = res.service_price if 'service_price' in res else 0
|
|
last_service_height = res.last_service_height
|
|
cost = service_price * area
|
|
res = self.wallet[2].cc_fight_fire(flag_id, fire_state, flag_mil1_id, last_service_height, cost)
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.fire_state > 0
|
|
|
|
# wait till fire runs out
|
|
on_fire = True
|
|
for i in range(100):
|
|
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_city(flag_city)
|
|
if res.special_event == SPECIAL_EVENT_NONE:
|
|
on_fire = False
|
|
break
|
|
assert not on_fire
|
|
on_fire = False
|
|
res = daemon.cc_get_flags()
|
|
flags = res.flags
|
|
for flag in flags:
|
|
res = daemon.cc_get_flag(flag.id)
|
|
if res.city == flag_city and res.fire_state != 0:
|
|
on_fire = True
|
|
assert not on_fire
|
|
|
|
res = daemon.cc_get_flag(flag_id)
|
|
assert res.fire_state == 0
|
|
|
|
flag_id = 3
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'good name', new_name = 'test:event:0')
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
def test_derelict(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing derelict buildings")
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account_id = res.account_id
|
|
res = daemon.cc_get_account(account_id)
|
|
flags = res.flags
|
|
flag_id = None
|
|
flag_repair = 1000000
|
|
flag_name = ""
|
|
for flag in flags:
|
|
res = daemon.cc_get_flag(flag)
|
|
if res.role != ROLE_EMPTY and res.repair < flag_repair:
|
|
flag_repair = res.repair
|
|
flag_id = flag
|
|
flag_name = res.name
|
|
assert flag_id != None
|
|
assert flag_repair > 0
|
|
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = flag_name, new_name = 'test:decay')
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
|
|
for i in range(25):
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', GAME_UPDATE_FREQUENCY // 2)
|
|
res = daemon.cc_get_flag(flag_id)
|
|
if res.role == ROLE_EMPTY:
|
|
break
|
|
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
res = daemon.cc_get_game_events(min_height = height - GAME_UPDATE_FREQUENCY, max_height = height, account = account_id)
|
|
found = False
|
|
for e in res.events:
|
|
if "derelict" in e.event and e.flags == [flag_id]:
|
|
found = True
|
|
break
|
|
assert found
|
|
|
|
self.wallet[2].cc_rename_flag(flag_id, old_name = 'test:decay', new_name = flag_name)
|
|
self.generate_blocks('TF1MM5mG6EQkz899pz3uFDR6D2EUowvZWw75hcE6TETrodxHXSKFK6u3SRtEQzJ6epc5HD85dEgYF7xhgBtoFjMHKNFAEuGg1Lk', 1)
|
|
|
|
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.level == 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)
|
|
self.wallet[1].cc_hunt(target = 0, city = 1)
|
|
self.wallet[1].cc_hunt(target = 1, city = 1)
|
|
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_SAWMILL, ROLE_STONECUTTER, ROLE_WORKFORCE, ROLE_AGRICULTURAL, ROLE_RESIDENTIAL1][i % 6]
|
|
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.level == 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))
|
|
|
|
res = self.wallet[1].cc_add_city_specialization(1, 4)
|
|
txid = res.tx_hash
|
|
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, 10, 11, 12, 13, 14, 15]:
|
|
self.wallet[1].cc_add_city_specialization(1, s)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
except:
|
|
rejected = True
|
|
assert rejected
|
|
|
|
# pop so we can add one later for another test
|
|
daemon.pop_blocks(1)
|
|
daemon.flush_txpool()
|
|
|
|
print("Testing tax break zone")
|
|
|
|
# no specialization
|
|
self.assert_exception(lambda: self.wallet[1].cc_set_tax_break_zone(1, 8000, 3000))
|
|
|
|
# add the specialization
|
|
res = self.wallet[1].cc_add_city_specialization(1, CITY_SPECIALIZATION_TAX_BREAK_ZONE)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# other invalid cases:
|
|
|
|
# not mayor
|
|
self.assert_exception(lambda: self.wallet[2].cc_set_tax_break_zone(1, 8000, 3000))
|
|
|
|
# no change
|
|
self.assert_exception(lambda: self.wallet[1].cc_set_tax_break_zone(1, 0, 0))
|
|
|
|
# now it works
|
|
self.wallet[1].cc_set_tax_break_zone(1, 8000, 3000)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_city(1)
|
|
assert res.tax_break_dx == 8000
|
|
assert res.tax_break_dy == 3000
|
|
|
|
# it can be moved
|
|
self.wallet[1].cc_set_tax_break_zone(1, -11000, 500)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_city(1)
|
|
assert res.tax_break_dx == -3000
|
|
assert res.tax_break_dy == 3500
|
|
|
|
# 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
|
|
|
|
print("Testing settler list")
|
|
|
|
# lists start out empty
|
|
res = daemon.cc_get_city(0)
|
|
assert 'allow_settlers' not in res or len(res.allow_settlers) == 0
|
|
res = daemon.cc_get_city(1)
|
|
assert 'allow_settlers' not in res or len(res.allow_settlers) == 0
|
|
|
|
# only the mayor may modify the list
|
|
res = self.wallet[1].cc_get_info()
|
|
account_id = res.account_id
|
|
self.assert_exception(lambda: self.wallet[1].cc_allow_settlers([account_id], 1, allow = True))
|
|
|
|
# we can't remove someone who's not in the list
|
|
self.assert_exception(lambda: self.wallet[2].cc_allow_settlers([account_id], 1, allow = False))
|
|
|
|
self.wallet[2].cc_allow_settlers([account_id], 1, allow = True)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_city(1)
|
|
assert res.allow_settlers == [account_id]
|
|
|
|
# we can't add someone who's already in the list
|
|
self.assert_exception(lambda: self.wallet[2].cc_allow_settlers([account_id], 1, allow = True))
|
|
|
|
# other accounts can now not buy land in the city
|
|
res = self.daemon.cc_get_city(1)
|
|
city_ox = res.ox
|
|
city_oy = res.oy
|
|
self.assert_exception(lambda: self.wallet[2].cc_buy_land(city_ox + 1200, city_oy + 60, city_ox + 1200 + 16 - 1, city_oy + 60 + 16 - 1, city = 1))
|
|
|
|
# but the allowed one can
|
|
self.wallet[1].cc_buy_land(city_ox + 1200, city_oy + 80, city_ox + 1200 + 16 - 1, city_oy + 80 + 16 - 1, city = 1)
|
|
|
|
# we can remove from the list
|
|
self.wallet[2].cc_allow_settlers([account_id], 1, allow = False)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# other accounts can now buy land in the city again
|
|
self.wallet[1].cc_buy_land(city_ox + 1200, city_oy + 60, city_ox + 1200 + 16 - 1, city_oy + 60 + 16 - 1, city = 1)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
print('Testing fishing in a different city\'s close fishing grounds')
|
|
|
|
# build a fishery, needs to be partway in water
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_STONE, 'amount': 1843}, {'type': ITEM_WOOD, 'amount': 30720 + 1000}, {'type': ITEM_LABOUR, 'amount': 137624}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_new_flag_cost(0, FIRST_CITY_X - 150, FIRST_CITY_Y - 3300, FIRST_CITY_X - 150 + 128 - 1, FIRST_CITY_Y - 3300 + 48 - 1)
|
|
res = self.wallet[2].cc_buy_land(FIRST_CITY_X - 150, FIRST_CITY_Y - 3300, FIRST_CITY_X - 150 + 128 - 1, FIRST_CITY_Y - 3300 + 48 - 1)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account2_id = res.account_id
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'flags' in res and len(res.flags) > 0
|
|
fishery_id = res.flags[-1]
|
|
assert fishery_id
|
|
res = daemon.cc_get_flag(fishery_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_building_settings(fishery_id, ROLE_FISHERY, 100, construction_height, name = 'test fishery 2')
|
|
assert len(res.tx_hash) == 64
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
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_flag(fishery_id)
|
|
assert res.city == 0
|
|
assert res.role == ROLE_FISHERY
|
|
assert res.active
|
|
assert res.num_fishing_ticks == 0
|
|
|
|
# get current fish numbers
|
|
res = daemon.cc_get_city(1)
|
|
close_fish = res.close_fish
|
|
medium_fish = res.medium_fish
|
|
res = daemon.cc_get_far_fish_population()
|
|
far_fish = res.fish
|
|
|
|
# start fishing in city 1 (can only be done in medium distance fishing grounds)
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(fishery_id, FISHING_DISTANCE_CLOSE, 1, MIN_FISHING_TICKS))
|
|
self.assert_exception(lambda: self.wallet[2].cc_fish(fishery_id, FISHING_DISTANCE_FAR, 1, MIN_FISHING_TICKS))
|
|
res = self.wallet[2].cc_fish(fishery_id, FISHING_DISTANCE_MEDIUM, 1, MIN_FISHING_TICKS)
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_flag(fishery_id)
|
|
assert res.num_fishing_ticks == MIN_FISHING_TICKS
|
|
|
|
for i in range(MIN_FISHING_TICKS):
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# fishing's done
|
|
res = daemon.cc_get_city(1)
|
|
assert res.close_fish >= close_fish
|
|
assert res.medium_fish < medium_fish
|
|
res = daemon.cc_get_far_fish_population()
|
|
assert res.fish >= far_fish
|
|
|
|
def test_merchant_ships(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing merchant ships")
|
|
|
|
expected_balances = [None, None, None, None]
|
|
expected_item_balances = [None, None, None, None]
|
|
account_id = [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
|
|
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_merchant_ship_available_items()
|
|
assert 'items_' not in res or len(res.items_) == 0
|
|
res = daemon.cc_get_merchant_ships()
|
|
assert 'ships' not in res or len(res.ships) == 0
|
|
|
|
# add a custom item with gold
|
|
res = self.wallet[3].cc_new_item(0, "Import", False, False, 0, "", "", gold = 8000, can_create_more = True)
|
|
expected_balances[3] -= res.fee
|
|
expected_balances[3] -= NEW_ITEM_FEE
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
item_id = res.items_[-1].id
|
|
assert item_id
|
|
res = self.wallet[3].cc_set_merchant_ship_items(add = [{'item': item_id, 'amount': 10, 'price': 9000, 'weight': 10, 'recurring': False }], remove = [])
|
|
expected_balances[3] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# and add wood
|
|
res = self.wallet[3].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK, 'amount': 1000, 'price': 500000, 'weight': 1, 'recurring': True }], remove = [])
|
|
expected_balances[3] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# invalid: duplicate item
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK, 'amount': 1001, 'price': 500001, 'weight': 2, 'recurring': True }], remove = []))
|
|
# invalid: wrong account
|
|
self.assert_exception(lambda: self.wallet[2].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK + 1, 'amount': 1000, 'price': 500000, 'weight': 1, 'recurring': True }], remove = []))
|
|
# invalid: bad amount in add
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK + 1, 'amount': 0, 'price': 500000, 'weight': 1, 'recurring': True }], remove = []))
|
|
# invalid: bad price in add
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK + 1, 'amount': 1000, 'price': 0, 'weight': 1, 'recurring': True }], remove = []))
|
|
# invalid: bad weight in add
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK + 1, 'amount': 1000, 'price': 500000, 'weight': 0, 'recurring': True }], remove = []))
|
|
# invalid: dupe in add in add
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [{'item': ITEM_OAK + 1, 'amount': 1000, 'price': 500000, 'weight': 1, 'recurring': True }, {'item': ITEM_OAK + 1, 'amount': 1001, 'price': 500001, 'weight': 2, 'recurring': True }], remove = []))
|
|
# invalid: bad amount in remove
|
|
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(remove = [{'item': ITEM_OAK, 'amount': 0, 'price': 500000, 'weight': 1, 'recurring': True }], add = []))
|
|
# invalid: bad price in remove
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(remove = [{'item': ITEM_OAK, 'amount': 1000, 'price': 0, 'weight': 1, 'recurring': True }], add = []))
|
|
# invalid: bad weight in remove
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(remove = [{'item': ITEM_OAK, 'amount': 1000, 'price': 500000, 'weight': 0, 'recurring': True }], add = []))
|
|
# invalid: dupe in add in remove
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(remove = [{'item': ITEM_OAK, 'amount': 1000, 'price': 500000, 'weight': 1, 'recurring': True }, {'item': ITEM_OAK + 1, 'amount': 1001, 'price': 500001, 'weight': 2, 'recurring': True }], add = []))
|
|
|
|
# invalid: no changes
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [], remove = []))
|
|
# invalid: removes an item not in the current list
|
|
self.assert_exception(lambda: self.wallet[3].cc_set_merchant_ship_items(add = [], remove = [{'item': ITEM_OAK, 'amount': 1000, 'price': 500001, 'weight': 1, 'recurring': True }]))
|
|
|
|
# check we get a sorted list
|
|
res = daemon.cc_get_merchant_ship_available_items()
|
|
assert len(res.items_) == 2
|
|
assert res.items_[0].item == ITEM_OAK
|
|
assert res.items_[0].amount == 1000
|
|
assert res.items_[0].price == 500000
|
|
assert res.items_[0].weight == 1
|
|
assert res.items_[0].recurring
|
|
assert res.items_[1].item == item_id
|
|
assert res.items_[1].amount == 10
|
|
assert res.items_[1].price == 9000
|
|
assert res.items_[1].weight == 10
|
|
assert not res.items_[1].recurring
|
|
|
|
# delete the custom item for now
|
|
res = self.wallet[3].cc_set_merchant_ship_items(remove = [{'item': item_id, 'amount': 10, 'price': 9000, 'weight': 10, 'recurring': False }], add = [])
|
|
expected_balances[3] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_merchant_ship_available_items()
|
|
assert len(res.items_) == 1
|
|
assert res.items_[0].item == ITEM_OAK
|
|
assert res.items_[0].amount == 1000
|
|
assert res.items_[0].price == 500000
|
|
assert res.items_[0].weight == 1
|
|
assert res.items_[0].recurring
|
|
|
|
# rig the game to start the merchant ship event asap
|
|
flag_id = 3
|
|
res = daemon.cc_get_flag(flag_id)
|
|
construction_height = res.construction_height
|
|
res = self.wallet[2].cc_rename_flag(flag_id, old_name = 'test:event:0', new_name = 'test:event:' + str(SPECIAL_EVENT_MERCHANT_SHIP))
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# City treasury should not have any oak yet
|
|
res = daemon.cc_get_account(FIRST_CITY_TREASURY)
|
|
assert 'item_balances' not in res or len(res.item_balances) == 0
|
|
|
|
# no orders for oak yet
|
|
res = daemon.cc_get_order_book(True, True, id = [ITEM_OAK])
|
|
assert 'bids' not in res or len(res.bids) == 0
|
|
assert 'offers' not in res or len(res.offers) == 0
|
|
|
|
# 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]
|
|
|
|
# wait till right before next game update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks - 1)
|
|
|
|
# if there was an event on, it takes two game updates (stop the first one, start the new one)
|
|
res = daemon.cc_get_city(0)
|
|
if res.special_event != SPECIAL_EVENT_NONE:
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', GAME_UPDATE_FREQUENCY)
|
|
|
|
# record state and pass the game update
|
|
state00 = self.get_state()
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state10 = self.remove_used_nonces(self.get_state())
|
|
|
|
# update balances afer game update
|
|
for i in range(4):
|
|
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(FIRST_CITY_TREASURY)
|
|
expected_treasury_balance = res.balance
|
|
expected_treasury_item_balances = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_treasury_item_balances = self.add_item(expected_treasury_item_balances, e.type, e.amount)
|
|
|
|
# a merchant ship has now arrived
|
|
res = daemon.cc_get_city(0)
|
|
assert res.special_event == SPECIAL_EVENT_MERCHANT_SHIP
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
res = daemon.cc_get_merchant_ships()
|
|
ships = [x for x in res.ships if x.city == 0]
|
|
assert len(ships) == 1
|
|
assert ships[0].city == 0
|
|
assert ships[0].height == base_height - 1
|
|
assert ships[0].item == ITEM_OAK
|
|
assert ships[0].amount == 1000
|
|
assert ships[0].price == 500000
|
|
assert len(ships[0].ship_name) > 0
|
|
assert len(ships[0].origin) > 0
|
|
assert ships[0].sold == 0
|
|
|
|
# City treasury should now have the oak it will sell
|
|
res = daemon.cc_get_account(FIRST_CITY_TREASURY)
|
|
assert len(res.item_balances) == 1
|
|
assert res.item_balances[0].type == ITEM_OAK
|
|
assert res.item_balances[0].amount == 1000
|
|
|
|
# there should be offers
|
|
res = daemon.cc_get_order_book(True, True, id = [ITEM_OAK], calculate_matchable = True)
|
|
assert len(res.offers) == MAX_MERCHANT_SHIP_OFFERS
|
|
for offer in res.offers:
|
|
assert not offer.mined
|
|
assert offer.account == FIRST_CITY_TREASURY
|
|
assert offer.type == 1
|
|
assert offer.id == ITEM_OAK
|
|
assert offer.amount == 1000 // MAX_MERCHANT_SHIP_OFFERS
|
|
assert offer.price >= 500000
|
|
assert offer.matchable == offer.amount
|
|
|
|
# the oak is still available for a subsequent ship
|
|
res = daemon.cc_get_merchant_ship_available_items()
|
|
assert len(res.items_) == 1
|
|
assert res.items_[0].item == ITEM_OAK
|
|
assert res.items_[0].amount == 1000
|
|
assert res.items_[0].price == 500000
|
|
assert res.items_[0].weight == 1
|
|
assert res.items_[0].recurring
|
|
|
|
# pop and check the state is restored
|
|
daemon.pop_blocks(1)
|
|
state01 = self.get_state()
|
|
assert state00 == state01, self.get_diff(state00, state01)
|
|
|
|
# orders are gone
|
|
res = daemon.cc_get_order_book(True, True, id = [ITEM_OAK])
|
|
assert 'bids' not in res or len(res.bids) == 0
|
|
assert 'offers' not in res or len(res.offers) == 0
|
|
|
|
# pass the game update again and check the new state is the same as the first time
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state11 = self.remove_used_nonces(self.get_state())
|
|
assert state10 == state11, self.get_diff(state10, state11)
|
|
|
|
# offers should be restored
|
|
res = daemon.cc_get_order_book(True, True, id = [ITEM_OAK], calculate_matchable = True)
|
|
assert len(res.offers) == MAX_MERCHANT_SHIP_OFFERS
|
|
merchant_nonces = []
|
|
merchant_prices = []
|
|
for offer in res.offers:
|
|
assert not offer.mined
|
|
assert offer.account == FIRST_CITY_TREASURY
|
|
assert offer.type == 1
|
|
assert offer.id == ITEM_OAK
|
|
assert offer.amount == 1000 // MAX_MERCHANT_SHIP_OFFERS
|
|
assert offer.price >= 500000
|
|
assert offer.matchable == offer.amount
|
|
merchant_nonces.append(offer.nonce)
|
|
merchant_prices.append(offer.price)
|
|
assert merchant_prices[0] == 500000
|
|
|
|
# someone else cancelling one of these nonces doesn't do a thing
|
|
res = self.wallet[1].cc_cancel_nonces([merchant_nonces[0]])
|
|
expected_balances[1] -= res.fee + NONCE_CANCELLATION_FEE
|
|
expected_treasury_balance += NONCE_CANCELLATION_FEE
|
|
|
|
# buy some
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
res = self.wallet[2].cc_trade_item(True, ITEM_OAK, 25, merchant_prices[0], 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': merchant_nonces[0], 'amount': 25}], cost = merchant_prices[0] * 25)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= 25 * merchant_prices[0]
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_OAK, 25)
|
|
expected_treasury_balance += 25 * merchant_prices[0]
|
|
expected_treasury_item_balances = self.add_item(expected_treasury_item_balances, ITEM_OAK, -25)
|
|
|
|
res = daemon.cc_get_order_book(True, True, id = [ITEM_OAK], calculate_matchable = True)
|
|
assert len(res.offers) == MAX_MERCHANT_SHIP_OFFERS
|
|
for offer in res.offers:
|
|
assert offer.mined if offer.nonce == merchant_nonces[0] else not offer.mined
|
|
assert offer.account == FIRST_CITY_TREASURY
|
|
assert offer.type == 1
|
|
assert offer.id == ITEM_OAK
|
|
assert offer.amount == 1000 // MAX_MERCHANT_SHIP_OFFERS
|
|
assert offer.price >= 500000
|
|
if offer.price == merchant_prices[0]:
|
|
assert offer.matchable == offer.amount - 25
|
|
else:
|
|
assert offer.matchable == offer.amount
|
|
|
|
# buy the rest of the first offer, plus part of the second one
|
|
cost = merchant_prices[0] * 100 + merchant_prices[1] * 50
|
|
res = self.wallet[2].cc_trade_item(True, ITEM_OAK, 150, 1000000, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': merchant_nonces[0], 'amount': 100}, {'nonce': merchant_nonces[1], 'amount': 50}], cost = cost)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= cost
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_OAK, 150)
|
|
expected_treasury_balance += cost
|
|
expected_treasury_item_balances = self.add_item(expected_treasury_item_balances, ITEM_OAK, -150)
|
|
|
|
# check the sold quantity is updated
|
|
res = daemon.cc_get_merchant_ships()
|
|
ships = [x for x in res.ships if x.city == 0]
|
|
assert len(ships) == 1
|
|
assert ships[0].sold == 175
|
|
|
|
# buy the rest to bring the event to a close
|
|
res = daemon.cc_get_order_book(True, True, id = [ITEM_OAK], calculate_matchable = True)
|
|
assert len(res.offers) == MAX_MERCHANT_SHIP_OFFERS - 1
|
|
offers = res.offers
|
|
matches = []
|
|
cost = 0
|
|
for i in range(MAX_MERCHANT_SHIP_OFFERS - 1):
|
|
e = offers[i]
|
|
matches.append({'nonce': merchant_nonces[i + 1], 'amount': e.matchable})
|
|
cost += e.matchable * e.price
|
|
res = self.wallet[2].cc_trade_item(True, ITEM_OAK, 825, 10000000, 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = matches, cost = cost)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= cost
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], ITEM_OAK, 825)
|
|
expected_treasury_balance += cost
|
|
expected_treasury_item_balances = self.add_item(expected_treasury_item_balances, ITEM_OAK, -825)
|
|
|
|
# check the sold quantity is updated
|
|
res = daemon.cc_get_merchant_ships()
|
|
ships = [x for x in res.ships if x.city == 0]
|
|
assert len(ships) == 1
|
|
assert ships[0].sold == 1000
|
|
|
|
# the treasury has no oak left
|
|
res = daemon.cc_get_account(FIRST_CITY_TREASURY)
|
|
assert 'item_balances' not in res or len(res.item_balances) == 0
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i], "wallet " + str(i) + ": expected " + str(expected_balances[i]) + ", got " + str(res.balance)
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
res = daemon.cc_get_account(FIRST_CITY_TREASURY)
|
|
assert res.balance == expected_treasury_balance
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_treasury_item_balances
|
|
|
|
# wait till right before next game update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks - 1)
|
|
|
|
# the ship is still around
|
|
res = daemon.cc_get_merchant_ships()
|
|
ships = [x for x in res.ships if x.city == 0]
|
|
assert len(ships) == 1
|
|
assert ships[0].sold == 1000
|
|
res = daemon.cc_get_city(0)
|
|
assert res.special_event == SPECIAL_EVENT_MERCHANT_SHIP
|
|
|
|
# record state and pass the game update
|
|
state00 = self.get_state()
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state10 = self.remove_used_nonces(self.get_state())
|
|
|
|
# the ship is now gone
|
|
res = daemon.cc_get_merchant_ships()
|
|
assert 'ships' not in res or len([x for x in res.ships if x.city == 0]) == 0
|
|
res = daemon.cc_get_city(0)
|
|
assert res.special_event == SPECIAL_EVENT_NONE
|
|
|
|
# pop and check the state is restored
|
|
daemon.pop_blocks(1)
|
|
state01 = self.get_state()
|
|
assert state00 == state01, self.get_diff(state00, state01)
|
|
|
|
# pass the game update again and check the new state is the same as the first time
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state11 = self.remove_used_nonces(self.get_state())
|
|
assert state10 == state11, self.get_diff(state10, state11)
|
|
|
|
# the oak was recurring
|
|
res = daemon.cc_get_merchant_ship_available_items()
|
|
assert len(res.items_) == 1
|
|
assert res.items_[0].item == ITEM_OAK
|
|
assert res.items_[0].amount == 1000
|
|
assert res.items_[0].price == 500000
|
|
assert res.items_[0].weight == 1
|
|
assert res.items_[0].recurring
|
|
|
|
# we replace the oak with a custom item with gold
|
|
res = self.wallet[3].cc_set_merchant_ship_items(add = [{'item': item_id, 'amount': 3, 'price': 9000, 'weight': 10, 'recurring': False }], remove = [{'item': ITEM_OAK, 'amount': 1000, 'price': 500000, 'weight': 1, 'recurring': True }])
|
|
expected_balances[3] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_merchant_ship_available_items()
|
|
assert len(res.items_) == 1
|
|
assert res.items_[0].item == item_id
|
|
assert res.items_[0].amount == 3
|
|
assert res.items_[0].price == 9000
|
|
assert res.items_[0].weight == 10
|
|
assert not res.items_[0].recurring
|
|
|
|
# pass next update
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks)
|
|
|
|
# a merchant ship has now arrived
|
|
res = daemon.cc_get_city(0)
|
|
assert res.special_event == SPECIAL_EVENT_MERCHANT_SHIP
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
res = daemon.cc_get_merchant_ships()
|
|
ships = [x for x in res.ships if x.city == 0]
|
|
assert len(ships) == 1
|
|
assert ships[0].city == 0
|
|
assert ships[0].height == base_height - 1
|
|
assert ships[0].item == item_id
|
|
assert ships[0].amount == 3
|
|
assert ships[0].price == 9000
|
|
assert len(ships[0].ship_name) > 0
|
|
assert len(ships[0].origin) > 0
|
|
assert ships[0].sold == 0
|
|
|
|
# update balances afer game update
|
|
for i in range(4):
|
|
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(FIRST_CITY_TREASURY)
|
|
expected_treasury_balance = res.balance
|
|
expected_treasury_item_balances = []
|
|
if 'item_balances' in res:
|
|
for e in res.item_balances:
|
|
expected_treasury_item_balances = self.add_item(expected_treasury_item_balances, e.type, e.amount)
|
|
|
|
# buy one
|
|
# offers should be restored
|
|
res = daemon.cc_get_order_book(True, True, id = [item_id])
|
|
assert len(res.offers) == 3
|
|
merchant_nonces = []
|
|
merchant_prices = []
|
|
for offer in res.offers:
|
|
assert not offer.mined
|
|
assert offer.account == FIRST_CITY_TREASURY
|
|
assert offer.type == 1
|
|
assert offer.id == item_id
|
|
assert offer.amount == 1
|
|
assert offer.price > 9000
|
|
merchant_nonces.append(offer.nonce)
|
|
merchant_prices.append(offer.price)
|
|
|
|
res = daemon.get_height()
|
|
base_height = res.height
|
|
res = self.wallet[2].cc_trade_item(True, item_id, 1, merchant_prices[0], 0, 0, 0, base_height + MIN_TRADE_EXPIRATION + 1000, matches = [{'nonce': merchant_nonces[0], 'amount': 1}], cost = merchant_prices[0] * 1)
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
expected_balances[2] -= 1 * merchant_prices[0]
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], item_id, 1)
|
|
expected_treasury_balance += 1 * merchant_prices[0]
|
|
expected_treasury_item_balances = self.add_item(expected_treasury_item_balances, item_id, -1)
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i], "wallet " + str(i) + ": expected " + str(expected_balances[i]) + ", got " + str(res.balance)
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
res = daemon.cc_get_account(FIRST_CITY_TREASURY)
|
|
assert res.balance == expected_treasury_balance
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_treasury_item_balances
|
|
|
|
# restore flag name now, since there won't be any available items anymore, so we don't want to force a ship without item
|
|
# in another city while we wait
|
|
res = self.wallet[2].cc_rename_flag(flag_id, old_name = 'test:event:' + str(SPECIAL_EVENT_MERCHANT_SHIP), new_name = 'test:event:0')
|
|
expected_balances[2] -= res.fee
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# wait till the ship leaves on its own
|
|
while True:
|
|
res = daemon.get_info()
|
|
height = res.height
|
|
blocks = (GAME_UPDATE_FREQUENCY * 8000 - height) % GAME_UPDATE_FREQUENCY + 1
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', blocks - 1)
|
|
state00 = self.get_state()
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_city(0)
|
|
if res.special_event != SPECIAL_EVENT_MERCHANT_SHIP:
|
|
break
|
|
|
|
state10 = self.remove_used_nonces(self.get_state())
|
|
|
|
# the ship's gone
|
|
res = daemon.cc_get_merchant_ships()
|
|
assert 'ships' not in res or len([x for x in res.ships if x.city == 0]) == 0
|
|
|
|
# the non recurring item won't be in any more ship
|
|
res = daemon.cc_get_merchant_ship_available_items()
|
|
assert 'items_' not in res or len(res.items_) == 0
|
|
|
|
# pop and check the state is restored
|
|
daemon.pop_blocks(1)
|
|
state01 = self.get_state()
|
|
assert state00 == state01, self.get_diff(state00, state01)
|
|
|
|
# pass the game update again and check the new state is the same as the first time
|
|
self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
state11 = self.remove_used_nonces(self.get_state())
|
|
assert state10 == state11, self.get_diff(state10, state11)
|
|
|
|
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[1].cc_get_info()
|
|
account1_id = res.account_id
|
|
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, owner = GAME_ACCOUNT))
|
|
|
|
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, owner = GAME_ACCOUNT)
|
|
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 = account2_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 { reserves { player gold 0.00001 } 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, owner = GAME_ACCOUNT))
|
|
|
|
res = self.wallet[3].cc_set_script_variables([{'name': 'allow', 'old_value': 0, 'new_value': 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, owner = GAME_ACCOUNT))
|
|
|
|
self.wallet[3].cc_enable_script(script_id, True)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
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
|
|
|
|
# end the script
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 2, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# check reserves are back to their original state
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert 'reserve' not in res
|
|
|
|
print('Testing script reserves')
|
|
script = """
|
|
script {
|
|
name "choice reserves test"
|
|
reserves {
|
|
owner gold 1.0
|
|
player gold 2.0
|
|
}
|
|
state "0" {
|
|
choice { text "end" }
|
|
choice { reserves { player gold 0.1 } text "1" next state "0" }
|
|
choice { reserves { owner gold 0.1 } text "2" next state "0" }
|
|
choice { reserves { player item 256 1 } text "3" next state "0" }
|
|
choice { reserves { owner item 256 1 } text "4" next state "0" }
|
|
choice { reserves { player gold 50000.0 } text "5" next state "0" }
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': 10}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
res = self.wallet[2].cc_give(res.public_key, [{'type': ITEM_LABOUR, 'amount': 5}])
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
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
|
|
|
|
# check start player reserves
|
|
reserve = res.reserve
|
|
assert len(reserve) == 1
|
|
reserve = reserve[0]
|
|
assert reserve.account == GAME_ACCOUNT
|
|
assert reserve.balance == 200000000
|
|
assert 'items' not in reserve or len(reserve.items) == 0
|
|
player_256 = [x.amount for x in res.item_balances if x.type == 256][0]
|
|
|
|
# check start owner reserves
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert 'reserve' in res
|
|
reserve = res.reserve
|
|
assert len(reserve) == 1
|
|
reserve = reserve[0]
|
|
assert reserve.account == account2_id
|
|
assert reserve.balance == 100000000
|
|
assert 'items' not in reserve or len(reserve.items) == 0
|
|
game_256 = [x.amount for x in res.item_balances if x.type == 256][0]
|
|
|
|
# loop a bit and check reserves are updated
|
|
for i in [1, 4, 1, 1, 2, 3, 1, 2, 4, 4]:
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = i)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# check start player reserves
|
|
res = daemon.cc_get_account(account2_id)
|
|
reserve = res.reserve
|
|
assert len(reserve) == 1
|
|
reserve = reserve[0]
|
|
assert reserve.account == GAME_ACCOUNT
|
|
assert reserve.balance == 240000000
|
|
assert len(reserve.items_) == 1
|
|
assert reserve.items_[0].type == 256
|
|
assert reserve.items_[0].amount == 1
|
|
|
|
# check start owner reserves
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert 'reserve' in res
|
|
reserve = res.reserve
|
|
assert len(reserve) == 1
|
|
reserve = reserve[0]
|
|
assert reserve.account == account2_id
|
|
assert reserve.balance == 120000000
|
|
assert len(reserve.items_) == 1
|
|
assert reserve.items_[0].type == 256
|
|
assert reserve.items_[0].amount == 3
|
|
|
|
# choice 5 reserves too much
|
|
self.assert_exception(lambda: self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 5))
|
|
|
|
# end the script
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# check reserves are back to their original state
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == 0
|
|
assert 'reserve' not in res
|
|
assert player_256 == [x.amount for x in res.item_balances if x.type == 256][0]
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert res.script == 0
|
|
assert 'reserve' not in res
|
|
assert game_256 == [x.amount for x in res.item_balances if x.type == 256][0]
|
|
|
|
print('Testing if/else in scripts')
|
|
script = """
|
|
script {
|
|
name "if/else test"
|
|
state "0" {
|
|
choice { text "end" }
|
|
choice { text "1" actions { if (local "x" == 1) { set local "z" 1 } else { set local "z" 2 } } next state "0" }
|
|
choice { text "2" actions { set local "x" 1 } next state "0" }
|
|
choice { text "3" actions { set local "x" 2 } next state "0" }
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == script_id
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script_local_variables[0] == { 'name': 'z', 'value': 2}
|
|
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 2)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script_local_variables[0] == { 'name': 'z', 'value': 1} or res.script_local_variables[1] == { 'name': 'z', 'value': 1}
|
|
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 3)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script_local_variables[0] == { 'name': 'z', 'value': 2} or res.script_local_variables[1] == { 'name': 'z', 'value': 2}
|
|
|
|
# end the script
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == 0
|
|
|
|
print('Testing operator precedence in scripts')
|
|
script = """
|
|
script {
|
|
name "operator precedence test"
|
|
state "0" {
|
|
init {
|
|
set local "prec" 6 * 4 - 3 + 6 * 7 / 2 + 18 # 60
|
|
}
|
|
choice {
|
|
text "end"
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert [x.value for x in res.script_local_variables if x.name == "prec"] == [60]
|
|
|
|
# end the script
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == 0
|
|
|
|
print('Testing script procedures')
|
|
script = """
|
|
script {
|
|
name "procedure test"
|
|
procedure "B" {
|
|
if (local "x" > 10) { set local "y" 19 }
|
|
}
|
|
procedure "A" {
|
|
set local "x" 18
|
|
call "B"
|
|
}
|
|
state "0" {
|
|
init { call "A" }
|
|
choice { text "end" }
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert [x.value for x in res.script_local_variables if x.name == "y"] == [19]
|
|
|
|
# end the script
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == 0
|
|
|
|
print('Testing awarding badge from script')
|
|
script = """
|
|
script {
|
|
name "actions"
|
|
state "0" {
|
|
choice { text "end" }
|
|
choice { text "1" actions { award badge global "scripted-badge" 1 } next state "0" }
|
|
choice { text "2" actions { award badge global "scripted-badge" 2 } next state "0" }
|
|
choice { text "3" actions { award badge global "scripted-badge" 3 } next state "0" }
|
|
choice { text "4" actions { award badge global "scripted-badge" 4 } next state "0" }
|
|
choice { text "5" actions { award badge global "scripted-badge" 4 award badge global "scripted-badge" 5 } next state "0" }
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# create the test badge
|
|
def make_thresholds(n):
|
|
thresholds = []
|
|
for i in range(n):
|
|
thresholds += [{'value': i + 1, 'text': ''}]
|
|
return thresholds
|
|
self.wallet[3].cc_event_badge(0, "scripted badge", "", "", make_thresholds(5), [])
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_badge([])
|
|
badge_id = res.badges[-1].id
|
|
res = self.wallet[3].cc_set_script_variables([{'name': 'scripted-badge', 'old_value': 0, 'new_value': badge_id}])
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# start the script
|
|
res = self.wallet[2].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# we don't have that badge yet
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert [x for x in res.badges if x.type == badge_id] == []
|
|
|
|
# get level 2, then level 1, then 2, only the first one does anything
|
|
expected_level = 0
|
|
expected_height = 0
|
|
for choice in [2, 1, 2, 5, 5, 1]:
|
|
if choice > expected_level:
|
|
expected_level = choice
|
|
expected_height = daemon.get_height().height
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = choice)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# we now have the badge
|
|
res = daemon.cc_get_account(account2_id)
|
|
x = [x for x in res.badges if x.type == badge_id]
|
|
assert len(x) == 1
|
|
assert x[0].level == expected_level
|
|
assert x[0].timestamp == expected_height
|
|
|
|
# end the script
|
|
res = self.wallet[2].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == 0
|
|
|
|
print('Testing script blob reuse')
|
|
script = """
|
|
script {
|
|
name "blob reuse"
|
|
icon "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
state "0" {
|
|
choice { text "end" }
|
|
}
|
|
}
|
|
"""
|
|
|
|
script_id = [None, None]
|
|
for i in range(2):
|
|
self.wallet[3].cc_create_script(source = script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
script_id[i] = res.scripts[-1].index
|
|
|
|
res = daemon.cc_get_script(script_id[i])
|
|
assert res.icon == "x" * 64
|
|
|
|
hash_of_64x = "d6e3c0c71a86a2ea06c7e3bfc96f22b8ce28132d61b3d3629ad0d85dab663746"
|
|
res = daemon.cc_get_blob(hash_of_64x)
|
|
assert res.blob == "78" * 64 # hex encoded as blobs are likely binary
|
|
assert res.refs == 1 + i
|
|
|
|
assert script_id[1] == script_id[0] + 1
|
|
|
|
print('Testing create items in scripts')
|
|
script = """
|
|
script {
|
|
name "item creation"
|
|
public
|
|
reserves { owner gold 6000 }
|
|
state "0" {
|
|
choice { text "end" }
|
|
choice { text "1" actions { create item ITEM 3 award item ITEM 2 } next state "0"}
|
|
}
|
|
}
|
|
"""
|
|
|
|
expected_balances = [None, None, None, None]
|
|
expected_item_balances = [None, None, None, None]
|
|
account_id = [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
|
|
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)
|
|
|
|
# create a suitable item
|
|
item_gold_content = 2000
|
|
res = self.wallet[2].cc_new_item(0, "Script item", False, False, 0, "primary desc", "secondary desc", can_create_more = True, gold = item_gold_content)
|
|
expected_balances[2] -= res.fee
|
|
expected_balances[2] -= NEW_ITEM_FEE
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_custom_items()
|
|
item = res.items_[-1]
|
|
assert item.can_create_more
|
|
item_id = item.id
|
|
assert item_id >= ITEM_FIRST_USER and item_id <= ITEM_LAST_USER
|
|
|
|
# create the script
|
|
res = self.wallet[3].cc_create_script(source = script.replace("ITEM", str(item_id)))
|
|
expected_balances[3] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts(all = True)
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# create a runestone with that script - we already have a suitable runestone
|
|
flag_id = 3
|
|
res = self.wallet[2].cc_carve_runestone(flag_id, 2, 4, 1, "bar", "bar", script_id - 0)
|
|
expected_balances[2] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# nobody has any of that item yet
|
|
for aid in [account1_id, account2_id]:
|
|
res = daemon.cc_get_account(aid)
|
|
for e in res.item_balances:
|
|
assert e['type'] != item_id or e['amount'] == 0
|
|
res = daemon.cc_get_item_count([item_id])
|
|
assert res.counts == [0]
|
|
|
|
# start the script
|
|
res = self.wallet[1].cc_start_script(script_id, city = 0, owner = account2_id, flag = flag_id, x = 2, y = 4, h = 1)
|
|
expected_balances[1] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account1_id)
|
|
assert res.script == script_id
|
|
assert res.script_city == 0
|
|
assert res.script_owner == account2_id
|
|
assert res.script_state == 0
|
|
|
|
res = self.wallet[1].cc_script_choice(script_id, state = 0, city = 0, owner = account2_id, choice = 1)
|
|
expected_balances[1] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# 3 were created, and 2 awarded, still in reserve
|
|
for aid in [account1_id, account2_id]:
|
|
res = daemon.cc_get_account(aid)
|
|
for e in res.item_balances:
|
|
assert e['type'] != item_id or e['amount'] == 0
|
|
res = daemon.cc_get_item_count([item_id])
|
|
assert res.counts == [3]
|
|
|
|
res = self.wallet[1].cc_script_choice(script_id, state = 0, city = 0, owner = account2_id, choice = 0)
|
|
expected_balances[1] -= res.fee
|
|
expected_balances[2] -= 3 * 2000
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], item_id, 2)
|
|
expected_item_balances[2] = self.add_item(expected_item_balances[2], item_id, 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# the script has ended
|
|
res = daemon.cc_get_account(account1_id)
|
|
assert res.script == 0
|
|
|
|
# now in inventories
|
|
matches = 0
|
|
for aid in [account1_id, account2_id]:
|
|
res = daemon.cc_get_account(aid)
|
|
for e in res.item_balances:
|
|
if e['type'] == item_id:
|
|
if aid == account1_id and e['amount'] == 2:
|
|
matches = matches + 1
|
|
if aid == account2_id and e['amount'] == 1:
|
|
matches = matches + 1
|
|
assert matches == 2
|
|
res = daemon.cc_get_item_count([item_id])
|
|
assert res.counts == [3]
|
|
|
|
# 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]
|
|
|
|
# consuming an item with gold should return the gold minus any relevant fees
|
|
print('Testing consuming items with gold in scripts')
|
|
script = """
|
|
script {
|
|
name "smelting"
|
|
reserves { player item ITEM 2 player item COIN 1 }
|
|
state "0" {
|
|
choice { text "end" }
|
|
choice { text "1" actions { consume item ITEM 2 consume item COIN 1 } next state "0"}
|
|
}
|
|
}
|
|
"""
|
|
|
|
coin_id = COIN_ITEM_SETTLEMENT
|
|
gold_content = get_gold_content(collectible_coin_type_event)
|
|
res = self.wallet[1].cc_deposit(amount = gold_content)
|
|
self.deposits += gold_content
|
|
expected_balances[1] += gold_content
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
res = self.wallet[1].cc_mint(coin_id, 1)
|
|
expected_balances[1] -= res.fee + gold_content + COIN_MINTING_FEE
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], coin_id, 1)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i], "exp " + str(expected_balances[i]) + ', got ' + str(res.balance)
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
# create the script
|
|
res = daemon.cc_get_account(account_id[1])
|
|
res = self.wallet[3].cc_create_script(source = script.replace("ITEM", str(item_id)).replace("COIN", str(coin_id)))
|
|
expected_balances[3] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts(all = True)
|
|
assert len(res.scripts) > 1
|
|
script_id = res.scripts[-1].index
|
|
|
|
# start the script
|
|
res = self.wallet[1].cc_start_script(script_id, city = 0, owner = GAME_ACCOUNT)
|
|
expected_balances[1] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_account(account1_id)
|
|
assert res.script == script_id
|
|
assert res.script_city == 0
|
|
assert res.script_owner == GAME_ACCOUNT
|
|
assert res.script_state == 0
|
|
|
|
res = self.wallet[1].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 1)
|
|
expected_balances[1] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = self.wallet[1].cc_script_choice(script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
expected_balances[1] -= res.fee
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# the gold goes to the script owner
|
|
expected_balances[3] += gold_content
|
|
res = daemon.cc_get_custom_items([item_id])
|
|
assert len(res.items_) == 1
|
|
expected_balances[3] += 2 * res.items_[0].gold
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], item_id, -2)
|
|
expected_item_balances[1] = self.add_item(expected_item_balances[1], coin_id, -1)
|
|
|
|
# the script has ended
|
|
res = daemon.cc_get_account(account1_id)
|
|
assert res.script == 0
|
|
|
|
# check balances
|
|
for i in range(4):
|
|
res = daemon.cc_get_account(account_id[i])
|
|
assert res.balance == expected_balances[i], "exp " + str(expected_balances[i]) + ', got ' + str(res.balance) + " for wallet " + str(i)
|
|
assert (res.item_balances if 'item_balances' in res else []) == expected_item_balances[i]
|
|
|
|
def test_background_scripts(self):
|
|
daemon = self.daemon
|
|
|
|
print("Testing background scripts")
|
|
background_script = """
|
|
script {
|
|
name "background script"
|
|
reserves {
|
|
player gold 1.0
|
|
owner gold 1.0
|
|
}
|
|
state "0" {
|
|
choice {
|
|
enabled local "x" < 2
|
|
text "0"
|
|
next state "0"
|
|
actions {
|
|
set local "x" local "x" + 1
|
|
}
|
|
}
|
|
choice { enabled local "x" >= 2 text "1" next state "1" actions { set local "y" 10 } }
|
|
}
|
|
state "1" {
|
|
choice { text "done" }
|
|
}
|
|
}
|
|
"""
|
|
|
|
self.wallet[3].cc_create_script(source = background_script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
background_script_id = res.scripts[-1].index
|
|
|
|
# make a copy so it can run twice in parallel
|
|
self.wallet[3].cc_create_script(source = background_script)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
background_script_id2 = res.scripts[-1].index
|
|
|
|
starter_script_base = """
|
|
script {
|
|
name "background script starter"
|
|
state "0" {
|
|
choice { text "start" actions { start background script SCRIPT } }
|
|
}
|
|
}
|
|
"""
|
|
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
res = self.wallet[2].cc_transfer(res.public_key, amount = 200000000)
|
|
self.generate_blocks('TF1MM8HqWBathu8hS5mwMNHm1da3cZCzg2rkqWLKCxpUarKtPszP3MjiocrJeLvph4AghgYu1AXonCmckfEuyE8Q2FFm8jNdiz3', 1)
|
|
|
|
self.wallet[3].cc_create_script(source = starter_script_base.replace("SCRIPT", str(background_script_id)))
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
starter_script_id = res.scripts[-1].index
|
|
|
|
self.wallet[3].cc_create_script(source = starter_script_base.replace("SCRIPT", str(background_script_id2)))
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.cc_get_scripts()
|
|
assert len(res.scripts) > 1
|
|
starter_script_id2 = res.scripts[-1].index
|
|
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert res.script == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
assert 'background_script_states' not in res or len(res.background_script_states) == 0
|
|
|
|
# let a player run the starter script, which will trigger the background script when used
|
|
res = self.wallet[2].cc_start_script(starter_script_id, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
res = self.wallet[2].cc_get_info()
|
|
account2_id = res.account_id
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == starter_script_id
|
|
|
|
# still nothing
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert res.script == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
assert 'background_script_states' not in res or len(res.background_script_states) == 0
|
|
|
|
res = self.wallet[2].cc_script_choice(starter_script_id, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
|
|
# game now has the background script going
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert res.script == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
assert 'background_script_states' in res
|
|
assert len(res.background_script_states) == 1
|
|
tst = res.background_script_states[0]
|
|
assert tst.script == background_script_id
|
|
assert tst.state == 0
|
|
assert tst.city == 0
|
|
assert tst.owner == GAME_ACCOUNT
|
|
assert 'variables' not in tst or len(tst.variables) == 0
|
|
|
|
# player and owner are both the game, reserves accumulate
|
|
assert len(res.reserve) == 1
|
|
assert res.reserve[0].account == GAME_ACCOUNT
|
|
assert res.reserve[0].balance == 200000000
|
|
assert 'item_balances' not in res.reserve[0] or len(res.reserve[0].item_balances) == 0
|
|
|
|
# the player script has ended
|
|
res = daemon.cc_get_account(account2_id)
|
|
assert res.script == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
assert 'background_script_states' not in res or len(res.background_script_states) == 0
|
|
|
|
# get past three game updates, x gets incremented to 1 then 2 (still in state 0), then goes to state 1, with y at 10 and x still at 2
|
|
# then a fourth one as the second script copy is one tick late
|
|
for i in range(4):
|
|
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_account(GAME_ACCOUNT)
|
|
assert res.script == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
assert 'background_script_states' in res
|
|
assert len(res.background_script_states) == 1 if i in [0, 3] else 2
|
|
|
|
if i == 3:
|
|
continue
|
|
|
|
tst = res.background_script_states[0]
|
|
if tst.script == background_script_id2:
|
|
tst = res.background_script_states[1]
|
|
assert tst.script == background_script_id
|
|
assert tst.state == 0 if i < 2 else 1
|
|
assert tst.city == 0
|
|
assert tst.owner == GAME_ACCOUNT
|
|
assert len(tst.variables) == (2 if i == 2 else 1)
|
|
assert tst.variables[0].name == "x"
|
|
assert tst.variables[0].value == min(1 + i, 2)
|
|
if i == 2:
|
|
assert tst.variables[1].name == "y"
|
|
assert tst.variables[1].value == 10
|
|
|
|
# start a copy of the sript in parallel
|
|
if i == 0:
|
|
# let a player run the starter script, which will trigger the background script when used
|
|
res = self.wallet[2].cc_start_script(starter_script_id2, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_script_choice(starter_script_id2, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or len(res.tx_hashes) == 0
|
|
|
|
if i == 1 or i == 2:
|
|
# player and owner are both the game, reserves accumulate
|
|
res = daemon.cc_get_account(GAME_ACCOUNT)
|
|
assert len(res.reserve) == 1
|
|
assert res.reserve[0].account == GAME_ACCOUNT
|
|
assert res.reserve[0].balance == 200000000 * 2
|
|
assert 'item_balances' not in res.reserve[0] or len(res.reserve[0].item_balances) == 0
|
|
|
|
# start it again - it'll be accepted, but not mined
|
|
res = self.wallet[2].cc_start_script(starter_script_id2, city = 0, owner = GAME_ACCOUNT)
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = self.wallet[2].cc_script_choice(starter_script_id2, state = 0, city = 0, owner = GAME_ACCOUNT, choice = 0)
|
|
txid = res.tx_hash
|
|
res = self.generate_blocks('TF1MMBg4zx18SnZC6oswCRB7DzdVeUKce5NdCMSWUHNY4wNvNhzmFj4WqZY2bFj8R1REAWR3qAH5zD7sjXyHz3tVayzHSswqymx', 1)
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert txid in res.tx_hashes
|
|
daemon.flush_txpool([txid])
|
|
res = daemon.get_transaction_pool_hashes()
|
|
assert 'tx_hashes' not in res or len(res.tx_hashes) == 0
|
|
|
|
# get past another game update and the script ends
|
|
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_account(GAME_ACCOUNT)
|
|
assert res.script == 0
|
|
assert res.script_city == 0
|
|
assert res.script_owner == 0
|
|
assert res.script_state == 0
|
|
assert 'script_local_variables' not in res or len(res.script_local_variables) == 0
|
|
assert 'background_script_states' not in res
|
|
|
|
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))
|
|
assert gold_content == res2.items_[0].gold
|
|
gold_balance_in_coins += e['amount'] * gold_content
|
|
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, "game", "treasury", "foreclosure"]:
|
|
try:
|
|
if i == "game":
|
|
account_id = GAME_ACCOUNT
|
|
elif i == "treasury":
|
|
res = daemon.cc_get_city(0)
|
|
account_id = res.treasury
|
|
elif i == "foreclosure":
|
|
account_id = FORECLOSURE_ACCOUNT
|
|
else:
|
|
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
|
|
if 'events' in res:
|
|
for e in res.events:
|
|
event_balance += e.balance
|
|
event_balance -= e.tx_fee
|
|
if balance != event_balance:
|
|
name = i if type(i) == type("") else ("wallet " + str(i))
|
|
print('Event balance does not match actual balance for account ' + str(account_id) + ' (' + name + ')')
|
|
print('balance: ' + str(balance))
|
|
print('event_balance: ' + str(event_balance))
|
|
print('difference: ' + str(balance - 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, "Ownership does not agree with totals for item " + str(item) + ": " + str(res.supply) + " vs " + str(total) + ", ownership: " + str(res.ownership)
|
|
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)
|
|
|
|
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)
|
|
|
|
# temporarily use second daemon
|
|
self.wallet[2].set_daemon('127.0.0.1:18183')
|
|
self.wallet[2].rescan_blockchain()
|
|
|
|
# mine
|
|
print('Mining on second daemon')
|
|
n_mined = 0
|
|
for i in range(1, GAME_UPDATE_FREQUENCY // 20 + 5):
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': HUNT_LABOUR_COST}])
|
|
res = second_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 1)
|
|
res = daemon.cc_get_city(0)
|
|
population = res.moose if int(i % 2) == 0 else res.bears
|
|
self.wallet[2].cc_hunt(target = int(i % 2), city = 0)
|
|
n_mined += 20
|
|
res = second_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 19)
|
|
|
|
# back to previous daemon
|
|
self.wallet[2].set_daemon('127.0.0.1:18182')
|
|
self.wallet[2].rescan_blockchain()
|
|
|
|
# reconnect daemons 1 and 2
|
|
daemon.out_peers(8)
|
|
daemon.in_peers(8)
|
|
second_daemon.out_peers(8)
|
|
second_daemon.in_peers(8)
|
|
|
|
# wait till the first daemon is synced
|
|
print('Waiting for sync 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)
|
|
|
|
# temporarily use third daemon
|
|
self.wallet[2].set_daemon('127.0.0.1:18184')
|
|
self.wallet[2].rescan_blockchain()
|
|
|
|
# mine on the third daemon, which still has the original chain
|
|
print('Mining another chain on third daemon')
|
|
n_mined_third = 0
|
|
while n_mined_third < n_mined:
|
|
res = self.wallet[2].cc_buy_items(entries = [{'type': ITEM_LABOUR, 'amount': HUNT_LABOUR_COST}])
|
|
res = second_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 1)
|
|
res = third_daemon.cc_get_city(0)
|
|
population = res.moose if int(i % 2) == 0 else res.bears
|
|
self.wallet[2].cc_hunt(target = int(i % 2), city = 0)
|
|
res = third_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 99)
|
|
n_mined_third += 100
|
|
res = third_daemon.generateblocks('TF1MMEY5v2dN49XKNCKCdBqmTMM6GdZZA5UBbDgTewaUd3c2jDazN5yKrG1BBHX3UyPqKD9hrh3DpPTDmWiCmsuRpePT1MTaPxm', 100)
|
|
res = third_daemon.get_info()
|
|
cumulative_difficulty = res.cumulative_difficulty
|
|
|
|
# back to previous daemon
|
|
self.wallet[2].set_daemon('127.0.0.1:18182')
|
|
self.wallet[2].rescan_blockchain()
|
|
|
|
state0 = get_daemon_state(third_daemon)
|
|
|
|
# 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 = get_daemon_state(daemon)
|
|
|
|
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()
|